Pregunta

Estoy tratando de desarrollar un cliente independiente de servicios web Java con JAX-WS (metro) que utiliza WS-Security con nombre de usuario Token de autenticación (contraseña digerir, valores de uso único y marca de tiempo) y la verificación de marca de tiempo, junto con WS-Addressing sobre SSL.

El WSDL que tengo que trabajar con no define ninguna información política de seguridad. No he sido capaz de averiguar exactamente cómo agregar esta información de cabecera (la forma correcta de hacerlo) cuando el WSDL no contiene esta información. La mayoría de los ejemplos que he encontrado usando Metro giran en torno al uso Netbeans para generar esto desde el WSDL que no me ayuda en absoluto automáticamente. He mirado en WSIT, XWSS, etc. sin mucha claridad o dirección. JBoss WS metro parecía prometedor, no mucha suerte todavía allí.

Alguien tiene experiencia haciendo esto o tiene alguna sugerencia sobre cómo realizar esta tarea? Incluso me apunta en la dirección correcta sería de gran ayuda. No estoy restringido a una tecnología específica aparte de que debe estar basado en Java.

¿Fue útil?

Solución

Yo no terminan averiguar más el tema, pero fui en otra dirección para hacerlo. Mi solución fue usar CXF 2.1 y su aplicación JAX-WS, que combina el poder de CXF con la infraestructura existente de primavera que ya tenía en su lugar. Yo era escéptico al principio, debido a los numerosos frascos requeridos por CXF, pero al final nos proporcionó el mejor y más sencilla solución.

Adaptación de un ejemplo de la CXF sitio web para configuración de cliente , he utilizado la costumbre CXF JAXWS espacio de nombres dentro de la primavera y se utiliza un interceptor de salida de nombre de usuario Token de autenticación (contraseña digerir, valores de uso único y marca de tiempo) y la verificación de marca de tiempo. El único otro paso para hacer este trabajo estaba creando mi propio manejador contraseña de devolución de llamada que se ejecuta para cada solicitud SOAP saliente.

Para la configuración SSL, I de nuevo se volvió a CXF y su soporte SSL a través de conductos , a pesar de que nunca podría hacer que el trabajo de SSL con una específica http:. nombre del conducto, que tuvo que utilizar el único propósito general que no se recomienda para entornos de producción

A continuación se muestra un ejemplo de mi archivo de configuración.

archivo de configuración de la primavera

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xmlns:sec="http://cxf.apache.org/configuration/security"
    xmlns:http="http://cxf.apache.org/transports/http/configuration"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:cxf="http://cxf.apache.org/core"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
    http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
    http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">

    <context:property-placeholder location="meta/my.properties" />
    <context:component-scan base-package="com.foo" />

    <import resource="remoting.xml" />
    <jaxws:client id="myWebService" address="${my.endpointAddress}"
                  serviceClass="com.foo.my.ServicePortType">

<!-- Testing only, adds logging of entire message in and out -->
<jaxws:outInterceptors>
    <ref bean="TimestampUsernameToken_Request" />
    <ref bean="logOutbound" />
</jaxws:outInterceptors>
<jaxws:inInterceptors>
        <ref bean="logInbound" />
    </jaxws:inInterceptors>
    <jaxws:inFaultInterceptors>
        <ref bean="logOutbound" />
    </jaxws:inFaultInterceptors>

<!-- Production settings -->
<!--
    <jaxws:outInterceptors> <ref bean="TimestampUsernameToken_Request" />
    </jaxws:outInterceptors>
    -->
</jaxws:client >



<!--
    CXF Interceptors for Inbound and Outbound messages
    Used for logging and adding Username token / Timestamp Security Header to SOAP message
-->
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />

<bean id="TimestampUsernameToken_Request" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
    <constructor-arg>
        <map>
            <entry key="action" value="UsernameToken Timestamp" />
            <entry key="user" value="${my.group}.${my.userId}" />
            <entry key="passwordType" value="PasswordDigest" />
            <entry key="passwordCallbackClass" value="com.foo.my.ClientPasswordHandler" />
        </map>
    </constructor-arg>
</bean>

<!--
    http:conduit namespace is used to configure SSL using keystores, etc
    *.http-conduit works but CXF says its only supposed to be for temporary use (not production),
    well until the correct way works, we're going to use it.
-->
<http:conduit name="*.http-conduit">
    <http:tlsClientParameters   
                  secureSocketProtocol="SSL">
                  <!--
          <sec:trustManagers>
        <sec:keyStore type="JKS"
                         password="${my.truststore.password}"
                         file="${my.truststore.file}" />
                  </sec:trustManagers>
                  -->
                  <sec:keyManagers keyPassword="${my.keystore.password}">
                    <sec:keyStore type="JKS"
                         password="${my.keystore.password}"
                         file="${my.keystore.file}" />
                  </sec:keyManagers>

                  <!-- Cipher suites filters specify the cipher suite to allow/disallow in SSL communcation  -->
                  <sec:cipherSuitesFilter>
                    <sec:include>.*_WITH_3DES_.*</sec:include>
                    <sec:include>.*_EXPORT_.*</sec:include>
                    <sec:include>.*_EXPORT1024_.*</sec:include
                    <sec:include>.*_WITH_DES_.*</sec:include
                    <sec:exclude>.*_WITH_NULL_.*</sec:exclude
                    <sec:exclude>.*_DH_anon_.*</sec:exclude>
                  </sec:cipherSuitesFilter>
    </http:tlsClientParameters>
</http:conduit>
</beans>

Java Contraseña Cliente Handler

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.log4j.Logger;
import org.apache.ws.security.WSPasswordCallback;


/**
 * <p>
 * Provides a callback handler for use processing outbound/inbound SOAP messages.
 * ClientPasswordHandler sets the password used in the WS-Security UsernameToken 
 * SOAP header.
 * 
 * </p>
 * 
 * Created: Apr 1, 2009
 * @author Jared Knipp
 * 
 */
public final class ClientPasswordHandler implements CallbackHandler {
    protected static Logger log = Logger.getLogger(ClientPasswordHandler.class);

    private static final PropertyManager PROPS = PropertyManager.getInstance();
    private static String PASSWORD = PROPS.getPassword();
    private static boolean IS_PASSWORD_CLEAR = PROPS.getIsClearPassword();

    /**
     * Client password handler call back.  This method is used to provide
     * additional outbound (or could be inbound also) message processing.
     * 
     * Here the method sets the password used in the UsernameToken SOAP security header
     * element in the SOAP header of the outbound message.  For our purposes the clear 
     * text password is SHA1 hashed first before it is hashed again along with the nonce and 
     * current timestamp in the security header.
     */
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        if(log.isDebugEnabled()) { log.debug("Setting password for UsernameToken"); }
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];


        // Check to see if the password is already Hashed via SHA1, if not then hash it first
        if(IS_PASSWORD_CLEAR) {
            synchronized(this) {
                PASSWORD = PasswordDigestUtil.doPasswordDigest(PASSWORD);
                IS_PASSWORD_CLEAR = false;
                PROPS.setIsClearPassword(IS_PASSWORD_CLEAR);
                PROPS.setPassword(PASSWORD);
                PROPS.saveProperties();
            }
        }

        pc.setPassword(PASSWORD);
    }
}

Otros consejos

Si la información no está en el WSDL, ¿estás seguro de que es en el servicio descrito por el WSDL? El WSDL está destinado a proporcionar toda la información necesaria para describir el servicio, incluyendo las políticas de seguridad necesarias para utilizar el servicio.

¿En qué plataforma se WSDL viene? ¿Es posible que el WSDL no es la descripción completa? Por ejemplo, podría ser un WSDL que es incluir d en otro WSDL que hace proporcionar la información de seguridad.

Hay un puesto aquí de explicar cómo configurar un cliente y un servidor en CXF con WS-Security: JAX-WS web Services con la primavera y CXF

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top