UsernameToken WS-Security с Apache CXF анотации (WSS4J)

Опитвам се да създам уеб услуга "java first", която ще използва обикновен и прост UsernameToken WS-Security. Опитах се да следвам примерите от CXF. Когато правя запитване към моя wsdl, не виждам нищо, свързано със сигурността на ws. Използвам CXF 2.7.5 и се опитвам да правя всичко с анотации.

Следното е моят неуспешен опит:

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 зависимости:

<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>

person aCodeMonkey    schedule 23.05.2013    source източник


Отговори (1)


Можете да използвате конфигурацията, базирана на WS-SecurityPolicy, вместо подхода на прихващача на WSS4J!

За целта създайте .wsdl файл от вашата уеб услуга "java first" и го разширете с частта и и го поставете навсякъде във вашия проект. (напр. /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>

Дефинирайте параметъра wsdlLocation в анотацията @Webservice и използвайте анотацията @EndpointConfig, а не @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();
   }
}

Дефинирайте вашия ws-security.callback-handler в WEB-INF/jaxws-endpoint-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
  <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>
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 зависимости:

  <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>

Заредете модула org.apache.ws.security JBOSS: 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>

Приложих проект helloworld: https://github.com/matyig/wsse-policy-username

Ако искате да използвате подход Non-WS-SecurityPolicy, можете да използвате начина за конфигурация на spring xml. Тук ще намерите добър урок:

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

person matyig    schedule 27.08.2013
comment
Не разбирам едно нещо защо трябва да внедрите манипулатор на обаждания на passworld от страна на клиента. Клиентът не трябва да се притеснява. Как би работило, ако клиентът беше PHP или .NET??? - person Makky; 05.12.2014