From 246e2f2d2fa01f71a6960952c622ff080d6eab5d Mon Sep 17 00:00:00 2001 From: Mohammed Hassan Date: Fri, 13 Nov 2026 14:44:08 +0530 Subject: [PATCH] do not hand system proxy credentials to the origin server SystemDefaultCredentialsProvider asked java.net.Authenticator for RequestorType.PROXY credentials whenever no SERVER credentials were found, whatever host issued the challenge. With an Authenticator that answers proxy requests, as is common for corporate proxies, any origin server replying 401 Basic was sent the proxy credentials. Use the challenge type now carried by AuthScope to pick the requestor type: SERVER for target challenges, PROXY for proxy challenges. Untyped scopes keep the SERVER-then-PROXY lookup. --- .../SystemDefaultCredentialsProvider.java | 18 ++++-- .../TestSystemDefaultCredentialsProvider.java | 61 +++++++++++++++++++ 2 files changed, 73 insertions(+), 6 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 4812e11a12..bbae36a139 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 @@ -34,6 +34,7 @@ import java.net.URL; import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.ChallengeType; import org.apache.hc.client5.http.auth.Credentials; import org.apache.hc.client5.http.auth.CredentialsStore; import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; @@ -106,13 +107,18 @@ public Credentials getCredentials(final AuthScope authScope, final HttpContext c if (host != null) { final HttpClientContext clientContext = context != null ? HttpClientContext.cast(context) : null; final String protocol = authScope.getProtocol() != null ? authScope.getProtocol() : (authScope.getPort() == 443 ? URIScheme.HTTPS.id : URIScheme.HTTP.id); - final PasswordAuthentication serverCreds = getSystemCreds(protocol, authScope, Authenticator.RequestorType.SERVER, clientContext); - if (serverCreds != null) { - return new UsernamePasswordCredentials(serverCreds.getUserName(), serverCreds.getPassword()); + final ChallengeType challengeType = authScope.getChallengeType(); + if (challengeType != ChallengeType.PROXY) { + final PasswordAuthentication serverCreds = getSystemCreds(protocol, authScope, Authenticator.RequestorType.SERVER, clientContext); + if (serverCreds != null) { + return new UsernamePasswordCredentials(serverCreds.getUserName(), serverCreds.getPassword()); + } } - final PasswordAuthentication proxyCreds = getSystemCreds(protocol, authScope, Authenticator.RequestorType.PROXY, clientContext); - if (proxyCreds != null) { - return new UsernamePasswordCredentials(proxyCreds.getUserName(), proxyCreds.getPassword()); + if (challengeType != ChallengeType.TARGET) { + final PasswordAuthentication proxyCreds = getSystemCreds(protocol, authScope, Authenticator.RequestorType.PROXY, clientContext); + if (proxyCreds != null) { + return new UsernamePasswordCredentials(proxyCreds.getUserName(), proxyCreds.getPassword()); + } } } return null; 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 index ce71b055bd..8924ee9a2f 100644 --- 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 @@ -34,6 +34,7 @@ import java.util.Locale; import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.ChallengeType; import org.apache.hc.client5.http.auth.Credentials; import org.apache.hc.client5.http.auth.StandardAuthScheme; import org.apache.hc.client5.http.classic.methods.HttpGet; @@ -129,6 +130,66 @@ void testSystemCredentialsProviderNoContext() { Assertions.assertEquals(AUTH1.getUserName(), receivedCredentials.getUserPrincipal().getName()); } + @Test + void testSystemCredentialsProviderNoProxyCredentialsForTarget() { + + final AuthenticatorDelegate authenticatorDelegate = installProxyAuthenticator(AUTH1); + + final AuthScope authScope = new AuthScope(TARGET_SCHEME1, TARGET_HOST1, TARGET_PORT1, PROMPT1, + StandardAuthScheme.BASIC, ChallengeType.TARGET); + + final Credentials receivedCredentials = + new SystemDefaultCredentialsProvider().getCredentials(authScope, HttpClientContext.create()); + + Mockito.verify(authenticatorDelegate, Mockito.never()).getPasswordAuthentication(ArgumentMatchers.any(), + ArgumentMatchers.any(), ArgumentMatchers.anyInt(), ArgumentMatchers.any(), ArgumentMatchers.any(), + ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.eq(RequestorType.PROXY)); + Assertions.assertNull(receivedCredentials); + } + + @Test + void testSystemCredentialsProviderProxyCredentialsForProxy() { + + final AuthenticatorDelegate authenticatorDelegate = installProxyAuthenticator(AUTH1); + + final AuthScope authScope = new AuthScope(PROXY_PROTOCOL1, PROXY_HOST1, PROXY_PORT1, PROMPT1, + StandardAuthScheme.BASIC, ChallengeType.PROXY); + + final Credentials receivedCredentials = + new SystemDefaultCredentialsProvider().getCredentials(authScope, HttpClientContext.create()); + + Mockito.verify(authenticatorDelegate, Mockito.never()).getPasswordAuthentication(ArgumentMatchers.any(), + ArgumentMatchers.any(), ArgumentMatchers.anyInt(), ArgumentMatchers.any(), ArgumentMatchers.any(), + ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.eq(RequestorType.SERVER)); + Assertions.assertNotNull(receivedCredentials); + Assertions.assertEquals(AUTH1.getUserName(), receivedCredentials.getUserPrincipal().getName()); + } + + @Test + void testSystemCredentialsProviderProxyCredentialsForUntypedScope() { + + installProxyAuthenticator(AUTH1); + + final AuthScope authScope = new AuthScope(PROXY_PROTOCOL1, PROXY_HOST1, PROXY_PORT1, PROMPT1, StandardAuthScheme.BASIC); + + final Credentials receivedCredentials = + new SystemDefaultCredentialsProvider().getCredentials(authScope, HttpClientContext.create()); + + Assertions.assertNotNull(receivedCredentials); + Assertions.assertEquals(AUTH1.getUserName(), receivedCredentials.getUserPrincipal().getName()); + } + + private AuthenticatorDelegate installProxyAuthenticator(final PasswordAuthentication proxyAuthentication) { + final AuthenticatorDelegate authenticatorDelegate = Mockito.mock(AuthenticatorDelegate.class); + Mockito.when(authenticatorDelegate.getPasswordAuthentication(ArgumentMatchers.any(), + ArgumentMatchers.any(), ArgumentMatchers.anyInt(), + ArgumentMatchers.any(), ArgumentMatchers.any(), + ArgumentMatchers.any(), ArgumentMatchers.any(), + ArgumentMatchers.eq(RequestorType.PROXY))).thenReturn(proxyAuthentication); + Authenticator.setDefault(new DelegatedAuthenticator(authenticatorDelegate)); + return authenticatorDelegate; + } + private AuthenticatorDelegate installAuthenticator(final PasswordAuthentication returedAuthentication) { final AuthenticatorDelegate authenticatorDelegate = Mockito.mock(AuthenticatorDelegate.class); Mockito.when(authenticatorDelegate.getPasswordAuthentication(ArgumentMatchers.anyString(),