java - 带有 Apache CXF 注释的 UsernameToken WS-Security (WSS4J)

标签 java cxf ws-security wss4j

我正在尝试创建一个“java 优先”的网络服务,它将使用简单明了的 UsernameToken WS-Security。我试图遵循 CXF 中的示例。当我查询我的 wsdl 时,我没有看到任何与 ws-security 相关的内容。我正在使用 CXF 2.7.5 并且我正在尝试使用注释来完成所有事情。

以下是我失败的尝试:

示例服务.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();
    }

}

密码处理程序.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>

最佳答案

您可以使用基于 WS-SecurityPolicy 的配置而不是 WSS4J 拦截器方法!

为此,从您的“java 优先”web 服务创建一个 .wsdl 文件,并使用 和 部分扩展它,并将它放在您项目中的任何位置。 (例如/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>

在@Webservice 注释中定义 wsdlLocation 参数并使用@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();
   }
}

在 WEB-INF/jaxws-endpoint-config.xml 中定义您的 ws-security.callback-handler。

<?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 依赖:

  <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

如果您想使用非 WS-SecurityPolicy 方法,您可以使用 spring xml 配置方式。您可以在这里找到一个很好的教程:

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

关于java - 带有 Apache CXF 注释的 UsernameToken WS-Security (WSS4J),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16722471/

相关文章:

java - 通过 ArrayList 进行搜索

java - 在 REST 服务中实现 SAML 的最佳实践

c# - 从 WCF 创建的 ws-security header 中删除时间戳元素

wcf - 使用 .Net Core 3.1 签署 Soap 1.1 主体

java hibernate 无法解析属性

java - JPA native 查询连接返回对象但取消引用引发类强制转换异常

java - 如何从 Java 中返回通用列表中删除 'Type Safety'/'Unchecked conversion' 警告?

java - 升级到 2.2.10 后,CXF Web 服务将无法运行

java - 当我不知道密码时使用 WS-Security 进行身份验证

java - WSO2 身份服务器管理控制台显示没有 STS 链接