HTTPCLIENT-1107: auth framework redesign
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1175375 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
47c6fa809f
commit
e5d83200fd
|
@ -65,6 +65,7 @@ public class AuthState {
|
|||
this.credentials = null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean isValid() {
|
||||
return this.authScheme != null;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ import org.apache.http.auth.AuthState;
|
|||
import org.apache.http.auth.Credentials;
|
||||
import org.apache.http.client.AuthCache;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||
import org.apache.http.protocol.ExecutionContext;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
|
@ -84,6 +86,14 @@ public class RequestAuthCache implements HttpRequestInterceptor {
|
|||
}
|
||||
|
||||
HttpHost target = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
|
||||
if (target.getPort() < 0) {
|
||||
SchemeRegistry schemeRegistry = (SchemeRegistry) context.getAttribute(
|
||||
ClientContext.SCHEME_REGISTRY);
|
||||
Scheme scheme = schemeRegistry.getScheme(target);
|
||||
target = new HttpHost(target.getHostName(),
|
||||
scheme.resolvePort(target.getPort()), target.getSchemeName());
|
||||
}
|
||||
|
||||
AuthState targetState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
|
||||
if (target != null && targetState != null && targetState.getAuthScheme() == null) {
|
||||
AuthScheme authScheme = authCache.get(target);
|
||||
|
|
|
@ -31,16 +31,11 @@ import java.io.IOException;
|
|||
import java.io.InterruptedIOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.http.annotation.NotThreadSafe;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.ConnectionReuseStrategy;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpException;
|
||||
|
@ -49,19 +44,16 @@ import org.apache.http.HttpRequest;
|
|||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolException;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.annotation.NotThreadSafe;
|
||||
import org.apache.http.auth.AuthScheme;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.AuthState;
|
||||
import org.apache.http.auth.AuthenticationException;
|
||||
import org.apache.http.auth.Credentials;
|
||||
import org.apache.http.auth.MalformedChallengeException;
|
||||
import org.apache.http.client.AuthenticationHandler;
|
||||
import org.apache.http.client.RedirectStrategy;
|
||||
import org.apache.http.client.RequestDirector;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.HttpRequestRetryHandler;
|
||||
import org.apache.http.client.NonRepeatableRequestException;
|
||||
import org.apache.http.client.RedirectException;
|
||||
import org.apache.http.client.RedirectStrategy;
|
||||
import org.apache.http.client.RequestDirector;
|
||||
import org.apache.http.client.UserTokenHandler;
|
||||
import org.apache.http.client.methods.AbortableHttpRequest;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
|
@ -183,6 +175,8 @@ public class DefaultRequestDirector implements RequestDirector {
|
|||
|
||||
protected final AuthState proxyAuthState;
|
||||
|
||||
private final HttpAuthenticator authenticator;
|
||||
|
||||
private int execCount;
|
||||
|
||||
private int redirectCount;
|
||||
|
@ -283,6 +277,7 @@ public class DefaultRequestDirector implements RequestDirector {
|
|||
("HTTP parameters may not be null");
|
||||
}
|
||||
this.log = log;
|
||||
this.authenticator = new HttpAuthenticator(log);
|
||||
this.requestExec = requestExec;
|
||||
this.connManager = conman;
|
||||
this.reuseStrategy = reustrat;
|
||||
|
@ -811,11 +806,7 @@ public class DefaultRequestDirector implements RequestDirector {
|
|||
HttpHost target = route.getTargetHost();
|
||||
HttpResponse response = null;
|
||||
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
|
||||
done = true;
|
||||
|
||||
for (;;) {
|
||||
if (!this.managedConn.isOpen()) {
|
||||
this.managedConn.open(route, context, this.params);
|
||||
}
|
||||
|
@ -853,27 +844,12 @@ public class DefaultRequestDirector implements RequestDirector {
|
|||
CredentialsProvider credsProvider = (CredentialsProvider)
|
||||
context.getAttribute(ClientContext.CREDS_PROVIDER);
|
||||
|
||||
if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
|
||||
if (credsProvider != null && HttpClientParams.isAuthenticating(this.params)) {
|
||||
if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {
|
||||
|
||||
this.log.debug("Proxy requested authentication");
|
||||
Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(
|
||||
response, context);
|
||||
try {
|
||||
processChallenges(
|
||||
challenges, this.proxyAuthState, this.proxyAuthHandler,
|
||||
response, context);
|
||||
} catch (AuthenticationException ex) {
|
||||
if (this.log.isWarnEnabled()) {
|
||||
this.log.warn("Authentication error: " + ex.getMessage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateAuthState(this.proxyAuthState, proxy, credsProvider);
|
||||
|
||||
if (this.proxyAuthState.getCredentials() != null) {
|
||||
done = false;
|
||||
|
||||
if (this.authenticator.authenticate(
|
||||
proxy, response,
|
||||
this.proxyAuthHandler, this.proxyAuthState,
|
||||
credsProvider, context)) {
|
||||
// Retry request
|
||||
if (this.reuseStrategy.keepAlive(response, context)) {
|
||||
this.log.debug("Connection kept alive");
|
||||
|
@ -883,12 +859,13 @@ public class DefaultRequestDirector implements RequestDirector {
|
|||
} else {
|
||||
this.managedConn.close();
|
||||
}
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Reset proxy auth scope
|
||||
// Reset target auth scope
|
||||
this.proxyAuthState.setAuthScope(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1081,23 +1058,15 @@ public class DefaultRequestDirector implements RequestDirector {
|
|||
if (target == null) {
|
||||
target = route.getTargetHost();
|
||||
}
|
||||
|
||||
this.log.debug("Target requested authentication");
|
||||
Map<String, Header> challenges = this.targetAuthHandler.getChallenges(
|
||||
response, context);
|
||||
try {
|
||||
processChallenges(challenges,
|
||||
this.targetAuthState, this.targetAuthHandler,
|
||||
response, context);
|
||||
} catch (AuthenticationException ex) {
|
||||
if (this.log.isWarnEnabled()) {
|
||||
this.log.warn("Authentication error: " + ex.getMessage());
|
||||
return null;
|
||||
}
|
||||
if (target.getPort() < 0) {
|
||||
Scheme scheme = connManager.getSchemeRegistry().getScheme(target);
|
||||
target = new HttpHost(
|
||||
target.getHostName(), scheme.getDefaultPort(), target.getSchemeName());
|
||||
}
|
||||
updateAuthState(this.targetAuthState, target, credsProvider);
|
||||
|
||||
if (this.targetAuthState.getCredentials() != null) {
|
||||
if (this.authenticator.authenticate(
|
||||
target, response,
|
||||
this.targetAuthHandler, this.targetAuthState,
|
||||
credsProvider, context)) {
|
||||
// Re-try the same request via the same route
|
||||
return roureq;
|
||||
} else {
|
||||
|
@ -1111,23 +1080,10 @@ public class DefaultRequestDirector implements RequestDirector {
|
|||
if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {
|
||||
|
||||
HttpHost proxy = route.getProxyHost();
|
||||
|
||||
this.log.debug("Proxy requested authentication");
|
||||
Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(
|
||||
response, context);
|
||||
try {
|
||||
processChallenges(challenges,
|
||||
this.proxyAuthState, this.proxyAuthHandler,
|
||||
response, context);
|
||||
} catch (AuthenticationException ex) {
|
||||
if (this.log.isWarnEnabled()) {
|
||||
this.log.warn("Authentication error: " + ex.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
updateAuthState(this.proxyAuthState, proxy, credsProvider);
|
||||
|
||||
if (this.proxyAuthState.getCredentials() != null) {
|
||||
if (this.authenticator.authenticate(
|
||||
proxy, response,
|
||||
this.proxyAuthHandler, this.proxyAuthState,
|
||||
credsProvider, context)) {
|
||||
// Re-try the same request via the same route
|
||||
return roureq;
|
||||
} else {
|
||||
|
@ -1170,78 +1126,6 @@ public class DefaultRequestDirector implements RequestDirector {
|
|||
} // abortConnection
|
||||
|
||||
|
||||
private void processChallenges(
|
||||
final Map<String, Header> challenges,
|
||||
final AuthState authState,
|
||||
final AuthenticationHandler authHandler,
|
||||
final HttpResponse response,
|
||||
final HttpContext context)
|
||||
throws MalformedChallengeException, AuthenticationException {
|
||||
|
||||
AuthScheme authScheme = authState.getAuthScheme();
|
||||
if (authScheme == null) {
|
||||
// Authentication not attempted before
|
||||
authScheme = authHandler.selectScheme(challenges, response, context);
|
||||
authState.setAuthScheme(authScheme);
|
||||
}
|
||||
String id = authScheme.getSchemeName();
|
||||
|
||||
Header challenge = challenges.get(id.toLowerCase(Locale.ENGLISH));
|
||||
if (challenge == null) {
|
||||
throw new AuthenticationException(id +
|
||||
" authorization challenge expected, but not found");
|
||||
}
|
||||
authScheme.processChallenge(challenge);
|
||||
this.log.debug("Authorization challenge processed");
|
||||
}
|
||||
|
||||
|
||||
private void updateAuthState(
|
||||
final AuthState authState,
|
||||
final HttpHost host,
|
||||
final CredentialsProvider credsProvider) {
|
||||
|
||||
if (!authState.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String hostname = host.getHostName();
|
||||
int port = host.getPort();
|
||||
if (port < 0) {
|
||||
Scheme scheme = connManager.getSchemeRegistry().getScheme(host);
|
||||
port = scheme.getDefaultPort();
|
||||
}
|
||||
|
||||
AuthScheme authScheme = authState.getAuthScheme();
|
||||
AuthScope authScope = new AuthScope(
|
||||
hostname,
|
||||
port,
|
||||
authScheme.getRealm(),
|
||||
authScheme.getSchemeName());
|
||||
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug("Authentication scope: " + authScope);
|
||||
}
|
||||
Credentials creds = authState.getCredentials();
|
||||
if (creds == null) {
|
||||
creds = credsProvider.getCredentials(authScope);
|
||||
if (this.log.isDebugEnabled()) {
|
||||
if (creds != null) {
|
||||
this.log.debug("Found credentials");
|
||||
} else {
|
||||
this.log.debug("Credentials not found");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (authScheme.isComplete()) {
|
||||
this.log.debug("Authentication failed");
|
||||
creds = null;
|
||||
}
|
||||
}
|
||||
authState.setAuthScope(authScope);
|
||||
authState.setCredentials(creds);
|
||||
}
|
||||
|
||||
private void invalidateAuthIfSuccessful(final AuthState authState) {
|
||||
AuthScheme authscheme = authState.getAuthScheme();
|
||||
if (authscheme != null
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.http.impl.client;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.auth.AuthScheme;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.AuthState;
|
||||
import org.apache.http.auth.AuthenticationException;
|
||||
import org.apache.http.auth.Credentials;
|
||||
import org.apache.http.auth.MalformedChallengeException;
|
||||
import org.apache.http.client.AuthenticationHandler;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
public class HttpAuthenticator {
|
||||
|
||||
private final Log log;
|
||||
|
||||
public HttpAuthenticator(final Log log) {
|
||||
super();
|
||||
this.log = log != null ? log : LogFactory.getLog(getClass());
|
||||
}
|
||||
|
||||
public HttpAuthenticator() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public boolean authenticate(
|
||||
final HttpHost host,
|
||||
final HttpResponse response,
|
||||
final AuthenticationHandler authHandler,
|
||||
final AuthState authState,
|
||||
final CredentialsProvider credsProvider,
|
||||
final HttpContext context) {
|
||||
try {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(host.toHostString() + " requested authentication");
|
||||
}
|
||||
Map<String, Header> challenges = authHandler.getChallenges(response, context);
|
||||
AuthScheme authScheme = authState.getAuthScheme();
|
||||
if (authScheme == null) {
|
||||
// Authentication not attempted before
|
||||
authScheme = authHandler.selectScheme(challenges, response, context);
|
||||
authState.setAuthScheme(authScheme);
|
||||
}
|
||||
String id = authScheme.getSchemeName();
|
||||
Header challenge = challenges.get(id.toLowerCase(Locale.US));
|
||||
if (challenge == null) {
|
||||
if (this.log.isWarnEnabled()) {
|
||||
this.log.warn(id + " authorization challenge expected, but not found");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
authScheme.processChallenge(challenge);
|
||||
this.log.debug("Authorization challenge processed");
|
||||
|
||||
AuthScope authScope = new AuthScope(
|
||||
host.getHostName(),
|
||||
host.getPort(),
|
||||
authScheme.getRealm(),
|
||||
authScheme.getSchemeName());
|
||||
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug("Authentication scope: " + authScope);
|
||||
}
|
||||
Credentials creds = authState.getCredentials();
|
||||
if (creds == null) {
|
||||
creds = credsProvider.getCredentials(authScope);
|
||||
if (this.log.isDebugEnabled()) {
|
||||
if (creds != null) {
|
||||
this.log.debug("Found credentials");
|
||||
} else {
|
||||
this.log.debug("Credentials not found");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (authScheme.isComplete()) {
|
||||
this.log.debug("Authentication failed");
|
||||
creds = null;
|
||||
}
|
||||
}
|
||||
authState.setAuthScope(authScope);
|
||||
authState.setCredentials(creds);
|
||||
return creds != null;
|
||||
} catch (MalformedChallengeException ex) {
|
||||
if (this.log.isWarnEnabled()) {
|
||||
this.log.warn("Malformed challenge: " + ex.getMessage());
|
||||
}
|
||||
return false;
|
||||
} catch (AuthenticationException ex) {
|
||||
if (this.log.isWarnEnabled()) {
|
||||
this.log.warn("Authentication error: " + ex.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue