I want to add a binary signature token (BST) to my WSDL-generated SOAP messages, but when I explicitly set WSHandlerConstants.SIG_KEY_ID to "DirectReference" instead of omitting the line of code, my STAX interceptor doesn't generate an XML of the SOAP message anymore (gives a null). When I'm not using "DirectReference" and leave it as default, my generated XML SOAP message contains a <ds:X509IssuerSerial> tag. This is the code:
SomeWsdlWebService service = new SomeWsdlWebService();
SomeWebServicePort port = service.SomeWebServicePort();
Client client = ClientProxy.getClient(port);
Endpoint endpoint = client.getEndpoint();
Map<String, Object> props = new HashMap<String, Object>();
props.put(WSHandlerConstants.ACTION, WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.TIMESTAMP);
props.put(WSHandlerConstants.USER, "EXAMPLE_ALIAS");
props.put(WSHandlerConstants.PW_CALLBACK_CLASS, CallbackPasswordHandler.class.getName());
props.put(WSHandlerConstants.SIG_PROP_FILE, "client.properties");
props.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
// Unsure if this is needed
// props.put(WSHandlerConstants.SIGNATURE_PARTS, "{}{http://schemas.xmlsoap.org/soap/envelope/}Body;{}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}BinarySecurityToken");
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(props);
endpoint.getOutInterceptors().add(wssOut);
EchoBuyerClient echoClient = new EchoClient(port);
MessageAckType messageAckType = echoBuyerClient.sendEchoBuyerMsg("test");
The client.properites file:
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=EXAMPLE_PASSWORD
org.apache.ws.security.crypto.merlin.keystore.alias=EXAMPLE_ALIAS
org.apache.ws.security.crypto.merlin.file=./certs/EXAMPLE_JKS.jks
Obviously, names and values are placeholders. I've verified that each entry is being correctly loaded. The JKS contains multiple certificates and a private key. Using the same JKS in a separate test project, the following code works flawlessly:
WSSecSignature signature = new WSSecSignature();
WSSecHeader header = new WSSecHeader();
WSSecTimestamp timestamp = new WSSecTimestamp();
Document document = xmlToDoc(message);
header.setMustUnderstand(true);
signature.setSignatureAlgorithm(WSConstants.C14N_EXCL_OMIT_COMMENTS);
signature.setSignatureAlgorithm(WSConstants.RSA);
signature.setUserInfo("EXAMPLE_ALIAS", "EXAMPLE_PASSWORD");
signature.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
try {
header.insertSecurityHeader(document);
timestamp.build(document, header);
signature.build(document, crypto, header);
} catch (WSSecurityException e) {
throw e;
}
Finally, don't know if this is relevant, but I'll list my Maven dependencies (had massive issues with dependency compatibility):
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-security</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.2.4</version>
</dependency>
</dependencies>
Considering I've built the aforementioned webservice through a WSDL file, I'd prefer to use apache cxf interceptors instead of manually modifying XML elements. However, I'm willing to do if it's the only way.
Using the debugger, I tried following the flow of the program and I've noticed usually there's a lot of null values involved. Honestly, I have no idea what I'm doing wrong here; a lot of other examples I've seen online are simpler than what I provided yet they work.