diff --git a/modules/integration/test/org/apache/axis2/transport/http/HTTPProxyConfiguratorTest.java b/modules/integration/test/org/apache/axis2/transport/http/HTTPProxyConfiguratorTest.java index f870ff316e..50b2eb03af 100644 --- a/modules/integration/test/org/apache/axis2/transport/http/HTTPProxyConfiguratorTest.java +++ b/modules/integration/test/org/apache/axis2/transport/http/HTTPProxyConfiguratorTest.java @@ -37,6 +37,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import org.apache.axis2.transport.http.impl.httpclient5.HTTPProxyConfigurator; @@ -93,10 +94,12 @@ public void testProxyWithCredentials() throws AxisFault { final CredentialsProvider provider = clientContext.getCredentialsProvider(); assertNotNull(provider); - final Credentials credentials = provider.getCredentials(new AuthScope(null, -1), clientContext); + final Credentials credentials = provider.getCredentials(new AuthScope(hostname, portNumber), clientContext); assertNotNull(credentials); assertEquals(user, credentials.getUserPrincipal().getName()); assertEquals(pass, new String(credentials.getPassword())); + // The origin server's challenge must not be answered with the proxy credentials + assertNull(provider.getCredentials(new AuthScope("origin.example", 443), clientContext)); } @Test diff --git a/modules/transport/http/src/main/java/org/apache/axis2/transport/http/impl/httpclient5/HTTPProxyConfigurator.java b/modules/transport/http/src/main/java/org/apache/axis2/transport/http/impl/httpclient5/HTTPProxyConfigurator.java index 149cf0b74c..cddab45817 100644 --- a/modules/transport/http/src/main/java/org/apache/axis2/transport/http/impl/httpclient5/HTTPProxyConfigurator.java +++ b/modules/transport/http/src/main/java/org/apache/axis2/transport/http/impl/httpclient5/HTTPProxyConfigurator.java @@ -146,11 +146,20 @@ public static void configure(MessageContext messageContext, RequestConfig.Builde // AXIS2-6051, CredentialsProvider no longer has setCredentials() however BasicCredentialsProvider // does have it. clientContext.getCredentialsProvider() returns CredentialsProvider. - if (proxyCredentials != null) { + if (proxyCredentials != null && proxyHost != null) { requestConfig.setAuthenticationEnabled(true); - BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); - clientContext.setCredentialsProvider(credsProvider); - credsProvider.setCredentials(new AuthScope(null, -1), proxyCredentials); + // The same provider answers the origin server's challenges, so the + // credentials are scoped to the proxy rather than to any host, and a + // provider already holding the origin's credentials is kept. + CredentialsProvider existingProvider = clientContext.getCredentialsProvider(); + BasicCredentialsProvider credsProvider; + if (existingProvider instanceof BasicCredentialsProvider) { + credsProvider = (BasicCredentialsProvider) existingProvider; + } else { + credsProvider = new BasicCredentialsProvider(); + clientContext.setCredentialsProvider(credsProvider); + } + credsProvider.setCredentials(new AuthScope(proxyHost, proxyPort), proxyCredentials); } if (proxyHost != null && proxyPort > 0) { HttpHost proxy = new HttpHost(proxyHost, proxyPort); diff --git a/modules/transport/http/src/test/java/org/apache/axis2/transport/http/impl/httpclient5/ProxyCredentialScopeTest.java b/modules/transport/http/src/test/java/org/apache/axis2/transport/http/impl/httpclient5/ProxyCredentialScopeTest.java new file mode 100644 index 0000000000..fc20fcfec1 --- /dev/null +++ b/modules/transport/http/src/test/java/org/apache/axis2/transport/http/impl/httpclient5/ProxyCredentialScopeTest.java @@ -0,0 +1,165 @@ +/* + * 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. + */ + +package org.apache.axis2.transport.http.impl.httpclient5; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import junit.framework.TestCase; +import org.apache.axis2.context.ConfigurationContext; +import org.apache.axis2.context.MessageContext; +import org.apache.axis2.engine.AxisConfiguration; +import org.apache.axis2.kernel.http.HTTPConstants; +import org.apache.axis2.transport.http.HttpTransportProperties; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Proxy credentials must answer the proxy's challenge only. + * + *
The client sends the same credentials provider to the proxy and to the
+ * origin server. Credentials registered for any host would therefore also be
+ * sent in reply to a 401 from the origin, which hands the proxy password to
+ * whatever server the request happens to reach.
+ */
+public class ProxyCredentialScopeTest extends TestCase {
+
+ private static final String PROXY_USER = "proxyuser";
+ private static final String PROXY_PASSWORD = "proxypass";
+ private static final String ORIGIN_USER = "originuser";
+ private static final String ORIGIN_PASSWORD = "originpass";
+
+ private HttpServer proxy;
+ private int proxyPort;
+ private final AtomicReference