[
https://issues.apache.org/jira/browse/HTTPCLIENT-2170?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17400633#comment-17400633
]
Erick commented on HTTPCLIENT-2170:
------------------------------------
[~olegk]
I have simplified the repro code to one file using http-client 5.0.4.
We are still working on getting a public NTLM endpoint,
meanwhile if you have an NTLM service you can just replace the requestUris with
one single endpoint and repeat the request several times.
{code:java}
public class JavaHttpClientWrapper {
public final CloseableHttpClient httpClient;
public static void main(String[] args) {
String username = "user";
String password = "password";
final String[] requestUris = new String[] {
"https://localhost/server/rest/services/CERT_Secured_Basemap/MapServer/tile/0/0/0",
"https://localhost/server/rest/services/CERT_Secured_Basemap/MapServer/tile/63/0/0",
"https://localhost/server/rest/services/CERT_Secured_Basemap/MapServer/tile/16/26166/11433",
"https://localhost/server/rest/services/CERT_Secured_Basemap/MapServer/tile/15/13083/5716",
"https://localhost/server/rest/services/CERT_Secured_Basemap/MapServer/tile/1/0/0",
"https://localhost/server/rest/services/CERT_Secured_Basemap/MapServer/tile/16/26166/11432",
"https://localhost/server/rest/services/CERT_Secured_Basemap/MapServer/tile/14/6541/2858",
"https://localhost/server/rest/services/CERT_Secured_Basemap/MapServer/tile/15/13082/5716"
};
try {
JavaHttpClientWrapper httpClientWrapper = new JavaHttpClientWrapper();
for(String uri : requestUris) {
new Thread(() -> {
httpClientWrapper.makeRequest(uri, username, password);
}).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public JavaHttpClientWrapper() throws Exception {
X509TrustManager trustManager = new X509TrustManager() {
@Override public void checkClientTrusted(X509Certificate[]
x509Certificates, String s)
throws CertificateException {}
@Override public void checkServerTrusted(X509Certificate[]
x509Certificates, String s)
throws CertificateException {}
@Override public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
TrustManager[] trustManagers = new TrustManager[] { trustManager };
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);
SSLConnectionSocketFactory sslConnectionSocketFactory =
SSLConnectionSocketFactoryBuilder.create()
.setSslContext(sslContext)
.setTlsVersions(TLS.V_1_2)
.setHostnameVerifier(new DefaultHostnameVerifier())
.build();
Registry sslSocketConnectionRegistry = RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", sslConnectionSocketFactory).build();
PoolingHttpClientConnectionManager connectionManager = new
PoolingHttpClientConnectionManager(sslSocketConnectionRegistry);
connectionManager.setValidateAfterInactivity(TimeValue.of(1L,
TimeUnit.SECONDS));
connectionManager.setMaxTotal(50);
connectionManager.setDefaultMaxPerRoute(50);
CacheConfig cacheConfig = CacheConfig.custom()
.setSharedCache(false).
setMaxObjectSize(153600L).
setMaxCacheEntries(600)
.build();
this.httpClient = CachingHttpClients.custom()
.setCacheConfig(cacheConfig)
.disableAutomaticRetries()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(NetworkDefaults.getDefaultRequestConfig())
.setUserAgent("test user agent")
.build();
}
public int makeRequest(String url, String username, String password) {
int httpStatusCode = -1;
HttpGet httpget = new HttpGet(url);
try {
System.out.println(" >>>>>> " + url);
CloseableHttpResponse response;
response = httpClient.execute(httpget,
createContext(url, username, password.toCharArray()));
httpStatusCode = response.getCode();
System.out.println("<------" + httpStatusCode + ":" + response);
} catch (Exception exception) {
System.out.println("IWA : network request failed: ");
}
return httpStatusCode;
}
public HttpClientContext createContext(String surl, String username, char[]
password) throws Exception{
URL url = new URL(surl);
String host = url.getHost();
int port = url.getPort();
AuthScope authScope = new AuthScope(host, port);
int finalPort = port >= 0 ? port : 443;
AuthScope ntlmAuthScope = new AuthScope(null, host, finalPort, null,
"NTLM");
HttpClientContext httpClientContext = HttpClientContext.create();
UsernamePasswordCredentials upc = new UsernamePasswordCredentials(username,
password);
NTCredentials ntc = new NTCredentials(this.processUsername(username),
password, host, null);
BasicCredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(authScope, upc);
provider.setCredentials(ntlmAuthScope, ntc);
httpClientContext.setCredentialsProvider(provider);
return httpClientContext;
}
public String processUsername(String username) {
String[] split = username.split("\\\\", 2);
if (split.length == 2) {
return split[1] + "@" + split[0];
}
return username;
}
}
{code}
> NTLM Authentication not working when sending multiple request concurrently
> --------------------------------------------------------------------------
>
> Key: HTTPCLIENT-2170
> URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2170
> Project: HttpComponents HttpClient
> Issue Type: Bug
> Components: HttpClient (classic)
> Affects Versions: 5.0.4, 5.1
> Environment: Java 1.8 and Android
> Reporter: Erick
> Priority: Minor
> Labels: 5.04, 5.1, NTLM, http-client
> Attachments: NTLMTestSample.zip
>
>
> We migrated our apache version from 4.5.x to 5.0.4 and we have encountered an
> authentication error using NTLM.
> We are making multiple requests in different threads to a NTLM secured server
> concurrently such as:
> {code:java}
> private fun test_Standalone() { val username = "username" val password
> = "password" val serverName = "localhost"
> val requestUrls = arrayOf(
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/0/0/0",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/63/0/0",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/16/26166/11433",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/15/13083/5716",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/1/0/0",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/16/26166/11432",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/14/6541/2858",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/15/13082/5716",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/15/13083/5715",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/16/26166/11431",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/15/13082/5715",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/14/6541/2857",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/16/26165/11434",
>
> "https://${serverName}/server/rest/services/CERT_Secured_Basemap/MapServer/tile/15/13082/5717"
> )
> for(url in requestUrls) { makeRequestAsync(url, username,
> password) }}
> {code}
> Some of the data request succeed but others fail with a *401 Unauthorized.*
> **the output looks something like this:
>
> {code:java}
> <------[Thread-7] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-1] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-4] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-6] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-3] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-10] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-2] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-9] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-13] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-12] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-0] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-11] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-5] 401 :401 Unauthorized HTTP/1.1
> <------[Thread-8] 200 :200 OK HTTP/1.1
> {code}
>
> Looking at the logs, it seems that the NTLM handshake fails for some request
> **We found that by synchronizing the method
> [ProtocolExec.execute()|https://github.com/apache/httpcomponents-client/blob/5.0.x/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java#L103],
> all the NTLM authentication requests succeed and we are able to fetch the
> data successfully.
>
> Attached is the repro java project that we are using.
> The project only needs an NTLM server and credentials to run.
>
> We tested version 5.1 and it was also reproducible.
>
--
This message was sent by Atlassian Jira
(v8.3.4#803005)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]