From 88ea39b476faf777fa2c01e4cb198a67927542e1 Mon Sep 17 00:00:00 2001 From: Sebastien Caille Date: Fri, 24 Jun 2016 17:11:34 +0200 Subject: [PATCH 1/4] HTTPCLIENT-1748: fixed proxy hostname so authentication works with java applets (started from firefox) --- .../http/impl/routing/SystemDefaultRoutePlanner.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java index 78e4e9758e..f2192e857c 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java @@ -97,8 +97,10 @@ private String getHost(final InetSocketAddress isa) { //@@@ Will this work with literal IPv6 addresses, or do we //@@@ need to wrap these in [] for the string representation? //@@@ Having it in this method at least allows for easy workarounds. - return isa.isUnresolved() ? - isa.getHostName() : isa.getAddress().getHostAddress(); + + //@@@ Maybe use HttpHost(isa.getAddress(), isa.getHostString(), isa.getPort(), null) to avoid + //@@@ resolving the address too many time + return isa.getHostString(); } From 7a87b59e9c20f443e3123425567153204e831453 Mon Sep 17 00:00:00 2001 From: Sebastien Caille Date: Fri, 24 Jun 2016 17:19:36 +0200 Subject: [PATCH 2/4] HTTPCLIENT-1748: improved creation of proxy's HttpHost --- .../impl/routing/SystemDefaultRoutePlanner.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java index f2192e857c..d04d07a617 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java @@ -86,24 +86,12 @@ protected HttpHost determineProxy( } final InetSocketAddress isa = (InetSocketAddress) p.address(); // assume default scheme (http) - result = new HttpHost(getHost(isa), isa.getPort()); + result = new HttpHost(isa.getAddress(), isa.getHostString(), isa.getPort(), null); } return result; } - private String getHost(final InetSocketAddress isa) { - - //@@@ Will this work with literal IPv6 addresses, or do we - //@@@ need to wrap these in [] for the string representation? - //@@@ Having it in this method at least allows for easy workarounds. - - //@@@ Maybe use HttpHost(isa.getAddress(), isa.getHostString(), isa.getPort(), null) to avoid - //@@@ resolving the address too many time - return isa.getHostString(); - - } - private Proxy chooseProxy(final List proxies) { Proxy result = null; // check the list for one we can use From f01cfa4bc82a0b73a723ed5d8fb3b0c5a05f071e Mon Sep 17 00:00:00 2001 From: Sebastien Caille Date: Sun, 3 Jul 2016 14:50:29 +0200 Subject: [PATCH 3/4] HTTPCLIENT-1748: fix for proxy authentication issue / trunk --- .../hc/client5/http/fluent/Executor.java | 4 +- .../osgi/impl/OSGiCredentialsProvider.java | 3 +- .../http/auth/CredentialsProvider.java | 6 +- .../client5/http/auth/CredentialsStore.java | 2 +- .../client5/http/impl/auth/BasicScheme.java | 3 +- .../client5/http/impl/auth/DigestScheme.java | 3 +- .../client5/http/impl/auth/GGSSchemeBase.java | 3 +- .../hc/client5/http/impl/auth/NTLMScheme.java | 3 +- .../SystemDefaultCredentialsProvider.java | 35 ++++- .../impl/sync/BasicCredentialsProvider.java | 4 +- .../auth/TestBasicCredentialsProvider.java | 26 ++-- .../http/impl/auth/TestHttpAuthenticator.java | 20 ++- .../TestSystemDefaultCredentialsProvider.java | 142 ++++++++++++++++++ .../integration/TestClientAuthentication.java | 2 +- .../TestClientAuthenticationFallBack.java | 2 +- .../TestClientReauthentication.java | 2 +- .../http/impl/sync/TestProtocolExec.java | 2 +- 17 files changed, 220 insertions(+), 42 deletions(-) create mode 100644 httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestSystemDefaultCredentialsProvider.java diff --git a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Executor.java b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Executor.java index 833d7cc157..6975c33cb2 100644 --- a/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Executor.java +++ b/httpclient5-fluent/src/main/java/org/apache/hc/client5/http/fluent/Executor.java @@ -146,7 +146,7 @@ public Executor auth(final String host, final Credentials creds) { public Executor authPreemptive(final HttpHost host) { if (this.credentialsStore != null) { - final Credentials credentials = this.credentialsStore.getCredentials(new AuthScope(host)); + final Credentials credentials = this.credentialsStore.getCredentials(new AuthScope(host), null); if (credentials == null) { final BasicScheme basicScheme = new BasicScheme(); basicScheme.initPreemptive(credentials); @@ -165,7 +165,7 @@ public Executor authPreemptive(final String host) { public Executor authPreemptiveProxy(final HttpHost proxy) { if (this.credentialsStore != null) { - final Credentials credentials = this.credentialsStore.getCredentials(new AuthScope(proxy)); + final Credentials credentials = this.credentialsStore.getCredentials(new AuthScope(proxy), null); if (credentials == null) { final BasicScheme basicScheme = new BasicScheme(); basicScheme.initPreemptive(credentials); diff --git a/httpclient5-osgi/src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiCredentialsProvider.java b/httpclient5-osgi/src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiCredentialsProvider.java index 9fc410c3f0..ee5d5df0e8 100644 --- a/httpclient5-osgi/src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiCredentialsProvider.java +++ b/httpclient5-osgi/src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiCredentialsProvider.java @@ -33,6 +33,7 @@ import org.apache.hc.client5.http.auth.CredentialsStore; import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; import org.apache.hc.client5.http.osgi.services.ProxyConfiguration; +import org.apache.hc.core5.http.protocol.HttpContext; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; @@ -64,7 +65,7 @@ public void setCredentials(final AuthScope authscope, final Credentials credenti * {@inheritDoc} */ @Override - public Credentials getCredentials(final AuthScope authscope) { + public Credentials getCredentials(final AuthScope authscope, final HttpContext context) { // iterate over all active proxy configurations at the moment of getting the credential for (final ServiceRegistration registration : registeredConfigurations.values()) { final Object proxyConfigurationObject = bundleContext.getService(registration.getReference()); diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsProvider.java b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsProvider.java index e160ddad37..13a595b5f9 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsProvider.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsProvider.java @@ -26,6 +26,8 @@ */ package org.apache.hc.client5.http.auth; +import org.apache.hc.core5.http.protocol.HttpContext; + /** * Provider of authentication credentials. *

@@ -42,8 +44,10 @@ public interface CredentialsProvider { * if available. * * @param authscope the {@link AuthScope authentication scope} + * @param context the {@link HttpContext http context} * @return the credentials + * @since 5.0 */ - Credentials getCredentials(AuthScope authscope); + Credentials getCredentials(AuthScope authscope, HttpContext context); } diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsStore.java b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsStore.java index 6a4194153e..510095f443 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsStore.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/CredentialsStore.java @@ -45,7 +45,7 @@ public interface CredentialsStore extends CredentialsProvider { * @param credentials the authentication {@link Credentials credentials} * for the given scope. * - * @see #getCredentials(AuthScope) + * @see #getCredentials(AuthScope, HttpContext) */ void setCredentials(AuthScope authscope, Credentials credentials); diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java index eb5ea46cf1..f7f5a77efd 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java @@ -140,7 +140,8 @@ public boolean isResponseReady( Args.notNull(host, "Auth host"); Args.notNull(credentialsProvider, "CredentialsProvider"); - final Credentials credentials = credentialsProvider.getCredentials(new AuthScope(host, getRealm(), getName())); + final Credentials credentials = + credentialsProvider.getCredentials(new AuthScope(host, getRealm(), getName()), context); if (credentials != null) { this.username = credentials.getUserPrincipal().getName(); this.password = credentials.getPassword(); diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java index fce54fc27d..91d1c718e4 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java @@ -172,7 +172,8 @@ public boolean isResponseReady( Args.notNull(host, "Auth host"); Args.notNull(credentialsProvider, "CredentialsProvider"); - final Credentials credentials = credentialsProvider.getCredentials(new AuthScope(host, getRealm(), getName())); + final Credentials credentials = + credentialsProvider.getCredentials(new AuthScope(host, getRealm(), getName()), context); if (credentials != null) { this.username = credentials.getUserPrincipal().getName(); this.password = credentials.getPassword(); diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java index 07bcd0de34..103b288314 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java @@ -175,7 +175,8 @@ public boolean isResponseReady( Args.notNull(host, "Auth host"); Args.notNull(credentialsProvider, "CredentialsProvider"); - final Credentials credentials = credentialsProvider.getCredentials(new AuthScope(host, null, getName())); + final Credentials credentials = + credentialsProvider.getCredentials(new AuthScope(host, null, getName()), context); if (credentials instanceof KerberosCredentials) { this.gssCredential = ((KerberosCredentials) credentials).getGSSCredential(); } else { diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMScheme.java index f67f608f76..d9eba1c75b 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMScheme.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMScheme.java @@ -129,7 +129,8 @@ public boolean isResponseReady( Args.notNull(host, "Auth host"); Args.notNull(credentialsProvider, "CredentialsProvider"); - final Credentials credentials = credentialsProvider.getCredentials(new AuthScope(host, null, getName())); + final Credentials credentials = + credentialsProvider.getCredentials(new AuthScope(host, null, getName()), context); if (credentials instanceof NTCredentials) { this.credentials = (NTCredentials) credentials; return true; diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java index e23032f110..3058200989 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java @@ -27,7 +27,9 @@ package org.apache.hc.client5.http.impl.auth; import java.net.Authenticator; +import java.net.MalformedURLException; import java.net.PasswordAuthentication; +import java.net.URL; import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -39,8 +41,11 @@ import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; import org.apache.hc.client5.http.config.AuthSchemes; import org.apache.hc.client5.http.impl.sync.BasicCredentialsProvider; +import org.apache.hc.client5.http.methods.HttpUriRequest; import org.apache.hc.core5.annotation.ThreadSafe; import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.http.protocol.HttpCoreContext; import org.apache.hc.core5.util.Args; /** @@ -88,35 +93,51 @@ public void setCredentials(final AuthScope authscope, final Credentials credenti private static PasswordAuthentication getSystemCreds( final AuthScope authscope, - final Authenticator.RequestorType requestorType) { + final Authenticator.RequestorType requestorType, + final HttpContext context) { final String hostname = authscope.getHost(); final int port = authscope.getPort(); final HttpHost origin = authscope.getOrigin(); final String protocol = origin != null ? origin.getSchemeName() : (port == 443 ? "https" : "http"); + + final URL targetHostURL; + if (context != null) { + final HttpUriRequest httpUriRequest = (HttpUriRequest) context.getAttribute(HttpCoreContext.HTTP_REQUEST); + try { + targetHostURL = httpUriRequest.getURI().toURL(); + } catch (final MalformedURLException e) { + throw new IllegalStateException("Unexpected request url format: " + httpUriRequest, e); + } + } else { + // Fluent case. + targetHostURL = null; + } + // use null addr, because the authentication fails if it does not exactly match the expected realm's host return Authenticator.requestPasswordAuthentication( hostname, null, port, protocol, - null, + authscope.getRealm(), translateScheme(authscope.getScheme()), - null, + targetHostURL, requestorType); } @Override - public Credentials getCredentials(final AuthScope authscope) { + public Credentials getCredentials(final AuthScope authscope, final HttpContext context) { Args.notNull(authscope, "Auth scope"); - final Credentials localcreds = internal.getCredentials(authscope); + final Credentials localcreds = internal.getCredentials(authscope, context); if (localcreds != null) { return localcreds; } final String host = authscope.getHost(); if (host != null) { - PasswordAuthentication systemcreds = getSystemCreds(authscope, Authenticator.RequestorType.SERVER); + PasswordAuthentication systemcreds = + getSystemCreds(authscope, Authenticator.RequestorType.SERVER, context); if (systemcreds == null) { - systemcreds = getSystemCreds(authscope, Authenticator.RequestorType.PROXY); + systemcreds = getSystemCreds(authscope, Authenticator.RequestorType.PROXY, context); } if (systemcreds == null) { final String proxyHost = System.getProperty("http.proxyHost"); diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicCredentialsProvider.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicCredentialsProvider.java index 091af4e4c2..08625671d3 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicCredentialsProvider.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/sync/BasicCredentialsProvider.java @@ -33,6 +33,7 @@ import org.apache.hc.client5.http.auth.Credentials; import org.apache.hc.client5.http.auth.CredentialsStore; import org.apache.hc.core5.annotation.ThreadSafe; +import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.util.Args; /** @@ -94,7 +95,8 @@ private static Credentials matchCredentials( } @Override - public Credentials getCredentials(final AuthScope authscope) { + public Credentials getCredentials(final AuthScope authscope, + final HttpContext httpContext) { Args.notNull(authscope, "Authentication scope"); return matchCredentials(this.credMap, authscope); } diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicCredentialsProvider.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicCredentialsProvider.java index df1cd627f6..96cdc0c625 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicCredentialsProvider.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicCredentialsProvider.java @@ -58,14 +58,14 @@ public void testBasicCredentialsProviderCredentials() { final BasicCredentialsProvider state = new BasicCredentialsProvider(); state.setCredentials(SCOPE1, CREDS1); state.setCredentials(SCOPE2, CREDS2); - Assert.assertEquals(CREDS1, state.getCredentials(SCOPE1)); - Assert.assertEquals(CREDS2, state.getCredentials(SCOPE2)); + Assert.assertEquals(CREDS1, state.getCredentials(SCOPE1, null)); + Assert.assertEquals(CREDS2, state.getCredentials(SCOPE2, null)); } @Test public void testBasicCredentialsProviderNoCredentials() { final BasicCredentialsProvider state = new BasicCredentialsProvider(); - Assert.assertEquals(null, state.getCredentials(BOGUS)); + Assert.assertEquals(null, state.getCredentials(BOGUS, null)); } @Test @@ -73,7 +73,7 @@ public void testBasicCredentialsProviderDefaultCredentials() { final BasicCredentialsProvider state = new BasicCredentialsProvider(); state.setCredentials(AuthScope.ANY, CREDS1); state.setCredentials(SCOPE2, CREDS2); - Assert.assertEquals(CREDS1, state.getCredentials(BOGUS)); + Assert.assertEquals(CREDS1, state.getCredentials(BOGUS, null)); } @Test @@ -81,7 +81,7 @@ public void testDefaultCredentials() throws Exception { final BasicCredentialsProvider state = new BasicCredentialsProvider(); final Credentials expected = new UsernamePasswordCredentials("name", "pass".toCharArray()); state.setCredentials(AuthScope.ANY, expected); - final Credentials got = state.getCredentials(DEFSCOPE); + final Credentials got = state.getCredentials(DEFSCOPE, null); Assert.assertEquals(got, expected); } @@ -90,7 +90,7 @@ public void testRealmCredentials() throws Exception { final BasicCredentialsProvider state = new BasicCredentialsProvider(); final Credentials expected = new UsernamePasswordCredentials("name", "pass".toCharArray()); state.setCredentials(DEFSCOPE, expected); - final Credentials got = state.getCredentials(DEFSCOPE); + final Credentials got = state.getCredentials(DEFSCOPE, null); Assert.assertEquals(expected, got); } @@ -100,7 +100,7 @@ public void testHostCredentials() throws Exception { final Credentials expected = new UsernamePasswordCredentials("name", "pass".toCharArray()); state.setCredentials( new AuthScope("host", AuthScope.ANY_PORT, AuthScope.ANY_REALM), expected); - final Credentials got = state.getCredentials(DEFSCOPE); + final Credentials got = state.getCredentials(DEFSCOPE, null); Assert.assertEquals(expected, got); } @@ -111,7 +111,7 @@ public void testWrongHostCredentials() throws Exception { state.setCredentials( new AuthScope("host1", AuthScope.ANY_PORT, "realm"), expected); final Credentials got = state.getCredentials( - new AuthScope("host2", AuthScope.ANY_PORT, "realm")); + new AuthScope("host2", AuthScope.ANY_PORT, "realm"), null); Assert.assertNotSame(expected, got); } @@ -122,7 +122,7 @@ public void testWrongRealmCredentials() throws Exception { state.setCredentials( new AuthScope("host", AuthScope.ANY_PORT, "realm1"), cred); final Credentials got = state.getCredentials( - new AuthScope("host", AuthScope.ANY_PORT, "realm2")); + new AuthScope("host", AuthScope.ANY_PORT, "realm2"), null); Assert.assertNotSame(cred, got); } @@ -132,7 +132,7 @@ public void testMixedCaseHostname() throws Exception { final BasicCredentialsProvider state = new BasicCredentialsProvider(); final Credentials expected = new UsernamePasswordCredentials("name", "pass".toCharArray()); state.setCredentials(new AuthScope(httpHost), expected); - final Credentials got = state.getCredentials(DEFSCOPE); + final Credentials got = state.getCredentials(DEFSCOPE, null); Assert.assertEquals(expected, got); } @@ -152,17 +152,17 @@ public void testCredentialsMatching() { state.setCredentials(scope3, creds3); Credentials got = state.getCredentials( - new AuthScope("someotherhost", 80, "someotherrealm", "basic")); + new AuthScope("someotherhost", 80, "someotherrealm", "basic"), null); Credentials expected = creds1; Assert.assertEquals(expected, got); got = state.getCredentials( - new AuthScope("someotherhost", 80, "somerealm", "basic")); + new AuthScope("someotherhost", 80, "somerealm", "basic"), null); expected = creds2; Assert.assertEquals(expected, got); got = state.getCredentials( - new AuthScope("somehost", 80, "someotherrealm", "basic")); + new AuthScope("somehost", 80, "someotherrealm", "basic"), null); expected = creds3; Assert.assertEquals(expected, got); } diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestHttpAuthenticator.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestHttpAuthenticator.java index caec70156a..7320ea86ba 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestHttpAuthenticator.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestHttpAuthenticator.java @@ -160,12 +160,13 @@ public void testAuthentication() throws Exception { response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "whatever realm=\"realm1\", stuff=\"1234\"")); final Credentials credentials = new UsernamePasswordCredentials("user", "pass".toCharArray()); - Mockito.when(this.credentialsProvider.getCredentials(Mockito.any())).thenReturn(credentials); + Mockito.when(this.credentialsProvider.getCredentials(Mockito.any(), + Mockito.any())).thenReturn(credentials); final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy(); - Assert.assertTrue(this.httpAuthenticator.prepareAuthResponse( - host, ChallengeType.TARGET, response, authStrategy, this.authExchange, this.context)); + Assert.assertTrue(this.httpAuthenticator.prepareAuthResponse(host, ChallengeType.TARGET, response, authStrategy, + this.authExchange, this.context)); Assert.assertEquals(AuthExchange.State.CHALLENGED, this.authExchange.getState()); final Queue options = this.authExchange.getAuthOptions(); @@ -182,17 +183,19 @@ public void testAuthentication() throws Exception { @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"); + 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".toCharArray()); - Mockito.when(this.credentialsProvider.getCredentials(new AuthScope(host, "test", "basic"))).thenReturn(credentials); + Mockito.when(this.credentialsProvider.getCredentials(Mockito.eq(new AuthScope(host, "test", "basic")), + Mockito.any())).thenReturn(credentials); final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy(); - Assert.assertTrue(this.httpAuthenticator.prepareAuthResponse( - host, ChallengeType.TARGET, response, authStrategy, this.authExchange, this.context)); + Assert.assertTrue(this.httpAuthenticator.prepareAuthResponse(host, ChallengeType.TARGET, response, authStrategy, + this.authExchange, this.context)); Assert.assertEquals(AuthExchange.State.CHALLENGED, this.authExchange.getState()); final Queue options = this.authExchange.getAuthOptions(); @@ -322,7 +325,8 @@ public void testAuthenticationNoMatchingChallenge() throws Exception { response.addHeader(new BasicHeader(HttpHeaders.WWW_AUTHENTICATE, "whatever realm=\"realm1\", stuff=\"1234\"")); final Credentials credentials = new UsernamePasswordCredentials("user", "pass".toCharArray()); - Mockito.when(this.credentialsProvider.getCredentials(new AuthScope(host, "realm1", "digest"))).thenReturn(credentials); + Mockito.when(this.credentialsProvider.getCredentials(Mockito.eq(new AuthScope(host, "realm1", "digest")), + Mockito.any())).thenReturn(credentials); final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy(); diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestSystemDefaultCredentialsProvider.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestSystemDefaultCredentialsProvider.java new file mode 100644 index 0000000000..ee58305e1b --- /dev/null +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestSystemDefaultCredentialsProvider.java @@ -0,0 +1,142 @@ +/* + * ==================================================================== + * 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.hc.client5.http.impl.auth; + +import java.net.Authenticator; +import java.net.Authenticator.RequestorType; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.PasswordAuthentication; +import java.net.URISyntaxException; +import java.net.URL; + +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.Credentials; +import org.apache.hc.client5.http.methods.HttpGet; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.protocol.HttpCoreContext; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +/** + * Simple tests for {@link SystemDefaultCredentialsProvider}. + */ +public class TestSystemDefaultCredentialsProvider { + + private final static String PROXY_PROTOCOL1 = "http"; + private final static String PROXY_HOST1 = "proxyhost1"; + private final static int PROXY_PORT1 = 3128; + private final static String PROMPT1 = "HttpClient authentication test prompt"; + private final static String TARGET_SCHEME1 = "https"; + private final static String TARGET_HOST1 = "targethost1"; + private final static int TARGET_PORT1 = 80; + private final static PasswordAuthentication AUTH1 = + new PasswordAuthentication("testUser", "testPassword".toCharArray()); + + // It's not possible to mock static Authenticator methods. So we mock a delegate + private final class DelegatedAuthenticator extends Authenticator { + private final AuthenticatorDelegate authenticatorDelegate; + + private DelegatedAuthenticator(final AuthenticatorDelegate authenticatorDelegate) { + this.authenticatorDelegate = authenticatorDelegate; + } + + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return authenticatorDelegate.getPasswordAuthentication(getRequestingHost(), getRequestingSite(), + getRequestingPort(), getRequestingProtocol(), + getRequestingPrompt(), getRequestingScheme(), + getRequestingURL(), getRequestorType()); + } + } + + private interface AuthenticatorDelegate { + PasswordAuthentication getPasswordAuthentication( + String host, + InetAddress addr, + int port, + String protocol, + String prompt, + String scheme, + URL url, + RequestorType reqType); + } + + @Test + public void testSystemCredentialsProviderCredentials() throws MalformedURLException, + URISyntaxException { + + final AuthenticatorDelegate authenticatorDelegate = installAuthenticator(AUTH1); + + final URL httpRequestUrl = new URL(TARGET_SCHEME1, TARGET_HOST1, TARGET_PORT1, ""); + final AuthScope authScope = new AuthScope(PROXY_HOST1, PROXY_PORT1, PROMPT1, "BASIC"); + final HttpCoreContext coreContext = new HttpCoreContext(); + coreContext.setTargetHost(new HttpHost(TARGET_HOST1, TARGET_PORT1, TARGET_SCHEME1)); + coreContext.setAttribute(HttpCoreContext.HTTP_REQUEST, new HttpGet(httpRequestUrl.toURI())); + + final Credentials receivedCredentials = + new SystemDefaultCredentialsProvider().getCredentials(authScope, coreContext); + + Mockito.verify(authenticatorDelegate).getPasswordAuthentication(PROXY_HOST1, null, PROXY_PORT1, PROXY_PROTOCOL1, + PROMPT1, "Basic", httpRequestUrl, + RequestorType.SERVER); + Assert.assertNotNull(receivedCredentials); + Assert.assertEquals(AUTH1.getUserName(), receivedCredentials.getUserPrincipal().getName()); + Assert.assertEquals(AUTH1.getPassword(), receivedCredentials.getPassword()); + } + + @Test + public void testSystemCredentialsProviderNoContext() throws MalformedURLException, + URISyntaxException { + + final AuthenticatorDelegate authenticatorDelegate = installAuthenticator(AUTH1); + + final AuthScope authScope = new AuthScope(PROXY_HOST1, PROXY_PORT1, PROMPT1, "BASIC"); + + final Credentials receivedCredentials = + new SystemDefaultCredentialsProvider().getCredentials(authScope, null); + + Mockito.verify(authenticatorDelegate).getPasswordAuthentication(PROXY_HOST1, null, PROXY_PORT1, PROXY_PROTOCOL1, + PROMPT1, "Basic", null, + RequestorType.SERVER); + Assert.assertNotNull(receivedCredentials); + Assert.assertEquals(AUTH1.getUserName(), receivedCredentials.getUserPrincipal().getName()); + Assert.assertEquals(AUTH1.getPassword(), receivedCredentials.getPassword()); + } + + private AuthenticatorDelegate installAuthenticator(final PasswordAuthentication returedAuthentication) { + final AuthenticatorDelegate authenticatorDelegate = Mockito.mock(AuthenticatorDelegate.class); + Mockito.when(authenticatorDelegate.getPasswordAuthentication(Mockito.anyString(), + Mockito.any(InetAddress.class), Mockito.anyInt(), + Mockito.anyString(), Mockito.anyString(), + Mockito.anyString(), Mockito.any(URL.class), + Mockito.any(RequestorType.class))).thenReturn(returedAuthentication); + Authenticator.setDefault(new DelegatedAuthenticator(authenticatorDelegate)); + return authenticatorDelegate; + } +} diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientAuthentication.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientAuthentication.java index c0d1e33506..d44cd5528f 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientAuthentication.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientAuthentication.java @@ -156,7 +156,7 @@ static class TestCredentialsProvider implements CredentialsProvider { } @Override - public Credentials getCredentials(final AuthScope authscope) { + public Credentials getCredentials(final AuthScope authscope, final HttpContext context) { this.authscope = authscope; return this.creds; } diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientAuthenticationFallBack.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientAuthenticationFallBack.java index 29c7bc2785..d95ffa3ec3 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientAuthenticationFallBack.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientAuthenticationFallBack.java @@ -118,7 +118,7 @@ static class TestCredentialsProvider implements CredentialsProvider { } @Override - public Credentials getCredentials(final AuthScope authscope) { + public Credentials getCredentials(final AuthScope authscope, final HttpContext context) { this.authscope = authscope; return this.creds; } diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientReauthentication.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientReauthentication.java index 847fd707d4..31db7ea71f 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientReauthentication.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/integration/TestClientReauthentication.java @@ -134,7 +134,7 @@ static class TestCredentialsProvider implements CredentialsProvider { } @Override - public Credentials getCredentials(final AuthScope authscope) { + public Credentials getCredentials(final AuthScope authscope, final HttpContext context) { this.authscope = authscope; return this.creds; } diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/sync/TestProtocolExec.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/sync/TestProtocolExec.java index 287c20af14..f6924e552a 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/sync/TestProtocolExec.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/sync/TestProtocolExec.java @@ -190,7 +190,7 @@ public void testUserInfoInRequestURI() throws Exception { Assert.assertEquals(new URI("/test"), request.getURI()); Assert.assertEquals(new HttpHost("bar", -1), context.getTargetHost()); final CredentialsProvider credentialsProvider = context.getCredentialsProvider(); - final Credentials creds = credentialsProvider.getCredentials(new AuthScope("bar", -1, null)); + final Credentials creds = credentialsProvider.getCredentials(new AuthScope("bar", -1, null), null); Assert.assertNotNull(creds); Assert.assertEquals("somefella", creds.getUserPrincipal().getName()); } From f44136fc1452affb7b5f88b639bc56514ef7d99e Mon Sep 17 00:00:00 2001 From: Sebastien Caille Date: Fri, 5 Aug 2016 13:12:23 +0200 Subject: [PATCH 4/4] Use HttpRequest instead of HttpUriRequest --- .../SystemDefaultCredentialsProvider.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java index 3058200989..0bb2b0299f 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SystemDefaultCredentialsProvider.java @@ -41,9 +41,9 @@ import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; import org.apache.hc.client5.http.config.AuthSchemes; import org.apache.hc.client5.http.impl.sync.BasicCredentialsProvider; -import org.apache.hc.client5.http.methods.HttpUriRequest; import org.apache.hc.core5.annotation.ThreadSafe; import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpCoreContext; import org.apache.hc.core5.util.Args; @@ -101,18 +101,7 @@ private static PasswordAuthentication getSystemCreds( final String protocol = origin != null ? origin.getSchemeName() : (port == 443 ? "https" : "http"); - final URL targetHostURL; - if (context != null) { - final HttpUriRequest httpUriRequest = (HttpUriRequest) context.getAttribute(HttpCoreContext.HTTP_REQUEST); - try { - targetHostURL = httpUriRequest.getURI().toURL(); - } catch (final MalformedURLException e) { - throw new IllegalStateException("Unexpected request url format: " + httpUriRequest, e); - } - } else { - // Fluent case. - targetHostURL = null; - } + final URL targetHostURL = getTargetHostURL(context); // use null addr, because the authentication fails if it does not exactly match the expected realm's host return Authenticator.requestPasswordAuthentication( hostname, @@ -125,6 +114,21 @@ private static PasswordAuthentication getSystemCreds( requestorType); } + private static URL getTargetHostURL(final HttpContext context) { + if (context == null) { + // Fluent case. + return null; + } + + final HttpRequest httpRequest = (HttpRequest)context.getAttribute(HttpCoreContext.HTTP_REQUEST); + final String uri = httpRequest.getRequestLine().getUri(); + try { + return new URL(uri); + } catch (final MalformedURLException e) { + throw new IllegalStateException("Unexpected request url format: " + uri, e); + } + } + @Override public Credentials getCredentials(final AuthScope authscope, final HttpContext context) { Args.notNull(authscope, "Auth scope");