在spring-ws(wss4j)中添加加密/解密的正确方法是什么?

mar*_*are 6 java encryption spring web-services spring-ws

我已经部署了2个Web应用程序,一个代表Web服务,另一个代表ws客户端.当使用SIGNING和TIMESTAMP-ing时,一切正常,客户端标记消息(但我认为他没有覆盖默认的300s ttl),用他的x509证书签名消息,并将其发送给ws.另一方面,他收集消息并能够在其密钥库中对客户端可信证书进行时间戳和证书/签名.

当我向我的配置添加加密操作时出现问题.客户端似乎能够加密消息,但似乎没有兴趣解密消息.他只是看到没有端点映射

[SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#}EncryptedData] 

并投掷

WebServiceTransportException: Not Found [404] exception.

有人可以解释我需要做些什么来实现时间戳,使用x509进行签名和加密,再次使用x509?

服务器app-context的一部分:

<bean id="wss4jSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor"> 
        <!-- valiadation -->
        <property name="validationActions" value="Timestamp Signature Encrypt"/> 
        <property name="enableSignatureConfirmation" value="true"/> 
        <property name="validationSignatureCrypto"> 
            <ref bean="keystore"/> 
        </property> 
        <property name="validationDecryptionCrypto"> 
                <ref bean="keystore"/> 
        </property> 
        <property name="validationCallbackHandler"> 
            <bean class="org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler"> 
                <property name="privateKeyPassword" value="password"/> 
            </bean> 
        </property> 
         <!-- timestamp options -->
        <property name="timestampStrict" value="true"/> 
        <property name="timeToLive" value="30"/> 
        <property name="timestampPrecisionInMilliseconds" value="true"/> 
         <!-- signing and encryption -->
        <property name="securementActions" value="Timestamp Signature Encrypt"/> 
        <property name="securementUsername" value="wsserver"/> 
        <property name="securementPassword" value="password"/> 
        <property name="securementSignatureKeyIdentifier" value="DirectReference"/> 

        <property name="securementSignatureCrypto"> 
            <ref bean="keystore"/> 
        </property> 
        <property name="securementEncryptionUser" value="wsclient"/> 
        <property name="securementEncryptionCrypto"> 
            <ref bean="keystore"/> 
        </property>
</bean>
 <!-- keystore -->
<bean id="keystore" class="org.springframework.ws.soap.security.wss4j.support.CryptoFactoryBean"> 
          <property name="keyStorePassword" value="password"/> 
          <property name="keyStoreLocation" value="WEB-INF/MyTruststore.jks"/> 
</bean>
<!-- interceptors -->
<sws:interceptors> 
<ref bean="wss4jSecurityInterceptor"/> 
<bean id="validatingInterceptor" 
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor"> 
  <property name="schema" value="/WEB-INF/person.xsd"/>
  <property name="validateRequest" value="true"/> 
  <property name="validateResponse" value="true"/> 
</bean> 
    <bean id ="loggingInterceptor"    class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"> 
    </bean> 
    </sws:interceptors>
Run Code Online (Sandbox Code Playgroud)

客户端基本上使用相同的配置,除了他使用服务器公钥进行加密,以及他的私钥用于解密.

我想,密钥库是可以的,因为签名工作正常...当我添加加密操作时,一切都崩溃了,服务器日志的一部分说:

DEBUG [org.springframework.ws.server.MessageTracing.recei ved] - Received request [SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#}EncryptedData]
DEBUG [org.springframework.ws.server.endpoint.mapping.Pay loadRootAnnotationMethodEndpointMapping] - Looking up endpoint for [{http://www.w3.org/2001/04/xmlenc#}EncryptedData]
DEBUG [org.springframework.ws.soap.server.SoapMessageDisp atcher] - Endpoint mapping [org.springframework.ws.server.endpoint.mapping.Pay loadRootAnnotationMethodEndpointMapping@30a14083] has no mapping for request
...
No endpoint mapping found for [SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#}EncryptedData]
org.springframework.ws.client.WebServiceTransportE xception: Not Found [404]
...

我想我必须以某种方式指示ws在开始寻找消息的端点之前解密SOAP主体,但我不知道如何.建议?

Vir*_*oll 7

由于你的评论很有帮助,但有点不完整,我拍了一些回答更多细节.

在spring教程中,使用@PayloadRoot注释端点方法: @PayloadRoot(localPart = "orderInput", namespace = "http://samples")

当soap消息未加密时,这可以正常工作.PayloadRootAnnotationMethodEndpointMapping能够将soap消息映射到相应的方法.

当soap消息被加密时,PayloadRootAnnotationMethodEndpointMapping无法映射soap消息,因为安全拦截器还没有时间来解密它.解决方案是用@SoapAction替换@PayloadRoot.

收到soap消息后,spring-ws首先调用PayloadRootAnnotationMethodEndpointMapping,然后调用SoapActionAnnotationMethodEndpointMapping.您可以使用它们以便与非spring客户端完全兼容(例如轴或.net):

@PayloadRoot(localPart = "orderInput", namespace = "http://samples")
@SoapAction("http://samples/order") 
Run Code Online (Sandbox Code Playgroud)

最后但并非最不重要:如果您使用带有安全肥皂消息的spring客户端,spring不会自动发送soap动作.您的服务器将无法使用适当的操作映射soap消息.为了解决这个问题,您应该使用WebServiceMessageCallback:

ClientMessageCallBack callBack = new ClientMessageCallBack(
"http://samples/order");                    
Object output = wsTemplate.marshalSendAndReceive(inputObject, callBack);
Run Code Online (Sandbox Code Playgroud)

ClientMessageCallBack类所在的位置

public final class ClientMessageCallBack 
    implements WebServiceMessageCallback {

    /**the soapAction to be appended to the soap message.*/
    private String soapAction;

    /**constructor.
     * @param action the soapAction to be set.*/
    public ClientMessageCallBack(final String action) {
        this.soapAction = action;
    }

    @Override
    public void doWithMessage(final WebServiceMessage message) 
            throws IOException, TransformerException {

        if (message instanceof SoapMessage) {
            SoapMessage soapMessage = (SoapMessage) message;
            soapMessage.setSoapAction(soapAction);
        }

    }
}
Run Code Online (Sandbox Code Playgroud)