/*
* Copyright 2010-2012, CloudBees Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloudbees.api.util;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.bio.SocketConnector;
import org.mortbay.jetty.security.B64Code;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.proxy.AsyncProxyServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
/**
* @author Olivier Lamy
*/
public class ProxyServer {
private Server proxyServer;
/**
* @param proxyServlet the wanted auth proxy servlet
*/
public ProxyServer(AuthAsyncProxyServlet proxyServlet) {
this("localhost", 0, proxyServlet);
}
/**
* @param hostName the server name
* @param port the server port
* @param proxyServlet the wanted auth proxy servlet
*/
public ProxyServer(String hostName, int port, AuthAsyncProxyServlet proxyServlet) {
proxyServer = new Server();
proxyServer.addConnector(getDefaultConnector(hostName, port));
Context context = new Context(proxyServer, "/", 0);
context.addServlet(new ServletHolder(proxyServlet), "/");
}
/**
* @return the host name
*/
public String getHostName() {
Connector connector = proxyServer.getConnectors()[0];
return connector.getHost();
}
/**
* @return the host port
*/
public int getPort() {
Connector connector = proxyServer.getConnectors()[0];
return (connector.getLocalPort() <= 0 ? connector.getPort() : connector.getLocalPort());
}
public void start() throws Exception {
proxyServer.start();
}
public void stop() throws Exception {
proxyServer.stop();
}
private Connector getDefaultConnector(String hostName, int port) {
Connector connector = new SocketConnector();
if (hostName != null) {
connector.setHost(hostName);
} else {
try {
connector.setHost(InetAddress.getLocalHost().getCanonicalHostName());
} catch (UnknownHostException e) {
// nop
}
}
if (port > 0) {
connector.setPort(port);
}
return connector;
}
public static class AuthAsyncProxyServlet
extends AsyncProxyServlet {
private Map<String, String> authentications;
private long sleepTime = 0;
public long requestsReceived = 0;
/**
* Constructor for non authentication servlet.
*/
public AuthAsyncProxyServlet() {
super();
}
public AuthAsyncProxyServlet(Map<String, String> authentications) {
this();
this.authentications = authentications;
}
public AuthAsyncProxyServlet(Map<String, String> authentications, long sleepTime) {
this();
this.authentications = authentications;
this.sleepTime = sleepTime;
}
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
requestsReceived++;
if (this.authentications != null && !this.authentications.isEmpty()) {
String proxyAuthorization = request.getHeader("Proxy-Authorization");
if (proxyAuthorization != null && proxyAuthorization.startsWith("Basic ")) {
String proxyAuth = proxyAuthorization.substring(6);
String authorization = B64Code.decode(proxyAuth);
String[] authTokens = authorization.split(":");
String user = authTokens[0];
String password = authTokens[1];
if (this.authentications.get(user) == null) {
throw new IllegalArgumentException(user + " not found in the map!");
}
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
// nop
}
}
String authPass = this.authentications.get(user).toString();
if (password.equals(authPass)) {
// could throw exceptions...
super.service(req, res);
return;
}
}
// Proxy-Authenticate Basic realm="CCProxy Authorization"
response.addHeader("Proxy-Authenticate", "Basic realm=\"Jetty Proxy Authorization\"");
response.setStatus(HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED);
return;
}
super.service(req, res);
}
}
}