Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is proper way to add encryption/decryption in spring-ws (wss4j)?

I have deployed 2 web apps, one representing web service and other representing ws client. When using SIGNING and TIMESTAMP-ing, everything works fine, client stamps message(but i think that he doesn't override the default 300s ttl), signs the message with his x509 cert, and sends it to ws. He, in the other hand, recives message and is able to valiadate timestamp and certificate/signature against clients trusted cert in his keystore.

Problem arises when i add Encrypt operation to my configuration. Client seems to be able to encrypt the message, but ws seems not to be intrested in decrypting the message. He just sees that there is no endpoint mapping for

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

and throws

WebServiceTransportException: Not Found [404] exception.

SO can someone explain what I need to do in order to achieve timestamping,signing with x509 and encryption, again with x509?

part of server 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>

Client basicly uses the same config, except that he uses server public key for encryption, and his private key for decryption.

Keystores are ok, i guess, because signing works ok...Everything juust falls apart when i add Encrypt action, part of server log says:

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]
...

I think I must somehow instruct ws to decrypt SOAP body before it starts to look for an endpoint for message,but I don't know how. Suggestions?

like image 838
mare Avatar asked Jul 15 '11 09:07

mare


1 Answers

Since your comments were helpful but kind of incomplete, I took a shoot of answering with a bit more of a detail.

In the spring tutorial, the endpoint method is annotated with @PayloadRoot: @PayloadRoot(localPart = "orderInput", namespace = "http://samples")

This works fine when the soap message is not encrypted. PayloadRootAnnotationMethodEndpointMapping is able to map to soap message to the corresponding method.

When the soap message is encrypted, the PayloadRootAnnotationMethodEndpointMapping is unable to map the soap message because The security interceptor did not have yet the time to decipher it. The solution is to replace @PayloadRoot with @SoapAction.

When a soap message is received, spring-ws calls first the PayloadRootAnnotationMethodEndpointMapping then SoapActionAnnotationMethodEndpointMapping. You can use both in order to be full compatible with non-spring client (axis for example or .net):

@PayloadRoot(localPart = "orderInput", namespace = "http://samples")
@SoapAction("http://samples/order") 

Last but not least: If you are using a spring client with secured soap message, spring does not send soap action automatically. Your server will not be able to map the soap message with the appropriate action. In order to solve this problem, you should use a WebServiceMessageCallback:

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

where ClientMessageCallBack class is

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

    }
}
like image 190
VirtualTroll Avatar answered Oct 06 '22 16:10

VirtualTroll