2013-05-23 4 views
5

Ich versuche, einen "Java First" Webservice zu erstellen, der einfache und einfache UsernameToken WS-Security verwendet. Ich habe versucht, den Beispielen von CXF zu folgen. Wenn ich meine WSDL abfrage, sehe ich keine Erwähnung von irgendetwas, was mit der Sicherheit zusammenhängt. Ich benutze CXF 2.7.5 und versuche alles mit Anmerkungen zu machen.UsernameToken WS-Security mit Apache CXF Anmerkungen (WSS4J)

Das Folgende ist meine gescheiterte Versuch:

SampleService.java:

import java.util.ArrayList; 
import java.util.Date; 

import javax.jws.WebParam; 
import javax.jws.WebMethod; 
import javax.jws.WebService; 
import javax.jws.soap.SOAPBinding; 

import org.apache.cxf.annotations.EndpointProperties; 
import org.apache.cxf.annotations.EndpointProperty; 

@WebService(targetNamespace="https://test.company.com/ws/") 
@SOAPBinding(style = SOAPBinding.Style.RPC) 
@EndpointProperties({ 
    @EndpointProperty(key = "action", value="UsernameToken"), 
    @EndpointProperty(key = "passwordType", value="PasswordText"), 
    @EndpointProperty(key = "ws-security.callback-handler", value="PasswordHandler"), 
    //@EndpointProperty(key = "ws-security.validate.token", value="false"), 
}) 
public interface SampleService { 

    @WebMethod 
    public String getSample(
      @WebParam(name="startDate") Date startDate, 
      @WebParam(name="endDate") Date endDate); 

} 

SampleServiceImpl.java:

import java.util.Date; 
import javax.jws.WebMethod; 
import javax.jws.WebService; 

@WebService(endpointInterface = "SampleService", targetNamespace="https://test.company.com/ws/") 
public class SampleServiceImpl implements SampleService { 

    @Override 
    @WebMethod 
    public String getSample(Date startDate, Date endDate) { 
     StringBuilder sb = new StringBuilder(); 
     sb.append("Start Date: "); 
     sb.append(startDate.toString()); 
     sb.append("\n"); 
     sb.append("End Date: "); 
     sb.append(endDate.toString()); 
     return sb.toString(); 
    } 

} 

PasswordHandler.java:

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.ws.security.WSPasswordCallback; 

public class PasswordHandler implements CallbackHandler { 

    @Override 
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { 

    WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]; 

    System.out.println("User: " + pc.getIdentifier()); 
    System.out.println("Password: " + pc.getIdentifier()); 
    System.out.println("Type: " + pc.getType()); 
    if (pc.getIdentifier().equals("joe")) { 
     // set the password on the callback. This will be compared to the 
     // password which was sent from the client. 
     pc.setPassword("password"); 

    } 
} 

} 

SampleServicePublisher.java:

import java.util.HashMap; 
import java.util.Map; 

import org.apache.cxf.endpoint.Endpoint; 
import org.apache.cxf.jaxws.EndpointImpl; 
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor; 
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor; 
import org.apache.ws.security.WSConstants; 
import org.apache.ws.security.handler.WSHandlerConstants; 

public class SampleServicePublisher { 
    public static void main(String[] args) { 
     String URL = "http://localhost:9999/ws/SampleService"; 
     EndpointImpl jaxWsEndpoint = 
        (EndpointImpl) javax.xml.ws.Endpoint.publish(URL, new SampleServiceImpl()); 
     Endpoint cxfEndpoint = jaxWsEndpoint.getServer().getEndpoint(); 

     Map<String,Object> inProps= new HashMap<String,Object>(); 
     // how to configure the properties is outlined below; 

     WSS4JInInterceptor wssIn = new WSS4JInInterceptor(inProps); 
     cxfEndpoint.getInInterceptors().add(wssIn); 

     Map<String,Object> outProps = new HashMap<String,Object>(); 
     // how to configure the properties is outlined below; 

     WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps); 
     cxfEndpoint.getOutInterceptors().add(wssOut); 

     inProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN); 
     // Password type : plain text 
     inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT); 
     // for hashed password use: 
     //properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST); 
     // Callback used to retrieve password for given user. 
     inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, PasswordHandler.class.getName()); 
     } 
} 

mvn Abhängigkeiten:

<dependencies> 
    <dependency> 
     <groupId>org.apache.cxf</groupId> 
     <artifactId>cxf-rt-frontend-jaxws</artifactId> 
     <version>2.7.5</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.cxf</groupId> 
     <artifactId>cxf-rt-transports-http</artifactId> 
     <version>2.7.5</version> 
    </dependency> 
    <!-- Jetty is needed if you're using the CXFServlet --> 
    <dependency> 
     <groupId>org.apache.cxf</groupId> 
     <artifactId>cxf-rt-transports-http-jetty</artifactId> 
     <version>2.7.5</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.cxf</groupId> 
     <artifactId>cxf-rt-ws-rm</artifactId> 
     <version>2.7.5</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.cxf</groupId> 
     <artifactId>cxf-rt-ws-security</artifactId> 
     <version>2.7.5</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.cxf</groupId> 
     <artifactId>cxf-rt-ws-addr</artifactId> 
     <version>2.7.5</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.cxf</groupId> 
     <artifactId>cxf-rt-ws-policy</artifactId> 
     <version>2.7.5</version> 
    </dependency> 
</dependencies> 

Antwort

2

Sie den WS-Securitypolicy basierte Konfiguration anstelle des WSS4J Interceptor Ansatz nutzen könnten!

Dazu erstellen Sie eine .wsdl-Datei von Ihrem "Java First" -Webdienst und erweitern Sie sie mit dem und Teil und legen Sie es irgendwo in Ihrem Projekt. (F. E./WEB-INF/WSDL)

 ... 
     <binding name="SecurityServicePortBinding" type="tns:ServiceIface"> 
     <wsp:PolicyReference URI="#SecurityServiceBindingPolicy"/> 
     .... 
     </binding>  
     <service name="SecurityService"> 
     <port name="SecurityServicePort" binding="tns:SecurityServicePortBinding"> 
      <soap:address location="https://localhost:8443/jaxws-samples-wsse-policy-username"/> 
     </port> 
     </service> 

    <wsp:Policy wsu:Id="SecurityServiceBindingPolicy"> 
     <wsp:ExactlyOne> 
      <wsp:All> 
       <wsaw:UsingAddressing 
       xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" 
       wsp:Optional="true" /> 
       <sp:TransportBinding> 
       <wsp:Policy> 
        <sp:TransportToken> 
         <wsp:Policy> 
          <sp:HttpsToken 
          RequireClientCertificate="false" /> 
         </wsp:Policy> 
        </sp:TransportToken> 
        <sp:Layout> 
         <wsp:Policy> 
          <sp:Lax /> 
         </wsp:Policy> 
        </sp:Layout> 
        <sp:IncludeTimestamp/> 
        <sp:AlgorithmSuite> 
         <wsp:Policy> 
          <sp:Basic128 /> 
         </wsp:Policy> 
        </sp:AlgorithmSuite> 
       </wsp:Policy> 
       </sp:TransportBinding> 
       <sp:SignedSupportingTokens> 
       <wsp:Policy> 
        <sp:UsernameToken 
         sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"> 
         <wsp:Policy> 
          <sp:WssUsernameToken10 /> 
         </wsp:Policy> 
        </sp:UsernameToken> 
       </wsp:Policy> 
       </sp:SignedSupportingTokens> 
       <sp:Wss11 /> 
      </wsp:All> 
     </wsp:ExactlyOne> 
    </wsp:Policy>    
</definitions> 

Definieren des WSDLLocation Parameter innerhalb der @WebService Annotation und verwenden, um die @EndpointConfig Annotation nicht @EndpointProperties.

@Stateless 
@WebService 
(
    portName = "SecurityServicePort", 
    serviceName = "SecurityService", 
    wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl", 
    targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", 
    endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.wsdl.ServiceIface" 
) 
@EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint") 
public class ServiceImpl implements ServiceIface 
{ 

    public String sayHello() 
    { 
     return helloservice.sayHello(); 
    } 
} 

Definieren Sie Ihre ws-security.callback-Handler im WEB-INF/jaxws-Endpunkt-config.xml.

<?xml version="1.0" encoding="UTF-8"?> 

<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee" 
    xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd"> 

    <endpoint-config> 
    <config-name>Custom WS-Security Endpoint</config-name> 
    <property> 
     <property-name>ws-security.callback-handler</property-name> 
     <property-value>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.UsernamePasswordCallback</property-value> 
    </property> 
    </endpoint-config> 

</jaxws-config> 

MVN Abhängigkeiten:

<dependency> 
    <groupId>org.apache.cxf</groupId> 
    <artifactId>cxf-rt-ws-security</artifactId> 
    <version>${cxf.version}</version> 
    <scope>provided</scope> 
    </dependency>  
    <dependency> 
    <groupId>org.jboss.ws.native</groupId> 
    <artifactId>jbossws-native-core</artifactId> 
    <version>4.1.1.Final</version> 
    <scope>provided</scope> 
    </dependency> 

laden org.apache.ws.security JBOSS Modul: WEB-INF/jboss-depoyment-structure.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<jboss-deployment-structure> 
    <deployment> 
     <dependencies> 
      <module name="org.apache.ws.security"/> 
     </dependencies> 
    </deployment> 
</jboss-deployment-structure> 

I ein Helloworld Projekt implementiert: https://github.com/matyig/wsse-policy-username

Wenn Sie möchten Bei einem Non-WS-SecurityPolicy-Ansatz könnten Sie die Spring-XML-Konfigurationsmethode verwenden. Sie finden ein gutes Tutorial hier:

http://www.jroller.com/gmazza/entry/cxf_usernametoken_profile

+1

ich nicht eine Sache bekommt, warum brauchen Sie Passworld® Anrufabwicklung auf der Client-Seite zu implementieren. Der Kunde sollte sich keine Sorgen machen müssen. Wie würde es funktionieren, wenn der Client PHP oder .NET wäre ??? – Makky

Verwandte Themen