9

Ich versuche, einen eigenständigen Java-Web-Service-Client mit JAX-WS (Metro) zu entwickeln, die WS-Sicherheit mit Benutzername Token-Authentifizierung (Passwort Digest, Nonces Zeitstempel) und Zeitstempelüberprüfung zusammen mit WS-Adressierung über SSL.JAX-WS Consuming Web Service mit WS-Security und WS-Addressing

Die WSDL, mit der ich arbeiten muss, definiert keine Sicherheitsrichtlinieninformationen. Ich konnte nicht genau herausfinden, wie diese Header-Informationen hinzugefügt werden (der richtige Weg), wenn die WSDL diese Informationen nicht enthält. Die meisten Beispiele, die ich mit Metro gefunden habe, drehen sich um die Verwendung von Netbeans, um dies automatisch aus der WSDL zu generieren, was mir überhaupt nicht hilft. Ich habe WSIT, XWSS, etc. ohne viel Klarheit oder Richtung untersucht. JBoss WS Metro sah auch dort noch nicht viel Glück aus.

Hat jemand Erfahrung damit oder Vorschläge zur Durchführung dieser Aufgabe? Es wäre hilfreich, wenn man mich in die richtige Richtung weist. Ich bin nicht auf eine bestimmte Technologie beschränkt, die Java-basiert sein muss.

Antwort

8

Ich habe am Ende dieses Problem aus, aber ich ging in eine andere Richtung, um dies zu tun. Meine Lösung bestand darin, CXF 2.1 und seine JAX-WS-Implementierung zu verwenden und die Leistungsfähigkeit von CXF mit der vorhandenen Spring-Infrastruktur zu kombinieren, die ich bereits eingerichtet hatte. Ich war zunächst skeptisch wegen der zahlreichen von CXF benötigten Gläser, aber am Ende bot es die beste und einfachste Lösung.

ein Beispiel aus dem CXF website for client configuration Anpassung, benutzte ich die benutzerdefinierte CXF JAXWS Namespace innerhalb Frühling und verwendet, um eine Out Interceptor für Benutzername Token-Authentifizierung (Passwort verdauen, Nonces und Zeitstempel) und Zeitstempel Prüfung. Der einzige andere Schritt, um dies zu erledigen, war die Erstellung meines eigenen Password Callback-Handlers, der für jede ausgehende SOAP-Anfrage ausgeführt wird.

Für SSL-Konfiguration habe ich wieder CXF and its SSL support via conduits, obwohl ich nie SSL mit einem bestimmten http: Conduit-Namen arbeiten konnte, musste ich die allgemeine verwenden, die nicht für Produktionsumgebungen empfohlen wird.

Unten ist ein Beispiel meiner Konfigurationsdatei.

Frühling Konfigurationsdatei

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

Wenn die Informationen nicht in der WSDL enthalten sind, sind Sie sicher, dass sie in dem von der WSDL beschriebenen Dienst enthalten sind? Die WSDL soll alle Informationen bereitstellen, die zur Beschreibung des Dienstes erforderlich sind, einschließlich der Sicherheitsrichtlinien, die für die Verwendung des Dienstes erforderlich sind.

Von welcher Plattform stammt die WSDL? Ist es möglich, dass die WSDL nicht die vollständige Beschreibung ist? Zum Beispiel könnte es eine WSDL sein, die enthält d in einer anderen WSDL, die bietet die Sicherheitsinformationen.

+0

Lassen Sie mich klären, es ist nicht in der WSDL, dass ich Zugang erhalten habe. Die Dokumentation, die ich habe, hat Löcher (keine Erwähnung des Zeitstempels), also würde die Ausschließung der WSDL-Info mich nicht überraschen. –

+0

Nun, Sie werden die echte WSDL brauchen, um den echten Service zu rufen.Das ist alles, was dazu gehört. –

+0

Also gibt es keine Möglichkeit, dass die WSDL dies auslässt, aber es ist auf dem Server implementiert? Der Server ist Java (wahrscheinlich JBoss oder Websphere) mit einigen Axis-Versionen. –