From d3bcbedec7254b909ba0ebdaa77f03df2e04cb21 Mon Sep 17 00:00:00 2001 From: Oleg Kalnichevski Date: Thu, 23 Jul 2015 10:00:46 +0000 Subject: [PATCH] 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 --- .../apache/http/client/fluent/Executor.java | 29 +- .../http/client/cache/HttpCacheStorage.java | 4 +- .../cache/HttpCacheUpdateException.java | 2 +- .../impl/client/cache/BasicHttpCache.java | 4 +- .../http/impl/client/cache/CacheConfig.java | 6 +- .../impl/client/cache/CacheEntryUpdater.java | 2 +- .../http/impl/client/cache/CachingExec.java | 4 +- .../client/cache/DefaultFailureCache.java | 2 +- .../http/impl/client/cache/HttpCache.java | 2 +- .../ehcache/EhcacheHttpCacheStorage.java | 2 +- .../memcached/MemcachedHttpCacheStorage.java | 2 +- .../cache/TestProtocolRecommendations.java | 2 +- .../cache/TestProtocolRequirements.java | 6 +- .../ehcache/TestEhcacheHttpCacheStorage.java | 4 +- .../auth/win/CurrentWindowsCredentials.java | 108 ----- .../auth/win/WindowsCredentialsProvider.java | 76 ---- .../impl/auth/win/WindowsNegotiateScheme.java | 86 ++-- .../http/impl/client/WinHttpClients.java | 4 - .../auth/win/TestWindowsNegotiateScheme.java | 5 - .../ClientPreemptiveBasicAuthentication.java | 13 +- .../ClientPreemptiveDigestAuthentication.java | 19 +- .../java/org/apache/http/auth/AuthOption.java | 63 --- .../java/org/apache/http/auth/AuthScheme.java | 184 +++++--- .../java/org/apache/http/auth/AuthState.java | 47 +-- .../client/protocol/RequestAuthCache.java | 37 +- .../http/cookie/CookieAttributeHandler.java | 2 +- .../http/cookie/CookiePriorityComparator.java | 2 +- .../apache/http/impl/auth/BasicScheme.java | 123 ++++-- .../apache/http/impl/auth/DigestScheme.java | 174 +++++--- .../apache/http/impl/auth/GGSSchemeBase.java | 123 +++--- .../http/impl/auth/HttpAuthenticator.java | 63 ++- .../apache/http/impl/auth/KerberosScheme.java | 7 +- .../apache/http/impl/auth/NTLMEngineImpl.java | 2 +- .../org/apache/http/impl/auth/NTLMScheme.java | 101 +++-- .../http/impl/auth/NonStandardAuthScheme.java | 70 ---- .../apache/http/impl/auth/SPNegoScheme.java | 7 +- .../http/impl/auth/StandardAuthScheme.java | 111 ----- .../impl/client/DefaultUserTokenHandler.java | 8 +- .../apache/http/impl/client/ProxyClient.java | 2 +- .../http/impl/execchain/MainClientExec.java | 10 +- .../http/impl/execchain/ProtocolExec.java | 2 +- .../client/protocol/TestRequestAuthCache.java | 41 +- .../http/impl/auth/TestBasicScheme.java | 70 ++-- .../http/impl/auth/TestDigestScheme.java | 395 +++++++++++------- .../http/impl/auth/TestHttpAuthenticator.java | 169 ++++---- .../impl/auth/TestNonStandardHttpScheme.java | 87 ---- .../impl/auth/TestStandardHttpScheme.java | 95 ----- .../integration/TestClientAuthentication.java | 8 +- .../TestClientReauthentication.java | 2 +- .../impl/execchain/TestMainClientExec.java | 4 +- .../http/impl/execchain/TestRedirectExec.java | 14 +- src/docbkx/connmgmt.xml | 2 +- 52 files changed, 974 insertions(+), 1433 deletions(-) delete mode 100644 httpclient-win/src/main/java/org/apache/http/impl/auth/win/CurrentWindowsCredentials.java delete mode 100644 httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsCredentialsProvider.java delete mode 100644 httpclient/src/main/java/org/apache/http/auth/AuthOption.java delete mode 100644 httpclient/src/main/java/org/apache/http/impl/auth/NonStandardAuthScheme.java delete mode 100644 httpclient/src/main/java/org/apache/http/impl/auth/StandardAuthScheme.java delete mode 100644 httpclient/src/test/java/org/apache/http/impl/auth/TestNonStandardHttpScheme.java delete mode 100644 httpclient/src/test/java/org/apache/http/impl/auth/TestStandardHttpScheme.java diff --git a/fluent-hc/src/main/java/org/apache/http/client/fluent/Executor.java b/fluent-hc/src/main/java/org/apache/http/client/fluent/Executor.java index 96fe823ee..c7f7be442 100644 --- a/fluent-hc/src/main/java/org/apache/http/client/fluent/Executor.java +++ b/fluent-hc/src/main/java/org/apache/http/client/fluent/Executor.java @@ -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.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.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; } diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheStorage.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheStorage.java index 157e5b50d..b7362ae36 100644 --- a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheStorage.java +++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheStorage.java @@ -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. diff --git a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheUpdateException.java b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheUpdateException.java index 5221406f1..dacf8753f 100644 --- a/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheUpdateException.java +++ b/httpclient-cache/src/main/java/org/apache/http/client/cache/HttpCacheUpdateException.java @@ -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 */ diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java index 7bc5b241a..09b0deed5 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java @@ -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); } } diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java index 1fc16fb23..1d436b0ea 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheConfig.java @@ -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; diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java index a2c459a28..926fbce91 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java @@ -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 */ diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java index 32e82bfc3..4182859cb 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingExec.java @@ -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); } } diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultFailureCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultFailureCache.java index cbf1d8c46..c0c0cf973 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultFailureCache.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/DefaultFailureCache.java @@ -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); diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java index 26897865a..b40ef2e6b 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/HttpCache.java @@ -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; diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java index d92102732..3fcda21a2 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ehcache/EhcacheHttpCacheStorage.java @@ -156,6 +156,6 @@ public class EhcacheHttpCacheStorage implements HttpCacheStorage { } } }while(numRetries <= maxUpdateRetries); - throw new HttpCacheUpdateException("Failed to update"); + throw new HttpCacheUpdateException("Failed to processChallenge"); } } diff --git a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java index 136150fb4..cbee5b110 100644 --- a/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java +++ b/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/memcached/MemcachedHttpCacheStorage.java @@ -268,6 +268,6 @@ public class MemcachedHttpCacheStorage implements HttpCacheStorage { } } while (numRetries <= maxUpdateRetries); - throw new HttpCacheUpdateException("Failed to update"); + throw new HttpCacheUpdateException("Failed to processChallenge"); } } diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java index f68d77a77..b9de85950 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java @@ -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." * diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java index c2fd67534..f62d1b7a3 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java @@ -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 diff --git a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCacheStorage.java b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCacheStorage.java index ee91cecc4..05187ca2b 100644 --- a/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCacheStorage.java +++ b/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/ehcache/TestEhcacheHttpCacheStorage.java @@ -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{ diff --git a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/CurrentWindowsCredentials.java b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/CurrentWindowsCredentials.java deleted file mode 100644 index 817499232..000000000 --- a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/CurrentWindowsCredentials.java +++ /dev/null @@ -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 - * . - * - */ - -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 - *

- * EXPERIMENTAL - *

- * - * @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(); - } - -} - - - diff --git a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsCredentialsProvider.java b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsCredentialsProvider.java deleted file mode 100644 index 26d554baf..000000000 --- a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsCredentialsProvider.java +++ /dev/null @@ -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 - * . - * - */ -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. - *

- * EXPERIMENTAL - *

- * - * @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(); - } -} - - diff --git a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateScheme.java b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateScheme.java index 1ef9c46a6..d308bd067 100644 --- a/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateScheme.java +++ b/httpclient-win/src/main/java/org/apache/http/impl/auth/win/WindowsNegotiateScheme.java @@ -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; } diff --git a/httpclient-win/src/main/java/org/apache/http/impl/client/WinHttpClients.java b/httpclient-win/src/main/java/org/apache/http/impl/client/WinHttpClients.java index 905809a54..9ac5df33e 100644 --- a/httpclient-win/src/main/java/org/apache/http/impl/client/WinHttpClients.java +++ b/httpclient-win/src/main/java/org/apache/http/impl/client/WinHttpClients.java @@ -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(); diff --git a/httpclient-win/src/test/java/org/apache/http/impl/auth/win/TestWindowsNegotiateScheme.java b/httpclient-win/src/test/java/org/apache/http/impl/auth/win/TestWindowsNegotiateScheme.java index fb28d5cd7..e805f629b 100644 --- a/httpclient-win/src/test/java/org/apache/http/impl/auth/win/TestWindowsNegotiateScheme.java +++ b/httpclient-win/src/test/java/org/apache/http/impl/auth/win/TestWindowsNegotiateScheme.java @@ -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(); diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java b/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java index f3be16672..d47042aa9 100644 --- a/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java +++ b/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveBasicAuthentication.java @@ -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 diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java b/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java index cb9579c66..07d2f8541 100644 --- a/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java +++ b/httpclient/src/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java @@ -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 diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthOption.java b/httpclient/src/main/java/org/apache/http/auth/AuthOption.java deleted file mode 100644 index 21f0bc965..000000000 --- a/httpclient/src/main/java/org/apache/http/auth/AuthOption.java +++ /dev/null @@ -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 - * . - * - */ -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(); - } - -} - diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthScheme.java b/httpclient/src/main/java/org/apache/http/auth/AuthScheme.java index e3fb57db8..627a93b27 100644 --- a/httpclient/src/main/java/org/apache/http/auth/AuthScheme.java +++ b/httpclient/src/main/java/org/apache/http/auth/AuthScheme.java @@ -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. *

- * 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. + *

+ * Authentication scheme are expected to transition through a series of standard phases or + * states. + *

+ * Authentication scheme starts off its life cycle with no context and no specific state. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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; } diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthState.java b/httpclient/src/main/java/org/apache/http/auth/AuthState.java index 1aa07190b..56ea0d2cd 100644 --- a/httpclient/src/main/java/org/apache/http/auth/AuthState.java +++ b/httpclient/src/main/java/org/apache/http/auth/AuthState.java @@ -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 authOptions; + private Queue 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 getAuthOptions() { + public Queue 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 authOptions) { + public void update(final Queue 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(); } diff --git a/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java b/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java index c33eade04..be5da0fa0 100644 --- a/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java +++ b/httpclient/src/main/java/org/apache/http/client/protocol/RequestAuthCache.java @@ -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"); - } - } - } diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookieAttributeHandler.java b/httpclient/src/main/java/org/apache/http/cookie/CookieAttributeHandler.java index 95e1c331a..40cf0b0d6 100644 --- a/httpclient/src/main/java/org/apache/http/cookie/CookieAttributeHandler.java +++ b/httpclient/src/main/java/org/apache/http/cookie/CookieAttributeHandler.java @@ -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 diff --git a/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java b/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java index 77e4e0132..cc52036da 100644 --- a/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java +++ b/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java @@ -54,7 +54,7 @@ public class CookiePriorityComparator implements Comparator { 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(); diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java index 509b4a1f1..b36d57f04 100644 --- a/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java +++ b/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java @@ -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 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 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(); + } + } diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java index c4d598139..e35453f02 100644 --- a/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java +++ b/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java @@ -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 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 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 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 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(); + } + } diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java b/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java index a2f432f51..e328b9c74 100644 --- a/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java +++ b/httpclient/src/main/java/org/apache/http/impl/auth/GGSSchemeBase.java @@ -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 + ']'; + } + } diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/HttpAuthenticator.java b/httpclient/src/main/java/org/apache/http/impl/auth/HttpAuthenticator.java index 5bda0666b..24ec29fef 100644 --- a/httpclient/src/main/java/org/apache/http/impl/auth/HttpAuthenticator.java +++ b/httpclient/src/main/java/org/apache/http/impl/auth/HttpAuthenticator.java @@ -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 authOptions = new LinkedList<>(); + final Queue 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 authOptions = authState.getAuthOptions(); + final Queue 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); - } - } diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java index c787fcc27..974361f13 100644 --- a/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java +++ b/httpclient/src/main/java/org/apache/http/impl/auth/KerberosScheme.java @@ -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 diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java index 038ae444d..4edd6914a 100644 --- a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java +++ b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java @@ -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); diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMScheme.java index 2b363996d..a00e6342e 100644 --- a/httpclient/src/main/java/org/apache/http/impl/auth/NTLMScheme.java +++ b/httpclient/src/main/java/org/apache/http/impl/auth/NTLMScheme.java @@ -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 + ']'; + } + } diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/NonStandardAuthScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/NonStandardAuthScheme.java deleted file mode 100644 index be3b13d2f..000000000 --- a/httpclient/src/main/java/org/apache/http/impl/auth/NonStandardAuthScheme.java +++ /dev/null @@ -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 - * . - * - */ -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; - } - -} diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java index 5d479264a..edf626c0c 100644 --- a/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java +++ b/httpclient/src/main/java/org/apache/http/impl/auth/SPNegoScheme.java @@ -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 diff --git a/httpclient/src/main/java/org/apache/http/impl/auth/StandardAuthScheme.java b/httpclient/src/main/java/org/apache/http/impl/auth/StandardAuthScheme.java deleted file mode 100644 index bcab410d1..000000000 --- a/httpclient/src/main/java/org/apache/http/impl/auth/StandardAuthScheme.java +++ /dev/null @@ -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 - * . - * - */ -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 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 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 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; - } - -} diff --git a/httpclient/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java b/httpclient/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java index 99fc92247..e4dfc8208 100644 --- a/httpclient/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java +++ b/httpclient/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java @@ -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; } diff --git a/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java b/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java index 9632e4e6c..660907bbe 100644 --- a/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java +++ b/httpclient/src/main/java/org/apache/http/impl/client/ProxyClient.java @@ -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); diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java b/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java index 302489f7c..950e65af6 100644 --- a/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java +++ b/httpclient/src/main/java/org/apache/http/impl/execchain/MainClientExec.java @@ -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 not update the connection with + * This method does not 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); diff --git a/httpclient/src/main/java/org/apache/http/impl/execchain/ProtocolExec.java b/httpclient/src/main/java/org/apache/http/impl/execchain/ProtocolExec.java index bacc42204..d1965e1b4 100644 --- a/httpclient/src/main/java/org/apache/http/impl/execchain/ProtocolExec.java +++ b/httpclient/src/main/java/org/apache/http/impl/execchain/ProtocolExec.java @@ -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}. *

* Further responsibilities such as communication with the opposite diff --git a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAuthCache.java b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAuthCache.java index 6bc3d95b9..239a4dd42 100644 --- a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAuthCache.java +++ b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAuthCache.java @@ -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()); } } diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java index 63fdf9431..9559b9ee2 100644 --- a/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java +++ b/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java @@ -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()); } } diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java index 351f8b151..55b9bf184 100644 --- a/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java +++ b/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java @@ -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 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 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 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 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 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 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 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 parseAuthResponse(final Header authResponse) { - final String s = authResponse.getValue(); - if (!s.startsWith("Digest ")) { + private static Map 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 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 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 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 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 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 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 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 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 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()); diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestHttpAuthenticator.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestHttpAuthenticator.java index 35337486a..eb806da40 100644 --- a/httpclient/src/test/java/org/apache/http/impl/auth/TestHttpAuthenticator.java +++ b/httpclient/src/test/java/org/apache/http/impl/auth/TestHttpAuthenticator.java @@ -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 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.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.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 options = this.authState.getAuthOptions(); + final Queue 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 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 options = this.authState.getAuthOptions(); + final Queue 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 authOptions = new LinkedList<>(); - authOptions.add(new AuthOption(this.authScheme, this.credentials)); + final LinkedList 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 authOptions = new LinkedList<>(); + final LinkedList 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)); } diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestNonStandardHttpScheme.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestNonStandardHttpScheme.java deleted file mode 100644 index a187a5d7e..000000000 --- a/httpclient/src/test/java/org/apache/http/impl/auth/TestNonStandardHttpScheme.java +++ /dev/null @@ -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 - * . - * - */ - -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()); - } - -} - diff --git a/httpclient/src/test/java/org/apache/http/impl/auth/TestStandardHttpScheme.java b/httpclient/src/test/java/org/apache/http/impl/auth/TestStandardHttpScheme.java deleted file mode 100644 index c4b988005..000000000 --- a/httpclient/src/test/java/org/apache/http/impl/auth/TestStandardHttpScheme.java +++ /dev/null @@ -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 - * . - * - */ - -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")); - } - -} - diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java index f134b223c..f46c070b1 100644 --- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java +++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientAuthentication.java @@ -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); diff --git a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientReauthentication.java b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientReauthentication.java index fd8218db0..f5c4c1c95 100644 --- a/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientReauthentication.java +++ b/httpclient/src/test/java/org/apache/http/impl/client/integration/TestClientReauthentication.java @@ -153,7 +153,7 @@ public class TestClientReauthentication extends LocalServerTestBase { private static final long serialVersionUID = 1L; @Override - public String getSchemeName() { + public String getName() { return "MyBasic"; } diff --git a/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java b/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java index 04ac73208..a0a34eadf 100644 --- a/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java +++ b/httpclient/src/test/java/org/apache/http/impl/execchain/TestMainClientExec.java @@ -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) diff --git a/httpclient/src/test/java/org/apache/http/impl/execchain/TestRedirectExec.java b/httpclient/src/test/java/org/apache/http/impl/execchain/TestRedirectExec.java index 3affd867a..6b1939f99 100644 --- a/httpclient/src/test/java/org/apache/http/impl/execchain/TestRedirectExec.java +++ b/httpclient/src/test/java/org/apache/http/impl/execchain/TestRedirectExec.java @@ -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); diff --git a/src/docbkx/connmgmt.xml b/src/docbkx/connmgmt.xml index 9e86cbdb9..b38241ae7 100644 --- a/src/docbkx/connmgmt.xml +++ b/src/docbkx/connmgmt.xml @@ -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())); } };