Spring-WS Wss4jSecurityInterceptor没有解密收到的消息

时间:2015-08-09 18:14:35

标签: spring cxf spring-ws ws-security

我的情况如下:

  1. 我使用CXF写了SOAP服务
  2. 我写了两个SOAP客户端 - 一个使用CXF,另一个使用Spring-WS
  3. 我设置了WSSecurity:"时间戳签名加密"双方的行动(客户/服务器)
  4. CXF客户端就像魅力一样,但是Spring-WS无法解密响应。
  5. 服务器端在与CXF-client和Spring-client交互时是正常的(它主要是解密,验证签名,处理请求,签名,加密和最终发送响应)。

    代码:

    CXF客户:

    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    
    <bean id="inbound-logging" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
    <bean id="outbound-logging" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
    
    <jaxws:client id="helloClient" serviceClass="com.example.HelloWorld"
        address="http://localhost:8282/HelloWorld">
        <jaxws:inInterceptors>
            <ref bean="inbound-logging" />
            <ref bean="inbound-security" />
        </jaxws:inInterceptors>
        <jaxws:outInterceptors>
            <ref bean="outbound-logging" />
            <ref bean="outbound-security" />
        </jaxws:outInterceptors>
    </jaxws:client>
    
    <bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor" id="outbound-security">
        <constructor-arg>
            <map>
                <entry key="action" value="Timestamp Signature Encrypt"/>
                <entry key="user" value="client"/>              
                <entry key="signaturePropFile" value="config/client-crypto.properties"/>
                <entry key="encryptionPropFile" value="config/client-crypto.properties"/>
                <entry key="signatureKeyIdentifier" value="DirectReference"/>
                <entry key="encryptionUser" value="server"/>
                <entry key="passwordCallbackClass" value="org.mydomain.ClientPasswordCallback"/>
                <entry key="signatureParts" value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
                <entry key="encryptionParts" value="{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
                <entry key="encryptionSymAlgorithm" value="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
            </map>
        </constructor-arg>
    </bean>
    
    <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" id="inbound-security">
        <constructor-arg>
            <map>
                <entry key="action" value="Timestamp Signature Encrypt"/>
                <entry key="signaturePropFile" value="config/client-crypto.properties"/>
                <entry key="decryptionPropFile" value="config/client-crypto.properties"/>
                <entry key="passwordCallbackClass" value="org.mydomain.CustomPasswordCallback"/>
            </map>
        </constructor-arg>
    </bean>
    

    Spring-WS客户端 - wss-interceptor:

    @Bean
    public Wss4jSecurityInterceptor wssInterceptor(
            @Qualifier("cryptoFactoryBean") CryptoFactoryBean cryptoFactoryBean,
            @Qualifier("signValidCryptoFactoryBean") CryptoFactoryBean signValidCryptoFactoryBean) throws Exception {
    
        Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
    
        // outgoing securement
    
        interceptor.setSecurementUsername("client");
        interceptor.setSecurementPassword("123456");
        interceptor.setSecurementSignatureKeyIdentifier("DirectReference");
        interceptor.setSecurementActions("Timestamp Signature Encrypt");
    
        interceptor.setSecurementSignatureCrypto(cryptoFactoryBean.getObject());
        interceptor.setSecurementSignatureParts(
                "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;" +
                "{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"
        );
    
        interceptor.setSecurementEncryptionCrypto(cryptoFactoryBean.getObject());
        interceptor.setSecurementEncryptionUser("server");
        interceptor.setSecurementEncryptionSymAlgorithm("http://www.w3.org/2001/04/xmlenc#tripledes-cbc");
        interceptor.setSecurementEncryptionParts(
                "{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;" +
                "{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"
        );
    
        // incoming validation:
    
        interceptor.setValidationActions("Timestamp Signature Encrypt");
        interceptor.setValidationDecryptionCrypto(cryptoFactoryBean.getObject());
        interceptor.setValidationSignatureCrypto(signValidCryptoFactoryBean.getObject());
    
        return interceptor;
    }
    

    记录级别设置为debug。结果如下:

    (... - 与加密数据befrore发送相关的日志) 2015-08-09 19:09:45.181 DEBUG WSSecEncrypt:258 - 加密完成。 2015-08-09 19:09:45.182 DEBUG已发送:620 - 已发送请求[SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#} EncryptedData] 2015-08-09 19:09:45.223 DEBUG收到:678 - 收到回复[SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#} EncryptedData]请求[SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#} EncryptedData] 2015-08-09 19:09:45.224 DEBUG Wss4jSecurityInterceptor:562 - 通过操作验证消息[SaajSoapMessage {http://www.w3.org/2001/04/xmlenc#} EncryptedData] [时间戳签名加密] 2015-08-09 19:09:45.225 DEBUG WSSecurityEngine:236 - 输入processSecurityHeader() 2015-08-09 19:09:45.229 WARN Wss4jSecurityInterceptor:281 - 无法验证请求:未找到WS-Security标头 2015-08-09 19:09:45.229 DEBUG Wss4jSecurityInterceptor:288 - 没有异常解析器存在,造成基本的肥皂故障 线程&#34; main&#34;中的例外情况org.springframework.oxm.UnmarshallingFailureException:JAXB解组异常;嵌套异常是javax.xml.bind.UnmarshalException:意外元素(uri:&#34; http://schemas.xmlsoap.org/soap/envelope/&#34;,local:&#34; Fault&#34;)。预期元素是&lt; {} helloRequest&gt;,&lt; {{{}}} helloResponse&gt;     在org.springframework.oxm.jaxb.Jaxb2Marshaller.convertJaxbException(Jaxb2Marshaller.java:809)     在org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:730)     在org.springframework.ws.support.MarshallingUtils.unmarshal(MarshallingUtils.java:62)     在org.springframework.ws.client.core.WebServiceTemplate $ 3.extractData(WebServiceTemplate.java:407)     在org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:596)     在org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:537)     在org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:384)     在org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:374)     在client.Main.main(Main.java:39)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     在java.lang.reflect.Method.invoke(Method.java:497)     在com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 引起:javax.xml.bind.UnmarshalException:意外元素(uri:&#34; http://example.com&#34;,local:&#34; Fault&#34;)。预期元素是&lt; {} helloRequest&gt;,&lt; {{{}}} helloResponse&gt;     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:109)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext $ DefaultRootLoader.childElement(UnmarshallingContext.java:1131)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:556)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:60)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153)     在com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:229)     在com.sun.xml.internal.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:112)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:354)     at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:337)     在javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:127)     在org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:726)     ......还有12个

    看起来Spring正在尝试处理响应而不先解密它。

    我找到了问题的解决方案。我没有设置密码回调,所以wss4j-interceptor无法解密响应。以下是解决问题的代码:

    KeyStoreCallbackHandler keyStoreCallbackHandler = new KeyStoreCallbackHandler();
    keyStoreCallbackHandler.setPrivateKeyPassword("123456");
    interceptor.setValidationCallbackHandler(keyStoreCallbackHandler);
    

2 个答案:

答案 0 :(得分:0)

您收到对方的肥皂故障。肥皂故障消息未加密,这就是 Wss4jSecurityInterceptor 抱怨ws-security标头的原因。

2015-08-09 19:09:45.229 WARN  Wss4jSecurityInterceptor:281 - 
**Could not validate request: No WS-Security header found**

似乎消息的处理在它应该正常停止的同时继续进行。 JAXB marshaller抱怨(uri:&#34; http://schemas.xmlsoap.org/soap/envelope/&#34;,local:&#34; Fault&#34;)不是来自上下文。

2015-08-09 19:09:45.229 DEBUG Wss4jSecurityInterceptor:288 - 
No exception resolver present, creating basic soap fault
Exception in thread "main"
 org.springframework.oxm.UnmarshallingFailureException: 
JAXB unmarshalling exception; nested exception is
javax.xml.bind.UnmarshalException: unexpected element
 (uri:"http://schemas.xmlsoap.org/soap/envelope/", local:"Fault"). 
Expected elements are <{}helloRequest>,<{http://example.com}helloResponse>

我会推荐以下内容:

  1. 记录肥皂故障以确定对方需要什么
  2. 每当收到肥皂故障时,您应该停止处理请求

答案 1 :(得分:0)

没有为拦截器定义KeyStoreCallbackHandler - 就是这种情况。初始帖子中的适当代码。