0

I'm using CXF 3.1.5, trying to send a request to a STS server, the STS server has a policy, the related part is as following

<wsp:Policy>
    <sp:RequireThumbprintReference />
    <sp:WssX509V3Token10 />
</wsp:Policy>

so in the request CXF sends to the STS server, the signature key looks like that:

<wsse:SecurityTokenReference wsu:Id="...">
    <wsse:KeyIdentifier EncodingType="..."ValueType="...#ThumbprintSHA1">...</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>

but I want to change the SecurityTokenReference into that

<wsse:SecurityTokenReference>
    <wsse:Reference URI="..." ValueType="...#**X509v3**"/>
</wsse:SecurityTokenReference>

it refers to the BinarySecurityToken which is a X.509 Certificate

So what should I do? I found something about PolicyBasedWSS4JOutInterceptor and PolicyBasedWSS4JInInterceptor, but don't known how they works.

Thanks a lots!

Lahiru Jayathilake
  • 601
  • 2
  • 10
  • 28
Jason
  • 64
  • 8

2 Answers2

1

You need a certificate issued by a CA accepted by your server to sign the SOAP request. You can use CXF with WSS4JOutInterceptor

This is the configuration to use WSS4J with CXF. Omit the part of creating the keystore

Set WSS4J properties (adjust to your policy)

outProps.put("action", "Signature");
outProps.put("user", certificateAlias);
outProps.put("passwordType", "PasswordText");
outProps.put("signaturePropFile", propertiesFile);
outProps.put("signatureKeyIdentifier","DirectReference");
outProps.put("passwordCallbackRef",clientPasswordCallback);

propertiesFile contains the path to a properties file where is configured the path to the keystore

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=changeit
org.apache.ws.security.crypto.merlin.file=keystore.jks

ClientPasswordCallback performs a callback from wss4j to get the password of the certificate

public class ClientPasswordCallback implements CallbackHandler {
   String password = ...; //Configure the password

   public void handle(Callback[] callbacks) {
     for (int i = 0; i < callbacks.length; i++) {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
        pc.setPassword(password);
      }
   }
}

Configure the CXF client using the WebService port

Client client = ClientProxy.getClient(port);
Endpoint cxfEndpoint = client.getEndpoint();
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);

//Include LoggingOutInterceptor to log the soap message
cxfEndpoint.getOutInterceptors().add(new LoggingOutInterceptor());

And finally call your service

port.myService();   
pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • Thank you for such a detail reply! I implemented your solution, right now, I got another problem. in the request, some elements in soap header are duplicated, like wsse:BinarySecurityToken, – Jason Aug 18 '16 at 09:54
  • Why you have those elements at header? Remove the original header before `WSS4JOutInterceptor` is executed and let this interceptor to configure the SOAP header – pedrofb Aug 18 '16 at 10:04
  • It's added by ws-policy, I think when CXF resolve the policy, those elements are added automatically. I don't know how to intercept the process. basically that's the problem. the problem is when CXF adds the element wsse:SecurityTokenReference according to the policy, it uses wsse:KeyIdentifier under it, but I want it to use wsse:Reference. if it's possible to remove something first, I think it's okay too. – Jason Aug 18 '16 at 10:13
  • and I cannot change the policy. – Jason Aug 18 '16 at 10:14
  • Seems CXF PolicyOutInterceptor is adding the policy before yours. I think it can disabled using `` See http://cxf.apache.org/docs/wspconfiguration.html. If it does not works the alternative is configure an alternative policy file with ` – pedrofb Aug 18 '16 at 10:46
  • the first solution doesn't work, I'll try to use the second one. and another problem, the timestamp element is not signed, so how to sign it? I wrote properties.put("action", "Signature Timestamp") but doesn't work. – Jason Aug 19 '16 at 07:41
  • You need to change the order of actions `properties.put("action", "Timestamp Signature");` and include the nodes to sign `properties.put("signatureParts", "{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");` See https://ws.apache.org/wss4j/using.html – pedrofb Aug 19 '16 at 08:17
0

@pedrofb, thanks a lot for your help. unfortunately, I still got two BinarySecurityToken Elements and I couldn't use an alternative policy file.

but I found a solution here:How to get incoming & outgoing soap xml in a simple way using Apache CXF?

It provides a solution for me to edit the soap envelop right before CXF sends it out. It's not very good, but it's the best solution I got.

Community
  • 1
  • 1
Jason
  • 64
  • 8