mardi 22 juillet 2014

Connexion à un serveur Http en utilisant une authentification NTLM [1/3]

Depuis Java version 1.6, la JVM support nativement l'authentification NTLM via la classe HttpUrlConnection.
Pour se faire, rien de plus facile.
Il est nécessaire de créer une classe contenant le login, le mot de passe et le domaine :
import java.net.Authenticator;
import java.net.PasswordAuthentication;

/**
 * Class to store login, password and NT domain
 */
public class MyAuthenticator extends Authenticator {
    public MyAuthenticator() {
        super();
    }

    @Override
    public PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication("MYNT-DOMAIN\\MY_USER", "Password".toCharArray());
    }
}
Enfin, il faut indiquer à la JVM notre classe d'authentification :
// Set authentication
Authenticator.setDefault(new MyAuthenticator());
A présent, nous pouvons lancer notre requête (exemple avec un appel de WebService) :
// Set authentication
Authenticator.setDefault(new MyAuthenticator());

String SOAPUrl = "http://mywebservice.com/ws";
String xmlFile2Send = "file_to_send";
String SOAPAction = "http://tempuri.org/echo";
        
// Create the connection where we're going to send the file.
URL url = new URL(SOAPUrl);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;        

// Open the input file. After we copy it to a byte array, we can see
// how big it is so that we can set the HTTP Cotnent-Length
// property.
FileInputStream fin = new FileInputStream(xmlFile2Send);
byte[] b = IOUtils.toByteArray(fin); // Apache commons-io

// Set the appropriate HTTP parameters.
httpConn.setRequestProperty( "Content-Length",
                             String.valueOf( b.length ) );
httpConn.setRequestProperty("Content-Type","text/xml; charset=utf-8");
  httpConn.setRequestProperty("SOAPAction",SOAPAction);
httpConn.setRequestMethod( "POST" );
httpConn.setDoOutput(true);
httpConn.setDoInput(true);

System.out.println("Send request >>>");

// Everything's set up; send the XML that was read in to b.
OutputStream out = httpConn.getOutputStream();
out.write( b );    
out.close();

System.out.println("Read response <<<");

// Requiered to lauch NTLM authentification
Map<String, List<String>> headerFields = httpConn.getHeaderFields();

// Read the response and write it to standard out.

InputStreamReader isr =
    new InputStreamReader(httpConn.getInputStream());
BufferedReader in = new BufferedReader(isr);

String inputLine;

while ((inputLine = in.readLine()) != null)
    System.out.println(inputLine);

in.close();
Il y a deux choses importantes dans l'exemple ci-dessus.
La première c'est de donner la classe contenant les crédentials, la deuxième c'est de lire les headers.
En effet, c'est le httpConn.getHeaderFields() qui va déclencher en interne l'authentification NTLM par la JVM.
Pourquoi ?
Parce que lorsque la classe HttpUrlConnection lit les header, elle vérifie la présence de l'entête WWW-Authenticate et s'assure que le type d'authentification demandée est supportée. Si c'est le cas, la JVM s'en charge avant de rendre la main.

Il y a tout de même un soucis que vous aurez peut-être remarqué, la classe d'authentification se passe à une méthode statique.
De plus, il faut savoir que la JVM à un cache host+url pour chaque autentification. De ce fait, sans couper la JVM, impossible de changer de credentials.
Pour rappel, l'authentification NTLM est un protocole négocié.

Information sur le NTLM :

Aucun commentaire:

Enregistrer un commentaire