Skip to content

Commit 577615a

Browse files
author
Stephane Landelle
committed
ProxyServer should have its own ntlmHost and scheme, close AsyncHttpClient#797
1 parent 71536e5 commit 577615a

File tree

10 files changed

+162
-121
lines changed

10 files changed

+162
-121
lines changed

api/src/main/java/org/asynchttpclient/ProxyServer.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
*/
1717
package org.asynchttpclient;
1818

19-
import static java.nio.charset.StandardCharsets.*;
19+
import static java.nio.charset.StandardCharsets.UTF_8;
2020

2121
import java.nio.charset.Charset;
2222
import java.util.ArrayList;
2323
import java.util.Collections;
2424
import java.util.List;
2525

26+
import org.asynchttpclient.Realm.AuthScheme;
27+
2628
/**
2729
* Represents a proxy server.
2830
*/
@@ -56,6 +58,8 @@ public String toString() {
5658
private final String url;
5759
private Charset charset = UTF_8;
5860
private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", "");
61+
private String ntlmHost;
62+
private AuthScheme scheme = AuthScheme.BASIC;
5963

6064
public ProxyServer(final Protocol protocol, final String host, final int port, String principal, String password) {
6165
this.protocol = protocol;
@@ -78,6 +82,15 @@ public ProxyServer(final String host, final int port) {
7882
this(Protocol.HTTP, host, port, null, null);
7983
}
8084

85+
public Realm.RealmBuilder realmBuilder() {
86+
return new Realm.RealmBuilder()//
87+
.setNtlmDomain(ntlmDomain)
88+
.setNtlmHost(ntlmHost)
89+
.setPrincipal(principal)
90+
.setPassword(password)
91+
.setScheme(scheme);
92+
}
93+
8194
public Protocol getProtocol() {
8295
return protocol;
8396
}
@@ -134,6 +147,22 @@ public String getNtlmDomain() {
134147
return ntlmDomain;
135148
}
136149

150+
public AuthScheme getScheme() {
151+
return scheme;
152+
}
153+
154+
public void setScheme(AuthScheme scheme) {
155+
this.scheme = scheme;
156+
}
157+
158+
public String getNtlmHost() {
159+
return ntlmHost;
160+
}
161+
162+
public void setNtlmHost(String ntlmHost) {
163+
this.ntlmHost = ntlmHost;
164+
}
165+
137166
@Override
138167
public String toString() {
139168
return url;

api/src/main/java/org/asynchttpclient/Realm.java

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class Realm {
5050
private final String methodName;
5151
private final boolean usePreemptiveAuth;
5252
private final Charset charset;
53-
private final String host;
53+
private final String ntlmHost;
5454
private final String ntlmDomain;
5555
private final boolean useAbsoluteURI;
5656
private final boolean omitQuery;
@@ -79,7 +79,7 @@ private Realm(AuthScheme scheme, String principal, String password, String realm
7979
this.methodName = method;
8080
this.usePreemptiveAuth = usePreemptiveAuth;
8181
this.ntlmDomain = ntlmDomain;
82-
this.host = host;
82+
this.ntlmHost = host;
8383
this.charset = charset;
8484
this.useAbsoluteURI = useAbsoluteURI;
8585
this.omitQuery = omitQuery;
@@ -94,10 +94,6 @@ public String getPassword() {
9494
return password;
9595
}
9696

97-
public AuthScheme getAuthScheme() {
98-
return scheme;
99-
}
100-
10197
public AuthScheme getScheme() {
10298

10399
return scheme;
@@ -171,7 +167,7 @@ public String getNtlmDomain() {
171167
* @return the NTLM host
172168
*/
173169
public String getNtlmHost() {
174-
return host;
170+
return ntlmHost;
175171
}
176172

177173
public boolean isUseAbsoluteURI() {
@@ -271,7 +267,7 @@ public static class RealmBuilder {
271267
private boolean usePreemptive;
272268
private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", "");
273269
private Charset charset = UTF_8;
274-
private String host = "localhost";
270+
private String ntlmHost = "localhost";
275271
private boolean useAbsoluteURI = true;
276272
private boolean omitQuery;
277273
private boolean targetProxy;
@@ -297,11 +293,11 @@ public RealmBuilder setNtlmDomain(String ntlmDomain) {
297293
}
298294

299295
public String getNtlmHost() {
300-
return host;
296+
return ntlmHost;
301297
}
302298

303299
public RealmBuilder setNtlmHost(String host) {
304-
this.host = host;
300+
this.ntlmHost = host;
305301
return this;
306302
}
307303

@@ -624,7 +620,7 @@ public Realm build() {
624620
}
625621

626622
return new Realm(scheme, principal, password, realmName, nonce, algorithm, response, qop, nc, cnonce, uri, methodName,
627-
usePreemptive, ntlmDomain, charset, host, opaque, useAbsoluteURI, omitQuery, targetProxy);
623+
usePreemptive, ntlmDomain, charset, ntlmHost, opaque, useAbsoluteURI, omitQuery, targetProxy);
628624
}
629625
}
630626
}

api/src/test/java/org/asynchttpclient/RealmTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void testClone() {
4040
assertEquals(clone.getUsePreemptiveAuth(), orig.getUsePreemptiveAuth());
4141
assertEquals(clone.getRealmName(), orig.getRealmName());
4242
assertEquals(clone.getAlgorithm(), orig.getAlgorithm());
43-
assertEquals(clone.getAuthScheme(), orig.getAuthScheme());
43+
assertEquals(clone.getScheme(), orig.getScheme());
4444
}
4545

4646
@Test(groups = "fast")

providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/AsyncHttpClientFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ private void addAuthorizationHeader(final Request request, final HttpRequestPack
451451

452452
private String generateAuthHeader(final Realm realm) {
453453
try {
454-
switch (realm.getAuthScheme()) {
454+
switch (realm.getScheme()) {
455455
case BASIC:
456456
return computeBasicAuthentication(realm);
457457
case DIGEST:

providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/filters/ProxyFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private Realm getRealm(final Request request) {
9696

9797
private String generateAuthHeader(final Realm realm) {
9898
try {
99-
switch (realm.getAuthScheme()) {
99+
switch (realm.getScheme()) {
100100
case BASIC:
101101
return computeBasicAuthentication(realm);
102102
case DIGEST:

providers/grizzly/src/main/java/org/asynchttpclient/providers/grizzly/statushandler/AuthorizationHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpT
6666
responsePacket.setSkipRemainder(true); // ignore the remainder of the response
6767

6868
final Request req = httpTransactionContext.getRequest();
69-
realm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(req.getUri())
69+
realm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getScheme()).setUri(req.getUri())
7070
.setMethodName(req.getMethod()).setUsePreemptiveAuth(true).parseWWWAuthenticateHeader(auth).build();
7171
String lowerCaseAuth = auth.toLowerCase(Locale.ENGLISH);
7272
if (lowerCaseAuth.startsWith("basic")) {

providers/netty3/src/main/java/org/asynchttpclient/providers/netty3/handler/HttpProtocol.java

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.asynchttpclient.FluentCaseInsensitiveStringsMap;
3131
import org.asynchttpclient.ProxyServer;
3232
import org.asynchttpclient.Realm;
33+
import org.asynchttpclient.Realm.AuthScheme;
3334
import org.asynchttpclient.Request;
3435
import org.asynchttpclient.RequestBuilder;
3536
import org.asynchttpclient.ntlm.NTLMEngine;
@@ -63,28 +64,51 @@ public HttpProtocol(ChannelManager channelManager, AsyncHttpClientConfig config,
6364
connectionStrategy = nettyConfig.getConnectionStrategy();
6465
}
6566

66-
private Realm.RealmBuilder newRealmBuilder(Realm realm) {
67-
return realm != null ? new Realm.RealmBuilder().clone(realm) : new Realm.RealmBuilder();
67+
private Realm kerberosChallenge(Channel channel,//
68+
List<String> authHeaders,//
69+
Request request,//
70+
FluentCaseInsensitiveStringsMap headers,//
71+
Realm realm,//
72+
NettyResponseFuture<?> future) throws NTLMEngineException {
73+
74+
Uri uri = request.getUri();
75+
String host = request.getVirtualHost() == null ? uri.getHost() : request.getVirtualHost();
76+
try {
77+
String challengeHeader = SpnegoEngine.instance().generateToken(host);
78+
headers.remove(HttpHeaders.Names.AUTHORIZATION);
79+
headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader);
80+
81+
return new Realm.RealmBuilder().clone(realm)//
82+
.setUri(uri)//
83+
.setMethodName(request.getMethod())//
84+
.setScheme(Realm.AuthScheme.KERBEROS)//
85+
.build();
86+
87+
88+
} catch (Throwable throwable) {
89+
String ntlmAuthenticate = getNTLM(authHeaders);
90+
if (ntlmAuthenticate != null) {
91+
return ntlmChallenge(ntlmAuthenticate, request, headers, realm, future);
92+
}
93+
requestSender.abort(channel, future, throwable);
94+
return null;
95+
}
6896
}
6997

70-
private Realm kerberosChallenge(Channel channel,//
98+
private Realm kerberosProxyChallenge(Channel channel,//
7199
List<String> proxyAuth,//
72100
Request request,//
73101
ProxyServer proxyServer,//
74102
FluentCaseInsensitiveStringsMap headers,//
75-
Realm realm,//
76-
NettyResponseFuture<?> future,//
77-
boolean proxyInd) throws NTLMEngineException {
103+
NettyResponseFuture<?> future) throws NTLMEngineException {
78104

79105
Uri uri = request.getUri();
80-
String host = request.getVirtualHost() == null ? uri.getHost() : request.getVirtualHost();
81-
String server = proxyServer == null ? host : proxyServer.getHost();
82106
try {
83-
String challengeHeader = SpnegoEngine.instance().generateToken(server);
107+
String challengeHeader = SpnegoEngine.instance().generateToken(proxyServer.getHost());
84108
headers.remove(HttpHeaders.Names.AUTHORIZATION);
85109
headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader);
86110

87-
return newRealmBuilder(realm)//
111+
return proxyServer.realmBuilder()//
88112
.setUri(uri)//
89113
.setMethodName(request.getMethod())//
90114
.setScheme(Realm.AuthScheme.KERBEROS)//
@@ -93,13 +117,13 @@ private Realm kerberosChallenge(Channel channel,//
93117
} catch (Throwable throwable) {
94118
String ntlmAuthenticate = getNTLM(proxyAuth);
95119
if (ntlmAuthenticate != null) {
96-
return ntlmChallenge(ntlmAuthenticate, request, proxyServer, headers, realm, future, proxyInd);
120+
return ntlmProxyChallenge(ntlmAuthenticate, request, proxyServer, headers, future);
97121
}
98122
requestSender.abort(channel, future, throwable);
99123
return null;
100124
}
101125
}
102-
126+
103127
private String authorizationHeaderName(boolean proxyInd) {
104128
return proxyInd ? HttpHeaders.Names.PROXY_AUTHORIZATION : HttpHeaders.Names.AUTHORIZATION;
105129
}
@@ -110,71 +134,55 @@ private void addNTLMAuthorizationHeader(FluentCaseInsensitiveStringsMap headers,
110134

111135
private Realm ntlmChallenge(String authenticateHeader,//
112136
Request request,//
113-
ProxyServer proxyServer,//
114137
FluentCaseInsensitiveStringsMap headers,//
115138
Realm realm,//
116-
NettyResponseFuture<?> future,//
117-
boolean proxyInd) throws NTLMEngineException {
118-
119-
boolean useRealm = proxyServer == null && realm != null;
139+
NettyResponseFuture<?> future) throws NTLMEngineException {
120140

121-
String ntlmDomain = useRealm ? realm.getNtlmDomain() : proxyServer.getNtlmDomain();
122-
String ntlmHost = useRealm ? realm.getNtlmHost() : proxyServer.getHost();
123-
String principal = useRealm ? realm.getPrincipal() : proxyServer.getPrincipal();
124-
String password = useRealm ? realm.getPassword() : proxyServer.getPassword();
125141
Uri uri = request.getUri();
126142

127143
if (authenticateHeader.equals("NTLM")) {
128144
// server replied bare NTLM => we didn't preemptively sent Type1Msg
129145
String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg();
130146

131-
addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd);
147+
addNTLMAuthorizationHeader(headers, challengeHeader, false);
132148
future.getAndSetAuth(false);
133-
return newRealmBuilder(realm)//
134-
.setScheme(realm.getAuthScheme())//
135-
.setUri(uri)//
136-
.setMethodName(request.getMethod())//
137-
.build();
138149

139150
} else {
140151
// probably receiving Type2Msg, so we issue Type3Msg
141-
addType3NTLMAuthorizationHeader(authenticateHeader, headers, principal, password, ntlmDomain, ntlmHost, proxyInd);
142-
Realm.AuthScheme authScheme = realm != null ? realm.getAuthScheme() : Realm.AuthScheme.NTLM;
143-
return newRealmBuilder(realm)//
144-
.setScheme(authScheme)//
145-
.setUri(uri)//
146-
.setMethodName(request.getMethod())//
147-
.build();
152+
addType3NTLMAuthorizationHeader(authenticateHeader, headers, realm, false);
148153
}
154+
155+
return new Realm.RealmBuilder().clone(realm)//
156+
.setUri(uri)//
157+
.setMethodName(request.getMethod())//
158+
.build();
149159
}
150160

151161
private Realm ntlmProxyChallenge(String authenticateHeader,//
152162
Request request,//
153163
ProxyServer proxyServer,//
154164
FluentCaseInsensitiveStringsMap headers,//
155-
Realm realm,//
156-
NettyResponseFuture<?> future,//
157-
boolean proxyInd) throws NTLMEngineException {
165+
NettyResponseFuture<?> future) throws NTLMEngineException {
158166

159167
future.getAndSetAuth(false);
160168
headers.remove(HttpHeaders.Names.PROXY_AUTHORIZATION);
161169

162-
addType3NTLMAuthorizationHeader(authenticateHeader, headers, proxyServer.getPrincipal(), proxyServer.getPassword(),
163-
proxyServer.getNtlmDomain(), proxyServer.getHost(), proxyInd);
164-
165-
return newRealmBuilder(realm)//
166-
// .setScheme(realm.getAuthScheme())
170+
Realm realm = proxyServer.realmBuilder()//
171+
.setScheme(AuthScheme.NTLM)//
167172
.setUri(request.getUri())//
168173
.setMethodName(request.getMethod()).build();
174+
175+
addType3NTLMAuthorizationHeader(authenticateHeader, headers, realm, true);
176+
177+
return realm;
169178
}
170179

171-
private void addType3NTLMAuthorizationHeader(String auth, FluentCaseInsensitiveStringsMap headers, String username,
172-
String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException {
180+
private void addType3NTLMAuthorizationHeader(String auth, FluentCaseInsensitiveStringsMap headers, Realm realm, boolean proxyInd) throws NTLMEngineException {
173181
headers.remove(authorizationHeaderName(proxyInd));
174182

175183
if (isNonEmpty(auth) && auth.startsWith("NTLM ")) {
176184
String serverChallenge = auth.substring("NTLM ".length()).trim();
177-
String challengeHeader = NTLMEngine.INSTANCE.generateType3Msg(username, password, domain, workstation, serverChallenge);
185+
String challengeHeader = NTLMEngine.INSTANCE.generateType3Msg(realm.getPrincipal(), realm.getPassword(), realm.getNtlmDomain(), realm.getNtlmHost(), serverChallenge);
178186
addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd);
179187
}
180188
}
@@ -233,18 +241,17 @@ private boolean exitAfterHandling401(//
233241
String ntlmAuthenticate = getNTLM(wwwAuthHeaders);
234242
if (!wwwAuthHeaders.contains("Kerberos") && ntlmAuthenticate != null) {
235243
// NTLM
236-
newRealm = ntlmChallenge(ntlmAuthenticate, request, proxyServer, request.getHeaders(), realm, future, false);
244+
newRealm = ntlmChallenge(ntlmAuthenticate, request, request.getHeaders(), realm, future);
237245

238246
} else if (negociate) {
239247
// SPNEGO KERBEROS
240-
newRealm = kerberosChallenge(channel, wwwAuthHeaders, request, proxyServer, request.getHeaders(), realm, future, false);
248+
newRealm = kerberosChallenge(channel, wwwAuthHeaders, request, request.getHeaders(), realm, future);
241249
if (newRealm == null)
242250
return true;
243251

244252
} else {
245253
newRealm = new Realm.RealmBuilder()//
246254
.clone(realm)//
247-
.setScheme(realm.getAuthScheme())//
248255
.setUri(request.getUri())//
249256
.setMethodName(request.getMethod())//
250257
.setUsePreemptiveAuth(true)//
@@ -304,17 +311,16 @@ private boolean exitAfterHandling407(//
304311
boolean negociate = proxyAuthHeaders.contains("Negotiate");
305312
String ntlmAuthenticate = getNTLM(proxyAuthHeaders);
306313
if (!proxyAuthHeaders.contains("Kerberos") && ntlmAuthenticate != null) {
307-
newRealm = ntlmProxyChallenge(ntlmAuthenticate, request, proxyServer, requestHeaders, realm, future, true);
314+
newRealm = ntlmProxyChallenge(ntlmAuthenticate, request, proxyServer, requestHeaders, future);
308315
// SPNEGO KERBEROS
309316

310317
} else if (negociate) {
311-
newRealm = kerberosChallenge(channel, proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true);
318+
newRealm = kerberosProxyChallenge(channel, proxyAuthHeaders, request, proxyServer, requestHeaders, future);
312319
if (newRealm == null)
313320
return true;
314321

315322
} else {
316323
newRealm = new Realm.RealmBuilder().clone(realm)//
317-
.setScheme(realm.getAuthScheme())//
318324
.setUri(request.getUri())//
319325
.setOmitQuery(true)//
320326
.setMethodName(HttpMethod.CONNECT.getName())//

0 commit comments

Comments
 (0)