package org.limewire.http.auth; import java.io.IOException; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.auth.Credentials; import org.apache.http.nio.entity.ConsumingNHttpEntity; import org.apache.http.nio.protocol.NHttpRequestHandler; import org.apache.http.nio.protocol.NHttpResponseTrigger; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.UriPatternMatcher; import org.limewire.logging.Log; import org.limewire.logging.LogFactory; import com.google.inject.Inject; import com.google.inject.Singleton; /** * Default implementation of {@link AuthenticationInterceptor}. * <p> * Intercepts {@link HttpRequest}, parses out authentication data and puts * {@link ServerAuthState} into the {@link HttpContext} so it can be queried * by other handlers for authentications state. */ @Singleton public class AuthenticationInterceptorImpl implements AuthenticationInterceptor { private static final Log LOG = LogFactory.getLog(AuthenticationInterceptorImpl.class); private final Authenticator authenticator; private final UriPatternMatcher protectedURIs; @Inject public AuthenticationInterceptorImpl(Authenticator authenticator) { this.authenticator = authenticator; protectedURIs = new UriPatternMatcher(); } public void process(HttpRequest request, HttpContext context) throws HttpException, IOException { if (request == null) { throw new IllegalArgumentException("HTTP request may not be null"); } if (context == null) { throw new IllegalArgumentException("HTTP context may not be null"); } ServerAuthState authState = new ServerAuthState(); ServerAuthScheme authScheme = new BasicServerAuthScheme(authenticator); authState.setScheme(authScheme); // TODO other schemes, scheme registry, etc context.setAttribute(ServerAuthState.AUTH_STATE, authState); if(protectedURIs.lookup(request.getRequestLine().getUri()) != null) { LOG.debugf("entering protected uri: {0}", request.getRequestLine().getUri()); Credentials credentials = authScheme.authenticate(request); if(credentials != null) { authState.setCredentials(credentials); authScheme.setComplete(); } } else { authScheme.setComplete(); } } public NHttpRequestHandler getGuardedHandler(String url, NHttpRequestHandler handler) { if(isProtected(handler)) { protectedURIs.register(url, url); return new GuardingHandler(handler); } else { return handler; } } @Override public void unregisterHandler(String urlPattern) { protectedURIs.unregister(urlPattern); } private boolean isProtected(NHttpRequestHandler handler) { return handler.getClass().getAnnotation(RequiresAuthentication.class) != null; } private static class GuardingHandler implements NHttpRequestHandler { private final NHttpRequestHandler handler; public GuardingHandler(NHttpRequestHandler handler) { this.handler = handler; } public ConsumingNHttpEntity entityRequest(HttpEntityEnclosingRequest request, HttpContext context) throws HttpException, IOException { ServerAuthState authState = (ServerAuthState) context.getAttribute(ServerAuthState.AUTH_STATE); ServerAuthScheme authScheme = authState.getScheme(); if(authScheme.isComplete()) { return handler.entityRequest(request, context); } else { return null; // TODO ? } } public void handle(HttpRequest request, HttpResponse response, NHttpResponseTrigger trigger, HttpContext context) throws HttpException, IOException { ServerAuthState authState = (ServerAuthState) context.getAttribute(ServerAuthState.AUTH_STATE); ServerAuthScheme authScheme = authState.getScheme(); if(authScheme.isComplete()) { handler.handle(request, response, trigger, context); } else { response.setStatusCode(HttpStatus.SC_UNAUTHORIZED); response.addHeader(authScheme.createChallenge()); trigger.submitResponse(response); } } } }