soapcxfsoap-clientws-securitycxf-client

Apache CXF WS-Security: "Security processing failed (actions mismatch)


I am trying to generate a SOAP request using Apache CXF WS-Security similar to the following request(I generated it using SoapUI) :

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                       xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <ds:Signature Id="SIG-xxx" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:SignedInfo>
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                        <ec:InclusiveNamespaces PrefixList="soapenv"
                                                xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </ds:CanonicalizationMethod>
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                    <ds:Reference URI="#xxxx">
                        <ds:Transforms>
                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                                <ec:InclusiveNamespaces PrefixList=""
                                                        xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                            </ds:Transform>
                        </ds:Transforms>
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <ds:DigestValue>xxxx</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>xxxx
                </ds:SignatureValue>
                <ds:KeyInfo Id="xxxxx">
                    <wsse:SecurityTokenReference wsu:Id="xxxxx">
                        <wsse:KeyIdentifier
                                EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
                                ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
                    xxxx
                        </wsse:KeyIdentifier>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
            </ds:Signature>
        </wsse:Security>

    </soapenv:Header>
    <soapenv:Body wsu:Id="id-xxx"
                  xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <v3:AccountRequest
                xmlns:v3="http://services.mysiste.com/V3">
            <Request>
                <SearchParametersBlock>
                    <MktCd>
                        <MktCdData>
                            <MktCd>US</MktCd>
                        </MktCdData>
                    </MktCd>
                </SearchParametersBlock>
            </Request>
        </v3:AccountRequest>
    </soapenv:Body>
</soapenv:Envelope>

I am using the following code to generate my Java client :

 Properties signatureProperties = new Properties();
        signatureProperties.put("org.apache.ws.security.crypto.provider", 
    "org.apache.ws.security.components.crypto.Merlin");
        signatureProperties.put("org.apache.ws.security.crypto.merlin.keystore.type", 
  "jks");
        signatureProperties.put("org.apache.ws.security.crypto.merlin.keystore.file", 
   "server.jks");  
        signatureProperties.put("org.apache.ws.security.crypto.merlin.keystore.password", 
    "password");  
        signatureProperties.put("org.apache.ws.security.crypto.merlin.keystore.alias", 
   "myAlias");      
        
signatureProperties.put("org.apache.ws.security.crypto.merlin.keystore.private.password", "password"); 

        Map<String,Object> outProps = new HashMap<>();
        outProps.put(WSHandlerConstants.USER, "myAlias");
        outProps.put(WSHandlerConstants.SIG_KEY_ID, "X509KeyIdentifier");
        outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.SIGNATURE);

        outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ServiceKeystorePasswordCallback.class.getName());
        outProps.put(WSHandlerConstants.SIG_ALGO, "http://www.w3.org/2000/09/xmldsig#sha1");
        outProps.put(WSHandlerConstants.SIG_C14N_ALGO, "http://www.w3.org/2001/10/xml-exc-c14n#");
        outProps.put(WSHandlerConstants.SIG_PROP_REF_ID, "signatureProperties");
        outProps.put("signatureProperties", signatureProperties);


        org.apache.cxf.endpoint.Client client = ClientProxy.getClient(this.service);
        org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();

        WSS4JInInterceptor wssIn = new WSS4JInInterceptor(outProps);
        cxfEndpoint.getOutInterceptors().add(wssIn);

But I am experiencing the following error : "Security processing failed (actions mismatch)"

I traced the exception and it boils down to the following snippet

 if (!checkReceiverResultsAnyOrder(wsResult, actions)) {
            LOG.warning("Security processing failed (actions mismatch)");
            throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
        }

Where actions != wsResult(it is empty)

I am not sure how to populate wsResult in this case. Any help would be greatly appreciated


Solution

  • Instead of WSS4JInInterceptor, I had to use a WSS4JOutInterceptor

     WSS4JOutInterceptor outInterceptor = new WSS4JOutInterceptor(outProps);
     cxfEndpoint.getOutInterceptors().add(outInterceptor);