Domanda

Sto cercando di sviluppare un client di servizi Web standalone Java con JAX-WS (Metro) che utilizza WS-Security con Username Token di autenticazione (password digerire, nonce e timestamp) e la verifica timestamp insieme a WS-Addressing su SSL.

Il WSDL devo lavorare con i non definisce alcuna informazione politica di sicurezza. Sono stato in grado di capire esattamente come aggiungere queste informazioni di intestazione (il modo corretto di farlo) quando il WSDL non contiene tali informazioni. La maggior parte degli esempi che ho trovato usando Metro ruotano intorno usando Netbeans per generare automaticamente questo dal WSDL che non mi aiuta affatto. Ho guardato in WSIT, XWSS, ecc senza molta chiarezza o direzione. WS Metro JBoss sembrava promettente non molta fortuna ancora ci sia.

Qualcuno ha esperienza di fare questo o avere suggerimenti su come eseguire questa operazione? Anche avermi nella giusta direzione sarebbe utile. Io non sono limitate a una specifica tecnologia diversa da quella che deve essere basato su Java.

È stato utile?

Soluzione

Ho fatto finire per capire questo problema fuori, ma sono andato in un'altra direzione per farlo. La mia soluzione era quella di utilizzare CXF 2.1 e la sua attuazione JAX-WS, combinando la potenza di CXF con l'infrastruttura esistente primavera avevo già in atto. Ero scettico in un primo momento a causa dei numerosi vasi richiesti da CXF, ma alla fine ha fornito la soluzione migliore e più semplice.

L'adattamento un esempio dal CXF sito web per la configurazione del client , ho usato il costume CXF jaxws namespace entro la primavera e usato un Interceptor out per Nome utente token di autenticazione (password digerire, nonce e timestamp) e la verifica timestamp. L'unico altro passo per rendere questo lavoro è stato creare il mio gestore di password di callback che viene eseguita per ogni richiesta SOAP in uscita.

Per la configurazione SSL, ho di nuovo rivolto a CXF e il suo supporto SSL tramite condotti , anche se non avrei mai potuto fare il lavoro SSL con una specifica http:. nome condotto, ho dovuto usare lo scopo generale uno che non è raccomandato per ambienti di produzione

Di seguito è un esempio di mio file di configurazione.

file di configurazione 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 client password 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);
    }
}

Altri suggerimenti

Se le informazioni non sono nel WSDL, sei sicuro che sia al servizio descritto dal WSDL? Il WSDL lo scopo di fornire tutte le informazioni necessarie per descrivere il servizio, comprese le politiche di sicurezza necessarie per utilizzare il servizio.

Quale piattaforma ha il WSDL viene? E 'possibile che il WSDL non è la descrizione completa? Per esempio, potrebbe essere un WSDL che è includere d in un altro WSDL che fa di fornire le informazioni di protezione.

C'è un post qui che spiega come configurare un client e un server in CXF con WS-Security: JAX-WS Web Services con molla e CXF

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top