Merge branch 'jetty-9.3.x' of github.com:eclipse/jetty.project into jetty-9.3.x

This commit is contained in:
Joakim Erdfelt 2016-03-02 16:48:15 -07:00
commit 8f8fcd1b1a
5 changed files with 108 additions and 21 deletions

View File

@ -40,7 +40,6 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
public static final int DEFAULT_MAX_CONTENT_LENGTH = 16*1024; public static final int DEFAULT_MAX_CONTENT_LENGTH = 16*1024;
public static final Logger LOG = Log.getLogger(AuthenticationProtocolHandler.class); public static final Logger LOG = Log.getLogger(AuthenticationProtocolHandler.class);
private static final Pattern AUTHENTICATE_PATTERN = Pattern.compile("([^\\s]+)\\s+realm=\"([^\"]+)\"(.*)", Pattern.CASE_INSENSITIVE); private static final Pattern AUTHENTICATE_PATTERN = Pattern.compile("([^\\s]+)\\s+realm=\"([^\"]+)\"(.*)", Pattern.CASE_INSENSITIVE);
private static final String AUTHENTICATION_ATTRIBUTE = AuthenticationProtocolHandler.class.getName() + ".authentication";
private final HttpClient client; private final HttpClient client;
private final int maxContentLength; private final int maxContentLength;
@ -64,6 +63,8 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
protected abstract URI getAuthenticationURI(Request request); protected abstract URI getAuthenticationURI(Request request);
protected abstract String getAuthenticationAttribute();
@Override @Override
public Response.Listener getResponseListener() public Response.Listener getResponseListener()
{ {
@ -92,8 +93,9 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
return; return;
} }
String authenticationAttribute = getAuthenticationAttribute();
HttpConversation conversation = request.getConversation(); HttpConversation conversation = request.getConversation();
if (conversation.getAttribute(AUTHENTICATION_ATTRIBUTE) != null) if (conversation.getAttribute(authenticationAttribute) != null)
{ {
// We have already tried to authenticate, but we failed again // We have already tried to authenticate, but we failed again
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -146,18 +148,12 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
return; return;
} }
conversation.setAttribute(AUTHENTICATION_ATTRIBUTE, true); conversation.setAttribute(authenticationAttribute, true);
Request newRequest = client.copyRequest(request, request.getURI()); Request newRequest = client.copyRequest(request, request.getURI());
authnResult.apply(newRequest); authnResult.apply(newRequest);
newRequest.onResponseSuccess(new Response.SuccessListener() newRequest.onResponseSuccess(r -> client.getAuthenticationStore().addAuthenticationResult(authnResult))
{ .send(null);
@Override
public void onSuccess(Response response)
{
client.getAuthenticationStore().addAuthenticationResult(authnResult);
}
}).send(null);
} }
catch (Throwable x) catch (Throwable x)
{ {

View File

@ -153,14 +153,9 @@ public abstract class HttpConnection implements Connection
request.header(HttpHeader.COOKIE.asString(), cookies.toString()); request.header(HttpHeader.COOKIE.asString(), cookies.toString());
} }
// Authorization // Authentication
URI authenticationURI = proxy != null ? proxy.getURI() : request.getURI(); applyAuthentication(request, proxy != null ? proxy.getURI() : null);
if (authenticationURI != null) applyAuthentication(request, request.getURI());
{
Authentication.Result authnResult = getHttpClient().getAuthenticationStore().findAuthenticationResult(authenticationURI);
if (authnResult != null)
authnResult.apply(request);
}
} }
private StringBuilder convertCookies(List<HttpCookie> cookies, StringBuilder builder) private StringBuilder convertCookies(List<HttpCookie> cookies, StringBuilder builder)
@ -177,6 +172,16 @@ public abstract class HttpConnection implements Connection
return builder; return builder;
} }
private void applyAuthentication(Request request, URI uri)
{
if (uri != null)
{
Authentication.Result result = getHttpClient().getAuthenticationStore().findAuthenticationResult(uri);
if (result != null)
result.apply(request);
}
}
protected SendFailure send(HttpChannel channel, HttpExchange exchange) protected SendFailure send(HttpChannel channel, HttpExchange exchange)
{ {
// Forbid idle timeouts for the time window where // Forbid idle timeouts for the time window where

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.http.HttpStatus;
public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHandler public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHandler
{ {
public static final String NAME = "proxy-authenticate"; public static final String NAME = "proxy-authenticate";
private static final String ATTRIBUTE = ProxyAuthenticationProtocolHandler.class.getName() + ".attribute";
public ProxyAuthenticationProtocolHandler(HttpClient client) public ProxyAuthenticationProtocolHandler(HttpClient client)
{ {
@ -76,4 +77,10 @@ public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHa
ProxyConfiguration.Proxy proxy = destination.getProxy(); ProxyConfiguration.Proxy proxy = destination.getProxy();
return proxy != null ? proxy.getURI() : request.getURI(); return proxy != null ? proxy.getURI() : request.getURI();
} }
@Override
protected String getAuthenticationAttribute()
{
return ATTRIBUTE;
}
} }

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.http.HttpStatus;
public class WWWAuthenticationProtocolHandler extends AuthenticationProtocolHandler public class WWWAuthenticationProtocolHandler extends AuthenticationProtocolHandler
{ {
public static final String NAME = "www-authenticate"; public static final String NAME = "www-authenticate";
private static final String ATTRIBUTE = WWWAuthenticationProtocolHandler.class.getName() + ".attribute";
public WWWAuthenticationProtocolHandler(HttpClient client) public WWWAuthenticationProtocolHandler(HttpClient client)
{ {
@ -74,4 +75,10 @@ public class WWWAuthenticationProtocolHandler extends AuthenticationProtocolHand
{ {
return request.getURI(); return request.getURI();
} }
@Override
protected String getAuthenticationAttribute()
{
return ATTRIBUTE;
}
} }

View File

@ -81,7 +81,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest
} }
@Test @Test
public void testAuthenticatedProxiedRequest() throws Exception public void testProxyAuthentication() throws Exception
{ {
final String user = "foo"; final String user = "foo";
final String password = "bar"; final String password = "bar";
@ -160,7 +160,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest
} }
@Test @Test
public void testAuthenticatedProxiedRequestWithRedirect() throws Exception public void testProxyAuthenticationWithRedirect() throws Exception
{ {
String user = "foo"; String user = "foo";
String password = "bar"; String password = "bar";
@ -254,4 +254,76 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest
Assert.assertEquals(status, response3.getStatus()); Assert.assertEquals(status, response3.getStatus());
Assert.assertEquals(1, requests.get()); Assert.assertEquals(1, requests.get());
} }
@Test
public void testProxyAuthenticationWithServerAuthentication() throws Exception
{
String proxyRealm = "proxyRealm";
String serverRealm = "serverRealm";
int status = HttpStatus.NO_CONTENT_204;
start(new AbstractHandler()
{
@Override
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
String authorization = request.getHeader(HttpHeader.PROXY_AUTHORIZATION.asString());
if (authorization == null)
{
response.setStatus(HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407);
response.setHeader(HttpHeader.PROXY_AUTHENTICATE.asString(), "Basic realm=\"" + proxyRealm + "\"");
}
else
{
authorization = request.getHeader(HttpHeader.AUTHORIZATION.asString());
if (authorization == null)
{
response.setStatus(HttpStatus.UNAUTHORIZED_401);
response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), "Basic realm=\"" + serverRealm + "\"");
}
else
{
response.setStatus(status);
}
}
}
});
String proxyHost = "localhost";
int proxyPort = connector.getLocalPort();
String serverHost = "server";
int serverPort = proxyPort + 1;
URI proxyURI = URI.create(scheme + "://" + proxyHost + ":" + proxyPort);
client.getAuthenticationStore().addAuthentication(new BasicAuthentication(proxyURI, proxyRealm, "proxyUser", "proxyPassword"));
URI serverURI = URI.create(scheme + "://" + serverHost + ":" + serverPort);
client.getAuthenticationStore().addAuthentication(new BasicAuthentication(serverURI, serverRealm, "serverUser", "serverPassword"));
client.getProxyConfiguration().getProxies().add(new HttpProxy(proxyHost, proxyPort));
final AtomicInteger requests = new AtomicInteger();
client.getRequestListeners().add(new Request.Listener.Adapter()
{
@Override
public void onSuccess(Request request)
{
requests.incrementAndGet();
}
});
// Make a request, expect 407 + 401 + 204.
ContentResponse response1 = client.newRequest(serverHost, serverPort)
.scheme(scheme)
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(status, response1.getStatus());
Assert.assertEquals(3, requests.get());
// Make again the request, authentication is cached, expect 204.
requests.set(0);
ContentResponse response2 = client.newRequest(serverHost, serverPort)
.scheme(scheme)
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(status, response2.getStatus());
Assert.assertEquals(1, requests.get());
}
} }