Closed tiboun closed 2 years ago
The problem is that you are sending a request using HTTP and not HTTPS so proxy authentication doesn't kick in. When you send a request using HTTP the JDK client just re-writes the target socket and does nothing else. In effect the proxying is done client side and so there is no way for MockServer to authenticate that. As soon as you switch the protocol to HTTPS as shown below the authentication works as expected. Also the initial CONNECT request shows the expected response you get back from MockServer for a CONNECT request. As soon as the protocol is switched to HTTPS that the Java JDK sends the CONNECT request and gets the expected authentication error i.e. 407.
@Test
public void shouldNotConnectToSecurePortRequiringAuthenticationWithHttpURLConnection() throws Exception {
int mockServerPort = new MockServer().getLocalPort();
String existingUsername = ConfigurationProperties.proxyAuthenticationUsername();
String existingPassword = ConfigurationProperties.proxyAuthenticationPassword();
ClientAndServer mockServer = ClientAndServer.startClientAndServer();
try {
String username = UUIDService.getUUID();
String password = UUIDService.getUUID();
ConfigurationProperties.proxyAuthenticationUsername(username);
ConfigurationProperties.proxyAuthenticationPassword(password);
try (Socket socket = new Socket("127.0.0.1", mockServerPort)) {
// given
OutputStream output = socket.getOutputStream();
// when
output.write(("" +
"CONNECT 127.0.0.1:443 HTTP/1.1\r\n" +
"Host: 127.0.0.1:" + mockServer.getPort() + "\r\n" +
"\r\n"
).getBytes(UTF_8));
output.flush();
// then
System.out.println(IOStreamUtils.readInputStreamToString(socket));
mockServer.when(
request().withPath("/subjects")
).respond(
response().withHeaders(
new Header(CONTENT_TYPE.toString(), MediaType.APPLICATION_JSON.toString())
).withBody(
"[\"abc\"]"
)
);
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
System.setProperty("jdk.http.auth.proxying.disabledSchemes", "");
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
System.out.println(getRequestorType().toString());
if (getRequestorType() == RequestorType.PROXY) {
System.out.println("return password authentication");
String randomPassword = UUIDService.getUUID();
return new PasswordAuthentication(username, randomPassword.toCharArray());
}
return null;
}
});
URL url = new URL("https://localhost:" + mockServer.getPort() + "/subjects");
HttpURLConnection con = (HttpURLConnection) url.openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", mockServerPort)));
System.out.println(con.getResponseCode());
}
} finally {
ConfigurationProperties.proxyAuthenticationUsername(existingUsername);
ConfigurationProperties.proxyAuthenticationPassword(existingPassword);
}
}
The only change I made was to update the protocol as follows, changing:
new URL("http://localhost:" + mockServer.getPort() + "/subjects");
to:
new URL("https://localhost:" + mockServer.getPort() + "/subjects");
Hi jamesdbloom,
Thanks for you answer. Do you mean that proxy authentication is only available for https or did I misunderstood ?
As far as I know, we can require authentication on proxy wether it's http or https.
Yes MockServer only supports authentication for HTTPS or SOCKS, the main issue being how would MockServer know that a request was being proxied if it is HTTP only because that request could equally be directed at MockServer as a target server not just a proxy.
I am however considering adding authentication in general to MockServer, it also might be a good idea to provide a configuration setting to make MockServer assume first it is a proxy by proxying any request that doesn't match an expectation (instead of returning a 404) in that case the proxy authentication could be enabled.
I'm going to re-open this ticket to add that configuration property which would mean when enabled it was possible to authenticate HTTP proxied requests.
I have released it is possible to detect accurately when MockServer is proxying an HTTP request so I have added support for authentication which will be shortly pushed to close this ticket.
Thank you very much jamesdbloom ! You're awesome !
0
this code snippet worked for me .. thank you for the help
import java.net.*
System.setProperty("http.proxyUser", "userid"); System.setProperty("http.proxyPassword", "mmmmm"); System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); val url = URL(uploadUrl) val proxyInet = InetSocketAddress(proxySettings.url, Utility.getPort()) val proxy = Proxy(Proxy.Type.HTTP, proxyInet) var uname_pwd = "userid"+":"+"mmmmm" val authString:String = "Basic " +Base64.getEncoder().encodeToString(uname_pwd.toByteArray()) val authenticator = object : Authenticator() { override fun getPasswordAuthentication(): PasswordAuthentication { return PasswordAuthentication("userid", "mmmmmmm".toCharArray()) } } Authenticator.setDefault(authenticator) val connection = url.openConnection(proxy) as HttpsURLConnection
Describe the issue Setting up a proxy with required authentication seems to be ignored when using HttpURLConnection. I should probably missing something.
What you are trying to do Trying to test corporate proxy with authentication requirement in order to have a good integration test.
MockServer version 5.11.1
To Reproduce
Expected behaviour I expect the request to use the Authenticator defined.