Better separations of concerns: AuthenticationStrategy is intended to select preferred auth schemes without performing actual authentication; auth handling code moved to HttpAuthenticator

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1692370 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2015-07-23 10:00:13 +00:00
parent b2a7cb9f10
commit e7190e7177
7 changed files with 164 additions and 263 deletions

View File

@ -34,19 +34,6 @@ import org.apache.http.protocol.HttpContext;
* This interface represents an abstract challenge-response oriented * This interface represents an abstract challenge-response oriented
* authentication scheme. * authentication scheme.
* <p> * <p>
* An authentication scheme should be able to support the following
* functions:
* <ul>
* <li>Parse and process the challenge sent by the target server
* in response to request for a protected resource
* <li>Provide its textual designation
* <li>Provide its parameters, if available
* <li>Provide the realm this authentication scheme is applicable to,
* if available
* <li>Generate authorization string for the given set of credentials
* and the HTTP request in response to the authorization challenge.
* </ul>
* <p>
* Authentication schemes may be stateful involving a series of * Authentication schemes may be stateful involving a series of
* challenge-response exchanges. * challenge-response exchanges.
* *

View File

@ -27,14 +27,12 @@
package org.apache.http.client; package org.apache.http.client;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthChallenge; import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption; import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.ChallengeType; import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
/** /**
@ -49,24 +47,19 @@ import org.apache.http.protocol.HttpContext;
public interface AuthenticationStrategy { public interface AuthenticationStrategy {
/** /**
* Selects one authentication challenge out of all available and * Returns an list of {@link AuthScheme}s to handle the given {@link AuthChallenge}s
* creates and generates {@link AuthOption} instance capable of * in their order of preference.
* processing that challenge.
* *
* @param challengeType challenge type. * @param challengeType challenge type.
* @param host authentication host.
* @param challenges collection of challenges. * @param challenges collection of challenges.
* @param context HTTP context. * @param context HTTP context.
* @return authentication auth schemes that can be used for authentication. Can be empty. * @return authentication auth schemes that can be used for authentication. Can be empty.
* @throws MalformedChallengeException if one of the authentication
* challenges is not valid or malformed.
* *
* @since 5.0 * @since 5.0
*/ */
Queue<AuthOption> select( List<AuthScheme> select(
ChallengeType challengeType, ChallengeType challengeType,
HttpHost host,
Map<String, AuthChallenge> challenges, Map<String, AuthChallenge> challenges,
HttpContext context) throws MalformedChallengeException; HttpContext context);
} }

View File

@ -29,6 +29,7 @@ package org.apache.http.impl.auth;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -49,10 +50,12 @@ import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption; import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthProtocolState; import org.apache.http.auth.AuthProtocolState;
import org.apache.http.auth.AuthScheme; import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState; import org.apache.http.auth.AuthState;
import org.apache.http.auth.AuthenticationException; import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType; import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials; import org.apache.http.auth.Credentials;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.MalformedChallengeException; import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.AuthCache; import org.apache.http.client.AuthCache;
import org.apache.http.client.AuthenticationStrategy; import org.apache.http.client.AuthenticationStrategy;
@ -98,10 +101,13 @@ public class HttpAuthenticator {
default: default:
throw new IllegalStateException("Unexpected challenge type: " + challengeType); throw new IllegalStateException("Unexpected challenge type: " + challengeType);
} }
final HttpClientContext clientContext = HttpClientContext.adapt(context);
if (response.getStatusLine().getStatusCode() == challengeCode) { if (response.getStatusLine().getStatusCode() == challengeCode) {
this.log.debug("Authentication required"); this.log.debug("Authentication required");
if (authState.getState() == AuthProtocolState.SUCCESS) { if (authState.getState() == AuthProtocolState.SUCCESS) {
clearCache(host, context); clearCache(host, clientContext);
} }
return true; return true;
} else { } else {
@ -110,7 +116,7 @@ public class HttpAuthenticator {
case HANDSHAKE: case HANDSHAKE:
this.log.debug("Authentication succeeded"); this.log.debug("Authentication succeeded");
authState.setState(AuthProtocolState.SUCCESS); authState.setState(AuthProtocolState.SUCCESS);
updateCache(host, authState.getAuthScheme(), context); updateCache(host, authState.getAuthScheme(), clientContext);
break; break;
case SUCCESS: case SUCCESS:
break; break;
@ -132,51 +138,52 @@ public class HttpAuthenticator {
if (this.log.isDebugEnabled()) { if (this.log.isDebugEnabled()) {
this.log.debug(host.toHostString() + " requested authentication"); this.log.debug(host.toHostString() + " requested authentication");
} }
try {
final Header[] headers = response.getHeaders( final HttpClientContext clientContext = HttpClientContext.adapt(context);
challengeType == ChallengeType.PROXY ? HttpHeaders.PROXY_AUTHENTICATE : HttpHeaders.WWW_AUTHENTICATE);
final Map<String, AuthChallenge> challengeMap = new HashMap<>(); final Header[] headers = response.getHeaders(
for (Header header: headers) { challengeType == ChallengeType.PROXY ? HttpHeaders.PROXY_AUTHENTICATE : HttpHeaders.WWW_AUTHENTICATE);
final CharArrayBuffer buffer; final Map<String, AuthChallenge> challengeMap = new HashMap<>();
final int pos; for (Header header: headers) {
if (header instanceof FormattedHeader) { final CharArrayBuffer buffer;
buffer = ((FormattedHeader) header).getBuffer(); final int pos;
pos = ((FormattedHeader) header).getValuePos(); if (header instanceof FormattedHeader) {
} else { buffer = ((FormattedHeader) header).getBuffer();
final String s = header.getValue(); pos = ((FormattedHeader) header).getValuePos();
if (s == null) { } else {
continue; final String s = header.getValue();
} if (s == null) {
buffer = new CharArrayBuffer(s.length());
buffer.append(s);
pos = 0;
}
final ParserCursor cursor = new ParserCursor(pos, buffer.length());
final List<AuthChallenge> authChallenges;
try {
authChallenges = parser.parse(buffer, cursor);
} catch (ParseException ex) {
if (this.log.isWarnEnabled()) {
this.log.warn("Malformed challenge: " + header.getValue());
}
continue; continue;
} }
for (AuthChallenge authChallenge: authChallenges) { buffer = new CharArrayBuffer(s.length());
final String scheme = authChallenge.getScheme().toLowerCase(Locale.ROOT); buffer.append(s);
if (!challengeMap.containsKey(scheme)) { pos = 0;
challengeMap.put(scheme, authChallenge); }
} final ParserCursor cursor = new ParserCursor(pos, buffer.length());
final List<AuthChallenge> authChallenges;
try {
authChallenges = parser.parse(buffer, cursor);
} catch (ParseException ex) {
if (this.log.isWarnEnabled()) {
this.log.warn("Malformed challenge: " + header.getValue());
}
continue;
}
for (AuthChallenge authChallenge: authChallenges) {
final String scheme = authChallenge.getScheme().toLowerCase(Locale.ROOT);
if (!challengeMap.containsKey(scheme)) {
challengeMap.put(scheme, authChallenge);
} }
} }
if (challengeMap.isEmpty()) { }
this.log.debug("Response contains no valid authentication challenges"); if (challengeMap.isEmpty()) {
clearCache(host, context); this.log.debug("Response contains no valid authentication challenges");
authState.reset(); clearCache(host, clientContext);
return false; authState.reset();
} return false;
}
final AuthScheme authScheme = authState.getAuthScheme(); switch (authState.getState()) {
switch (authState.getState()) {
case FAILURE: case FAILURE:
return false; return false;
case SUCCESS: case SUCCESS:
@ -184,17 +191,27 @@ public class HttpAuthenticator {
break; break;
case CHALLENGED: case CHALLENGED:
case HANDSHAKE: case HANDSHAKE:
Asserts.notNull(authScheme, "AuthScheme"); Asserts.notNull(authState.getAuthScheme(), "AuthScheme");
case UNCHALLENGED: case UNCHALLENGED:
final AuthScheme authScheme = authState.getAuthScheme();
if (authScheme != null) { if (authScheme != null) {
final String id = authScheme.getSchemeName(); final String id = authScheme.getSchemeName();
final AuthChallenge challenge = challengeMap.get(id.toLowerCase(Locale.ROOT)); final AuthChallenge challenge = challengeMap.get(id.toLowerCase(Locale.ROOT));
if (challenge != null) { if (challenge != null) {
this.log.debug("Authorization challenge processed"); this.log.debug("Authorization challenge processed");
authScheme.processChallenge(challengeType, challenge); try {
authScheme.processChallenge(challengeType, challenge);
} catch (MalformedChallengeException ex) {
if (this.log.isWarnEnabled()) {
this.log.warn(ex.getMessage());
}
clearCache(host, clientContext);
authState.reset();
return false;
}
if (authScheme.isComplete()) { if (authScheme.isComplete()) {
this.log.debug("Authentication failed"); this.log.debug("Authentication failed");
clearCache(host, context); clearCache(host, clientContext);
authState.reset(); authState.reset();
authState.setState(AuthProtocolState.FAILURE); authState.setState(AuthProtocolState.FAILURE);
return false; return false;
@ -207,23 +224,44 @@ public class HttpAuthenticator {
// Retry authentication with a different scheme // Retry authentication with a different scheme
} }
} }
} }
final Queue<AuthOption> authOptions = authStrategy.select(challengeType, host, challengeMap, context);
if (authOptions != null && !authOptions.isEmpty()) { final List<AuthScheme> preferredSchemes = authStrategy.select(challengeType, challengeMap, context);
if (this.log.isDebugEnabled()) { final CredentialsProvider credsProvider = clientContext.getCredentialsProvider();
this.log.debug("Selected authentication options: " + authOptions); if (credsProvider == null) {
this.log.debug("Credentials provider not set in the context");
return false;
}
final Queue<AuthOption> authOptions = new LinkedList<>();
for (AuthScheme authScheme: preferredSchemes) {
try {
final String id = authScheme.getSchemeName();
final AuthChallenge challenge = challengeMap.get(id.toLowerCase(Locale.ROOT));
authScheme.processChallenge(challengeType, challenge);
final AuthScope authScope = new AuthScope(
host.getHostName(),
host.getPort(),
authScheme.getRealm(),
authScheme.getSchemeName());
final Credentials credentials = credsProvider.getCredentials(authScope);
if (credentials != null) {
authOptions.add(new AuthOption(authScheme, credentials));
}
} catch (MalformedChallengeException ex) {
if (this.log.isWarnEnabled()) {
this.log.warn(ex.getMessage());
} }
authState.setState(AuthProtocolState.CHALLENGED);
authState.update(authOptions);
return true;
} else {
return false;
} }
} catch (final MalformedChallengeException ex) { }
if (this.log.isWarnEnabled()) { if (!authOptions.isEmpty()) {
this.log.warn("Malformed challenge: " + ex.getMessage()); if (this.log.isDebugEnabled()) {
this.log.debug("Selected authentication options: " + authOptions);
} }
authState.reset(); authState.setState(AuthProtocolState.CHALLENGED);
authState.update(authOptions);
return true;
} else {
return false; return false;
} }
} }
@ -292,9 +330,8 @@ public class HttpAuthenticator {
schemeName.equalsIgnoreCase(AuthSchemes.DIGEST); schemeName.equalsIgnoreCase(AuthSchemes.DIGEST);
} }
private void updateCache(final HttpHost host, final AuthScheme authScheme, final HttpContext context) { private void updateCache(final HttpHost host, final AuthScheme authScheme, final HttpClientContext clientContext) {
if (isCachable(authScheme)) { if (isCachable(authScheme)) {
final HttpClientContext clientContext = HttpClientContext.adapt(context);
final AuthCache authCache = clientContext.getAuthCache(); final AuthCache authCache = clientContext.getAuthCache();
if (authCache != null) { if (authCache != null) {
if (this.log.isDebugEnabled()) { if (this.log.isDebugEnabled()) {
@ -305,9 +342,8 @@ public class HttpAuthenticator {
} }
} }
private void clearCache(final HttpHost host, final HttpContext context) { private void clearCache(final HttpHost host, final HttpClientContext clientContext) {
final HttpClientContext clientContext = HttpClientContext.adapt(context);
final AuthCache authCache = clientContext.getAuthCache(); final AuthCache authCache = clientContext.getAuthCache();
if (authCache != null) { if (authCache != null) {
if (this.log.isDebugEnabled()) { if (this.log.isDebugEnabled()) {

View File

@ -27,28 +27,21 @@
package org.apache.http.impl.client; package org.apache.http.impl.client;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHost;
import org.apache.http.annotation.Immutable; import org.apache.http.annotation.Immutable;
import org.apache.http.auth.AuthChallenge; import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthScheme; import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeProvider; import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.ChallengeType; import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.AuthenticationStrategy; import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
@ -78,28 +71,21 @@ public class DefaultAuthenticationStrategy implements AuthenticationStrategy {
AuthSchemes.BASIC)); AuthSchemes.BASIC));
@Override @Override
public Queue<AuthOption> select( public List<AuthScheme> select(
final ChallengeType challengeType, final ChallengeType challengeType,
final HttpHost authhost,
final Map<String, AuthChallenge> challenges, final Map<String, AuthChallenge> challenges,
final HttpContext context) throws MalformedChallengeException { final HttpContext context) {
Args.notNull(challengeType, "ChallengeType"); Args.notNull(challengeType, "ChallengeType");
Args.notNull(challenges, "Map of auth challenges"); Args.notNull(challenges, "Map of auth challenges");
Args.notNull(authhost, "Host");
Args.notNull(context, "HTTP context"); Args.notNull(context, "HTTP context");
final HttpClientContext clientContext = HttpClientContext.adapt(context); final HttpClientContext clientContext = HttpClientContext.adapt(context);
final Queue<AuthOption> options = new LinkedList<>(); final List<AuthScheme> options = new ArrayList<>();
final Lookup<AuthSchemeProvider> registry = clientContext.getAuthSchemeRegistry(); final Lookup<AuthSchemeProvider> registry = clientContext.getAuthSchemeRegistry();
if (registry == null) { if (registry == null) {
this.log.debug("Auth scheme registry not set in the context"); this.log.debug("Auth scheme registry not set in the context");
return options; return options;
} }
final CredentialsProvider credsProvider = clientContext.getCredentialsProvider();
if (credsProvider == null) {
this.log.debug("Credentials provider not set in the context");
return options;
}
final RequestConfig config = clientContext.getRequestConfig(); final RequestConfig config = clientContext.getRequestConfig();
Collection<String> authPrefs = challengeType == ChallengeType.TARGET ? Collection<String> authPrefs = challengeType == ChallengeType.TARGET ?
config.getTargetPreferredAuthSchemes() : config.getProxyPreferredAuthSchemes(); config.getTargetPreferredAuthSchemes() : config.getProxyPreferredAuthSchemes();
@ -122,22 +108,10 @@ public class DefaultAuthenticationStrategy implements AuthenticationStrategy {
continue; continue;
} }
final AuthScheme authScheme = authSchemeProvider.create(context); final AuthScheme authScheme = authSchemeProvider.create(context);
authScheme.processChallenge(challengeType, challenge); options.add(authScheme);
final AuthScope authScope = new AuthScope(
authhost.getHostName(),
authhost.getPort(),
authScheme.getRealm(),
authScheme.getSchemeName());
final Credentials credentials = credsProvider.getCredentials(authScope);
if (credentials != null) {
options.add(new AuthOption(authScheme, credentials));
}
} else { } else {
if (this.log.isDebugEnabled()) { if (this.log.isDebugEnabled()) {
this.log.debug("Challenge for " + id + " authentication scheme not available"); this.log.debug("Challenge for " + id + " authentication scheme not available");
// Try again
} }
} }
} }

View File

@ -29,16 +29,14 @@ package org.apache.http.impl.client;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthChallenge; import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption; import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeProvider; import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthScope;
import org.apache.http.auth.ChallengeType; import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
@ -62,25 +60,19 @@ public class TestAuthenticationStrategy {
@Test @Test
public void testSelectInvalidInput() throws Exception { public void testSelectInvalidInput() throws Exception {
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy(); final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final HttpClientContext context = HttpClientContext.create(); final HttpClientContext context = HttpClientContext.create();
try { try {
authStrategy.select(null, authhost, Collections.<String, AuthChallenge>emptyMap(), context); authStrategy.select(null, Collections.<String, AuthChallenge>emptyMap(), context);
Assert.fail("IllegalArgumentException expected"); Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) { } catch (final IllegalArgumentException ex) {
} }
try { try {
authStrategy.select(ChallengeType.TARGET, null, Collections.<String, AuthChallenge>emptyMap(), context); authStrategy.select(ChallengeType.TARGET, null, context);
Assert.fail("IllegalArgumentException expected"); Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) { } catch (final IllegalArgumentException ex) {
} }
try { try {
authStrategy.select(ChallengeType.TARGET, authhost, null, context); authStrategy.select(ChallengeType.TARGET, Collections.<String, AuthChallenge>emptyMap(), null);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
authStrategy.select(ChallengeType.TARGET, authhost, Collections.<String, AuthChallenge>emptyMap(), null);
Assert.fail("IllegalArgumentException expected"); Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) { } catch (final IllegalArgumentException ex) {
} }
@ -89,7 +81,6 @@ public class TestAuthenticationStrategy {
@Test @Test
public void testSelectNoSchemeRegistry() throws Exception { public void testSelectNoSchemeRegistry() throws Exception {
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy(); final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final HttpClientContext context = HttpClientContext.create(); final HttpClientContext context = HttpClientContext.create();
final Map<String, AuthChallenge> challenges = new HashMap<>(); final Map<String, AuthChallenge> challenges = new HashMap<>();
@ -98,91 +89,14 @@ public class TestAuthenticationStrategy {
challenges.put("digest", new AuthChallenge("Digest", challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "test"), new BasicNameValuePair("nonce", "1234"))); new BasicNameValuePair("realm", "test"), new BasicNameValuePair("nonce", "1234")));
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context); final List<AuthScheme> authSchemes = authStrategy.select(ChallengeType.TARGET, challenges, context);
Assert.assertNotNull(options); Assert.assertNotNull(authSchemes);
Assert.assertEquals(0, options.size()); Assert.assertEquals(0, authSchemes.size());
}
@Test
public void testSelectNoCredentialsProvider() throws Exception {
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final HttpClientContext context = HttpClientContext.create();
final Map<String, AuthChallenge> challenges = new HashMap<>();
challenges.put("basic", new AuthChallenge("Basic",
new BasicNameValuePair("realm", "test")));
challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "test"), new BasicNameValuePair("nonce", "1234")));
final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("basic", new BasicSchemeFactory())
.register("digest", new DigestSchemeFactory()).build();
context.setAuthSchemeRegistry(authSchemeRegistry);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context);
Assert.assertNotNull(options);
Assert.assertEquals(0, options.size());
}
@Test
public void testNoCredentials() throws Exception {
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final HttpClientContext context = HttpClientContext.create();
final Map<String, AuthChallenge> challenges = new HashMap<>();
challenges.put("basic", new AuthChallenge("Basic",
new BasicNameValuePair("realm", "realm1")));
challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "realm2"), new BasicNameValuePair("nonce", "1234")));
final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("basic", new BasicSchemeFactory())
.register("digest", new DigestSchemeFactory()).build();
context.setAuthSchemeRegistry(authSchemeRegistry);
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
context.setCredentialsProvider(credentialsProvider);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context);
Assert.assertNotNull(options);
Assert.assertEquals(0, options.size());
}
@Test
public void testCredentialsFound() throws Exception {
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final HttpClientContext context = HttpClientContext.create();
final Map<String, AuthChallenge> challenges = new HashMap<>();
challenges.put("basic", new AuthChallenge("Basic",
new BasicNameValuePair("realm", "realm1")));
challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "realm2"), new BasicNameValuePair("nonce", "1234")));
final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("basic", new BasicSchemeFactory())
.register("digest", new DigestSchemeFactory()).build();
context.setAuthSchemeRegistry(authSchemeRegistry);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope("somehost", 80, "realm2"),
new UsernamePasswordCredentials("user", "pwd"));
context.setCredentialsProvider(credentialsProvider);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context);
Assert.assertNotNull(options);
Assert.assertEquals(1, options.size());
final AuthOption option = options.remove();
Assert.assertTrue(option.getAuthScheme() instanceof DigestScheme);
} }
@Test @Test
public void testUnsupportedScheme() throws Exception { public void testUnsupportedScheme() throws Exception {
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy(); final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final HttpClientContext context = HttpClientContext.create(); final HttpClientContext context = HttpClientContext.create();
final Map<String, AuthChallenge> challenges = new HashMap<>(); final Map<String, AuthChallenge> challenges = new HashMap<>();
@ -203,13 +117,13 @@ public class TestAuthenticationStrategy {
new UsernamePasswordCredentials("user", "pwd")); new UsernamePasswordCredentials("user", "pwd"));
context.setCredentialsProvider(credentialsProvider); context.setCredentialsProvider(credentialsProvider);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context); final List<AuthScheme> authSchemes = authStrategy.select(ChallengeType.TARGET, challenges, context);
Assert.assertNotNull(options); Assert.assertNotNull(authSchemes);
Assert.assertEquals(2, options.size()); Assert.assertEquals(2, authSchemes.size());
final AuthOption option1 = options.remove(); final AuthScheme authScheme1 = authSchemes.get(0);
Assert.assertTrue(option1.getAuthScheme() instanceof DigestScheme); Assert.assertTrue(authScheme1 instanceof DigestScheme);
final AuthOption option2 = options.remove(); final AuthScheme authScheme2 = authSchemes.get(1);
Assert.assertTrue(option2.getAuthScheme() instanceof BasicScheme); Assert.assertTrue(authScheme2 instanceof BasicScheme);
} }
@Test @Test
@ -219,7 +133,6 @@ public class TestAuthenticationStrategy {
.setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)) .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
.build(); .build();
final HttpHost authhost = new HttpHost("somehost", 80);
final HttpClientContext context = HttpClientContext.create(); final HttpClientContext context = HttpClientContext.create();
final Map<String, AuthChallenge> challenges = new HashMap<>(); final Map<String, AuthChallenge> challenges = new HashMap<>();
@ -239,11 +152,11 @@ public class TestAuthenticationStrategy {
new UsernamePasswordCredentials("user", "pwd")); new UsernamePasswordCredentials("user", "pwd"));
context.setCredentialsProvider(credentialsProvider); context.setCredentialsProvider(credentialsProvider);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context); final List<AuthScheme> authSchemes = authStrategy.select(ChallengeType.TARGET, challenges, context);
Assert.assertNotNull(options); Assert.assertNotNull(authSchemes);
Assert.assertEquals(1, options.size()); Assert.assertEquals(1, authSchemes.size());
final AuthOption option1 = options.remove(); final AuthScheme authScheme1 = authSchemes.get(0);
Assert.assertTrue(option1.getAuthScheme() instanceof BasicScheme); Assert.assertTrue(authScheme1 instanceof BasicScheme);
} }
} }

View File

@ -28,8 +28,8 @@ package org.apache.http.impl.client.integration;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import org.apache.http.Consts; import org.apache.http.Consts;
@ -42,12 +42,11 @@ import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthChallenge; import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption; import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthScope;
import org.apache.http.auth.ChallengeType; import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials; import org.apache.http.auth.Credentials;
import org.apache.http.auth.CredentialsProvider; import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache; import org.apache.http.client.AuthCache;
import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ClientProtocolException;
@ -358,14 +357,13 @@ public class TestClientAuthentication extends LocalServerTestBase {
} }
@Override @Override
public Queue<AuthOption> select( public List<AuthScheme> select(
final ChallengeType challengeType, final ChallengeType challengeType,
final HttpHost host,
final Map<String, AuthChallenge> challenges, final Map<String, AuthChallenge> challenges,
final HttpContext context) throws MalformedChallengeException { final HttpContext context) {
final Queue<AuthOption> authOptions = super.select(challengeType, host, challenges, context); final List<AuthScheme> authSchemes = super.select(challengeType, challenges, context);
this.count.incrementAndGet(); this.count.incrementAndGet();
return authOptions; return authSchemes;
} }
public long getCount() { public long getCount() {

View File

@ -31,9 +31,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InterruptedIOException; import java.io.InterruptedIOException;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -48,8 +46,9 @@ import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion; import org.apache.http.HttpVersion;
import org.apache.http.auth.AuthChallenge; import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthProtocolState; import org.apache.http.auth.AuthProtocolState;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState; import org.apache.http.auth.AuthState;
import org.apache.http.auth.ChallengeType; import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.NTCredentials; import org.apache.http.auth.NTCredentials;
@ -74,6 +73,7 @@ import org.apache.http.conn.routing.RouteInfo;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.auth.NTLMScheme; import org.apache.http.impl.auth.NTLMScheme;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.conn.ConnectionShutdownException; import org.apache.http.impl.conn.ConnectionShutdownException;
import org.apache.http.message.BasicHttpResponse; import org.apache.http.message.BasicHttpResponse;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
@ -396,6 +396,10 @@ public class TestMainClientExec {
.setStream(instream2) .setStream(instream2)
.build()); .build());
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user:pass"));
context.setCredentialsProvider(credentialsProvider);
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE); Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE); Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
Mockito.when(requestExecutor.execute( Mockito.when(requestExecutor.execute(
@ -407,12 +411,8 @@ public class TestMainClientExec {
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE); Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
Mockito.when(targetAuthStrategy.select( Mockito.when(targetAuthStrategy.select(
Mockito.eq(ChallengeType.TARGET), Mockito.eq(ChallengeType.TARGET),
Mockito.eq(target),
Mockito.<Map<String, AuthChallenge>>any(), Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn(new LinkedList<>( Mockito.<HttpClientContext>any())).thenReturn(Collections.<AuthScheme>singletonList(new BasicScheme()));
Collections.singleton(new AuthOption(
new BasicScheme(),
new UsernamePasswordCredentials("user", "pass")))));
final CloseableHttpResponse finalResponse = mainClientExec.execute( final CloseableHttpResponse finalResponse = mainClientExec.execute(
route, request, context, execAware); route, request, context, execAware);
@ -447,6 +447,10 @@ public class TestMainClientExec {
final HttpClientContext context = new HttpClientContext(); final HttpClientContext context = new HttpClientContext();
context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, proxyAuthState); context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, proxyAuthState);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user:pass"));
context.setCredentialsProvider(credentialsProvider);
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE); Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE); Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
Mockito.when(requestExecutor.execute( Mockito.when(requestExecutor.execute(
@ -457,14 +461,10 @@ public class TestMainClientExec {
Mockito.<HttpResponse>any(), Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE); Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
final AuthOption authOption = new AuthOption(
new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
Mockito.when(targetAuthStrategy.select( Mockito.when(targetAuthStrategy.select(
Mockito.eq(ChallengeType.TARGET), Mockito.eq(ChallengeType.TARGET),
Mockito.eq(target),
Mockito.<Map<String, AuthChallenge>>any(), Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn( Mockito.<HttpClientContext>any())).thenReturn(Collections.<AuthScheme>singletonList(new BasicScheme()));
new LinkedList<>(Arrays.asList(authOption)));
final CloseableHttpResponse finalResponse = mainClientExec.execute( final CloseableHttpResponse finalResponse = mainClientExec.execute(
route, request, context, execAware); route, request, context, execAware);
@ -496,6 +496,10 @@ public class TestMainClientExec {
.setStream(instream1) .setStream(instream1)
.build()); .build());
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user:pass"));
context.setCredentialsProvider(credentialsProvider);
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE); Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE); Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
Mockito.when(requestExecutor.execute( Mockito.when(requestExecutor.execute(
@ -516,14 +520,10 @@ public class TestMainClientExec {
Mockito.<HttpResponse>any(), Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE); Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
final AuthOption authOption = new AuthOption(
new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
Mockito.when(targetAuthStrategy.select( Mockito.when(targetAuthStrategy.select(
Mockito.eq(ChallengeType.TARGET), Mockito.eq(ChallengeType.TARGET),
Mockito.eq(target),
Mockito.<Map<String, AuthChallenge>>any(), Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn( Mockito.<HttpClientContext>any())).thenReturn(Collections.<AuthScheme>singletonList(new BasicScheme()));
new LinkedList<>(Arrays.asList(authOption)));
mainClientExec.execute(route, request, context, execAware); mainClientExec.execute(route, request, context, execAware);
} }
@ -724,6 +724,10 @@ public class TestMainClientExec {
.build()); .build());
final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"); final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user:pass"));
context.setCredentialsProvider(credentialsProvider);
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE); Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
Mockito.when(reuseStrategy.keepAlive( Mockito.when(reuseStrategy.keepAlive(
Mockito.<HttpResponse>any(), Mockito.<HttpResponse>any(),
@ -733,14 +737,10 @@ public class TestMainClientExec {
Mockito.<HttpClientConnection>any(), Mockito.<HttpClientConnection>any(),
Mockito.<HttpClientContext>any())).thenReturn(response1, response2); Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
final AuthOption authOption = new AuthOption(
new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
Mockito.when(proxyAuthStrategy.select( Mockito.when(proxyAuthStrategy.select(
Mockito.eq(ChallengeType.PROXY), Mockito.eq(ChallengeType.PROXY),
Mockito.eq(proxy),
Mockito.<Map<String, AuthChallenge>>any(), Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn( Mockito.<HttpClientContext>any())).thenReturn(Collections.<AuthScheme>singletonList(new BasicScheme()));
new LinkedList<>(Arrays.asList(authOption)));
mainClientExec.establishRoute(authState, managedConn, route, request, context); mainClientExec.establishRoute(authState, managedConn, route, request, context);
@ -763,6 +763,10 @@ public class TestMainClientExec {
.build()); .build());
final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"); final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user:pass"));
context.setCredentialsProvider(credentialsProvider);
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE); Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
Mockito.when(reuseStrategy.keepAlive( Mockito.when(reuseStrategy.keepAlive(
Mockito.<HttpResponse>any(), Mockito.<HttpResponse>any(),
@ -772,14 +776,10 @@ public class TestMainClientExec {
Mockito.<HttpClientConnection>any(), Mockito.<HttpClientConnection>any(),
Mockito.<HttpClientContext>any())).thenReturn(response1, response2); Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
final AuthOption authOption = new AuthOption(
new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
Mockito.when(proxyAuthStrategy.select( Mockito.when(proxyAuthStrategy.select(
Mockito.eq(ChallengeType.PROXY), Mockito.eq(ChallengeType.PROXY),
Mockito.eq(proxy),
Mockito.<Map<String, AuthChallenge>>any(), Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn( Mockito.<HttpClientContext>any())).thenReturn(Collections.<AuthScheme>singletonList(new BasicScheme()));
new LinkedList<>(Arrays.asList(authOption)));
mainClientExec.establishRoute(authState, managedConn, route, request, context); mainClientExec.establishRoute(authState, managedConn, route, request, context);