Skip to content

Commit

Permalink
LP-5: Added general framework for adding basic authentication handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
afisk committed Nov 6, 2009
1 parent c5c1286 commit 1423e6e
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 137 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.littleshoot.proxy.HttpProxyServer</mainClass>
<mainClass>org.littleshoot.proxy.Launcher</mainClass>
</transformer>
</transformers>
</configuration>
Expand Down
52 changes: 52 additions & 0 deletions src/main/java/org/littleshoot/proxy/DefaultHttpProxyServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.littleshoot.proxy;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* HTTP proxy server.
*/
public class DefaultHttpProxyServer implements HttpProxyServer {

private final Logger m_log =
LoggerFactory.getLogger(DefaultHttpProxyServer.class);
private final int m_port;

private final ProxyAuthorizationManager m_authenticationManager =
new DefaultProxyAuthorizationManager();

public DefaultHttpProxyServer(final int port) {
this.m_port = port;
}

public void start() {
m_log.info("Starting proxy on port: "+this.m_port);
final ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));

bootstrap.setPipelineFactory(
new HttpServerPipelineFactory(m_authenticationManager));
bootstrap.bind(new InetSocketAddress(m_port));

/*
final ServerBootstrap sslBootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
sslBootstrap.setPipelineFactory(new HttpServerPipelineFactory());
sslBootstrap.bind(new InetSocketAddress("127.0.0.1", 8443));
*/
}

public void addProxyAuthenticationHandler(
final ProxyAuthorizationHandler pah) {
this.m_authenticationManager.addHandler(pah);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.littleshoot.proxy;

import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Default authentication manager that simply processes each authentication
* handler in the order it was added.
*
* See: http://tools.ietf.org/html/rfc2617
*/
public class DefaultProxyAuthorizationManager implements
ProxyAuthorizationManager {

private final Logger m_log = LoggerFactory.getLogger(getClass());
private final Collection<ProxyAuthorizationHandler> m_handlers =
new LinkedList<ProxyAuthorizationHandler>();

public void addHandler(final ProxyAuthorizationHandler pah) {
this.m_handlers.add(pah);
}

public boolean handleProxyAuthorization(final HttpRequest request,
final ChannelHandlerContext ctx) {
if (!request.containsHeader("Proxy-Authorization")) {
if (!m_handlers.isEmpty()) {
rejectRequest(ctx);
return false;
}
return true;
}

final List<String> values = request.getHeaders("Proxy-Authorization");
final String fullValue = values.iterator().next();
final String value =
StringUtils.substringAfter(fullValue, "Basic ").trim();
final byte[] decodedValue = Base64.decode(value);
try {
final String decodedString = new String(decodedValue, "UTF-8");
final String userName = StringUtils.substringBefore(decodedString, ":");
final String password = StringUtils.substringAfter(decodedString, ":");
for (final ProxyAuthorizationHandler handler : this.m_handlers) {
if (!handler.authenticate(userName, password)) {
rejectRequest(ctx);
return false;
}
}
}
catch (final UnsupportedEncodingException e) {
m_log.error("Could not decode?", e);
}

m_log.info("Got proxy authorization!");
// We need to remove the header before sending the request on.
final String authentication =
request.getHeader("Proxy-Authorization");
m_log.info(authentication);
request.removeHeader("Proxy-Authorization");
return true;
}

private void rejectRequest(final ChannelHandlerContext ctx) {
final String statusLine = "HTTP/1.1 407 Proxy Authentication Required\r\n";
final String headers =
"Date: "+ProxyUtils.httpDate()+"\r\n"+
"Proxy-Authenticate: Basic realm=\"Restricted Files\"\r\n"+
"Content-Length: 415\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"\r\n";

final String responseBody =
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"+
"<html><head>\n"+
"<title>407 Proxy Authentication Required</title>\n"+
"</head><body>\n"+
"<h1>Proxy Authentication Required</h1>\n"+
"<p>This server could not verify that you\n"+
"are authorized to access the document\n"+
"requested. Either you supplied the wrong\n"+
"credentials (e.g., bad password), or your\n"+
"browser doesn't understand how to supply\n"+
"the credentials required.</p>\n"+
"</body></html>\n";
m_log.info("Content-Length is really: "+responseBody.length());
ProxyUtils.writeResponse(ctx.getChannel(), statusLine, headers, responseBody);
}
}
78 changes: 21 additions & 57 deletions src/main/java/org/littleshoot/proxy/HttpProxyServer.java
Original file line number Diff line number Diff line change
@@ -1,57 +1,21 @@
package org.littleshoot.proxy;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* HTTP proxy server.
*/
public class HttpProxyServer {

private static final Logger LOG =
LoggerFactory.getLogger(HttpProxyServer.class);

/**
* Starts the proxy from the command line.
*
* @param args Any command line arguments.
*/
public static void main(final String[] args) {
final ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));

bootstrap.setPipelineFactory(new HttpServerPipelineFactory());

final int defaultPort = 8080;
int port;
if (args.length > 0) {
final String arg = args[0];
try {
port = Integer.parseInt(arg);
} catch (final NumberFormatException e) {
port = defaultPort;
}
} else {
port = defaultPort;
}
LOG.info("Starting proxy on port: "+port);
//bootstrap.bind(new InetSocketAddress("127.0.0.1", port));
bootstrap.bind(new InetSocketAddress(port));

/*
final ServerBootstrap sslBootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
sslBootstrap.setPipelineFactory(new HttpServerPipelineFactory());
sslBootstrap.bind(new InetSocketAddress("127.0.0.1", 8443));
*/
}
}
package org.littleshoot.proxy;

/**
* Interface for the top-level proxy server class.
*/
public interface HttpProxyServer {

/**
* Starts the server.
*/
void start();

/**
* Adds a new handler for proxy authentication. Handlers are called in the
* order they're added. If one handler accepts the user's credentials, it
* passes them on to the next handler.
*
* @param pah The new authentication handler.
*/
void addProxyAuthenticationHandler(ProxyAuthorizationHandler pah);
}
Loading

0 comments on commit 1423e6e

Please sign in to comment.