UsernameToken en Jax-ws (2/2) – Cliente

El objetivo de este artículo es mostrar como implementar crear un cliente Jax-ws que consuma servicios securizados con   UsernameToken según la especificación Web Services Security UsernameToken Profile 1.0.

El artículo consiera que el lector ya tiene experiencia en Jax-ws y se centra sólo en la configuración del mecanismo de seguridad  consumir servicios que requieran la identificación del solicitante con usuario y password haciendo uso de Jax-ws.

Dependencias requeridas

Aunque las dependencias necesarias están incluidas en algunos servidores de aplicaciones, si lo deseamos podemos o bien bajar la implementación de referencia directamente desde su web:

https://jax-ws-commons.dev.java.net y https://jax-ws.dev.java.net

O definir la dependencia en caso de que el proyecto sea Maven.

[code]
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.1.12</version>
</dependency>

<dependency>
<groupId>com.sun.xml.wss</groupId>
<artifactId>xws-security</artifactId>
<version>3.0</version>
</dependency>

<dependency>
<groupId>com.sun.org.apache.xml.security</groupId>
<artifactId>xmlsec</artifactId>
<version>2.0</version>
</dependency>

<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxp-api</artifactId>
<version>1.4.2</version>
</dependency>

<dependency>
<groupId>activesoap</groupId>
<artifactId>xercesImpl</artifactId>
<version>1.5</version>
</dependency>

<dependency>
<groupId>activesoap</groupId>
<artifactId>jaxb-xalan</artifactId>
<version>1.5</version>
</dependency>
[/code]

Configuaramos el acceso al Servicio

[code lang=”java”]

URL url = new URL("http://rutaAplicacionDeEjemplo/IE3SEnvironmentalMasterData");
QName qname = new QName("e3swsdl-master", "IE3SEnvironmentalMasterData");
IE3SEnvironmentalMasterDataService locator = new IE3SEnvironmentalMasterDataService(url, qname);
IE3SEnvironmentalMasterData clienteProxy = locator.getPort(IE3SEnvironmentalMasterData.class);

//Añadimos el manejador
final List<Handler> chain = new ArrayList<Handler>();
chain.add(new SecurityHandler());
((BindingProvider) clienteProxy).getBinding().setHandlerChain(chain);

//Accedemos al servicio
clienteProxy.addTemporaryProducerCenterData(null, null, null, null, holder);

[/code]

Creamos el manejador (SecurityHandler.java)

[code lang=”java”]
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import com.sun.xml.wss.ProcessingContext;
import com.sun.xml.wss.XWSSProcessor;
import com.sun.xml.wss.XWSSProcessorFactory;
import com.sun.xml.wss.XWSSecurityException;

public class SecurityHandler implements SOAPHandler<SOAPMessageContext> {

XWSSProcessor cprocessor = null;

public SecurityHandler() {
//Leemos el archivo de configuración del servidor
final InputStream input = this.getClass().getResourceAsStream("/user-pass-authenticate-client.xml");

try {
// inicializamos el XWSSProcessor
final XWSSProcessorFactory factory = XWSSProcessorFactory.newInstance();
cprocessor = factory.createProcessorForSecurityConfiguration(input, new SecurityEnvironmentHandler());
input.close();

} catch (final XWSSecurityException e) {
//TODO tratar la excepción
throw new RuntimeException(e);
} catch (final IOException e) {
//TODO tratar la excepción
}

}

public Set<QName> getHeaders() {
final QName securityHeader = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security", "wsse");
final HashSet<QName> headers = new HashSet<QName>();
headers.add(securityHeader);
return headers;
}

public boolean handleFault(final SOAPMessageContext messageContext) {
return true;
}

public boolean handleMessage(final SOAPMessageContext messageContext) {
return secureClient(messageContext);

}

public void close(final MessageContext messageContext) {
}

private boolean secureClient(final SOAPMessageContext messageContext) {
final Boolean outMessageIndicator = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
final SOAPMessage message = messageContext.getMessage();
boolean ok = false;
if (outMessageIndicator.booleanValue()) {
ProcessingContext context;
try {
context = cprocessor.createProcessingContext(message);
context.setSOAPMessage(message);
final SOAPMessage secureMsg = cprocessor.secureOutboundMessage(context);
secureMsg.writeTo(System.out);
messageContext.setMessage(secureMsg);
ok = true;
} catch (final Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
} else {
ok = false;
}
return ok;
}
}
[/code]

Creamos la clase que maneja la seguridad (SecurityEnvironmentHandler.java)

[code lang=”java”]
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import com.sun.xml.wss.impl.callback.PasswordCallback;
import com.sun.xml.wss.impl.callback.UsernameCallback;

/**
* Handle the WSS user/pass security.
*/
public class SecurityEnvironmentHandler implements CallbackHandler {

public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (final Callback callback : callbacks) {
if (callback instanceof UsernameCallback) {

final UsernameCallback cb = (UsernameCallback) callback;
final String userName = "USUARIO";
if (userName == null) {
throw new IOException("La configuaricion del parametro ‘" + "USARIO" + "’ es requerida");
}
cb.setUsername(userName);

} else if (callback instanceof PasswordCallback) {
final String pass = "CLAVE";
if (pass == null) {
throw new IOException("La configuaricion del parametro ‘" + "CLAVE" + "’ es requerida");
}

final PasswordCallback cb = (PasswordCallback) callback;
cb.setPassword(pass);
}
}
}
}
[/code]

Configuramos el manejador (user-pass-authenticate-client.xml)

[code]
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config" dumpMessages="true" >
<xwss:UsernameToken digestPassword="false"/>
</xwss:SecurityConfiguration>
[/code]

Nuestra petición de acceso debe contener el usuario y contraseña de acceso en la cabecera de la petición http siendo similar a la siguiente

[code]
<pre><code><?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" S:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="XWSSGID-1255949753848350309586">
<strong><wsse:Username>usuario</wsse:Username></strong>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">****</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">9w+YwOatF9l1/otioQ75d5Yr</wsse:Nonce>
<wsu:Created>2009-10-19T10:55:54.418Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</S:Header>
<S:Body>
</S:Body>
</S:Envelope>
</code></pre>
[/code]

Comentarios

  1. Hola Jesús, gracias por el post.
    Yo tengo un servicio hecho con axis2, y en la parte de seguridad lo tengo con usernametoken sobre https. desde axis2 tengo muy claro como consumirlo, pero tengo un cliente que quiere consumirlo desde jaxws y ahí ya me perdí. ellos usan netbeans y no saben si tienen que hacer todo esto o se puede hacer de manera gráfica. me podrías ayudar.?
    tienes mi correo: jorgeio at uci dot cu por si me quieres escribir. gracias.

    1. Desconosco si desde netbeans lo puedes probar de forma gráfica la verdad, lo que si es verdad es que para implementar la conexión con el servicio si necesitas hacer todo esto

  2. I read a lot of interesting content here.
    Probably you spend a lot of time writing, i know how to save you a lot of time, there is an online tool that creates high quality,
    google friendly articles in minutes, just type in google – laranitas
    free content source

Comments are closed.