Páginas

jueves, 12 de enero de 2012

Autenticación JAX-WS UsernameToken desde cliente

En este POST se pretende mostrar como configurar un cliente JAX-WS que consuma un servicio que requiera autenticación a través de UsernameToken.

A continuación se indican las librerías necesarias para la implementación del ejemplo así como sus coordenadas para la herramienta Maven.

  • jaxb-impl
    • groupId: com.sun.xml.bind
    • artifactId: jaxb-impl
  • xws-security
    • groupId: com.sun.xml.wss
    • artifactId: xws-security
  • xmlsec
    • groupId: com.sun.org.xml.security
    • artifactId: xmlsec
  • jaxp-api
    • groupId: javax.xml
    • artifactId: jaxp-api
  • xercesImpl
    • groupId: activesoap
    • artifactId: xercesImpl
  • jaxb-xalan
    • groupId: activesoap
    • artifactId: jaxb-xalan
Acceso al servicio

 URL url = new URL("http://rutaAplicacion/nombreServicio");
 QName qname = new QName("e3swsdl-master", "nombreServicio");
NombreServicioService locator = new NombreServicioService(url, qname);
NombreServicio port = locator.getPort(NombreServicio.class);
//Manejador
final List<Handler> chain = new ArrayList<Handler>();
 chain.add(new SecurityHandler());
 ((BindingProvider) port).getBinding().setHandlerChain(chain);
 //Llamada operación del servicio
 port.metodoServicio(...);


Manejador

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;
 }
}




Seguridad

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);
 }
 }
 }
}


Configuración del manejador
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config" dumpMessages="true" >
 <xwss:UsernameToken digestPassword="false"/>
</xwss:SecurityConfiguration>

Este mágnifico ejemplo debemos agradecerlo a los compañeros del blog Xnoccio donde podemos consultar el ejemplo original haciendo clic aqui

viernes, 28 de octubre de 2011

Conflicto Hibernate y Jersey

Ultimamente he tenido que añadir la librería Jersey a un proyecto que se encuentra desarrollado con Struts e Hibernate. Para aquellos que no conozcan esta librería, decir que es una implementación de JAXB-WS que nos permite crear, de forma rápida y sencilla, Servicios WEB REST.

Una vez integrado jersey en el proyecto, cuando realicé mi primera petición al servicio, el cual me devolvía una entidad que se encontraba persistida en la base de datos, me elevó la siguiente excepción:

               java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V

¿Qué está pasando?
Se debe a un conflicto con la librería "asm". Hibernate, hace uso de la librería "cglib", que esta, a su vez hace uso de la librería "asm-1.5.3". Por otro lado, Jersey usa la librería "asm-3.5.1"

                                                    ¡¡¡¡CONFLICTO!!!

Si eliminamos la librería cglib, Jersey funcionará correctamente pero Hibernate NO. Y si eliminamos la librería asm, Hibernate funcionará correctamente pero Jersey NO.

SOLUCIÓN:
Para resolver este conflicto, debemos hacer uso de la librería "cglib-nodep.jar". Esta librería es una implementación de cglib, que incluye las clases de ASM demandadas por esta. Con lo cual, lo que tenemos que hacer, es reemplazar en nuestro proyecto la librería cglib por cglib-nodep y problema resuelto.