Webservice-client con Metro JAX-WS y Autenticación Básica

En esta ocasión os voy a comentar cómo generar un cliente de un webService con autenticación básica (usuario/contraseña , Basic Authentication) usando el plugin para maven JAX-WS.
Doy por hecho que todos sabeis cómo integrar este plugin con maven, podeis obtener toda la información necesaria sobre este plugin en su página oficial.

Al final tendremos algo parecido a esto, introduciendo una nueva entrada en la lista de plugins:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>wsimport</goal>
</goals>
</execution>
</executions>
<configuration>
……
</configuration>
<dependencies>
… lista de dependencias del plugin …
</dependencies>
</plugin>

Para el caso que nos ocupa, vamos a suponer que tenemos un WSDL (Web Services Description Language) desplegado en un servidor que requiere Usuario y Contraseña, ¿cómo podemos indicarle a este plugin la URL al fichero descriptor del servicio web? ¿cómo le indicamos el usuario y contraseña?
Pues todo esto se hace en la sección «configuration«.
Tenemos mucha documentación disponible la web relacionada con wsimport.

Un sabio amigo mío se quejaba una vez en clase de programación, diciendo que la programación era como empanar filetes, y que no le podían enseñar a hacer filetes empanados si antes no se había comido ninguno. Pues bien, siguiendo esta corriente filosófica os pongo un ejemplo y os comento después las secciones que nos afectan:
<configuration>
<wsdlUrls>
<wsdlUrl>[http/https]://[servidor1]:[puerto1]/[rutaAlDescriptor1]?wsdl</wsdlUrl>
<wsdlUrl>[http/https]://[servidor2]:[puerto2]/[rutaAlDescriptor2]?wsdl</wsdlUrl>
</wsdlUrls>
<packageName>mipaquete.ws.client</packageName>
<sourceDestDir>${basedir}/src/main/java</sourceDestDir>
<verbose>true</verbose>
<extension>true</extension>
<xadditionalHeaders>true</xadditionalHeaders>
<xdebug>true</xdebug>
<xauthFile>${basedir}/src/site/resources/auth.conf</xauthFile>
</configuration>

En primer lugar definimos una lista de URL a los distintos ficheros descriptores y posteriormente el paquete en el que generarán las clases consumidoras del servicio web.
Otro parámetro importante en el caso que nos ocupa es «xauthFile». Este parámetro le indica al plugin una ruta a un fichero, en dicho fichero se almacena el Usuario/Contraseña de acceso a la lista de wsld’s anterior.

Este fichero debe contener una serie de lineas de la siguiente manera:
[http/https]://[usuario]:[contraseña]@[servidor]:[puerto]/[rutaAlDescriptor]?wsdl

Tantas líneas como se requieran según las URL’s indicadas en «wsdlUrls».

Pues bien, si generamos a continuación las clases, nuestro plugin le pedirá a los servidores los distintos wslds’s y se autenticará correctamente usando el fichero auth.conf.

¿Hemos acabado ya?
Pues hemos hecho la mitad, por ahora lo que tenemos es una serie de clases que pueden consumir los distintos servicios web.

Pregunta, ¿Se volverá a requerir Usuario/Contraseña cuando se invoque a unos de estos métodos clientes del servicio web?
Pues sí.

¿Y se supone que ese usuario y contraseña lo coge del fichero de autenticación anterior?
Pues no, este fichero sólo nos ha servido para generar las clases clientes, nada más.

Entonces, un segundo paso es introducir un sistema de autenticación dentro de nuestro cliente, ¡vamos a ello!

Una de las posibles opciones es generar una clase de autenticación, que extienda de «java.net.Authenticator».
Su implementación es bastante simple, os pongo un ejemplo:


import java.net.Authenticator;
import java.net.PasswordAuthentication;

public class MiAutenticador extends Authenticator {
static final String user = «miNombreDeUsuario»; // Login
static final String pass = «miContraseña»; // Password

public PasswordAuthentication getPasswordAuthentication() {
return (new PasswordAuthentication(user, pass.toCharArray()));
}
}

Creo que no merece más comentarios, sólo indicar que los atributos «user» y «pass» deberían leerse de un fichero de propiedades por ejemplo, pero de ninguna manera deberían estar a fuego en nuestro código.

Ahora que tenemos nuestra clase de autenticación ¿cómo «conectarla» en nuestras clases clientes?
Pues bien, lo que debemos hacer es indicar que deseamos usar este «Autenticador» justo antes de la llamada al
webService que requiere dicha autenticación, algo como:

........
Authenticator.setDefault(new MiAutenticador());
API_webService.metodo(params);
........

Esto se puede implementar de manera elegante usando el patrón de Diseño Decorador (Decorator Pattern ), de manera que por defecto se «decore» los distintos métodos del api webService con nuestro autenticador.

Pues nada más, espero haber sido claro.

Gracias, namasté y buena suerte.