Java JAX-WS 使用 WS-Security 和 WS-Addressing 使用 Web 服务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/699254/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 18:29:17  来源:igfitidea点击:

JAX-WS Consuming web service with WS-Security and WS-Addressing

javaweb-servicesjax-wsws-securityjava-metro-framework

提问by Jared Knipp

I'm trying to develop a standalone Java web service client with JAX-WS (Metro) that uses WS-Security with Username Token Authentication (Password digest, nonces and timestamp) and timestamp verification along with WS-Addressing over SSL.

我正在尝试使用 JAX-WS(Metro)开发一个独立的 Java Web 服务客户端,该客户端使用 WS-Security 和用户名令牌身份验证(密码摘要、随机数和时间戳)和时间戳验证以及 WS-Addressing over SSL。

The WSDL I have to work with does not define any security policy information. I have been unable to figure out exactly how to add this header information (the correct way to do so) when the WSDL does not contain this information. Most examples I have found using Metro revolve around using Netbeans to automatically generate this from the WSDL which does not help me at all. I have looked into WSIT, XWSS, etc. without much clarity or direction. JBoss WS Metro looked promising not much luck yet there either.

我必须使用的 WSDL 没有定义任何安全策略信息。当 WSDL 不包含此信息时,我一直无法确切地弄清楚如何添加此标题信息(正确的方法)。我发现的大多数使用 Metro 的例子都围绕着使用 Netbeans 从 WSDL 自动生成它,这对我没有任何帮助。我研究了 WSIT、XWSS 等,但没有太多明确性或方向。JBoss WS Metro 看起来也不怎么好运。

Anyone have experience doing this or have suggestions on how to accomplish this task? Even pointing me in the right direction would be helpful. I am not restricted to a specific technology other than it must be Java based.

任何人都有这样做的经验或对如何完成这项任务有建议?即使将我指向正确的方向也会有所帮助。除了必须基于 Java 之外,我不限于特定技术。

采纳答案by Jared Knipp

I did end up figuring this issue out but I went in another direction to do so. My solution was to use CXF 2.1 and its JAX-WS implementation, combining the power of CXF with the existing Spring infrastructure I already had in place. I was skeptical at first because of the numerous jars required by CXF, but in the end it provided the best and simplest solution.

我确实最终解决了这个问题,但我转向了另一个方向。我的解决方案是使用 CXF 2.1 及其 JAX-WS 实现,将 CXF 的强大功能与我已经拥有的现有 Spring 基础设施相结合。起初我很怀疑,因为 CXF 需要大量的 jar,但最终它提供了最好和最简单的解决方案。

Adapting an example from the CXF website for client configuration, I used the custom CXF JAXWS namespace within spring and used an Out Interceptor for Username Token Authentication (Password digest, nonces and timestamp) and timestamp verification. The only other step to make this work was creating my own Password Callback handler that is executed for each outbound SOAP request.

根据CXF 网站上的一个示例进行客户端配置,我在 spring 中使用了自定义 CXF JAXWS 命名空间,并使用了一个 Out Interceptor 进行用户名令牌身份验证(密码摘要、随机数和时间戳)和时间戳验证。完成这项工作的唯一其他步骤是创建我自己的密码回调处理程序,该处理程序为每个出站 SOAP 请求执行。

For SSL configuration, I again turned to CXF and its SSL support via conduits, although I could never make SSL work with a specific http:conduit name, I had to use the general purpose one that is not recommended for production environments.

对于 SSL 配置,我再次求助于CXF 及其通过管道的 SSL 支持,尽管我永远无法使用特定的 http:conduit 名称使 SSL 工作,但我不得不使用不推荐用于生产环境的通用名称。

Below is an example of my config file.

下面是我的配置文件的示例。

Spring config file

弹簧配置文件

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

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.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);
    }
}

回答by John Saunders

If the information isn't in the WSDL, are you sure it's in the service described by the WSDL? The WSDL is meant to provide all the information necessary to describe the service, including the security policies necessary to use the service.

如果信息不在 WSDL 中,您确定它在 WSDL 描述的服务中吗?WSDL 旨在提供描述服务所需的所有信息,包括使用服务所需的安全策略。

What platform did the WSDL come from? Is it possible that the WSDL is not the complete description? For instance, it might be a WSDL that is included in another WSDL that doesprovide the security information.

WSDL 来自哪个平台?WSDL 是否有可能不是完整的描述?例如,它可能是一个WSDL是包括d在另一个WSDL是提供的安全信息。

回答by Jeshurun

There is a post here explaining how to configure a Client and a Server in CXF with WS-Security: JAX-WS Web Services with Spring and CXF

这里有一篇文章解释了如何使用 WS-Security 在 CXF 中配置客户端和服务器:JAX-WS Web Services with Spring and CXF