Question

Je suis en train de développer un client de services Web Java autonome avec JAX-WS (Metro) qui utilise WS-Security avec nom d'utilisateur authentification par jeton (mot de passe digest, nonces et horodatage) et la vérification de l'horodatage avec WS-Addressing sur SSL.

Le WSDL je dois travailler avec ne définit aucune information sur la politique de sécurité. Je suis incapable de comprendre exactement comment ajouter ces informations d'en-tête (la bonne façon de le faire) quand le WSDL ne contient pas ces informations. La plupart des exemples j'ai trouvé en utilisant Metro gravitent autour de l'utilisation Netbeans pour générer automatiquement ce à partir du WSDL qui ne me permet pas du tout. Je l'ai regardé dans WSIT, XWSS, etc., sans beaucoup de clarté ou de direction. JBoss WS Metro semblait prometteur chance pas beaucoup encore là non plus.

Toute personne ont de l'expérience ou le faire des suggestions sur la façon d'accomplir cette tâche? Même moi pointant dans la bonne direction serait utile. Je ne suis pas limité à une technologie spécifique autre que doit être basé sur Java.

Était-ce utile?

La solution

J'ai fini par comprendre cette question, mais je suis allé sur dans une autre direction pour le faire. Ma solution était d'utiliser CXF 2.1 et sa mise en œuvre JAX-WS, combinant la puissance de CXF avec le j'avais déjà en place l'infrastructure existante de printemps. J'étais sceptique au début à cause des nombreux pots requis par CXF, mais à la fin il a fourni la meilleure et la solution la plus simple.

L'adaptation d'un exemple de la CXF site pour la configuration du client , J'ai utilisé l'espace de noms CXF JAXWS personnalisé au sein de printemps et utilisé un Out Interceptor pour l'authentification par jeton Nom d'utilisateur (mot de passe digest, nonces et horodatage) et la vérification de l'horodatage. La seule autre étape pour faire ce travail a été crée mon propre mot de passe gestionnaire de rappel qui est exécuté pour chaque requête SOAP sortant.

Pour la configuration SSL, je me tournai à nouveau CXF et son support SSL via des conduits , bien que je ne pourrais jamais faire le travail SSL avec un spécifique http:. nom de conduite, je devais utiliser une à usage général qui n'est pas recommandé pour les environnements de production

Voici un exemple de mon fichier de configuration.

fichier de configuration Spring

<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 Mot de passe client 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);
    }
}

Autres conseils

Si les informations ne sont pas dans le WSDL, êtes-vous sûr qu'il est au service décrit par le WSDL? Le WSDL est destiné à fournir toutes les informations nécessaires pour décrire le service, y compris les politiques de sécurité nécessaires pour utiliser le service.

Quelle plate-forme ne le WSDL vient? Est-il possible que le WSDL n'est pas la description complète? Par exemple, il pourrait être un WSDL qui est inclure dans un autre d WSDL Finalité fournir les informations de sécurité.

Il y a un poste ici expliquant comment configurer un client et un serveur en CXF avec WS-Security: JAX-WS Web services avec Spring et CXF

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top