Skip to content

Commit 8df9615

Browse files
author
Stephane Landelle
committed
NTLM preemptive auth should only happen when sending the first request on a new connection, close AsyncHttpClient#726
1 parent 7cd6d94 commit 8df9615

File tree

2 files changed

+70
-34
lines changed

2 files changed

+70
-34
lines changed

src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -92,20 +92,11 @@ private String hostHeader(Request request, Uri uri) {
9292
return request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort();
9393
}
9494

95-
private String authorizationHeader(Request request, Uri uri, ProxyServer proxyServer, Realm realm) throws IOException {
96-
95+
public String firstRequestOnlyAuthorizationHeader(Request request, Uri uri, ProxyServer proxyServer, Realm realm) throws IOException {
9796
String authorizationHeader = null;
9897

9998
if (realm != null && realm.getUsePreemptiveAuth()) {
100-
10199
switch (realm.getAuthScheme()) {
102-
case BASIC:
103-
authorizationHeader = computeBasicAuthentication(realm);
104-
break;
105-
case DIGEST:
106-
if (isNonEmpty(realm.getNonce()))
107-
authorizationHeader = computeDigestAuthentication(realm);
108-
break;
109100
case NTLM:
110101
String domain;
111102
if (proxyServer != null && proxyServer.getNtlmDomain() != null) {
@@ -122,7 +113,6 @@ private String authorizationHeader(Request request, Uri uri, ProxyServer proxySe
122113
break;
123114
case KERBEROS:
124115
case SPNEGO:
125-
126116
String host;
127117
if (proxyServer != null)
128118
host = proxyServer.getHost();
@@ -137,6 +127,32 @@ else if (request.getVirtualHost() != null)
137127
throw new IOException(e);
138128
}
139129
break;
130+
default:
131+
break;
132+
}
133+
}
134+
135+
return authorizationHeader;
136+
}
137+
138+
private String systematicAuthorizationHeader(Request request, Uri uri, ProxyServer proxyServer, Realm realm) {
139+
140+
String authorizationHeader = null;
141+
142+
if (realm != null && realm.getUsePreemptiveAuth()) {
143+
144+
switch (realm.getAuthScheme()) {
145+
case BASIC:
146+
authorizationHeader = computeBasicAuthentication(realm);
147+
break;
148+
case DIGEST:
149+
if (isNonEmpty(realm.getNonce()))
150+
authorizationHeader = computeDigestAuthentication(realm);
151+
break;
152+
case NTLM:
153+
case KERBEROS:
154+
case SPNEGO:
155+
// NTLM, KERBEROS and SPNEGO are only set on the first request, see firstRequestOnlyAuthorizationHeader
140156
case NONE:
141157
break;
142158
default:
@@ -147,8 +163,7 @@ else if (request.getVirtualHost() != null)
147163
return authorizationHeader;
148164
}
149165

150-
private String proxyAuthorizationHeader(Request request, ProxyServer proxyServer, HttpMethod method) throws IOException {
151-
166+
public String firstRequestOnlyProxyAuthorizationHeader(Request request, ProxyServer proxyServer, HttpMethod method) throws IOException {
152167
String proxyAuthorization = null;
153168

154169
if (method == HttpMethod.CONNECT) {
@@ -157,26 +172,31 @@ private String proxyAuthorizationHeader(Request request, ProxyServer proxyServer
157172
proxyAuthorization = auth.get(0);
158173
}
159174

160-
} else if (proxyServer != null && proxyServer.getPrincipal() != null) {
161-
if (isNonEmpty(proxyServer.getNtlmDomain())) {
162-
List<String> auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION);
163-
if (!isNTLM(auth)) {
164-
try {
165-
String msg = NTLMEngine.INSTANCE.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost());
166-
proxyAuthorization = "NTLM " + msg;
167-
} catch (NTLMEngineException e) {
168-
IOException ie = new IOException();
169-
ie.initCause(e);
170-
throw ie;
171-
}
175+
} else if (proxyServer != null && proxyServer.getPrincipal() != null && isNonEmpty(proxyServer.getNtlmDomain())) {
176+
List<String> auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION);
177+
if (!isNTLM(auth)) {
178+
try {
179+
String msg = NTLMEngine.INSTANCE.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost());
180+
proxyAuthorization = "NTLM " + msg;
181+
} catch (NTLMEngineException e) {
182+
throw new IOException(e);
172183
}
173-
} else {
174-
proxyAuthorization = computeBasicAuthentication(proxyServer);
175184
}
176185
}
177186

178187
return proxyAuthorization;
179188
}
189+
190+
private String systematicProxyAuthorizationHeader(Request request, ProxyServer proxyServer, HttpMethod method) {
191+
192+
String proxyAuthorization = null;
193+
194+
if (method != HttpMethod.CONNECT && proxyServer != null && proxyServer.getPrincipal() != null && !isNonEmpty(proxyServer.getNtlmDomain())) {
195+
proxyAuthorization = computeBasicAuthentication(proxyServer);
196+
}
197+
198+
return proxyAuthorization;
199+
}
180200

181201
private byte[] computeBodyFromParams(List<Param> params, Charset bodyCharset) {
182202

@@ -235,6 +255,17 @@ else if (request.getBodyGenerator() != null)
235255
return nettyBody;
236256
}
237257

258+
public void addAuthorizationHeader(HttpHeaders headers, String authorizationHeader) {
259+
if (authorizationHeader != null)
260+
// don't override authorization but append
261+
headers.add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader);
262+
}
263+
264+
public void setProxyAuthorizationHeader(HttpHeaders headers, String proxyAuthorizationHeader) {
265+
if (proxyAuthorizationHeader != null)
266+
headers.set(HttpHeaders.Names.PROXY_AUTHORIZATION, proxyAuthorizationHeader);
267+
}
268+
238269
public NettyRequest newNettyRequest(Request request, Uri uri, boolean forceConnect, ProxyServer proxyServer)
239270
throws IOException {
240271

@@ -301,14 +332,11 @@ public NettyRequest newNettyRequest(Request request, Uri uri, boolean forceConne
301332
headers.set(HttpHeaders.Names.HOST, hostHeader(request, uri));
302333

303334
Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm();
304-
String authorizationHeader = authorizationHeader(request, uri, proxyServer, realm);
305-
if (authorizationHeader != null)
306-
// don't override authorization but append
307-
headers.add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader);
308335

309-
String proxyAuthorizationHeader = proxyAuthorizationHeader(request, proxyServer, method);
310-
if (proxyAuthorizationHeader != null)
311-
headers.set(HttpHeaders.Names.PROXY_AUTHORIZATION, proxyAuthorizationHeader);
336+
// don't override authorization but append
337+
addAuthorizationHeader(headers, systematicAuthorizationHeader(request, uri, proxyServer, realm));
338+
339+
setProxyAuthorizationHeader(headers, systematicProxyAuthorizationHeader(request, proxyServer, method));
312340

313341
// Add default accept headers
314342
if (!headers.contains(HttpHeaders.Names.ACCEPT))

src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.ning.http.client.FluentCaseInsensitiveStringsMap;
4040
import com.ning.http.client.ListenableFuture;
4141
import com.ning.http.client.ProxyServer;
42+
import com.ning.http.client.Realm;
4243
import com.ning.http.client.Request;
4344
import com.ning.http.client.filter.FilterContext;
4445
import com.ning.http.client.filter.FilterException;
@@ -243,6 +244,13 @@ private <T> ListenableFuture<T> sendRequestWithNewChannel(//
243244

244245
boolean useSSl = isSecure(uri) && !useProxy;
245246

247+
// some headers are only set when performing the first request
248+
HttpHeaders headers = future.getNettyRequest().getHttpRequest().headers();
249+
Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm();
250+
HttpMethod method = future.getNettyRequest().getHttpRequest().getMethod();
251+
requestFactory.addAuthorizationHeader(headers, requestFactory.firstRequestOnlyAuthorizationHeader(request, uri, proxy, realm));
252+
requestFactory.setProxyAuthorizationHeader(headers, requestFactory.firstRequestOnlyProxyAuthorizationHeader(request, proxy, method));
253+
246254
// Do not throw an exception when we need an extra connection for a
247255
// redirect
248256
// FIXME why? This violate the max connection per host handling, right?

0 commit comments

Comments
 (0)