AuthScheme API changes; User credentials made optional for those schemes that do not require them

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

View File

@ -29,18 +29,13 @@ package org.apache.http.client.fluent;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
@ -151,12 +146,14 @@ public class Executor {
}
public Executor authPreemptive(final HttpHost host) {
final BasicScheme basicScheme = new BasicScheme();
try {
basicScheme.processChallenge(ChallengeType.TARGET, new AuthChallenge("basic", null, Collections.<NameValuePair>emptyList()));
} catch (final MalformedChallengeException ignore) {
if (this.credentialsStore != null) {
final Credentials credentials = this.credentialsStore.getCredentials(new AuthScope(host));
if (credentials == null) {
final BasicScheme basicScheme = new BasicScheme();
basicScheme.initPreemptive(credentials);
this.authCache.put(host, basicScheme);
}
}
this.authCache.put(host, basicScheme);
return this;
}
@ -168,12 +165,14 @@ public class Executor {
}
public Executor authPreemptiveProxy(final HttpHost proxy) {
final BasicScheme basicScheme = new BasicScheme();
try {
basicScheme.processChallenge(ChallengeType.PROXY, new AuthChallenge("basic", null, Collections.<NameValuePair>emptyList()));
} catch (final MalformedChallengeException ignore) {
if (this.credentialsStore != null) {
final Credentials credentials = this.credentialsStore.getCredentials(new AuthScope(proxy));
if (credentials == null) {
final BasicScheme basicScheme = new BasicScheme();
basicScheme.initPreemptive(credentials);
this.authCache.put(proxy, basicScheme);
}
}
this.authCache.put(proxy, basicScheme);
return this;
}

View File

@ -65,10 +65,10 @@ public interface HttpCacheStorage {
void removeEntry(String key) throws IOException;
/**
* Atomically applies the given callback to update an existing cache
* Atomically applies the given callback to processChallenge an existing cache
* entry under a given key.
* @param key indicates which entry to modify
* @param callback performs the update; see
* @param callback performs the processChallenge; see
* {@link HttpCacheUpdateCallback} for details, but roughly the
* callback expects to be handed the current entry and will return
* the new value for the entry.

View File

@ -28,7 +28,7 @@ package org.apache.http.client.cache;
/**
* Signals that {@link HttpCacheStorage} encountered an error performing an
* update operation.
* processChallenge operation.
*
* @since 4.1
*/

View File

@ -165,7 +165,7 @@ class BasicHttpCache implements HttpCache {
try {
storage.updateEntry(parentURI, callback);
} catch (final HttpCacheUpdateException e) {
log.warn("Could not update key [" + parentURI + "]", e);
log.warn("Could not processChallenge key [" + parentURI + "]", e);
}
}
@ -189,7 +189,7 @@ class BasicHttpCache implements HttpCache {
try {
storage.updateEntry(parentCacheKey, callback);
} catch (final HttpCacheUpdateException e) {
log.warn("Could not update key [" + parentCacheKey + "]", e);
log.warn("Could not processChallenge key [" + parentCacheKey + "]", e);
}
}

View File

@ -113,7 +113,7 @@ public class CacheConfig implements Cloneable {
public final static int DEFAULT_MAX_CACHE_ENTRIES = 1000;
/** Default setting for the number of retries on a failed
* cache update
* cache processChallenge
*/
public final static int DEFAULT_MAX_UPDATE_RETRIES = 1;
@ -234,7 +234,7 @@ public class CacheConfig implements Cloneable {
}
/**
* Returns the number of times to retry a cache update on failure
* Returns the number of times to retry a cache processChallenge on failure
*/
public int getMaxUpdateRetries(){
return maxUpdateRetries;
@ -400,7 +400,7 @@ public class CacheConfig implements Cloneable {
}
/**
* Sets the number of times to retry a cache update on failure
* Sets the number of times to retry a cache processChallenge on failure
*/
public Builder setMaxUpdateRetries(final int maxUpdateRetries) {
this.maxUpdateRetries = maxUpdateRetries;

View File

@ -48,7 +48,7 @@ import org.apache.http.util.Args;
/**
* Update a {@link HttpCacheEntry} with new or updated information based on the latest
* 304 status response from the Server. Use the {@link HttpResponse} to perform
* the update.
* the processChallenge.
*
* @since 4.1
*/

View File

@ -712,7 +712,7 @@ public class CachingExec implements ClientExecChain {
responseEntry = responseCache.updateVariantCacheEntry(target, conditionalRequest,
matchedEntry, backendResponse, requestDate, responseDate, matchingVariant.getCacheKey());
} catch (final IOException ioe) {
log.warn("Could not update cache entry", ioe);
log.warn("Could not processChallenge cache entry", ioe);
} finally {
backendResponse.close();
}
@ -726,7 +726,7 @@ public class CachingExec implements ClientExecChain {
try {
responseCache.reuseVariantEntryFor(target, request, matchingVariant);
} catch (final IOException ioe) {
log.warn("Could not update cache entry to reuse variant", ioe);
log.warn("Could not processChallenge cache entry to reuse variant", ioe);
}
}

View File

@ -98,7 +98,7 @@ public class DefaultFailureCache implements FailureCache {
*
* In case there is a lot of contention on that identifier, a thread
* might starve. Thus it gives up after a certain number of failed
* update tries.
* processChallenge tries.
*/
for (int i = 0; i < MAX_UPDATE_TRIES; i++) {
final FailureCacheValue oldValue = storage.get(identifier);

View File

@ -159,7 +159,7 @@ interface HttpCache {
* @param target host of the upstream client request
* @param req request sent by upstream client
* @param variant variant cache entry to reuse
* @throws IOException may be thrown during cache update
* @throws IOException may be thrown during cache processChallenge
*/
void reuseVariantEntryFor(HttpHost target, final HttpRequest req,
final Variant variant) throws IOException;

View File

@ -156,6 +156,6 @@ public class EhcacheHttpCacheStorage implements HttpCacheStorage {
}
}
}while(numRetries <= maxUpdateRetries);
throw new HttpCacheUpdateException("Failed to update");
throw new HttpCacheUpdateException("Failed to processChallenge");
}
}

View File

@ -268,6 +268,6 @@ public class MemcachedHttpCacheStorage implements HttpCacheStorage {
}
} while (numRetries <= maxUpdateRetries);
throw new HttpCacheUpdateException("Failed to update");
throw new HttpCacheUpdateException("Failed to processChallenge");
}
}

View File

@ -1208,7 +1208,7 @@ public class TestProtocolRecommendations extends AbstractProtocolTest {
}
/* "If the entity-tag of the new response matches that of an existing
* entry, the new response SHOULD be used to update the header fields
* entry, the new response SHOULD be used to processChallenge the header fields
* of the existing entry, and the result MUST be returned to the
* client."
*

View File

@ -2198,8 +2198,8 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
}
/*
* "If a cache uses a received 304 response to update a cache entry, the
* cache MUST update the entry to reflect any new field values given in the
* "If a cache uses a received 304 response to processChallenge a cache entry, the
* cache MUST processChallenge the entry to reflect any new field values given in the
* response.
*
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
@ -4539,7 +4539,7 @@ public class TestProtocolRequirements extends AbstractProtocolTest {
* the ETag header field in its 304 (Not Modified) response to
* tell the cache which entry is appropriate. If the entity-tag of
* the new response matches that of an existing entry, the new
* response SHOULD be used to update the header fields of the
* response SHOULD be used to processChallenge the header fields of the
* existing entry, and the result MUST be returned to the client.
*
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.6

View File

@ -168,7 +168,7 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
when(mockCache.get(key)).thenReturn(existingElement);
when(mockSerializer.readFrom(isA(InputStream.class))).thenReturn(existingValue);
// update
// processChallenge
mockSerializer.writeTo(same(updatedValue), isA(OutputStream.class));
when(mockCache.replace(same(existingElement), isA(Element.class))).thenReturn(true);
@ -231,7 +231,7 @@ public class TestEhcacheHttpCacheStorage extends TestCase {
when(mockCache.get(key)).thenReturn(existingElement);
when(mockSerializer.readFrom(isA(InputStream.class))).thenReturn(existingValue);
// update but fail
// processChallenge but fail
when(mockCache.replace(same(existingElement), isA(Element.class))).thenReturn(false);
try{

View File

@ -1,108 +0,0 @@
/*
* ====================================================================
* 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.auth.win;
import java.io.Serializable;
import java.security.Principal;
import org.apache.http.annotation.Immutable;
import org.apache.http.auth.Credentials;
import com.sun.jna.platform.win32.Secur32.EXTENDED_NAME_FORMAT;
import com.sun.jna.platform.win32.Secur32Util;
/**
* Returns the current Windows user credentials
* <p>
* EXPERIMENTAL
* </p>
*
* @since 4.4
*/
@Immutable
public final class CurrentWindowsCredentials implements Credentials, Serializable, Principal {
private static final long serialVersionUID = 4361166468529298169L;
public static final CurrentWindowsCredentials INSTANCE = new CurrentWindowsCredentials();
/**
* Get the SAM-compatible username of the currently logged-on user.
*
* @return String.
*/
public static String getCurrentUsername() {
return Secur32Util.getUserNameEx(EXTENDED_NAME_FORMAT.NameSamCompatible);
}
private CurrentWindowsCredentials() {
}
@Override
public Principal getUserPrincipal() {
return this;
}
@Override
public int hashCode() {
return getClass().hashCode();
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
return getClass().equals(o.getClass());
}
@Override
public String toString() {
return getCurrentUsername();
}
/**
* Returns an empty password
*/
@Override
public String getPassword() {
return "";
}
@Override
public String getName() {
return getCurrentUsername();
}
}

View File

@ -1,76 +0,0 @@
/*
* ====================================================================
* 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.auth.win;
import org.apache.http.annotation.ThreadSafe;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.client.CredentialsStore;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.util.Args;
/**
* {@link CredentialsStore} implementation that always returns
* {@link org.apache.http.impl.auth.win.CurrentWindowsCredentials} instance to NTLM
* and SPNego authentication challenges.
* <p>
* EXPERIMENTAL
* </p>
*
* @since 4.4
*/
@ThreadSafe
public class WindowsCredentialsProvider implements CredentialsStore {
private final CredentialsStore provider;
public WindowsCredentialsProvider(final CredentialsStore provider) {
this.provider = Args.notNull(provider, "Credentials provider");
}
@Override
public Credentials getCredentials(final AuthScope authscope) {
final String scheme = authscope.getScheme();
if (AuthSchemes.NTLM.equalsIgnoreCase(scheme) || AuthSchemes.SPNEGO.equalsIgnoreCase(scheme)) {
return CurrentWindowsCredentials.INSTANCE;
} else {
return provider.getCredentials(authscope);
}
}
@Override
public void setCredentials(final AuthScope authscope, final Credentials credentials) {
provider.setCredentials(authscope, credentials);
}
@Override
public void clear() {
provider.clear();
}
}

View File

@ -26,29 +26,28 @@
*/
package org.apache.http.impl.auth.win;
import java.security.Principal;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.InvalidCredentialsException;
import org.apache.http.auth.BasicUserPrincipal;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.routing.RouteInfo;
import org.apache.http.impl.auth.NonStandardAuthScheme;
import org.apache.http.message.BufferedHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.Args;
import com.sun.jna.platform.win32.Secur32;
import com.sun.jna.platform.win32.Secur32Util;
import com.sun.jna.platform.win32.Sspi;
import com.sun.jna.platform.win32.Sspi.CredHandle;
import com.sun.jna.platform.win32.Sspi.CtxtHandle;
@ -70,7 +69,7 @@ import com.sun.jna.ptr.IntByReference;
* @since 4.4
*/
@NotThreadSafe
public class WindowsNegotiateScheme extends NonStandardAuthScheme {
public class WindowsNegotiateScheme implements AuthScheme {
private final Log log = LogFactory.getLog(getClass());
@ -78,6 +77,7 @@ public class WindowsNegotiateScheme extends NonStandardAuthScheme {
private final String scheme;
private final String servicePrincipalName;
private String challenge;
private CredHandle clientCred;
private CtxtHandle sspiContext;
private boolean continueNeeded;
@ -119,7 +119,7 @@ public class WindowsNegotiateScheme extends NonStandardAuthScheme {
}
@Override
public String getSchemeName() {
public String getName() {
return scheme;
}
@ -128,11 +128,20 @@ public class WindowsNegotiateScheme extends NonStandardAuthScheme {
return true;
}
@Override
public String getRealm() {
return null;
}
@Override
public void processChallenge(
final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
final String challenge = getChallenge();
final AuthChallenge authChallenge,
final HttpContext context) throws MalformedChallengeException {
Args.notNull(authChallenge, "AuthChallenge");
if (authChallenge.getValue() == null) {
throw new MalformedChallengeException("Missing auth challenge");
}
challenge = authChallenge.getValue();
if (challenge.isEmpty()) {
if (clientCred != null) {
dispose(); // run cleanup first before throwing an exception otherwise can leak OS resources
@ -144,24 +153,38 @@ public class WindowsNegotiateScheme extends NonStandardAuthScheme {
}
@Override
public Header authenticate(
final Credentials credentials,
public boolean isResponseReady(
final HttpHost host,
final CredentialsProvider credentialsProvider,
final HttpContext context) throws AuthenticationException {
return true;
}
/**
* Get the SAM-compatible username of the currently logged-on user.
*
* @return String.
*/
public static String getCurrentUsername() {
return Secur32Util.getUserNameEx(Secur32.EXTENDED_NAME_FORMAT.NameSamCompatible);
}
@Override
public Principal getPrinciple() {
return new BasicUserPrincipal(getCurrentUsername());
}
@Override
public String generateAuthResponse(
final HttpHost host,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
final String challenge = getChallenge();
final String response;
if (clientCred == null) {
// ?? We don't use the credentials, should we allow anything?
if (!(credentials instanceof CurrentWindowsCredentials)) {
throw new InvalidCredentialsException(
"Credentials cannot be used for " + getSchemeName() + " authentication: "
+ credentials.getClass().getName());
}
// client credentials handle
try {
final String username = CurrentWindowsCredentials.getCurrentUsername();
final String username = getCurrentUsername();
final TimeStamp lifetime = new TimeStamp();
clientCred = new CredHandle();
@ -202,18 +225,7 @@ public class WindowsNegotiateScheme extends NonStandardAuthScheme {
}
}
}
final CharArrayBuffer buffer = new CharArrayBuffer(scheme.length() + 30);
if (isProxy()) {
buffer.append(HttpHeaders.PROXY_AUTHORIZATION);
} else {
buffer.append(HttpHeaders.AUTHORIZATION);
}
buffer.append(": ");
buffer.append(scheme); // NTLM or Negotiate
buffer.append(" ");
buffer.append(response);
return new BufferedHeader(buffer);
return scheme + " " + response;
}
private void failAuthCleanup() {
@ -281,7 +293,7 @@ public class WindowsNegotiateScheme extends NonStandardAuthScheme {
}
@Override
public boolean isComplete() {
public boolean isChallengeComplete() {
return !continueNeeded;
}

View File

@ -29,13 +29,11 @@ package org.apache.http.impl.client;
import java.util.Locale;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.auth.DigestSchemeFactory;
import org.apache.http.impl.auth.win.WindowsCredentialsProvider;
import org.apache.http.impl.auth.win.WindowsNTLMSchemeFactory;
import org.apache.http.impl.auth.win.WindowsNegotiateSchemeFactory;
@ -74,9 +72,7 @@ public class WinHttpClients {
.register(AuthSchemes.NTLM, new WindowsNTLMSchemeFactory(null))
.register(AuthSchemes.SPNEGO, new WindowsNegotiateSchemeFactory(null))
.build();
final CredentialsProvider credsProvider = new WindowsCredentialsProvider(new SystemDefaultCredentialsProvider());
return HttpClientBuilder.create()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultAuthSchemeRegistry(authSchemeRegistry);
} else {
return HttpClientBuilder.create();

View File

@ -36,7 +36,6 @@ import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
@ -44,7 +43,6 @@ import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
import org.apache.http.impl.client.WinHttpClients;
import org.apache.http.localserver.LocalServerTestBase;
import org.apache.http.protocol.HttpContext;
@ -105,10 +103,7 @@ public class TestWindowsNegotiateScheme extends LocalServerTestBase {
return new WindowsNegotiateSchemeGetTokenFail(AuthSchemes.SPNEGO, "HTTP/example.com");
}
}).build();
final CredentialsProvider credsProvider =
new WindowsCredentialsProvider(new SystemDefaultCredentialsProvider());
final CloseableHttpClient customClient = HttpClientBuilder.create()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultAuthSchemeRegistry(authSchemeRegistry).build();
final HttpHost target = start();

View File

@ -27,7 +27,6 @@
package org.apache.http.examples.client;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.methods.CloseableHttpResponse;
@ -35,7 +34,6 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
@ -52,18 +50,13 @@ public class ClientPreemptiveBasicAuthentication {
public static void main(String[] args) throws Exception {
HttpHost target = new HttpHost("localhost", 80, "http");
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(target.getHostName(), target.getPort()),
new UsernamePasswordCredentials("username", "password"));
try (CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider).build()) {
try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local
// auth cache
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
basicAuth.initPreemptive(new UsernamePasswordCredentials("username", "password"));
authCache.put(target, basicAuth);
// Add AuthCache to the execution context

View File

@ -27,7 +27,6 @@
package org.apache.http.examples.client;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.methods.CloseableHttpResponse;
@ -35,7 +34,6 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
@ -53,23 +51,14 @@ public class ClientPreemptiveDigestAuthentication {
public static void main(String[] args) throws Exception {
HttpHost target = new HttpHost("localhost", 80, "http");
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(target.getHostName(), target.getPort()),
new UsernamePasswordCredentials("username", "password"));
try (CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.build()) {
try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate DIGEST scheme object, initialize it and add it to the local
// auth cache
// Generate DIGEST scheme object, initialize it and add it to the local auth cache
DigestScheme digestAuth = new DigestScheme();
// Suppose we already know the realm name
digestAuth.overrideParamter("realm", "some realm");
// Suppose we already know the expected nonce value
digestAuth.overrideParamter("nonce", "whatever");
// Suppose we already know the realm name and the expected nonce value
digestAuth.initPreemptive(new UsernamePasswordCredentials("username", "password"), "whatever", "realm");
authCache.put(target, digestAuth);
// Add AuthCache to the execution context

View File

@ -1,63 +0,0 @@
/*
* ====================================================================
* 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.auth;
import org.apache.http.annotation.Immutable;
import org.apache.http.util.Args;
/**
* @since 4.2
*/
@Immutable
public final class AuthOption {
private final AuthScheme authScheme;
private final Credentials creds;
public AuthOption(final AuthScheme authScheme, final Credentials creds) {
super();
Args.notNull(authScheme, "Auth scheme");
Args.notNull(creds, "User credentials");
this.authScheme = authScheme;
this.creds = creds;
}
public AuthScheme getAuthScheme() {
return this.authScheme;
}
public Credentials getCredentials() {
return this.creds;
}
@Override
public String toString() {
return this.authScheme.toString();
}
}

View File

@ -26,69 +26,106 @@
*/
package org.apache.http.auth;
import org.apache.http.Header;
import java.security.Principal;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.protocol.HttpContext;
/**
* This interface represents an abstract challenge-response oriented
* authentication scheme.
* This interface represents an abstract challenge-response oriented authentication scheme.
* <p>
* Authentication schemes may be stateful involving a series of
* challenge-response exchanges.
* Authentication schemes can be either request or connection based. The former are
* expected to provide an authorization response with each request message while the latter
* is executed only once and applies to the underlying connection for its entire life span.
* Care must be taken when re-using connections authorized through a connection based
* authentication scheme and they may carry a particular security context and be authorized
* for a particular user identity. It is important that such schemes always provide
* the user identity they represent through the {@link #getPrinciple()} method.
* <p>
* Authentication scheme are expected to transition through a series of standard phases or
* states.
* <p>
* Authentication scheme starts off its life cycle with no context and no specific state.
* <p>
* The {@link #processChallenge(AuthChallenge, HttpContext)} method is called to
* process an authentication challenge received either from the target server or a proxy.
* The authentication scheme transitions to CHALLENGED state and is expected to validate
* the token passed to it as a parameter and initialize its internal state based on
* challenge details. Standard authentication schemes are expected to provide a realm
* attribute in the challenge. {@link #getRealm()} can be called to obtain an identifier
* of the realm that requires authorization.
* <p>
* Once the challenge has been fully processed the {@link #isResponseReady(HttpHost,
* CredentialsProvider, HttpContext)} method to determine whether the scheme is capable of
* generating a authorization response based on its current state and it holds user credentials
* required to do so. If this method returns {@code false} the authentication is considered
* to be in FAILED state and no authorization response. Otherwise the scheme is considered
* to be in RESPONSE_READY state.
* <p>
* Once the scheme is ready to respond to the challenge the {@link #generateAuthResponse(
* HttpHost, HttpRequest, HttpContext)} method to generate a response token, which will
* be sent to the opposite endpoint in the subsequent request message.
* <p>
* Certain non-standard schemes may involve multiple challenge / response exchanges to
* fully establish a shared context and complete the authentication process. Authentication
* schemes are required to return {@code true} {@link #isChallengeComplete()} once the
* handshake is considered complete.
* <p>
* The authentication scheme is considered successfully completed and in SUCCESS state
* if the opposite endpoint accepts the request message containing the authorization
* response and responds with a message indicating no authentication failure .
* If the opposite endpoint sends status code 401 or 407 in response to a request message
* containing the terminal authorization response, the scheme is considered unsuccessful
* and in FAILED state.
*
* @since 4.0
*/
public interface AuthScheme {
/**
* Processes the given challenge token. Some authentication schemes
* may involve multiple challenge-response exchanges. Such schemes must be able
* to maintain the state information when dealing with sequential challenges
*
* @param challengeType the challenge type
* @param authChallenge the auth challenge
*
* @since 5.0
*/
void processChallenge(
ChallengeType challengeType,
AuthChallenge authChallenge) throws MalformedChallengeException;
/**
* Produces an authorization string for the given set of {@link Credentials}.
*
* @param credentials The credentials to be used for authentication
* @param request The request being authenticated
* @param context HTTP context
* @throws AuthenticationException if authorization string cannot
* be generated due to an authentication failure
*
* @return authorization header
*
* @since 5.0
*/
Header authenticate(
Credentials credentials,
HttpRequest request,
HttpContext context) throws AuthenticationException;
/**
* Returns textual designation of the given authentication scheme.
*
* @return the name of the given authentication scheme
*/
String getSchemeName();
String getName();
/**
* Returns authentication parameter with the given name, if available.
* Determines if the authentication scheme is expected to provide an authorization response
* on a per connection basis instead of the standard per request basis
*
* @param name The name of the parameter to be returned
*
* @return the parameter with the given name
* @return {@code true} if the scheme is connection based, {@code false}
* if the scheme is request based.
*/
String getParameter(final String name);
boolean isConnectionBased();
/**
* Processes the given auth challenge. Some authentication schemes may involve multiple
* challenge-response exchanges. Such schemes must be able to maintain internal state
* when dealing with sequential challenges
*
* @param authChallenge the auth challenge
* @param context HTTP context
* @throws MalformedChallengeException in case the auth challenge is incomplete,
* malformed or otherwise invalid.
* @since 5.0
*/
void processChallenge(
AuthChallenge authChallenge,
HttpContext context) throws MalformedChallengeException;
/**
* Authentication process may involve a series of challenge-response exchanges.
* This method tests if the authorization process has been fully completed (either
* successfully or unsuccessfully), that is, all the required authorization
* challenges have been processed in their entirety.
*
* @return {@code true} if the authentication process has been completed,
* {@code false} otherwise.
*
* @since 5.0
*/
boolean isChallengeComplete();
/**
* Returns authentication realm. If the concept of an authentication
@ -100,23 +137,58 @@ public interface AuthScheme {
String getRealm();
/**
* Tests if the authentication scheme is provides authorization on a per
* connection basis instead of usual per request basis
* Determines whether or not an authorization response can be generated based on
* the actual authentication state. Generally the outcome of this method will depend
* upon availability of user credentials necessary to produce an authorization
* response.
*
* @return {@code true} if the scheme is connection based, {@code false}
* if the scheme is request based.
* @param credentialsProvider The credentials to be used for authentication
* @param context HTTP context
* @throws AuthenticationException if authorization string cannot
* be generated due to an authentication failure
*
* @return {@code true} if an authorization response can be generated and
* the authentication handshake can proceed, {@code false} otherwise.
*
* @since 5.0
*/
boolean isConnectionBased();
boolean isResponseReady(
HttpHost host,
CredentialsProvider credentialsProvider,
HttpContext context) throws AuthenticationException;
/**
* Authentication process may involve a series of challenge-response exchanges.
* This method tests if the authorization process has been completed, either
* successfully or unsuccessfully, that is, all the required authorization
* challenges have been processed in their entirety.
* Returns {@link Principal} whose credentials are used to generate
* an authentication response. Connection based schemes are required
* to return a user {@link Principal} if authorization applies to
* for the entire life span of connection.
* @return user principle
*
* @return {@code true} if the authentication process has been completed,
* {@code false} otherwise.
* @see #isConnectionBased()
*
* @since 5.0
*/
boolean isComplete();
Principal getPrinciple();
/**
* Generates an authorization response based on the current state. Some authentication
* schemes may need to load user credentials required to generate an authorization
* response from a {@link CredentialsProvider} prior to this method call.
*
* @param request The request being authenticated
* @param context HTTP context
* @throws AuthenticationException if authorization string cannot
* be generated due to an authentication failure
*
* @return authorization header
*
* @see #isResponseReady(HttpHost, CredentialsProvider, HttpContext)
*
* @since 5.0
*/
String generateAuthResponse(
HttpHost host,
HttpRequest request,
HttpContext context) throws AuthenticationException;
}

View File

@ -45,11 +45,8 @@ public class AuthState {
/** Actual authentication scheme */
private AuthScheme authScheme;
/** Credentials selected for authentication */
private Credentials credentials;
/** Available auth options */
private Queue<AuthOption> authOptions;
private Queue<AuthScheme> authOptions;
public AuthState() {
super();
@ -65,7 +62,6 @@ public class AuthState {
this.state = AuthProtocolState.UNCHALLENGED;
this.authOptions = null;
this.authScheme = null;
this.credentials = null;
}
/**
@ -90,71 +86,48 @@ public class AuthState {
}
/**
* Returns actual {@link Credentials}. May be null.
*/
public Credentials getCredentials() {
return this.credentials;
}
/**
* Updates the auth state with {@link AuthScheme} and {@link Credentials}.
* Updates the auth state with {@link AuthScheme} and clears auth options.
*
* @param authScheme auth scheme. May not be null.
* @param credentials user crednetials. May not be null.
*
* @since 4.2
*/
public void update(final AuthScheme authScheme, final Credentials credentials) {
public void update(final AuthScheme authScheme) {
Args.notNull(authScheme, "Auth scheme");
Args.notNull(credentials, "Credentials");
this.authScheme = authScheme;
this.credentials = credentials;
this.authOptions = null;
}
/**
* Returns available {@link AuthOption}s. May be null.
* Returns available auth options. May be null.
*
* @since 4.2
*/
public Queue<AuthOption> getAuthOptions() {
public Queue<AuthScheme> getAuthOptions() {
return this.authOptions;
}
/**
* Returns {@code true} if {@link AuthOption}s are available, {@code false}
* otherwise.
*
* @since 4.2
*/
public boolean hasAuthOptions() {
return this.authOptions != null && !this.authOptions.isEmpty();
}
/**
* Updates the auth state with a queue of {@link AuthOption}s.
* Updates the auth state with a queue of auth options.
*
* @param authOptions a queue of auth options. May not be null or empty.
*
* @since 4.2
*/
public void update(final Queue<AuthOption> authOptions) {
public void update(final Queue<AuthScheme> authOptions) {
Args.notEmpty(authOptions, "Queue of auth options");
this.authOptions = authOptions;
this.authScheme = null;
this.credentials = null;
}
@Override
public String toString() {
final StringBuilder buffer = new StringBuilder();
buffer.append("state:").append(this.state).append(";");
buffer.append("[").append(this.state);
if (this.authScheme != null) {
buffer.append("auth scheme:").append(this.authScheme.getSchemeName()).append(";");
}
if (this.credentials != null) {
buffer.append("credentials present");
buffer.append(" ").append(this.authScheme);
}
buffer.append("]");
return buffer.toString();
}

View File

@ -38,9 +38,7 @@ import org.apache.http.HttpRequestInterceptor;
import org.apache.http.annotation.Immutable;
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.Credentials;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.client.AuthCache;
import org.apache.http.conn.routing.RouteInfo;
@ -106,7 +104,10 @@ public class RequestAuthCache implements HttpRequestInterceptor {
if (targetState != null && targetState.getState() == AuthProtocolState.UNCHALLENGED) {
final AuthScheme authScheme = authCache.get(target);
if (authScheme != null) {
doPreemptiveAuth(target, authScheme, targetState, credsProvider);
if (this.log.isDebugEnabled()) {
this.log.debug("Re-using cached '" + authScheme.getName() + "' auth scheme for " + target);
}
targetState.update(authScheme);
}
}
@ -115,34 +116,12 @@ public class RequestAuthCache implements HttpRequestInterceptor {
if (proxy != null && proxyState != null && proxyState.getState() == AuthProtocolState.UNCHALLENGED) {
final AuthScheme authScheme = authCache.get(proxy);
if (authScheme != null) {
doPreemptiveAuth(proxy, authScheme, proxyState, credsProvider);
if (this.log.isDebugEnabled()) {
this.log.debug("Re-using cached '" + authScheme.getName() + "' auth scheme for " + proxy);
}
proxyState.update(authScheme);
}
}
}
private void doPreemptiveAuth(
final HttpHost host,
final AuthScheme authScheme,
final AuthState authState,
final CredentialsProvider credsProvider) {
final String schemeName = authScheme.getSchemeName();
if (this.log.isDebugEnabled()) {
this.log.debug("Re-using cached '" + schemeName + "' auth scheme for " + host);
}
final AuthScope authScope = new AuthScope(host, AuthScope.ANY_REALM, schemeName);
final Credentials creds = credsProvider.getCredentials(authScope);
if (creds != null) {
if ("BASIC".equalsIgnoreCase(authScheme.getSchemeName())) {
authState.setState(AuthProtocolState.CHALLENGED);
} else {
authState.setState(AuthProtocolState.SUCCESS);
}
authState.update(authScheme, creds);
} else {
this.log.debug("No credentials for preemptive authentication");
}
}
}

View File

@ -41,7 +41,7 @@ package org.apache.http.cookie;
public interface CookieAttributeHandler {
/**
* Parse the given cookie attribute value and update the corresponding
* Parse the given cookie attribute value and processChallenge the corresponding
* {@link org.apache.http.cookie.Cookie} property.
*
* @param cookie {@link org.apache.http.cookie.Cookie} to be updated

View File

@ -54,7 +54,7 @@ public class CookiePriorityComparator implements Comparator<Cookie> {
public int compare(final Cookie c1, final Cookie c2) {
final int l1 = getPathLength(c1);
final int l2 = getPathLength(c2);
//TODO: update this class once Cookie interface has been expended with #getCreationTime method
//TODO: processChallenge this class once Cookie interface has been expended with #getCreationTime method
final int result = l2 - l1;
if (result == 0 && c1 instanceof BasicClientCookie && c2 instanceof BasicClientCookie) {
final Date d1 = ((BasicClientCookie) c1).getCreationDate();

View File

@ -30,23 +30,29 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.security.Principal;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthenticationException;
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.message.BufferedHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.CharsetUtils;
import org.apache.http.util.EncodingUtils;
@ -56,17 +62,21 @@ import org.apache.http.util.EncodingUtils;
* @since 4.0
*/
@NotThreadSafe
public class BasicScheme extends StandardAuthScheme {
public class BasicScheme implements AuthScheme, Serializable {
private static final long serialVersionUID = -1931571557597830536L;
private final Map<String, String> paramMap;
private transient Charset charset;
private boolean complete;
private String username;
private String password;
/**
* @since 4.3
*/
public BasicScheme(final Charset charset) {
this.paramMap = new HashMap<>();
this.charset = charset != null ? charset : Consts.ASCII;
this.complete = false;
}
@ -75,54 +85,88 @@ public class BasicScheme extends StandardAuthScheme {
this(Consts.ASCII);
}
public void initPreemptive(final Credentials credentials) {
if (credentials != null) {
this.username = credentials.getUserPrincipal().getName();
this.password = credentials.getPassword();
} else {
this.username = null;
this.password = null;
}
}
@Override
public String getSchemeName() {
public String getName() {
return "basic";
}
public void processChallenge(
final ChallengeType challengeType,
final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
this.complete = true;
}
@Override
public boolean isComplete() {
return this.complete;
}
@Override
public boolean isConnectionBased() {
return false;
}
@Override
public Header authenticate(
final Credentials credentials,
final HttpRequest request,
public String getRealm() {
return this.paramMap.get("realm");
}
@Override
public void processChallenge(
final AuthChallenge authChallenge,
final HttpContext context) throws MalformedChallengeException {
this.paramMap.clear();
final List<NameValuePair> params = authChallenge.getParams();
if (params != null) {
for (NameValuePair param: params) {
this.paramMap.put(param.getName().toLowerCase(Locale.ROOT), param.getValue());
}
}
this.complete = true;
}
@Override
public boolean isChallengeComplete() {
return this.complete;
}
@Override
public boolean isResponseReady(
final HttpHost host,
final CredentialsProvider credentialsProvider,
final HttpContext context) throws AuthenticationException {
Args.notNull(credentials, "Credentials");
Args.notNull(request, "HTTP request");
final CharArrayBuffer buffer = new CharArrayBuffer(32);
if (isProxy()) {
buffer.append(HttpHeaders.PROXY_AUTHORIZATION);
Args.notNull(host, "Auth host");
Args.notNull(credentialsProvider, "CredentialsProvider");
final Credentials credentials = credentialsProvider.getCredentials(new AuthScope(host, getRealm(), getName()));
if (credentials != null) {
this.username = credentials.getUserPrincipal().getName();
this.password = credentials.getPassword();
return true;
} else {
buffer.append(HttpHeaders.AUTHORIZATION);
this.username = null;
this.password = null;
return false;
}
buffer.append(": Basic ");
}
final StringBuilder tmp = new StringBuilder();
tmp.append(credentials.getUserPrincipal().getName());
tmp.append(":");
tmp.append((credentials.getPassword() == null) ? "null" : credentials.getPassword());
@Override
public Principal getPrinciple() {
return null;
}
@Override
public String generateAuthResponse(
final HttpHost host,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
final StringBuilder buffer = new StringBuilder();
buffer.append(this.username);
buffer.append(":");
buffer.append(this.password);
final Base64 base64codec = new Base64(0);
final byte[] base64password = base64codec.encode(EncodingUtils.getBytes(tmp.toString(), charset.name()));
buffer.append(base64password, 0, base64password.length);
return new BufferedHeader(buffer);
final byte[] encodedCreds = base64codec.encode(EncodingUtils.getBytes(buffer.toString(), charset.name()));
return "Basic " + new String(encodedCreds, 0, encodedCreds.length, Consts.ASCII);
}
private void writeObject(final ObjectOutputStream out) throws IOException {
@ -142,4 +186,9 @@ public class BasicScheme extends StandardAuthScheme {
private void readObjectNoData() throws ObjectStreamException {
}
@Override
public String toString() {
return this.paramMap.toString();
}
}

View File

@ -27,30 +27,35 @@
package org.apache.http.impl.auth;
import java.io.IOException;
import java.io.Serializable;
import java.security.MessageDigest;
import java.security.Principal;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthenticationException;
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.message.BasicHeaderValueFormatter;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.message.BufferedHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;
import org.apache.http.util.CharArrayBuffer;
@ -71,7 +76,7 @@ import org.apache.http.util.EncodingUtils;
* @since 4.0
*/
@NotThreadSafe
public class DigestScheme extends StandardAuthScheme {
public class DigestScheme implements AuthScheme, Serializable {
private static final long serialVersionUID = 3883908186234566916L;
@ -86,49 +91,37 @@ public class DigestScheme extends StandardAuthScheme {
'e', 'f'
};
/** Whether the digest authentication process is complete */
private boolean complete;
private static final int QOP_UNKNOWN = -1;
private static final int QOP_MISSING = 0;
private static final int QOP_AUTH_INT = 1;
private static final int QOP_AUTH = 2;
private final Map<String, String> paramMap;
private boolean complete;
private String lastNonce;
private long nounceCount;
private String cnonce;
private String a1;
private String a2;
private String username;
private String password;
public DigestScheme() {
this.paramMap = new HashMap<>();
this.complete = false;
}
@Override
public void processChallenge(
final ChallengeType challengeType,
final AuthChallenge authChallenge) throws MalformedChallengeException {
Args.notNull(challengeType, "ChallengeType");
Args.notNull(authChallenge, "AuthChallenge");
update(challengeType, authChallenge);
if (getParameters().isEmpty()) {
throw new MalformedChallengeException("Missing digest auth parameters");
}
this.complete = true;
public void initPreemptive(final Credentials credentials, final String cnonce, final String realm) {
Args.notNull(credentials, "Credentials");
this.username = credentials.getUserPrincipal().getName();
this.password = credentials.getPassword();
this.paramMap.put("cnonce", cnonce);
this.paramMap.put("realm", realm);
}
@Override
public boolean isComplete() {
final String s = getParameter("stale");
if ("true".equalsIgnoreCase(s)) {
return false;
} else {
return this.complete;
}
}
@Override
public String getSchemeName() {
public String getName() {
return "digest";
}
@ -137,28 +130,79 @@ public class DigestScheme extends StandardAuthScheme {
return false;
}
public void overrideParamter(final String name, final String value) {
getParameters().put(name, value);
@Override
public String getRealm() {
return this.paramMap.get("realm");
}
@Override
public Header authenticate(
final Credentials credentials,
public void processChallenge(
final AuthChallenge authChallenge,
final HttpContext context) throws MalformedChallengeException {
Args.notNull(authChallenge, "AuthChallenge");
this.paramMap.clear();
final List<NameValuePair> params = authChallenge.getParams();
if (params != null) {
for (NameValuePair param: params) {
this.paramMap.put(param.getName().toLowerCase(Locale.ROOT), param.getValue());
}
}
if (this.paramMap.isEmpty()) {
throw new MalformedChallengeException("Missing digest auth parameters");
}
this.complete = true;
}
@Override
public boolean isChallengeComplete() {
final String s = this.paramMap.get("stale");
if ("true".equalsIgnoreCase(s)) {
return false;
} else {
return this.complete;
}
}
@Override
public boolean isResponseReady(
final HttpHost host,
final CredentialsProvider credentialsProvider,
final HttpContext context) throws AuthenticationException {
Args.notNull(host, "Auth host");
Args.notNull(credentialsProvider, "CredentialsProvider");
final Credentials credentials = credentialsProvider.getCredentials(new AuthScope(host, getRealm(), getName()));
if (credentials != null) {
this.username = credentials.getUserPrincipal().getName();
this.password = credentials.getPassword();
return true;
} else {
this.username = null;
this.password = null;
return false;
}
}
@Override
public Principal getPrinciple() {
return null;
}
@Override
public String generateAuthResponse(
final HttpHost host,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
Args.notNull(credentials, "Credentials");
Args.notNull(request, "HTTP request");
if (getParameter("realm") == null) {
throw new AuthenticationException("missing realm in challenge");
if (this.paramMap.get("realm") == null) {
throw new AuthenticationException("missing realm");
}
if (getParameter("nonce") == null) {
throw new AuthenticationException("missing nonce in challenge");
if (this.paramMap.get("nonce") == null) {
throw new AuthenticationException("missing nonce");
}
// Add method name and request-URI to the parameter map
getParameters().put("methodname", request.getRequestLine().getMethod());
getParameters().put("uri", request.getRequestLine().getUri());
return createDigestHeader(credentials, request);
return createDigestResponse(request);
}
private static MessageDigest createMessageDigest(
@ -172,15 +216,14 @@ public class DigestScheme extends StandardAuthScheme {
}
}
private Header createDigestHeader(
final Credentials credentials,
final HttpRequest request) throws AuthenticationException {
final String uri = getParameter("uri");
final String realm = getParameter("realm");
final String nonce = getParameter("nonce");
final String opaque = getParameter("opaque");
final String method = getParameter("methodname");
String algorithm = getParameter("algorithm");
private String createDigestResponse(final HttpRequest request) throws AuthenticationException {
final String uri = request.getRequestLine().getUri();
final String method = request.getRequestLine().getMethod();
final String realm = this.paramMap.get("realm");
final String nonce = this.paramMap.get("nonce");
final String opaque = this.paramMap.get("opaque");
String algorithm = this.paramMap.get("algorithm");
// If an algorithm is not specified, default to MD5.
if (algorithm == null) {
algorithm = "MD5";
@ -188,7 +231,7 @@ public class DigestScheme extends StandardAuthScheme {
final Set<String> qopset = new HashSet<>(8);
int qop = QOP_UNKNOWN;
final String qoplist = getParameter("qop");
final String qoplist = this.paramMap.get("qop");
if (qoplist != null) {
final StringTokenizer tok = new StringTokenizer(qoplist, ",");
while (tok.hasMoreTokens()) {
@ -208,7 +251,7 @@ public class DigestScheme extends StandardAuthScheme {
throw new AuthenticationException("None of the qop methods is supported: " + qoplist);
}
String charset = getParameter("charset");
String charset = this.paramMap.get("charset");
if (charset == null) {
charset = "ISO-8859-1";
}
@ -225,9 +268,6 @@ public class DigestScheme extends StandardAuthScheme {
throw new AuthenticationException("Unsuppported digest algorithm: " + digAlg);
}
final String uname = credentials.getUserPrincipal().getName();
final String pwd = credentials.getPassword();
if (nonce.equals(this.lastNonce)) {
nounceCount++;
} else {
@ -255,7 +295,7 @@ public class DigestScheme extends StandardAuthScheme {
// calculated one per session
sb.setLength(0);
sb.append(uname).append(':').append(realm).append(':').append(pwd);
sb.append(username).append(':').append(realm).append(':').append(password);
final String checksum = encode(digester.digest(EncodingUtils.getBytes(sb.toString(), charset)));
sb.setLength(0);
sb.append(checksum).append(':').append(nonce).append(':').append(cnonce);
@ -263,7 +303,7 @@ public class DigestScheme extends StandardAuthScheme {
} else {
// unq(username-value) ":" unq(realm-value) ":" passwd
sb.setLength(0);
sb.append(uname).append(':').append(realm).append(':').append(pwd);
sb.append(username).append(':').append(realm).append(':').append(password);
a1 = sb.toString();
}
@ -323,15 +363,10 @@ public class DigestScheme extends StandardAuthScheme {
final String digest = encode(digester.digest(EncodingUtils.getAsciiBytes(digestValue)));
final CharArrayBuffer buffer = new CharArrayBuffer(128);
if (isProxy()) {
buffer.append(HttpHeaders.PROXY_AUTHORIZATION);
} else {
buffer.append(HttpHeaders.AUTHORIZATION);
}
buffer.append(": Digest ");
buffer.append("Digest ");
final List<BasicNameValuePair> params = new ArrayList<>(20);
params.add(new BasicNameValuePair("username", uname));
params.add(new BasicNameValuePair("username", username));
params.add(new BasicNameValuePair("realm", realm));
params.add(new BasicNameValuePair("nonce", nonce));
params.add(new BasicNameValuePair("uri", uri));
@ -358,7 +393,7 @@ public class DigestScheme extends StandardAuthScheme {
|| "algorithm".equals(name));
BasicHeaderValueFormatter.INSTANCE.formatNameValuePair(buffer, param, !noQuotes);
}
return new BufferedHeader(buffer);
return buffer.toString();
}
String getCnonce() {
@ -405,4 +440,9 @@ public class DigestScheme extends StandardAuthScheme {
return encode(tmp);
}
@Override
public String toString() {
return this.paramMap.toString();
}
}

View File

@ -28,28 +28,25 @@ package org.apache.http.impl.auth;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.Principal;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.InvalidCredentialsException;
import org.apache.http.auth.KerberosCredentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.message.BufferedHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;
import org.apache.http.util.CharArrayBuffer;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
@ -61,7 +58,7 @@ import org.ietf.jgss.Oid;
* @since 4.2
*/
@NotThreadSafe
public abstract class GGSSchemeBase extends NonStandardAuthScheme {
public abstract class GGSSchemeBase implements AuthScheme {
enum State {
UNINITIATED,
@ -77,8 +74,8 @@ public abstract class GGSSchemeBase extends NonStandardAuthScheme {
/** Authentication process state */
private State state;
/** base64 decoded challenge **/
private GSSCredential gssCredential;
private String challenge;
private byte[] token;
GGSSchemeBase(final boolean stripPort, final boolean useCanonicalHostname) {
@ -93,19 +90,25 @@ public abstract class GGSSchemeBase extends NonStandardAuthScheme {
}
GGSSchemeBase() {
this(true,true);
this(true, true);
}
@Override
public String getRealm() {
return null;
}
@Override
public void processChallenge(
final ChallengeType challengeType,
final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
final AuthChallenge authChallenge,
final HttpContext context) throws MalformedChallengeException {
Args.notNull(authChallenge, "AuthChallenge");
if (authChallenge.getValue() == null) {
throw new MalformedChallengeException("Missing auth challenge");
}
this.challenge = authChallenge.getValue();
if (state == State.UNINITIATED) {
final String challenge = getChallenge();
token = Base64.decodeBase64(challenge.getBytes());
if (log.isDebugEnabled()) {
log.debug("Received token '" + token + "' from the auth server");
}
state = State.CHALLENGE_RECEIVED;
} else {
log.debug("Authentication already attempted");
@ -117,17 +120,10 @@ public abstract class GGSSchemeBase extends NonStandardAuthScheme {
return GSSManager.getInstance();
}
protected byte[] generateGSSToken(
final byte[] input, final Oid oid, final String authServer) throws GSSException {
return generateGSSToken(input, oid, authServer, null);
}
/**
* @since 4.4
*/
protected byte[] generateGSSToken(
final byte[] input, final Oid oid, final String authServer,
final Credentials credentials) throws GSSException {
protected byte[] generateGSSToken(final byte[] input, final Oid oid, final String authServer) throws GSSException {
byte[] inputBuff = input;
if (inputBuff == null) {
inputBuff = new byte[0];
@ -135,13 +131,6 @@ public abstract class GGSSchemeBase extends NonStandardAuthScheme {
final GSSManager manager = getManager();
final GSSName serverName = manager.createName("HTTP@" + authServer, GSSName.NT_HOSTBASED_SERVICE);
final GSSCredential gssCredential;
if (credentials instanceof KerberosCredentials) {
gssCredential = ((KerberosCredentials) credentials).getGSSCredential();
} else {
gssCredential = null;
}
final GSSContext gssContext = manager.createContext(
serverName.canonicalize(oid), oid, gssCredential, GSSContext.DEFAULT_LIFETIME);
gssContext.requestMutualAuth(true);
@ -152,43 +141,52 @@ public abstract class GGSSchemeBase extends NonStandardAuthScheme {
/**
* @since 4.4
*/
protected abstract byte[] generateToken(
byte[] input, String authServer, Credentials credentials) throws GSSException;
protected abstract byte[] generateToken(byte[] input, String authServer) throws GSSException;
@Override
public boolean isComplete() {
public boolean isChallengeComplete() {
return this.state == State.TOKEN_GENERATED || this.state == State.FAILED;
}
@Override
public Header authenticate(
final Credentials credentials,
public boolean isResponseReady(
final HttpHost host,
final CredentialsProvider credentialsProvider,
final HttpContext context) throws AuthenticationException {
Args.notNull(host, "Auth host");
Args.notNull(credentialsProvider, "CredentialsProvider");
final Credentials credentials = credentialsProvider.getCredentials(new AuthScope(host, null, getName()));
if (credentials instanceof KerberosCredentials) {
this.gssCredential = ((KerberosCredentials) credentials).getGSSCredential();
} else {
this.gssCredential = null;
}
return true;
}
@Override
public Principal getPrinciple() {
return null;
}
@Override
public String generateAuthResponse(
final HttpHost host,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
Args.notNull(host, "HTTP host");
Args.notNull(request, "HTTP request");
switch (state) {
case UNINITIATED:
throw new AuthenticationException(getSchemeName() + " authentication has not been initiated");
throw new AuthenticationException(getName() + " authentication has not been initiated");
case FAILED:
throw new AuthenticationException(getSchemeName() + " authentication has failed");
throw new AuthenticationException(getName() + " authentication has failed");
case CHALLENGE_RECEIVED:
try {
final HttpRoute route = (HttpRoute) context.getAttribute(HttpClientContext.HTTP_ROUTE);
if (route == null) {
throw new AuthenticationException("Connection route is not available");
}
HttpHost host;
if (isProxy()) {
host = route.getProxyHost();
if (host == null) {
host = route.getTargetHost();
}
} else {
host = route.getTargetHost();
}
final String authServer;
String hostname = host.getHostName();
if (this.useCanonicalHostname){
try {
//TODO: uncomment this statement and delete the resolveCanonicalHostname,
@ -208,7 +206,7 @@ public abstract class GGSSchemeBase extends NonStandardAuthScheme {
if (log.isDebugEnabled()) {
log.debug("init " + authServer);
}
token = generateToken(token, authServer, credentials);
token = generateToken(token, authServer);
state = State.TOKEN_GENERATED;
} catch (final GSSException gsse) {
state = State.FAILED;
@ -233,15 +231,7 @@ public abstract class GGSSchemeBase extends NonStandardAuthScheme {
if (log.isDebugEnabled()) {
log.debug("Sending response '" + tokenstr + "' back to the auth server");
}
final CharArrayBuffer buffer = new CharArrayBuffer(32);
if (isProxy()) {
buffer.append(HttpHeaders.PROXY_AUTHORIZATION);
} else {
buffer.append(HttpHeaders.AUTHORIZATION);
}
buffer.append(": Negotiate ");
buffer.append(tokenstr);
return new BufferedHeader(buffer);
return "Negotiate " + tokenstr;
default:
throw new IllegalStateException("Illegal state: " + state);
}
@ -256,4 +246,9 @@ public abstract class GGSSchemeBase extends NonStandardAuthScheme {
return canonicalServer;
}
@Override
public String toString() {
return "[" + this.state + " " + challenge + ']';
}
}

View File

@ -47,20 +47,18 @@ import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.ParseException;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption;
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.AuthenticationException;
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.AuthCache;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.ParserCursor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Asserts;
@ -195,12 +193,12 @@ public class HttpAuthenticator {
case UNCHALLENGED:
final AuthScheme authScheme = authState.getAuthScheme();
if (authScheme != null) {
final String id = authScheme.getSchemeName();
final String id = authScheme.getName();
final AuthChallenge challenge = challengeMap.get(id.toLowerCase(Locale.ROOT));
if (challenge != null) {
this.log.debug("Authorization challenge processed");
try {
authScheme.processChallenge(challengeType, challenge);
authScheme.processChallenge(challenge, context);
} catch (MalformedChallengeException ex) {
if (this.log.isWarnEnabled()) {
this.log.warn(ex.getMessage());
@ -209,7 +207,7 @@ public class HttpAuthenticator {
authState.reset();
return false;
}
if (authScheme.isComplete()) {
if (authScheme.isChallengeComplete()) {
this.log.debug("Authentication failed");
clearCache(host, clientContext);
authState.reset();
@ -233,22 +231,16 @@ public class HttpAuthenticator {
return false;
}
final Queue<AuthOption> authOptions = new LinkedList<>();
final Queue<AuthScheme> authOptions = new LinkedList<>();
for (AuthScheme authScheme: preferredSchemes) {
try {
final String id = authScheme.getSchemeName();
final String id = authScheme.getName();
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));
authScheme.processChallenge(challenge, context);
if (authScheme.isResponseReady(host, credsProvider, context)) {
authOptions.add(authScheme);
}
} catch (MalformedChallengeException ex) {
} catch (AuthenticationException | MalformedChallengeException ex) {
if (this.log.isWarnEnabled()) {
this.log.warn(ex.getMessage());
}
@ -267,11 +259,12 @@ public class HttpAuthenticator {
}
public void addAuthResponse(
final HttpHost host,
final ChallengeType challengeType,
final HttpRequest request,
final AuthState authState,
final HttpContext context) throws HttpException, IOException {
AuthScheme authScheme = authState.getAuthScheme();
Credentials creds = authState.getCredentials();
switch (authState.getState()) {
case FAILURE:
return;
@ -285,19 +278,20 @@ public class HttpAuthenticator {
Asserts.notNull(authScheme, "AuthScheme");
break;
case CHALLENGED:
final Queue<AuthOption> authOptions = authState.getAuthOptions();
final Queue<AuthScheme> authOptions = authState.getAuthOptions();
if (authOptions != null) {
while (!authOptions.isEmpty()) {
final AuthOption authOption = authOptions.remove();
authScheme = authOption.getAuthScheme();
creds = authOption.getCredentials();
authState.update(authScheme, creds);
authScheme = authOptions.remove();
authState.update(authScheme);
if (this.log.isDebugEnabled()) {
this.log.debug("Generating response to an authentication challenge using "
+ authScheme.getSchemeName() + " scheme");
+ authScheme.getName() + " scheme");
}
try {
final Header header = doAuth(authScheme, creds, request, context);
final String authResponse = authScheme.generateAuthResponse(host, request, context);
final Header header = new BasicHeader(
challengeType == ChallengeType.TARGET ? HttpHeaders.AUTHORIZATION : HttpHeaders.PROXY_AUTHORIZATION,
authResponse);
request.addHeader(header);
break;
} catch (final AuthenticationException ex) {
@ -314,7 +308,10 @@ public class HttpAuthenticator {
}
if (authScheme != null) {
try {
final Header header = doAuth(authScheme, creds, request, context);
final String authResponse = authScheme.generateAuthResponse(host, request, context);
final Header header = new BasicHeader(
challengeType == ChallengeType.TARGET ? HttpHeaders.AUTHORIZATION : HttpHeaders.PROXY_AUTHORIZATION,
authResponse);
request.addHeader(header);
} catch (final AuthenticationException ex) {
if (this.log.isErrorEnabled()) {
@ -325,7 +322,7 @@ public class HttpAuthenticator {
}
private boolean isCachable(final AuthScheme authScheme) {
final String schemeName = authScheme.getSchemeName();
final String schemeName = authScheme.getName();
return schemeName.equalsIgnoreCase(AuthSchemes.BASIC) ||
schemeName.equalsIgnoreCase(AuthSchemes.DIGEST);
}
@ -335,7 +332,7 @@ public class HttpAuthenticator {
final AuthCache authCache = clientContext.getAuthCache();
if (authCache != null) {
if (this.log.isDebugEnabled()) {
this.log.debug("Caching '" + authScheme.getSchemeName() + "' auth scheme for " + host);
this.log.debug("Caching '" + authScheme.getName() + "' auth scheme for " + host);
}
authCache.put(host, authScheme);
}
@ -353,12 +350,4 @@ public class HttpAuthenticator {
}
}
private Header doAuth(
final AuthScheme authScheme,
final Credentials creds,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
return authScheme.authenticate(creds, request, context);
}
}

View File

@ -27,7 +27,6 @@
package org.apache.http.impl.auth;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.Credentials;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.Oid;
@ -57,13 +56,13 @@ public class KerberosScheme extends GGSSchemeBase {
}
@Override
public String getSchemeName() {
public String getName() {
return "Kerberos";
}
@Override
protected byte[] generateToken(final byte[] input, final String authServer, final Credentials credentials) throws GSSException {
return generateGSSToken(input, new Oid(KERBEROS_OID), authServer, credentials);
protected byte[] generateToken(final byte[] input, final String authServer) throws GSSException {
return generateGSSToken(input, new Oid(KERBEROS_OID), authServer);
}
@Override

View File

@ -1574,7 +1574,7 @@ final class NTLMEngineImpl implements NTLMEngine {
i++;
}
// Very important: update the digest with the ipad buffer
// Very important: processChallenge the digest with the ipad buffer
md5.reset();
md5.update(ipad);

View File

@ -26,21 +26,21 @@
*/
package org.apache.http.impl.auth;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import java.security.Principal;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.InvalidCredentialsException;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.NTCredentials;
import org.apache.http.message.BufferedHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;
import org.apache.http.util.CharArrayBuffer;
/**
* NTLM is a proprietary authentication scheme developed by Microsoft
@ -49,7 +49,7 @@ import org.apache.http.util.CharArrayBuffer;
* @since 4.0
*/
@NotThreadSafe
public class NTLMScheme extends NonStandardAuthScheme {
public class NTLMScheme implements AuthScheme {
enum State {
UNINITIATED,
@ -63,6 +63,8 @@ public class NTLMScheme extends NonStandardAuthScheme {
private final NTLMEngine engine;
private State state;
private String challenge;
private NTCredentials credentials;
public NTLMScheme(final NTLMEngine engine) {
super();
@ -79,7 +81,7 @@ public class NTLMScheme extends NonStandardAuthScheme {
}
@Override
public String getSchemeName() {
public String getName() {
return "ntlm";
}
@ -88,13 +90,21 @@ public class NTLMScheme extends NonStandardAuthScheme {
return true;
}
@Override
public String getRealm() {
return null;
}
@Override
public void processChallenge(
final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
Args.notNull(challengeType, "ChallengeType");
final AuthChallenge authChallenge,
final HttpContext context) throws MalformedChallengeException {
Args.notNull(authChallenge, "AuthChallenge");
final String value = authChallenge.getValue();
if (value == null || value.isEmpty()) {
if (authChallenge.getValue() == null) {
throw new MalformedChallengeException("Missing auth challenge");
}
this.challenge = authChallenge.getValue();
if (this.challenge == null || this.challenge.isEmpty()) {
if (this.state == State.UNINITIATED) {
this.state = State.CHALLENGE_RECEIVED;
} else {
@ -111,51 +121,66 @@ public class NTLMScheme extends NonStandardAuthScheme {
}
@Override
public Header authenticate(
final Credentials credentials,
public boolean isResponseReady(
final HttpHost host,
final CredentialsProvider credentialsProvider,
final HttpContext context) throws AuthenticationException {
Args.notNull(host, "Auth host");
Args.notNull(credentialsProvider, "CredentialsProvider");
final Credentials credentials = credentialsProvider.getCredentials(new AuthScope(host, null, getName()));
if (credentials instanceof NTCredentials) {
this.credentials = (NTCredentials) credentials;
return true;
} else {
return false;
}
}
@Override
public Principal getPrinciple() {
return this.credentials != null ? this.credentials.getUserPrincipal() : null;
}
@Override
public String generateAuthResponse(
final HttpHost host,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
final NTCredentials ntcredentials;
try {
ntcredentials = (NTCredentials) credentials;
} catch (final ClassCastException e) {
throw new InvalidCredentialsException(
"Credentials cannot be used for NTLM authentication: "
+ credentials.getClass().getName());
if (this.credentials == null) {
throw new AuthenticationException("NT credentials not available");
}
final String response;
if (this.state == State.FAILED) {
throw new AuthenticationException("NTLM authentication failed");
} else if (this.state == State.CHALLENGE_RECEIVED) {
response = this.engine.generateType1Msg(
ntcredentials.getNetbiosDomain(),
ntcredentials.getWorkstation());
this.credentials.getNetbiosDomain(),
this.credentials.getWorkstation());
this.state = State.MSG_TYPE1_GENERATED;
} else if (this.state == State.MSG_TYPE2_RECEVIED) {
response = this.engine.generateType3Msg(
ntcredentials.getUserName(),
ntcredentials.getPassword(),
ntcredentials.getNetbiosDomain(),
ntcredentials.getWorkstation(),
getChallenge());
this.credentials.getUserName(),
this.credentials.getPassword(),
this.credentials.getNetbiosDomain(),
this.credentials.getWorkstation(),
this.challenge);
this.state = State.MSG_TYPE3_GENERATED;
} else {
throw new AuthenticationException("Unexpected state: " + this.state);
}
final CharArrayBuffer buffer = new CharArrayBuffer(32);
if (isProxy()) {
buffer.append(HttpHeaders.PROXY_AUTHORIZATION);
} else {
buffer.append(HttpHeaders.AUTHORIZATION);
}
buffer.append(": NTLM ");
buffer.append(response);
return new BufferedHeader(buffer);
return "NTLM " + response;
}
@Override
public boolean isComplete() {
public boolean isChallengeComplete() {
return this.state == State.MSG_TYPE3_GENERATED || this.state == State.FAILED;
}
@Override
public String toString() {
return "[" + this.state + " " + challenge + ']';
}
}

View File

@ -1,70 +0,0 @@
/*
* ====================================================================
* 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.auth;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.MalformedChallengeException;
public abstract class NonStandardAuthScheme implements AuthScheme {
private ChallengeType challengeType;
private String challenge;
public boolean isProxy() {
return this.challengeType != null && this.challengeType == ChallengeType.PROXY;
}
protected void update(final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException{
if (authChallenge.getValue() == null) {
throw new MalformedChallengeException("Missing auth challenge");
}
this.challengeType = challengeType;
this.challenge = authChallenge.getValue();
}
protected String getChallenge() {
return this.challenge;
}
@Override
public String getParameter(final String name) {
return null;
}
@Override
public String getRealm() {
return null;
}
@Override
public String toString() {
return getSchemeName() + "(" + this.challengeType + ") " + this.challenge;
}
}

View File

@ -27,7 +27,6 @@
package org.apache.http.impl.auth;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.Credentials;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.Oid;
@ -58,13 +57,13 @@ public class SPNegoScheme extends GGSSchemeBase {
}
@Override
public String getSchemeName() {
public String getName() {
return "Negotiate";
}
@Override
protected byte[] generateToken(final byte[] input, final String authServer, final Credentials credentials) throws GSSException {
return generateGSSToken(input, new Oid(SPNEGO_OID), authServer, credentials);
protected byte[] generateToken(final byte[] input, final String authServer) throws GSSException {
return generateGSSToken(input, new Oid(SPNEGO_OID), authServer);
}
@Override

View File

@ -1,111 +0,0 @@
/*
* ====================================================================
* 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.auth;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.MalformedChallengeException;
/**
* Abstract authentication scheme class that lays foundation for standard HTTP authentication schemes and
* provides capabilities common to all authentication schemes defined in the HTTP specification.
*
* @since 4.0
*/
@NotThreadSafe
public abstract class StandardAuthScheme implements AuthScheme, Serializable {
private static final long serialVersionUID = -2845454858205884623L;
private final Map<String, String> paramMap;
private ChallengeType challengeType;
/**
* @since 4.3
*/
public StandardAuthScheme() {
super();
this.paramMap = new LinkedHashMap<>();
}
protected void update(final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
final List<NameValuePair> params = authChallenge.getParams();
this.challengeType = challengeType;
if (params != null) {
for (NameValuePair param: params) {
this.paramMap.put(param.getName().toLowerCase(Locale.ROOT), param.getValue());
}
}
}
@Override
public String getRealm() {
return getParameter("realm");
}
protected Map<String, String> getParameters() {
return this.paramMap;
}
/**
* Returns authentication parameter with the given name, if available.
*
* @param name The name of the parameter to be returned
*
* @return the parameter with the given name
*/
@Override
public String getParameter(final String name) {
if (name == null) {
return null;
}
return this.paramMap.get(name.toLowerCase(Locale.ROOT));
}
/**
* Returns {@code true} if authenticating against a proxy, {@code false}
* otherwise.
*/
public boolean isProxy() {
return this.challengeType != null && this.challengeType == ChallengeType.PROXY;
}
@Override
public String toString() {
return getSchemeName() + "(" + this.challengeType + ") " + this.paramMap;
}
}

View File

@ -34,7 +34,6 @@ import org.apache.http.HttpConnection;
import org.apache.http.annotation.Immutable;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.client.UserTokenHandler;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ManagedHttpClientConnection;
@ -90,11 +89,8 @@ public class DefaultUserTokenHandler implements UserTokenHandler {
private static Principal getAuthPrincipal(final AuthState authState) {
final AuthScheme scheme = authState.getAuthScheme();
if (scheme != null && scheme.isComplete() && scheme.isConnectionBased()) {
final Credentials creds = authState.getCredentials();
if (creds != null) {
return creds.getUserPrincipal();
}
if (scheme != null && scheme.isConnectionBased()) {
return scheme.getPrinciple();
}
return null;
}

View File

@ -177,7 +177,7 @@ public class ProxyClient {
conn.bind(socket);
}
this.authenticator.addAuthResponse(connect, this.proxyAuthState, context);
this.authenticator.addAuthResponse(proxy, ChallengeType.PROXY, connect, this.proxyAuthState, context);
response = this.requestExec.execute(connect, conn, context);

View File

@ -248,13 +248,15 @@ public class MainClientExec implements ClientExecChain {
if (this.log.isDebugEnabled()) {
this.log.debug("Target auth state: " + targetAuthState.getState());
}
this.authenticator.addAuthResponse(request, targetAuthState, context);
this.authenticator.addAuthResponse(
route.getTargetHost(), ChallengeType.TARGET, request, targetAuthState, context);
}
if (!request.containsHeader(HttpHeaders.PROXY_AUTHORIZATION) && !route.isTunnelled()) {
if (this.log.isDebugEnabled()) {
this.log.debug("Proxy auth state: " + proxyAuthState.getState());
}
this.authenticator.addAuthResponse(request, proxyAuthState, context);
this.authenticator.addAuthResponse(
route.getProxyHost(), ChallengeType.PROXY, request, proxyAuthState, context);
}
response = requestExecutor.execute(request, managedConn, context);
@ -423,7 +425,7 @@ public class MainClientExec implements ClientExecChain {
* The connection must be established to the (last) proxy.
* A CONNECT request for tunnelling through the proxy will
* be created and sent, the response received and checked.
* This method does <i>not</i> update the connection with
* This method does <i>not</i> processChallenge the connection with
* information about the tunnel, that is left to the caller.
*/
private boolean createTunnelToTarget(
@ -455,7 +457,7 @@ public class MainClientExec implements ClientExecChain {
}
connect.removeHeaders(HttpHeaders.PROXY_AUTHORIZATION);
this.authenticator.addAuthResponse(connect, proxyAuthState, context);
this.authenticator.addAuthResponse(proxy, ChallengeType.PROXY, connect, proxyAuthState, context);
response = this.requestExecutor.execute(connect, managedConn, context);

View File

@ -57,7 +57,7 @@ import org.apache.http.util.Args;
* Request executor in the request execution chain that is responsible
* for implementation of HTTP specification requirements.
* Internally this executor relies on a {@link HttpProcessor} to populate
* requisite HTTP request headers, process HTTP response headers and update
* requisite HTTP request headers, process HTTP response headers and processChallenge
* session state in {@link HttpClientContext}.
* <p>
* Further responsibilities such as communication with the opposite

View File

@ -113,9 +113,7 @@ public class TestRequestAuthCache {
final HttpRequestInterceptor interceptor = new RequestAuthCache();
interceptor.process(request, context);
Assert.assertNotNull(this.targetState.getAuthScheme());
Assert.assertSame(this.creds1, this.targetState.getCredentials());
Assert.assertNotNull(this.proxyState.getAuthScheme());
Assert.assertSame(this.creds2, this.proxyState.getCredentials());
}
@Test
@ -138,9 +136,7 @@ public class TestRequestAuthCache {
final HttpRequestInterceptor interceptor = new RequestAuthCache();
interceptor.process(request, context);
Assert.assertNull(this.targetState.getAuthScheme());
Assert.assertNull(this.targetState.getCredentials());
Assert.assertNull(this.proxyState.getAuthScheme());
Assert.assertNull(this.proxyState.getCredentials());
}
@Test
@ -158,9 +154,7 @@ public class TestRequestAuthCache {
final HttpRequestInterceptor interceptor = new RequestAuthCache();
interceptor.process(request, context);
Assert.assertNull(this.targetState.getAuthScheme());
Assert.assertNull(this.targetState.getCredentials());
Assert.assertNull(this.proxyState.getAuthScheme());
Assert.assertNull(this.proxyState.getCredentials());
}
@Test
@ -180,36 +174,7 @@ public class TestRequestAuthCache {
final HttpRequestInterceptor interceptor = new RequestAuthCache();
interceptor.process(request, context);
Assert.assertNull(this.targetState.getAuthScheme());
Assert.assertNull(this.targetState.getCredentials());
Assert.assertNull(this.proxyState.getAuthScheme());
Assert.assertNull(this.proxyState.getCredentials());
}
@Test
public void testNoMatchingCredentials() throws Exception {
final HttpRequest request = new BasicHttpRequest("GET", "/");
this.credProvider.clear();
final HttpClientContext context = HttpClientContext.create();
context.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credProvider);
context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, this.target);
context.setAttribute(HttpClientContext.HTTP_ROUTE, new HttpRoute(this.target, null, this.proxy, false));
context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, this.targetState);
context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, this.proxyState);
final AuthCache authCache = new BasicAuthCache();
authCache.put(this.target, this.authscheme1);
authCache.put(this.proxy, this.authscheme2);
context.setAttribute(HttpClientContext.AUTH_CACHE, authCache);
final HttpRequestInterceptor interceptor = new RequestAuthCache();
interceptor.process(request, context);
Assert.assertNull(this.targetState.getAuthScheme());
Assert.assertNull(this.targetState.getCredentials());
Assert.assertNull(this.proxyState.getAuthScheme());
Assert.assertNull(this.proxyState.getCredentials());
}
@Test
@ -230,16 +195,14 @@ public class TestRequestAuthCache {
context.setAttribute(HttpClientContext.AUTH_CACHE, authCache);
this.targetState.setState(AuthProtocolState.CHALLENGED);
this.targetState.update(new BasicScheme(), new UsernamePasswordCredentials("user3", "secret3"));
this.targetState.update(new BasicScheme());
this.proxyState.setState(AuthProtocolState.CHALLENGED);
this.proxyState.update(new BasicScheme(), new UsernamePasswordCredentials("user4", "secret4"));
this.proxyState.update(new BasicScheme());
final HttpRequestInterceptor interceptor = new RequestAuthCache();
interceptor.process(request, context);
Assert.assertNotSame(this.authscheme1, this.targetState.getAuthScheme());
Assert.assertNotSame(this.creds1, this.targetState.getCredentials());
Assert.assertNotSame(this.authscheme2, this.proxyState.getAuthScheme());
Assert.assertNotSame(this.creds2, this.proxyState.getCredentials());
}
}

View File

@ -34,17 +34,15 @@ import java.util.List;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.ParserCursor;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.EncodingUtils;
import org.junit.Assert;
@ -69,7 +67,7 @@ public class TestBasicScheme {
final String challenge = "Basic";
final AuthChallenge authChallenge = parse(challenge);
final AuthScheme authscheme = new BasicScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
Assert.assertNull(authscheme.getRealm());
}
@ -81,56 +79,66 @@ public class TestBasicScheme {
buffer.append((char)germanChar);
}
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "some realm", null);
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("dh", buffer.toString());
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(authScope, creds);
final BasicScheme authscheme = new BasicScheme(Consts.ISO_8859_1);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final HttpRequest request = new BasicHttpRequest("GET", "/");
final HttpContext context = new BasicHttpContext();
final Header header = authscheme.authenticate(creds, request, context);
Assert.assertEquals("Basic ZGg65C32Lfw=", header.getValue());
final String authResponse = authscheme.generateAuthResponse(host, request, null);
Assert.assertEquals("Basic ZGg65C32Lfw=", authResponse);
}
@Test
public void testBasicAuthentication() throws Exception {
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("testuser", "testpass");
final AuthChallenge authChallenge = parse("Basic realm=\"test\"");
final BasicScheme authscheme = new BasicScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "test", null);
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("testuser", "testpass");
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(authScope, creds);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final HttpContext context = new BasicHttpContext();
final Header authResponse = authscheme.authenticate(creds, request, context);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
final String expected = "Basic " + EncodingUtils.getAsciiString(
Base64.encodeBase64(EncodingUtils.getAsciiBytes("testuser:testpass")));
Assert.assertEquals(HttpHeaders.AUTHORIZATION, authResponse.getName());
Assert.assertEquals(expected, authResponse.getValue());
Assert.assertEquals(expected, authResponse);
Assert.assertEquals("test", authscheme.getRealm());
Assert.assertTrue(authscheme.isComplete());
Assert.assertTrue(authscheme.isChallengeComplete());
Assert.assertFalse(authscheme.isConnectionBased());
}
@Test
public void testBasicProxyAuthentication() throws Exception {
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("testuser", "testpass");
final AuthChallenge authChallenge = parse("Basic realm=\"test\"");
final BasicScheme authscheme = new BasicScheme();
authscheme.processChallenge(ChallengeType.PROXY, authChallenge);
authscheme.processChallenge(authChallenge, null);
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "test", null);
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("testuser", "testpass");
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(authScope, creds);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final HttpContext context = new BasicHttpContext();
final Header authResponse = authscheme.authenticate(creds, request, context);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
final String expected = "Basic " + EncodingUtils.getAsciiString(
Base64.encodeBase64(EncodingUtils.getAsciiBytes("testuser:testpass")));
Assert.assertEquals(HttpHeaders.PROXY_AUTHORIZATION, authResponse.getName());
Assert.assertEquals(expected, authResponse.getValue());
Assert.assertEquals(expected, authResponse);
Assert.assertEquals("test", authscheme.getRealm());
Assert.assertTrue(authscheme.isComplete());
Assert.assertTrue(authscheme.isChallengeComplete());
Assert.assertFalse(authscheme.isConnectionBased());
}
@ -139,7 +147,7 @@ public class TestBasicScheme {
final AuthChallenge authChallenge = parse("Basic realm=\"test\"");
final BasicScheme basicScheme = new BasicScheme();
basicScheme.processChallenge(ChallengeType.PROXY, authChallenge);
basicScheme.processChallenge(authChallenge, null);
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final ObjectOutputStream out = new ObjectOutputStream(buffer);
@ -149,10 +157,9 @@ public class TestBasicScheme {
final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
final BasicScheme authScheme = (BasicScheme) in.readObject();
Assert.assertEquals(basicScheme.getSchemeName(), authScheme.getSchemeName());
Assert.assertEquals(basicScheme.getName(), authScheme.getName());
Assert.assertEquals(basicScheme.getRealm(), authScheme.getRealm());
Assert.assertEquals(basicScheme.isComplete(), authScheme.isComplete());
Assert.assertEquals(true, basicScheme.isProxy());
Assert.assertEquals(basicScheme.isChallengeComplete(), authScheme.isChallengeComplete());
}
@Test
@ -167,10 +174,9 @@ public class TestBasicScheme {
final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
final BasicScheme authScheme = (BasicScheme) in.readObject();
Assert.assertEquals(basicScheme.getSchemeName(), authScheme.getSchemeName());
Assert.assertEquals(basicScheme.getName(), authScheme.getName());
Assert.assertEquals(basicScheme.getRealm(), authScheme.getRealm());
Assert.assertEquals(basicScheme.isComplete(), authScheme.isComplete());
Assert.assertEquals(false, basicScheme.isProxy());
Assert.assertEquals(basicScheme.isChallengeComplete(), authScheme.isChallengeComplete());
}
}

View File

@ -36,26 +36,25 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.message.BasicHeaderValueParser;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.ParserCursor;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;
import org.junit.Assert;
import org.junit.Test;
@ -78,27 +77,33 @@ public class TestDigestScheme {
public void testDigestAuthenticationEmptyChallenge1() throws Exception {
final AuthChallenge authChallenge = parse("Digest");
final AuthScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
}
@Test(expected=MalformedChallengeException.class)
public void testDigestAuthenticationEmptyChallenge2() throws Exception {
final AuthChallenge authChallenge = parse("Digest ");
final AuthScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
}
@Test
public void testDigestAuthenticationWithDefaultCreds() throws Exception {
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
Assert.assertTrue(authscheme.isComplete());
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
Assert.assertTrue(authscheme.isChallengeComplete());
Assert.assertFalse(authscheme.isConnectionBased());
final Map<String, String> table = parseAuthResponse(authResponse);
@ -111,14 +116,20 @@ public class TestDigestScheme {
@Test
public void testDigestAuthentication() throws Exception {
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
@ -130,20 +141,29 @@ public class TestDigestScheme {
@Test
public void testDigestAuthenticationInvalidInput() throws Exception {
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
try {
authscheme.authenticate(null, request, context);
authscheme.isResponseReady(null, credentialsProvider, null);
Assert.fail("IllegalArgumentException should have been thrown");
} catch (final IllegalArgumentException ex) {
}
try {
authscheme.authenticate(cred, null, context);
authscheme.isResponseReady(host, null, null);
Assert.fail("IllegalArgumentException should have been thrown");
} catch (final IllegalArgumentException ex) {
}
try {
authscheme.generateAuthResponse(host, null, null);
Assert.fail("IllegalArgumentException should have been thrown");
} catch (final IllegalArgumentException ex) {
}
@ -151,16 +171,22 @@ public class TestDigestScheme {
@Test
public void testDigestAuthenticationWithSHA() throws Exception {
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", " +
"nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"algorithm=SHA";
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
@ -172,14 +198,20 @@ public class TestDigestScheme {
@Test
public void testDigestAuthenticationWithQueryStringInDigestURI() throws Exception {
final HttpRequest request = new BasicHttpRequest("Simple", "/?param=value");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/?param=value");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
@ -189,64 +221,40 @@ public class TestDigestScheme {
Assert.assertEquals("a847f58f5fef0bc087bcb9c3eb30e042", table.get("response"));
}
@Test
public void testDigestAuthenticationWithMultipleRealms() throws Exception {
final String challenge1 = "Digest realm=\"realm1\", nonce=\"abcde\"";
final String challenge2 = "Digest realm=\"realm2\", nonce=\"123546\"";
final Credentials cred = new UsernamePasswordCredentials("username","password");
final Credentials cred2 = new UsernamePasswordCredentials("uname2","password2");
final AuthChallenge authChallenge1 = parse(challenge1);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge1);
Header authResponse = authscheme.authenticate(cred, request, context);
Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
Assert.assertEquals("realm1", table.get("realm"));
Assert.assertEquals("/", table.get("uri"));
Assert.assertEquals("abcde", table.get("nonce"));
Assert.assertEquals("786f500303eac1478f3c2865e676ed68", table.get("response"));
final AuthChallenge authChallenge2 = parse(challenge2);
final DigestScheme authscheme2 = new DigestScheme();
authscheme2.processChallenge(ChallengeType.TARGET, authChallenge2);
authResponse = authscheme2.authenticate(cred2, request, context);
table = parseAuthResponse(authResponse);
Assert.assertEquals("uname2", table.get("username"));
Assert.assertEquals("realm2", table.get("realm"));
Assert.assertEquals("/", table.get("uri"));
Assert.assertEquals("123546", table.get("nonce"));
Assert.assertEquals("0283edd9ef06a38b378b3b74661391e9", table.get("response"));
}
@Test(expected=AuthenticationException.class)
public void testDigestAuthenticationNoRealm() throws Exception {
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest no-realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpRequest request = new BasicHttpRequest("Simple", "/");
authscheme.authenticate(cred, request, context);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
authscheme.generateAuthResponse(host, request, null);
}
@Test(expected=AuthenticationException.class)
public void testDigestAuthenticationNoNonce() throws Exception {
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", no-nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpRequest request = new BasicHttpRequest("Simple", "/");
authscheme.authenticate(cred, request, context);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
authscheme.generateAuthResponse(host, request, null);
}
/**
@ -261,6 +269,13 @@ public class TestDigestScheme {
final String password="password";
final String nonce="e273f1776275974f1a120d8b92c5b3cb";
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, realm, null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials(username, password);
credentialsProvider.setCredentials(authScope, creds);
final String challenge="Digest realm=\"" + realm + "\", "
+ "nonce=\"" + nonce + "\", "
+ "opaque=\"SomeString\", "
@ -270,17 +285,14 @@ public class TestDigestScheme {
final AuthChallenge authChallenge = parse(challenge);
final Credentials cred = new UsernamePasswordCredentials(username, password);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
final String response = authResponse.getValue();
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(response.indexOf("nc=00000001") > 0); // test for quotes
Assert.assertTrue(response.indexOf("qop=auth") > 0); // test for quotes
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
Assert.assertTrue(authResponse.indexOf("nc=00000001") > 0); // test for quotes
Assert.assertTrue(authResponse.indexOf("qop=auth") > 0); // test for quotes
final Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals(username, table.get("username"));
@ -308,6 +320,13 @@ public class TestDigestScheme {
final String password="password";
final String nonce="e273f1776275974f1a120d8b92c5b3cb";
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, realm, null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials(username, password);
credentialsProvider.setCredentials(authScope, creds);
final String challenge="Digest realm=\"" + realm + "\", "
+ "nonce=\"" + nonce + "\", "
+ "opaque=\"SomeString\", "
@ -316,14 +335,10 @@ public class TestDigestScheme {
final AuthChallenge authChallenge = parse(challenge);
final Credentials cred = new UsernamePasswordCredentials(username, password);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals(username, table.get("username"));
@ -350,6 +365,13 @@ public class TestDigestScheme {
final String password="password";
final String nonce="e273f1776275974f1a120d8b92c5b3cb";
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, realm, null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials(username, password);
credentialsProvider.setCredentials(authScope, creds);
final String challenge="Digest realm=\"" + realm + "\", "
+ "nonce=\"" + nonce + "\", "
+ "opaque=\"SomeString\", "
@ -360,12 +382,10 @@ public class TestDigestScheme {
final AuthChallenge authChallenge = parse(challenge);
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
final Credentials cred = new UsernamePasswordCredentials(username, password);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpContext context = new BasicHttpContext();
authscheme.authenticate(cred, request, context);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
authscheme.generateAuthResponse(host, request, null);
}
/**
@ -380,6 +400,13 @@ public class TestDigestScheme {
final String password="password";
final String nonce="e273f1776275974f1a120d8b92c5b3cb";
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, realm, null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials(username, password);
credentialsProvider.setCredentials(authScope, creds);
final String challenge="Digest realm=\"" + realm + "\", "
+ "nonce=\"" + nonce + "\", "
+ "opaque=\"SomeString\", "
@ -390,12 +417,10 @@ public class TestDigestScheme {
final AuthChallenge authChallenge = parse(challenge);
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
final Credentials cred = new UsernamePasswordCredentials(username, password);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpContext context = new BasicHttpContext();
authscheme.authenticate(cred, request, context);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
authscheme.generateAuthResponse(host, request, null);
}
@Test
@ -404,17 +429,16 @@ public class TestDigestScheme {
"nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", stale=\"true\"";
final AuthChallenge authChallenge = parse(challenge);
final AuthScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
Assert.assertFalse(authscheme.isComplete());
Assert.assertFalse(authscheme.isChallengeComplete());
}
private static Map<String, String> parseAuthResponse(final Header authResponse) {
final String s = authResponse.getValue();
if (!s.startsWith("Digest ")) {
private static Map<String, String> parseAuthResponse(final String authResponse) {
if (!authResponse.startsWith("Digest ")) {
return null;
}
final HeaderElement[] elements = BasicHeaderValueParser.parseElements(s.substring(7), null);
final HeaderElement[] elements = BasicHeaderValueParser.parseElements(authResponse.substring(7), null);
final Map<String, String> map = new HashMap<>(elements.length);
for (final HeaderElement element : elements) {
map.put(element.getName(), element.getValue());
@ -424,50 +448,73 @@ public class TestDigestScheme {
@Test
public void testDigestNouceCount() throws Exception {
final HttpRequest request = new BasicHttpRequest("GET", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge1 = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
final AuthChallenge authChallenge1 = parse(challenge1);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge1);
final Header authResponse1 = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge1, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse1 = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table1 = parseAuthResponse(authResponse1);
Assert.assertEquals("00000001", table1.get("nc"));
final Header authResponse2 = authscheme.authenticate(cred, request, context);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse2 = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table2 = parseAuthResponse(authResponse2);
Assert.assertEquals("00000002", table2.get("nc"));
final String challenge2 = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
final AuthChallenge authChallenge2 = parse(challenge2);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge2);
final Header authResponse3 = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge2, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse3 = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table3 = parseAuthResponse(authResponse3);
Assert.assertEquals("00000003", table3.get("nc"));
final String challenge3 = "Digest realm=\"realm1\", nonce=\"e273f1776275974f1a120d8b92c5b3cb\", qop=auth";
final AuthChallenge authChallenge3 = parse(challenge3);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge3);
final Header authResponse4 = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge3, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse4 = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table4 = parseAuthResponse(authResponse4);
Assert.assertEquals("00000001", table4.get("nc"));
}
@Test
public void testDigestMD5SessA1AndCnonceConsistency() throws Exception {
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "subnet.domain.com", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final HttpRequest request = new BasicHttpRequest("GET", "/");
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge1 = "Digest qop=\"auth\", algorithm=MD5-sess, nonce=\"1234567890abcdef\", " +
"charset=utf-8, realm=\"subnet.domain.com\"";
final AuthChallenge authChallenge1 = parse(challenge1);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge1);
final Header authResponse1 = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge1, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse1 = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table1 = parseAuthResponse(authResponse1);
Assert.assertEquals("00000001", table1.get("nc"));
final String cnonce1 = authscheme.getCnonce();
final String sessionKey1 = authscheme.getA1();
final Header authResponse2 = authscheme.authenticate(cred, request, context);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse2 = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table2 = parseAuthResponse(authResponse2);
Assert.assertEquals("00000002", table2.get("nc"));
final String cnonce2 = authscheme.getCnonce();
@ -479,8 +526,9 @@ public class TestDigestScheme {
final String challenge2 = "Digest qop=\"auth\", algorithm=MD5-sess, nonce=\"1234567890abcdef\", " +
"charset=utf-8, realm=\"subnet.domain.com\"";
final AuthChallenge authChallenge2 = parse(challenge2);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge2);
final Header authResponse3 = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge2, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse3 = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table3 = parseAuthResponse(authResponse3);
Assert.assertEquals("00000003", table3.get("nc"));
@ -493,8 +541,9 @@ public class TestDigestScheme {
final String challenge3 = "Digest qop=\"auth\", algorithm=MD5-sess, nonce=\"fedcba0987654321\", " +
"charset=utf-8, realm=\"subnet.domain.com\"";
final AuthChallenge authChallenge3 = parse(challenge3);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge3);
final Header authResponse4 = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge3, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse4 = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table4 = parseAuthResponse(authResponse4);
Assert.assertEquals("00000001", table4.get("nc"));
@ -533,16 +582,21 @@ public class TestDigestScheme {
@Test
public void testDigestAuthenticationQopAuthInt() throws Exception {
final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
request.setEntity(new StringEntity("abc\u00e4\u00f6\u00fcabc", HTTP.DEF_CONTENT_CHARSET));
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"qop=\"auth,auth-int\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
request.setEntity(new StringEntity("abc\u00e4\u00f6\u00fcabc", HTTP.DEF_CONTENT_CHARSET));
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
Assert.assertEquals("Post:/:acd2b59cd01c7737d8069015584c6cac", authscheme.getA2());
@ -556,15 +610,20 @@ public class TestDigestScheme {
@Test
public void testDigestAuthenticationQopAuthIntNullEntity() throws Exception {
final HttpRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"qop=\"auth,auth-int\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
Assert.assertEquals("Post:/:d41d8cd98f00b204e9800998ecf8427e", authscheme.getA2());
@ -578,16 +637,21 @@ public class TestDigestScheme {
@Test
public void testDigestAuthenticationQopAuthOrAuthIntNonRepeatableEntity() throws Exception {
final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1));
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"qop=\"auth,auth-int\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1));
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
Assert.assertEquals("Post:/", authscheme.getA2());
@ -601,32 +665,43 @@ public class TestDigestScheme {
@Test
public void testParameterCaseSensitivity() throws Exception {
final HttpRequest request = new BasicHttpRequest("GET", "/");
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "-", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest Realm=\"-\", " +
"nonce=\"YjYuNGYyYmJhMzUuY2I5ZDhlZDE5M2ZlZDM 1Mjk3NGJkNTIyYjgyNTcwMjQ=\", " +
"opaque=\"98700A3D9CE17065E2246B41035C6609\", qop=\"auth\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.processChallenge(authChallenge, null);
Assert.assertEquals("-", authscheme.getRealm());
authscheme.authenticate(cred, request, context);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
authscheme.generateAuthResponse(host, request, null);
}
@Test(expected=AuthenticationException.class)
public void testDigestAuthenticationQopIntOnlyNonRepeatableEntity() throws Exception {
final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1));
final HttpHost host = new HttpHost("somehost", 80);
final AuthScope authScope = new AuthScope(host, "realm1", null);
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
final Credentials creds = new UsernamePasswordCredentials("username","password");
credentialsProvider.setCredentials(authScope, creds);
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"qop=\"auth-int\"";
final AuthChallenge authChallenge = parse(challenge);
final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1));
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.authenticate(cred, request, context);
authscheme.processChallenge(authChallenge, null);
Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
authscheme.generateAuthResponse(host, request, null);
}
@Test
@ -635,7 +710,7 @@ public class TestDigestScheme {
"qop=\"auth,auth-int\"";
final AuthChallenge authChallenge = parse(challenge);
final DigestScheme digestScheme = new DigestScheme();
digestScheme.processChallenge(ChallengeType.TARGET, authChallenge);
digestScheme.processChallenge(authChallenge, null);
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final ObjectOutputStream out = new ObjectOutputStream(buffer);
@ -645,9 +720,9 @@ public class TestDigestScheme {
final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
final DigestScheme authScheme = (DigestScheme) in.readObject();
Assert.assertEquals(digestScheme.getSchemeName(), authScheme.getSchemeName());
Assert.assertEquals(digestScheme.getName(), authScheme.getName());
Assert.assertEquals(digestScheme.getRealm(), authScheme.getRealm());
Assert.assertEquals(digestScheme.isComplete(), authScheme.isComplete());
Assert.assertEquals(digestScheme.isChallengeComplete(), authScheme.isChallengeComplete());
Assert.assertEquals(digestScheme.getA1(), authScheme.getA1());
Assert.assertEquals(digestScheme.getA2(), authScheme.getA2());
Assert.assertEquals(digestScheme.getCnonce(), authScheme.getCnonce());

View File

@ -35,7 +35,6 @@ import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthProtocolState;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeProvider;
@ -44,11 +43,12 @@ import org.apache.http.auth.AuthState;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Lookup;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultAuthenticationStrategy;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpRequest;
@ -68,8 +68,7 @@ public class TestHttpAuthenticator {
private AuthScheme authScheme;
private HttpContext context;
private HttpHost defaultHost;
private Credentials credentials;
private BasicCredentialsProvider credentialsProvider;
private CredentialsProvider credentialsProvider;
private Lookup<AuthSchemeProvider> authSchemeRegistry;
private AuthCache authCache;
private HttpAuthenticator httpAuthenticator;
@ -78,14 +77,12 @@ public class TestHttpAuthenticator {
public void setUp() throws Exception {
this.authState = new AuthState();
this.authScheme = Mockito.mock(AuthScheme.class);
Mockito.when(this.authScheme.getSchemeName()).thenReturn("Basic");
Mockito.when(this.authScheme.isComplete()).thenReturn(Boolean.TRUE);
Mockito.when(this.authScheme.getName()).thenReturn("Basic");
Mockito.when(this.authScheme.isChallengeComplete()).thenReturn(Boolean.TRUE);
this.context = new BasicHttpContext();
this.defaultHost = new HttpHost("localhost", 80);
this.context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, this.defaultHost);
this.credentials = Mockito.mock(Credentials.class);
this.credentialsProvider = new BasicCredentialsProvider();
this.credentialsProvider.setCredentials(AuthScope.ANY, this.credentials);
this.credentialsProvider = Mockito.mock(CredentialsProvider.class);
this.context.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credentialsProvider);
this.authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("basic", new BasicSchemeFactory())
@ -111,7 +108,7 @@ public class TestHttpAuthenticator {
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=test");
this.authState.update(this.authScheme, this.credentials);
this.authState.update(this.authScheme);
this.authState.setState(AuthProtocolState.SUCCESS);
Assert.assertTrue(this.httpAuthenticator.isChallenged(
@ -132,7 +129,7 @@ public class TestHttpAuthenticator {
@Test
public void testAuthenticationNotRequestedSuccess1() throws Exception {
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
this.authState.update(this.authScheme, this.credentials);
this.authState.update(this.authScheme);
this.authState.setState(AuthProtocolState.CHALLENGED);
Assert.assertFalse(this.httpAuthenticator.isChallenged(
@ -145,7 +142,7 @@ public class TestHttpAuthenticator {
@Test
public void testAuthenticationNotRequestedSuccess2() throws Exception {
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
this.authState.update(this.authScheme, this.credentials);
this.authState.update(this.authScheme);
this.authState.setState(AuthProtocolState.HANDSHAKE);
Assert.assertFalse(this.httpAuthenticator.isChallenged(
@ -163,20 +160,47 @@ public class TestHttpAuthenticator {
response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"realm1\", nonce=\"1234\""));
response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "whatever realm=\"realm1\", stuff=\"1234\""));
final Credentials credentials = new UsernamePasswordCredentials("user:pass");
Mockito.when(this.credentialsProvider.getCredentials(Mockito.<AuthScope>any())).thenReturn(credentials);
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertTrue(this.httpAuthenticator.prepareAuthResponse(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.CHALLENGED, this.authState.getState());
final Queue<AuthOption> options = this.authState.getAuthOptions();
final Queue<AuthScheme> options = this.authState.getAuthOptions();
Assert.assertNotNull(options);
final AuthOption option1 = options.poll();
Assert.assertNotNull(option1);
Assert.assertEquals("digest", option1.getAuthScheme().getSchemeName());
final AuthOption option2 = options.poll();
Assert.assertNotNull(option2);
Assert.assertEquals("basic", option2.getAuthScheme().getSchemeName());
final AuthScheme authScheme1 = options.poll();
Assert.assertNotNull(authScheme1);
Assert.assertEquals("digest", authScheme1.getName());
final AuthScheme authScheme2 = options.poll();
Assert.assertNotNull(authScheme2);
Assert.assertEquals("basic", authScheme2.getName());
Assert.assertNull(options.poll());
}
@Test
public void testAuthenticationCredentialsForBasic() throws Exception {
final HttpHost host = new HttpHost("somehost", 80);
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"test\""));
response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"realm1\", nonce=\"1234\""));
final Credentials credentials = new UsernamePasswordCredentials("user:pass");
Mockito.when(this.credentialsProvider.getCredentials(new AuthScope(host, "test", "basic"))).thenReturn(credentials);
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertTrue(this.httpAuthenticator.prepareAuthResponse(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.CHALLENGED, this.authState.getState());
final Queue<AuthScheme> options = this.authState.getAuthOptions();
Assert.assertNotNull(options);
final AuthScheme authScheme1 = options.poll();
Assert.assertNotNull(authScheme1);
Assert.assertEquals("basic", authScheme1.getName());
Assert.assertNull(options.poll());
}
@ -211,8 +235,6 @@ public class TestHttpAuthenticator {
response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"test\""));
response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"realm1\", nonce=\"1234\""));
this.credentialsProvider.clear();
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertFalse(this.httpAuthenticator.prepareAuthResponse(
@ -227,7 +249,7 @@ public class TestHttpAuthenticator {
response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"realm1\", nonce=\"1234\""));
this.authState.setState(AuthProtocolState.CHALLENGED);
this.authState.update(this.authScheme, this.credentials);
this.authState.update(this.authScheme);
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
@ -267,12 +289,11 @@ public class TestHttpAuthenticator {
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
this.authState.setState(AuthProtocolState.CHALLENGED);
this.authState.update(new BasicScheme(), this.credentials);
this.authState.update(new BasicScheme());
Assert.assertFalse(this.httpAuthenticator.prepareAuthResponse(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.FAILURE, this.authState.getState());
Assert.assertNull(this.authState.getCredentials());
}
@Test
@ -286,7 +307,7 @@ public class TestHttpAuthenticator {
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
this.authState.setState(AuthProtocolState.CHALLENGED);
this.authState.update(new DigestScheme(), this.credentials);
this.authState.update(new DigestScheme());
Assert.assertTrue(this.httpAuthenticator.prepareAuthResponse(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
@ -301,20 +322,23 @@ public class TestHttpAuthenticator {
response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"realm1\", nonce=\"1234\""));
response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "whatever realm=\"realm1\", stuff=\"1234\""));
final Credentials credentials = new UsernamePasswordCredentials("user:pass");
Mockito.when(this.credentialsProvider.getCredentials(new AuthScope(host, "realm1", "digest"))).thenReturn(credentials);
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
this.authState.setState(AuthProtocolState.CHALLENGED);
this.authState.update(new BasicScheme(), this.credentials);
this.authState.update(new BasicScheme());
Assert.assertTrue(this.httpAuthenticator.prepareAuthResponse(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.CHALLENGED, this.authState.getState());
final Queue<AuthOption> options = this.authState.getAuthOptions();
final Queue<AuthScheme> options = this.authState.getAuthOptions();
Assert.assertNotNull(options);
final AuthOption option1 = options.poll();
Assert.assertNotNull(option1);
Assert.assertEquals("digest", option1.getAuthScheme().getSchemeName());
final AuthScheme authScheme1 = options.poll();
Assert.assertNotNull(authScheme1);
Assert.assertEquals("digest", authScheme1.getName());
Assert.assertNull(options.poll());
}
@ -333,21 +357,20 @@ public class TestHttpAuthenticator {
Assert.assertEquals(AuthProtocolState.UNCHALLENGED, this.authState.getState());
Assert.assertNull(this.authState.getAuthScheme());
Assert.assertNull(this.authState.getCredentials());
}
@Test
public void testAuthFailureState() throws Exception {
final HttpRequest request = new BasicHttpRequest("GET", "/");
this.authState.setState(AuthProtocolState.FAILURE);
this.authState.update(this.authScheme, this.credentials);
this.authState.update(this.authScheme);
this.httpAuthenticator.addAuthResponse(request, authState, context);
this.httpAuthenticator.addAuthResponse(defaultHost, ChallengeType.TARGET, request, authState, context);
Assert.assertFalse(request.containsHeader(HttpHeaders.AUTHORIZATION));
Mockito.verify(this.authScheme, Mockito.never()).authenticate(
Mockito.any(Credentials.class),
Mockito.verify(this.authScheme, Mockito.never()).generateAuthResponse(
Mockito.eq(defaultHost),
Mockito.any(HttpRequest.class),
Mockito.any(HttpContext.class));
}
@ -356,42 +379,37 @@ public class TestHttpAuthenticator {
public void testAuthChallengeStateNoOption() throws Exception {
final HttpRequest request = new BasicHttpRequest("GET", "/");
this.authState.setState(AuthProtocolState.CHALLENGED);
this.authState.update(this.authScheme, this.credentials);
this.authState.update(this.authScheme);
Mockito.when(this.authScheme.authenticate(
Mockito.any(Credentials.class),
Mockito.when(this.authScheme.generateAuthResponse(
Mockito.eq(defaultHost),
Mockito.any(HttpRequest.class),
Mockito.any(HttpContext.class))).thenReturn(new BasicHeader(HttpHeaders.AUTHORIZATION, "stuff"));
Mockito.any(HttpContext.class))).thenReturn("stuff");
this.httpAuthenticator.addAuthResponse(request, authState, context);
this.httpAuthenticator.addAuthResponse(defaultHost, ChallengeType.TARGET, request, authState, context);
Assert.assertTrue(request.containsHeader(HttpHeaders.AUTHORIZATION));
Mockito.verify(this.authScheme).authenticate(this.credentials, request, this.context);
}
@Test
public void testAuthChallengeStateOneOptions() throws Exception {
final HttpRequest request = new BasicHttpRequest("GET", "/");
this.authState.setState(AuthProtocolState.CHALLENGED);
final LinkedList<AuthOption> authOptions = new LinkedList<>();
authOptions.add(new AuthOption(this.authScheme, this.credentials));
final LinkedList<AuthScheme> authOptions = new LinkedList<>();
authOptions.add(this.authScheme);
this.authState.update(authOptions);
Mockito.when(this.authScheme.authenticate(
Mockito.any(Credentials.class),
Mockito.when(this.authScheme.generateAuthResponse(
Mockito.eq(defaultHost),
Mockito.any(HttpRequest.class),
Mockito.any(HttpContext.class))).thenReturn(new BasicHeader(HttpHeaders.AUTHORIZATION, "stuff"));
Mockito.any(HttpContext.class))).thenReturn("stuff");
this.httpAuthenticator.addAuthResponse(request, authState, context);
this.httpAuthenticator.addAuthResponse(defaultHost, ChallengeType.TARGET, request, authState, context);
Assert.assertSame(this.authScheme, this.authState.getAuthScheme());
Assert.assertSame(this.credentials, this.authState.getCredentials());
Assert.assertNull(this.authState.getAuthOptions());
Assert.assertTrue(request.containsHeader(HttpHeaders.AUTHORIZATION));
Mockito.verify(this.authScheme).authenticate(this.credentials, request, this.context);
}
@Test
@ -399,74 +417,67 @@ public class TestHttpAuthenticator {
final HttpRequest request = new BasicHttpRequest("GET", "/");
this.authState.setState(AuthProtocolState.CHALLENGED);
final LinkedList<AuthOption> authOptions = new LinkedList<>();
final LinkedList<AuthScheme> authOptions = new LinkedList<>();
final AuthScheme authScheme1 = Mockito.mock(AuthScheme.class);
Mockito.doThrow(new AuthenticationException()).when(authScheme1).authenticate(
Mockito.any(Credentials.class),
Mockito.doThrow(new AuthenticationException()).when(authScheme1).generateAuthResponse(
Mockito.eq(defaultHost),
Mockito.any(HttpRequest.class),
Mockito.any(HttpContext.class));
final AuthScheme authScheme2 = Mockito.mock(AuthScheme.class);
Mockito.when(authScheme2.authenticate(
Mockito.any(Credentials.class),
Mockito.when(authScheme2.generateAuthResponse(
Mockito.eq(defaultHost),
Mockito.any(HttpRequest.class),
Mockito.any(HttpContext.class))).thenReturn(new BasicHeader(HttpHeaders.AUTHORIZATION, "stuff"));
authOptions.add(new AuthOption(authScheme1, this.credentials));
authOptions.add(new AuthOption(authScheme2, this.credentials));
Mockito.any(HttpContext.class))).thenReturn("stuff");
authOptions.add(authScheme1);
authOptions.add(authScheme2);
this.authState.update(authOptions);
this.httpAuthenticator.addAuthResponse(request, authState, context);
this.httpAuthenticator.addAuthResponse(defaultHost, ChallengeType.TARGET, request, authState, context);
Assert.assertSame(authScheme2, this.authState.getAuthScheme());
Assert.assertSame(this.credentials, this.authState.getCredentials());
Assert.assertNull(this.authState.getAuthOptions());
Assert.assertTrue(request.containsHeader(HttpHeaders.AUTHORIZATION));
Mockito.verify(authScheme1, Mockito.times(1)).authenticate(this.credentials, request, this.context);
Mockito.verify(authScheme2, Mockito.times(1)).authenticate(this.credentials, request, this.context);
}
@Test
public void testAuthSuccess() throws Exception {
final HttpRequest request = new BasicHttpRequest("GET", "/");
this.authState.setState(AuthProtocolState.SUCCESS);
this.authState.update(this.authScheme, this.credentials);
this.authState.update(this.authScheme);
Mockito.when(this.authScheme.isConnectionBased()).thenReturn(Boolean.FALSE);
Mockito.when(this.authScheme.authenticate(
Mockito.any(Credentials.class),
Mockito.when(this.authScheme.generateAuthResponse(
Mockito.eq(defaultHost),
Mockito.any(HttpRequest.class),
Mockito.any(HttpContext.class))).thenReturn(new BasicHeader(HttpHeaders.AUTHORIZATION, "stuff"));
Mockito.any(HttpContext.class))).thenReturn("stuff");
this.httpAuthenticator.addAuthResponse(request, authState, context);
this.httpAuthenticator.addAuthResponse(defaultHost, ChallengeType.TARGET, request, authState, context);
Assert.assertSame(this.authScheme, this.authState.getAuthScheme());
Assert.assertSame(this.credentials, this.authState.getCredentials());
Assert.assertNull(this.authState.getAuthOptions());
Assert.assertTrue(request.containsHeader(HttpHeaders.AUTHORIZATION));
Mockito.verify(this.authScheme).authenticate(this.credentials, request, this.context);
}
@Test
public void testAuthSuccessConnectionBased() throws Exception {
final HttpRequest request = new BasicHttpRequest("GET", "/");
this.authState.setState(AuthProtocolState.SUCCESS);
this.authState.update(this.authScheme, this.credentials);
this.authState.update(this.authScheme);
Mockito.when(this.authScheme.isConnectionBased()).thenReturn(Boolean.TRUE);
Mockito.when(this.authScheme.authenticate(
Mockito.any(Credentials.class),
Mockito.when(this.authScheme.generateAuthResponse(
Mockito.eq(defaultHost),
Mockito.any(HttpRequest.class),
Mockito.any(HttpContext.class))).thenReturn(new BasicHeader(HttpHeaders.AUTHORIZATION, "stuff"));
Mockito.any(HttpContext.class))).thenReturn("stuff");
this.httpAuthenticator.addAuthResponse(request, authState, context);
this.httpAuthenticator.addAuthResponse(defaultHost, ChallengeType.TARGET, request, authState, context);
Assert.assertFalse(request.containsHeader(HttpHeaders.AUTHORIZATION));
Mockito.verify(this.authScheme, Mockito.never()).authenticate(
Mockito.any(Credentials.class),
Mockito.verify(this.authScheme, Mockito.never()).generateAuthResponse(
Mockito.eq(defaultHost),
Mockito.any(HttpRequest.class),
Mockito.any(HttpContext.class));
}

View File

@ -1,87 +0,0 @@
/*
* ====================================================================
* 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.auth;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.protocol.HttpContext;
import org.junit.Assert;
import org.junit.Test;
public class TestNonStandardHttpScheme {
static class TestAuthScheme extends NonStandardAuthScheme {
@Override
public void processChallenge(
final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
}
@Override
public Header authenticate(
final Credentials credentials,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
return null;
}
@Override
public String getSchemeName() {
return "test";
}
@Override
public boolean isComplete() {
return false;
}
@Override
public boolean isConnectionBased() {
return false;
}
}
@Test
public void testProcessChallenge() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
authscheme.processChallenge(ChallengeType.TARGET, new AuthChallenge("Test", "this_and_that", null));
Assert.assertEquals("test", authscheme.getSchemeName());
Assert.assertEquals("test(TARGET) this_and_that", authscheme.toString());
Assert.assertEquals("this_and_that", authscheme.getChallenge());
}
}

View File

@ -1,95 +0,0 @@
/*
* ====================================================================
* 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.auth;
import java.util.Arrays;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.junit.Assert;
import org.junit.Test;
public class TestStandardHttpScheme {
static class TestAuthScheme extends StandardAuthScheme {
private static final long serialVersionUID = 1L;
@Override
public void processChallenge(
final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
}
@Override
public Header authenticate(
final Credentials credentials,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
return null;
}
@Override
public String getSchemeName() {
return "test";
}
@Override
public boolean isComplete() {
return false;
}
@Override
public boolean isConnectionBased() {
return false;
}
}
@Test
public void testProcessChallenge() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
authscheme.processChallenge(ChallengeType.TARGET, new AuthChallenge("Test", null, Arrays.asList(
new BasicNameValuePair("realm", "realm1"), new BasicNameValuePair("this", "blah"))));
Assert.assertEquals("test", authscheme.getSchemeName());
Assert.assertEquals("test(TARGET) {realm=realm1, this=blah}", authscheme.toString());
Assert.assertEquals("realm1", authscheme.getParameter("realm"));
Assert.assertEquals(null, authscheme.getParameter("test"));
Assert.assertEquals("blah", authscheme.getParameter("this"));
}
}

View File

@ -588,14 +588,12 @@ public class TestClientAuthentication extends LocalServerTestBase {
final HttpHost target = start();
final BasicScheme basicScheme = new BasicScheme();
basicScheme.initPreemptive(new UsernamePasswordCredentials("test", "test"));
final HttpClientContext context = HttpClientContext.create();
final AuthCache authCache = new BasicAuthCache();
authCache.put(target, new BasicScheme());
authCache.put(target, basicScheme);
context.setAuthCache(authCache);
final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("test", "test"));
context.setCredentialsProvider(credsProvider);
final HttpGet httpget = new HttpGet("/");
final HttpResponse response1 = this.httpclient.execute(target, httpget, context);

View File

@ -153,7 +153,7 @@ public class TestClientReauthentication extends LocalServerTestBase {
private static final long serialVersionUID = 1L;
@Override
public String getSchemeName() {
public String getName() {
return "MyBasic";
}

View File

@ -51,7 +51,6 @@ import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.NonRepeatableRequestException;
@ -442,7 +441,7 @@ public class TestMainClientExec {
final AuthState proxyAuthState = new AuthState();
proxyAuthState.setState(AuthProtocolState.SUCCESS);
proxyAuthState.update(new NTLMScheme(), new NTCredentials("user:pass"));
proxyAuthState.update(new NTLMScheme());
final HttpClientContext context = new HttpClientContext();
context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, proxyAuthState);
@ -475,7 +474,6 @@ public class TestMainClientExec {
Assert.assertNotNull(finalResponse);
Assert.assertEquals(200, finalResponse.getStatusLine().getStatusCode());
Assert.assertNull(proxyAuthState.getAuthScheme());
Assert.assertNull(proxyAuthState.getCredentials());
}
@Test(expected = NonRepeatableRequestException.class)

View File

@ -26,6 +26,10 @@
*/
package org.apache.http.impl.execchain;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
@ -35,8 +39,6 @@ import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.auth.AuthProtocolState;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.RedirectException;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.client.config.RequestConfig;
@ -60,10 +62,6 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
@SuppressWarnings({"boxing","static-access"}) // test code
public class TestRedirectExec {
@ -240,10 +238,10 @@ public class TestRedirectExec {
final AuthState targetAuthState = new AuthState();
targetAuthState.setState(AuthProtocolState.SUCCESS);
targetAuthState.update(new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
targetAuthState.update(new BasicScheme());
final AuthState proxyAuthState = new AuthState();
proxyAuthState.setState(AuthProtocolState.SUCCESS);
proxyAuthState.update(new NTLMScheme(), new NTCredentials("user:pass"));
proxyAuthState.update(new NTLMScheme());
context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, targetAuthState);
context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, proxyAuthState);

View File

@ -546,7 +546,7 @@ HttpRoutePlanner routePlanner = new HttpRoutePlanner() {
HttpRequest request,
HttpContext context) throws HttpException {
return new HttpRoute(target, null, new HttpHost("someproxy", 8080),
"https".equalsIgnoreCase(target.getSchemeName()));
"https".equalsIgnoreCase(target.getName()));
}
};