Skip to content

Commit

Permalink
Make ProxyServer use a Realm, close #999
Browse files Browse the repository at this point in the history
  • Loading branch information
slandelle committed Oct 12, 2015
1 parent 696c372 commit d82c46c
Show file tree
Hide file tree
Showing 12 changed files with 125 additions and 145 deletions.
2 changes: 1 addition & 1 deletion client/src/main/java/org/asynchttpclient/Realm.java
Expand Up @@ -277,7 +277,7 @@ public static class RealmBuilder {
private Uri uri; private Uri uri;
private String methodName = "GET"; private String methodName = "GET";
private boolean usePreemptive; private boolean usePreemptive;
private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); private String ntlmDomain = System.getProperty("http.auth.ntlm.domain");
private Charset charset = UTF_8; private Charset charset = UTF_8;
private String ntlmHost = "localhost"; private String ntlmHost = "localhost";
private boolean useAbsoluteURI = false; private boolean useAbsoluteURI = false;
Expand Down
Expand Up @@ -33,7 +33,6 @@
import org.asynchttpclient.AsyncHandler.State; import org.asynchttpclient.AsyncHandler.State;
import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpClientConfig;
import org.asynchttpclient.Realm; import org.asynchttpclient.Realm;
import org.asynchttpclient.Realm.AuthScheme;
import org.asynchttpclient.Request; import org.asynchttpclient.Request;
import org.asynchttpclient.RequestBuilder; import org.asynchttpclient.RequestBuilder;
import org.asynchttpclient.channel.pool.ConnectionStrategy; import org.asynchttpclient.channel.pool.ConnectionStrategy;
Expand Down Expand Up @@ -101,14 +100,9 @@ private Realm kerberosProxyChallenge(Channel channel,//


try { try {
String challengeHeader = SpnegoEngine.instance().generateToken(proxyServer.getHost()); String challengeHeader = SpnegoEngine.instance().generateToken(proxyServer.getHost());
headers.remove(HttpHeaders.Names.AUTHORIZATION); headers.set(HttpHeaders.Names.PROXY_AUTHORIZATION, "Negotiate " + challengeHeader);
headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader);


return proxyServer.realmBuilder()// return proxyServer.getRealm();
.setUri(request.getUri())//
.setMethodName(request.getMethod())//
.setScheme(Realm.AuthScheme.KERBEROS)//
.build();


} catch (SpnegoEngineException throwable) { } catch (SpnegoEngineException throwable) {
String ntlmAuthenticate = getNTLM(proxyAuth); String ntlmAuthenticate = getNTLM(proxyAuth);
Expand Down Expand Up @@ -161,10 +155,7 @@ private Realm ntlmProxyChallenge(String authenticateHeader,//
headers.remove(HttpHeaders.Names.PROXY_AUTHORIZATION); headers.remove(HttpHeaders.Names.PROXY_AUTHORIZATION);


// FIXME we should probably check that the scheme is NTLM // FIXME we should probably check that the scheme is NTLM
Realm realm = proxyServer.realmBuilder()// Realm realm = proxyServer.getRealm();
.setScheme(AuthScheme.NTLM)//
.setUri(request.getUri())//
.setMethodName(request.getMethod()).build();


addType3NTLMAuthorizationHeader(authenticateHeader, headers, realm, true); addType3NTLMAuthorizationHeader(authenticateHeader, headers, realm, true);


Expand Down Expand Up @@ -313,7 +304,7 @@ private boolean exitAfterHandling407(//


} else { } else {
// BASIC or DIGEST // BASIC or DIGEST
newRealm = proxyServer.realmBuilder() newRealm = new Realm.RealmBuilder().clone(proxyServer.getRealm())
.setUri(request.getUri())// .setUri(request.getUri())//
.setOmitQuery(true)// .setOmitQuery(true)//
.setMethodName(request.getMethod())// .setMethodName(request.getMethod())//
Expand Down
155 changes: 66 additions & 89 deletions client/src/main/java/org/asynchttpclient/proxy/ProxyServer.java
Expand Up @@ -16,61 +16,35 @@
*/ */
package org.asynchttpclient.proxy; package org.asynchttpclient.proxy;


import static java.nio.charset.StandardCharsets.UTF_8;

import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;


import org.asynchttpclient.Realm; import org.asynchttpclient.Realm;
import org.asynchttpclient.Realm.AuthScheme;


/** /**
* Represents a proxy server. * Represents a proxy server.
*/ */
public class ProxyServer { public class ProxyServer {


private final List<String> nonProxyHosts = new ArrayList<>(); public static Builder newProxyServer(String host, int port) {
return new Builder(host, port);
}

private final String host; private final String host;
private final String principal;
private final String password;
private final int port; private final int port;
private final int securedPort; private final int securedPort;
private Charset charset = UTF_8; private final Realm realm;
private String ntlmDomain = System.getProperty("http.auth.ntlm.domain"); private final List<String> nonProxyHosts;
private String ntlmHost; private final boolean forceHttp10;
private AuthScheme scheme;
private boolean forceHttp10 = false; public ProxyServer(String host, int port, int securedPort, Realm realm, List<String> nonProxyHosts, boolean forceHttp10) {

public ProxyServer(AuthScheme scheme, String host, int port, int securedPort, String principal, String password) {
this.scheme = scheme;
this.host = host; this.host = host;
this.port = port; this.port = port;
this.securedPort = securedPort; this.securedPort = securedPort;
this.principal = principal; this.realm = realm;
this.password = password; this.nonProxyHosts = nonProxyHosts;
} this.forceHttp10 = forceHttp10;

public ProxyServer(AuthScheme scheme, String host, int port, String principal, String password) {
this(scheme, host, port, port, principal, password);
}

public ProxyServer(String host, int port, String principal, String password) {
this(AuthScheme.BASIC, host, port, principal, password);
}

public ProxyServer(final String host, final int port) {
this(AuthScheme.NONE, host, port, null, null);
}

public Realm.RealmBuilder realmBuilder() {
return new Realm.RealmBuilder()//
.setNtlmDomain(ntlmDomain)
.setNtlmHost(ntlmHost)
.setPrincipal(principal)
.setPassword(password)
.setScheme(scheme);
} }


public String getHost() { public String getHost() {
Expand All @@ -85,63 +59,66 @@ public int getSecuredPort() {
return securedPort; return securedPort;
} }


public String getPrincipal() {
return principal;
}

public String getPassword() {
return password;
}

public ProxyServer setCharset(Charset charset) {
this.charset = charset;
return this;
}

public Charset getCharset() {
return charset;
}

public ProxyServer addNonProxyHost(String uri) {
nonProxyHosts.add(uri);
return this;
}

public ProxyServer removeNonProxyHost(String uri) {
nonProxyHosts.remove(uri);
return this;
}

public List<String> getNonProxyHosts() { public List<String> getNonProxyHosts() {
return Collections.unmodifiableList(nonProxyHosts); return nonProxyHosts;
} }


public ProxyServer setNtlmDomain(String ntlmDomain) {
this.ntlmDomain = ntlmDomain;
return this;
}

public AuthScheme getScheme() {
return scheme;
}

public void setScheme(AuthScheme scheme) {
if (principal == null)
throw new NullPointerException("principal");
if (password == null)
throw new NullPointerException("password");
this.scheme = scheme;
}

public void setNtlmHost(String ntlmHost) {
this.ntlmHost = ntlmHost;
}

public boolean isForceHttp10() { public boolean isForceHttp10() {
return forceHttp10; return forceHttp10;
} }


public void setForceHttp10(boolean forceHttp10) { public Realm getRealm() {
this.forceHttp10 = forceHttp10; return realm;
}

public static class Builder {

private String host;
private int port;
private int securedPort;
private Realm realm;
private List<String> nonProxyHosts;
private boolean forceHttp10;

public Builder(String host, int port) {
this.host = host;
this.port = port;
this.securedPort = port;
}

public Builder securedPort(int securedPort) {
this.securedPort = securedPort;
return this;
}

public Builder realm(Realm realm) {
this.realm = realm;
return this;
}

public Builder nonProxyHost(String nonProxyHost) {
if (nonProxyHosts == null)
nonProxyHosts = new ArrayList<String>(1);
nonProxyHosts.add(nonProxyHost);
return this;
}

public Builder nonProxyHosts(List<String> nonProxyHosts) {
this.nonProxyHosts = nonProxyHosts;
return this;
}

public Builder forceHttp10() {
this.forceHttp10 = true;
return this;
}

public ProxyServer build() {
List<String> nonProxyHosts = this.nonProxyHosts != null ? Collections.unmodifiableList(this.nonProxyHosts) : Collections.emptyList();
// FIXME!!!!!!!!!!!!!!!!!!!!!!!!
Realm realm = this.realm != null && !this.realm.isTargetProxy() ? new Realm.RealmBuilder().clone(this.realm).setTargetProxy(true).build() : this.realm;

return new ProxyServer(host, port, securedPort, realm, nonProxyHosts, forceHttp10);
}
} }
} }
Expand Up @@ -692,8 +692,13 @@ public SimpleAsyncHttpClient build() {
} }


if (proxyHost != null) { if (proxyHost != null) {
AuthScheme proxyAuthScheme = proxyPrincipal != null && this.proxyAuthScheme == AuthScheme.NONE ? AuthScheme.BASIC : this.proxyAuthScheme; Realm realm = null;
configBuilder.setProxyServer(new ProxyServer(proxyAuthScheme, proxyHost, proxyPort, proxyPrincipal, proxyPassword)); if (proxyPrincipal != null) {
AuthScheme proxyAuthScheme = this.proxyAuthScheme == AuthScheme.NONE ? AuthScheme.BASIC : this.proxyAuthScheme;
realm = new Realm.RealmBuilder().setScheme(proxyAuthScheme).setPrincipal(proxyPrincipal).setPassword(proxyPassword).build();
}

configBuilder.setProxyServer(ProxyServer.newProxyServer(proxyHost, proxyPort).realm(realm).build());
} }


configBuilder.addIOExceptionFilter(new ResumableIOExceptionFilter()); configBuilder.addIOExceptionFilter(new ResumableIOExceptionFilter());
Expand Down
Expand Up @@ -33,11 +33,11 @@ public final class AuthenticatorUtils {
private static final String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization"; private static final String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization";


public static String computeBasicAuthentication(Realm realm) { public static String computeBasicAuthentication(Realm realm) {
return computeBasicAuthentication(realm.getPrincipal(), realm.getPassword(), realm.getCharset()); return realm != null ? computeBasicAuthentication(realm.getPrincipal(), realm.getPassword(), realm.getCharset()) : null;
} }


public static String computeBasicAuthentication(ProxyServer proxyServer) { public static String computeBasicAuthentication(ProxyServer proxyServer) {
return computeBasicAuthentication(proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getCharset()); return computeBasicAuthentication(proxyServer.getRealm());
} }


private static String computeBasicAuthentication(String principal, String password, Charset charset) { private static String computeBasicAuthentication(String principal, String password, Charset charset) {
Expand Down Expand Up @@ -109,7 +109,7 @@ public static String perConnectionProxyAuthorizationHeader(Request request, Prox
proxyAuthorization = ntlmHeader; proxyAuthorization = ntlmHeader;
} }


} else if (proxyServer != null && proxyServer.getPrincipal() != null && proxyServer.getScheme().isLikeNtlm()) { } else if (proxyServer != null && proxyServer.getRealm() != null && proxyServer.getRealm().getScheme().isLikeNtlm()) {
List<String> auth = getProxyAuthorizationHeader(request); List<String> auth = getProxyAuthorizationHeader(request);
if (getNTLM(auth) == null) { if (getNTLM(auth) == null) {
String msg = NtlmEngine.INSTANCE.generateType1Msg(); String msg = NtlmEngine.INSTANCE.generateType1Msg();
Expand All @@ -124,7 +124,7 @@ public static String perRequestProxyAuthorizationHeader(Request request, ProxySe


String proxyAuthorization = null; String proxyAuthorization = null;


if (!connect && proxyServer != null && proxyServer.getScheme() == AuthScheme.BASIC) { if (!connect && proxyServer != null && proxyServer.getRealm() != null && proxyServer.getRealm().getScheme() == AuthScheme.BASIC) {
proxyAuthorization = computeBasicAuthentication(proxyServer); proxyAuthorization = computeBasicAuthentication(proxyServer);
} else if (realm != null && realm.getUsePreemptiveAuth() && realm.isTargetProxy()) { } else if (realm != null && realm.getUsePreemptiveAuth() && realm.isTargetProxy()) {


Expand Down
36 changes: 21 additions & 15 deletions client/src/main/java/org/asynchttpclient/util/ProxyUtils.java
Expand Up @@ -14,7 +14,18 @@


import static org.asynchttpclient.util.MiscUtils.isNonEmpty; import static org.asynchttpclient.util.MiscUtils.isNonEmpty;


import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.AsyncHttpClientConfig;
import org.asynchttpclient.Realm;
import org.asynchttpclient.Realm.AuthScheme; import org.asynchttpclient.Realm.AuthScheme;
import org.asynchttpclient.Request; import org.asynchttpclient.Request;
import org.asynchttpclient.proxy.ProxyServer; import org.asynchttpclient.proxy.ProxyServer;
Expand All @@ -23,14 +34,6 @@
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Properties;

/** /**
* Utilities for Proxy handling. * Utilities for Proxy handling.
* *
Expand Down Expand Up @@ -160,19 +163,22 @@ public static ProxyServerSelector createProxyServerSelector(Properties propertie
if (host != null) { if (host != null) {
int port = Integer.valueOf(properties.getProperty(PROXY_PORT, "80")); int port = Integer.valueOf(properties.getProperty(PROXY_PORT, "80"));


String user = properties.getProperty(PROXY_USER); String principal = properties.getProperty(PROXY_USER);
String password = properties.getProperty(PROXY_PASSWORD); String password = properties.getProperty(PROXY_PASSWORD);


ProxyServer proxyServer = new ProxyServer(user != null ? AuthScheme.BASIC : AuthScheme.NONE, host, port, user, password); Realm realm = null;
if (principal != null) {
realm = new Realm.RealmBuilder().setScheme(AuthScheme.BASIC).setPrincipal(principal).setPassword(password).build();
}

ProxyServer.Builder proxyServer = ProxyServer.newProxyServer(host, port).realm(realm);


String nonProxyHosts = properties.getProperty(PROXY_NONPROXYHOSTS); String nonProxyHosts = properties.getProperty(PROXY_NONPROXYHOSTS);
if (nonProxyHosts != null) { if (nonProxyHosts != null) {
for (String spec : nonProxyHosts.split("\\|")) { proxyServer.nonProxyHosts(new ArrayList<String>(Arrays.asList(nonProxyHosts.split("\\|"))));
proxyServer.addNonProxyHost(spec);
}
} }


return createProxyServerSelector(proxyServer); return createProxyServerSelector(proxyServer.build());
} }


return ProxyServerSelector.NO_PROXY_SELECTOR; return ProxyServerSelector.NO_PROXY_SELECTOR;
Expand Down Expand Up @@ -210,7 +216,7 @@ public ProxyServer select(Uri uri) {
return null; return null;
} else { } else {
InetSocketAddress address = (InetSocketAddress) proxy.address(); InetSocketAddress address = (InetSocketAddress) proxy.address();
return new ProxyServer(address.getHostName(), address.getPort()); return ProxyServer.newProxyServer(address.getHostName(), address.getPort()).build();
} }
case DIRECT: case DIRECT:
return null; return null;
Expand Down
Expand Up @@ -646,7 +646,7 @@ public Response onCompleted(Response response) throws Exception {


@Test(groups = { "standalone", "default_provider", "async" }) @Test(groups = { "standalone", "default_provider", "async" })
public void asyncDoPostProxyTest() throws Exception { public void asyncDoPostProxyTest() throws Exception {
try (AsyncHttpClient client = new DefaultAsyncHttpClient(new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer("127.0.0.1", port2)).build())) { try (AsyncHttpClient client = new DefaultAsyncHttpClient(new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer.Builder("127.0.0.1", port2).build()).build())) {
HttpHeaders h = new DefaultHttpHeaders(); HttpHeaders h = new DefaultHttpHeaders();
h.add(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); h.add(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
Expand Down

0 comments on commit d82c46c

Please sign in to comment.