Pour rappel, voici un exemple d'authentification NTLM :
Client -> Server POST ... Server -> Client 401 Unauthorized WWW-Authenticate: NTLM Client -> Server POST ... Authorization: NTLM TlRMTVNTUAABAAAAA7IAAAoACgApAAAACQAJACAAAABMSUdIVENJVFlVUlNBLU1JTk9S Server -> Client 401 Unauthorized WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA== Client -> Server POST ... Authorization: NTLM TlRMTVNTUAADAAAAGAAYAHIAAAAYABgAigAAABQAFABAAAAADAAMAFQAAAASABIAYAAAAAAAAACiAAAAAYIAAFUAUgBTAEEALQBNAEkATgBPAFIAWgBhAHAAaABvAGQATABJAEcASABUAEMASQBUAFkArYfKbe/jRoW5xDxHeoxC1gBmfWiS5+iX4OAN4xBKG/IFPwfH3agtPEia6YnhsADT Server -> Client 200 OkOn remarque qu'on envoie deux fois le contenu de la requête.
La première fois, évidement le server rejete le contenu.
Ce qui est important dans le code ci-dessous c'est :
1 - définir les crédential
CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials(AuthScope.ANY, new NTCredentials("", " ", null, " "));
2 - bien définir les paramètres de connexion et en particulier ne pas avoir l'entête Expect:
.setExpectContinueEnabled(false)
3 - fournir un entity repétable. En effet, la première fois, le contenu de la requête est envoyée, mais le serveur répond un 401
HttpEntity reqEntity = new FileEntity(new File(xmlFile2Send));
Code complet :
import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.NTCredentials; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.CookieSpecs; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.entity.FileEntity; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; /** * Test NTLM with Apache HttpClient 4.3.x. * * HttpClient have pool, becarefull. NTLM is statefull. When TCP connection is avaible, no authentification are requiere. * * Add JVM argument to show all http request debug : * -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog * -Dorg.apache.commons.logging.simplelog.showdatetime=true * -Dorg.apache.commons.logging.simplelog.log.org.apache.http.impl.conn=DEBUG * -Dorg.apache.commons.logging.simplelog.log.org.apache.http.impl.client=DEBUG * -Dorg.apache.commons.logging.simplelog.log.org.apache.http.client=DEBUG * -Dorg.apache.commons.logging.simplelog.log.org.apache.http=DEBUG */ public class TestNtlmSoap { public static void main(String[] args) throws ClientProtocolException, IOException { String SOAPUrl = "http://mywebservice.com/ws"; String xmlFile2Send = "file_to_send"; String SOAPAction = "http://tempuri.org/echo"; CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials(AuthScope.ANY, new NTCredentials("", " ", null, " ")); // Create global request configuration RequestConfig defaultRequestConfig = RequestConfig.custom() .setRedirectsEnabled(true) .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM)) // Remove Http Header Expect: 100-continue // http://stackoverflow.com/questions/14459704/does-empty-expect-header-mean-anything .setExpectContinueEnabled(false) .build(); CloseableHttpClient httpclient = HttpClients.custom() .setDefaultCredentialsProvider(credsProvider) .setDefaultRequestConfig(defaultRequestConfig) .build(); try { HttpPost httppost = new HttpPost(SOAPUrl); httppost.addHeader("Content-Type","text/xml; charset=utf-8"); httppost.addHeader("SOAPAction", SOAPAction); // Read request file. // WARNING : must be repeatable ! At fist connection, content send, then authentification done, finaly resend file HttpEntity reqEntity = new FileEntity(new File(xmlFile2Send)); httppost.setEntity(reqEntity); System.out.println("executing request " + httppost.getRequestLine()); HttpResponse response = httpclient.execute(httppost); HttpEntity resEntity = response.getEntity(); System.out.println("----------------------------------------"); System.out.println(response.getStatusLine()); if (resEntity != null) { System.out.println("Response content length: " + resEntity.getContentLength()); System.out.println("Chunked?: " + resEntity.isChunked()); } if (resEntity != null && resEntity.isStreaming()) { InputStream instream = resEntity.getContent(); if (instream != null) { InputStreamReader isr = new InputStreamReader(instream); BufferedReader in = new BufferedReader(isr); String inputLine; while ((inputLine = in.readLine()) != null) System.out.println(inputLine); instream.close(); } } } finally { // When HttpClient instance is no longer needed, // shut down the connection to ensure // immediate deallocation of all system resources httpclient.close(); } } }
Attention, toutefois, il ne faut surtout pas activer l'authentification preemptive, le composant Http Client envoye un authentification basic.
L'authentification preemptive consiste à envoyer les credentials avant que le serveur ne les demande.
Attention aussi, dans l'exemple, il n'y a pas de configuration du pool manager. Il faut savoir que NTLM identifie au niveau de la connexion TCP, donc s'il y a réutilisation de la connexion, il n'y aura pas d'authentification puisque la connexion TCP est déjà identifié. Du coup, il peut y avoir un mélange de connexion.
Aucun commentaire:
Enregistrer un commentaire