I'm working on a Spring-WS project and I'm trying to consume a certain SOAP service but I'm getting some issues with the request's Header tag.
PS: I ran the same request on SOAP UI and it works perfectly.
This is the code I ran:
JAXBElement<ChangeOtherIDsRequestType> request = createRequestBody();
WebServiceTemplate template = new WebServiceTemplate(marshaller);
template.setDefaultUri(URI);
@SuppressWarnings({ "unchecked" })
JAXBElement<ChangeOtherIDsResponseType> response = (JAXBElement<ChangeOtherIDsResponseType>) template
.marshalSendAndReceive(request, new WebServiceMessageCallback() {
@Override
public void doWithMessage(WebServiceMessage message) {
Instant instant = Instant.now();
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) message;
SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
try {
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPHeader soapHeader = soapEnvelope.getHeader();
Name headerElementName = soapEnvelope.createName("Security", "wsse",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
// Add "Security" soapHeaderElement to soapHeader
SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(headerElementName);
soapHeaderElement.setMustUnderstand(true);
soapHeaderElement.addNamespaceDeclaration("wsu",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
// Add usernameToken to "Security" soapHeaderElement
SOAPElement usernameTokenSOAPElement = soapHeaderElement.addChildElement("UsernameToken",
"wsse");
// Add username to usernameToken
QName userQname = soapHeaderElement.createQName("Username", "wsse");
SOAPElement userNameSOAPElement = usernameTokenSOAPElement.addChildElement(userQname);
userNameSOAPElement.addTextNode("username");
// Add password to usernameToken
QName passwordQname = usernameTokenSOAPElement.createQName("Password", "wsse");
SOAPElement passwordSOAPElement = usernameTokenSOAPElement.addChildElement("Password");
passwordSOAPElement.setAttribute("Type",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
passwordSOAPElement.addTextNode("password");
// Add Nonce to usernameToken.
QName nonceQname = soapHeaderElement.createQName("Nonce", "wsse");
SOAPElement nonceSOAPElement = usernameTokenSOAPElement.addChildElement("Nonce");
nonceSOAPElement.setAttribute("EncodingType",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
// Add Created to usernameToken.
QName createdQname = soapHeaderElement.createQName("Created", "wsu");
SOAPElement createdElement = usernameTokenSOAPElement.addChildElement(createdQname);
createdElement.addTextNode(instant.toString());
} catch (SOAPException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
});
template.marshalSendAndReceive(URI, request);
This code is supposed to add the Header tag in the request and it serves to authenticate the user through "username" and "password".
The result I'm expecting is the same that is generated by SOAP UI for the same request. The result is this:
<SOAP-ENV:Header>
<wsse:Security SOAP-ENV:mustUnderstand="1" 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">
<wsse:UsernameToken wsu:Id="UsernameToken-C17C5A667A3F11A8DA153735499778322">
<wsse:Username>username</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">Tl6jznnHitsSE9F16FWTsw==</wsse:Nonce>
<wsu:Created>2018-09-19T11:03:17.783Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
But the result I'm getting looks like this:
<SOAP-ENV: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" SOAP-ENV:mustUnderstand="1">
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</Password>
<Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"> </Nonce>
<wsu:Created>2018-09-19T11:02:21.918Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
Let's see that there are some things that are missing in my result such as:
I faced some issues when trying to fix these things but I still have some problems:
Last resort, is there another way to mock the SOAP UI request ?
Thanks in advance.
You are trying to shoehorn security into your request whereas there is an interceptor and default way of doing that. Configure the Wss4jSecurityInterceptor
for your WebServiceTemplate
.
Something like the following should do the trick.
@Bean
public Wss4jSecurityInterceptor securityInterceptor() {
Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
interceptor.setSecurementUsername("username");
interceptor.setSecurementPassword("password");
interceptor.setSecurementUsernameTokenNonce(true);
interceptor.setSecurementActions("UsernameToken Timestamp");
return interceptor;
}
Then inject this into your WebServiceTemplate
. That should add the needed headers without you having to do anything else. Ideally you would configure the WebServiceTemplate
once and reuse it.
@Bean
public WebServiceTemplate webServiceTemplate(Marshaller marshaller) {
WebServiceTemplate wsTemplate = new WebServiceTemplate(marshaller);
wsTemplate.setInterceptors(new ClientInterceptor[]{ securityInterceptor() });
return wsTemplate;
}
Then use the pre configured WebServiceTemplate
in your code.