我正在尝试使用 JAX-WS (Metro) 开发一个独立的 Java Web 服务客户端,该客户端使用 WS-Security 和用户名令牌身份验证(密码摘要、随机数和时间戳)和时间戳验证以及基于 SSL 的 WS-Addressing。
我必须使用的 WSDL 没有定义任何安全策略信息。当 WSDL 不包含此信息时,我一直无法准确地弄清楚如何添加此标头信息(正确的方法)。我发现的大多数使用 Metro 的示例都围绕着使用 Netbeans 从 WSDL 自动生成它,这对我没有任何帮助。我研究过 WSIT、XWSS 等,但没有太多清晰度或方向。 JBoss WS Metro 看起来也没什么运气。
有人有这样做的经验或对如何完成这项任务有建议吗?即使为我指明正确的方向也会有所帮助。除了必须基于 Java 之外,我不限于特定技术。
我最终确实解决了这个问题,但我走了另一个方向。我的解决方案是使用 CXF 2.1 及其 JAX-WS 实现,将 CXF 的强大功能与我已有的现有 Spring 基础设施相结合。一开始我很怀疑,因为 CXF 需要大量的 jar,但最终它提供了最好、最简单的解决方案。
改编一个例子用于客户端配置的 CXF 网站,我在 spring 中使用了自定义 CXF JAXWS 命名空间,并使用 Out Interceptor 进行用户名令牌身份验证(密码摘要、随机数和时间戳)和时间戳验证。完成这项工作的唯一其他步骤是创建我自己的密码回调处理程序,该处理程序针对每个出站 SOAP 请求执行。
对于 SSL 配置,我再次转向CXF 及其通过管道的 SSL 支持,虽然我永远无法使 SSL 与特定的 http:conduit 名称一起工作,但我必须使用不建议用于生产环境的通用名称。
下面是我的配置文件的示例。
弹簧配置文件
<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 客户端密码处理程序:
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);
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)