I am upgrading my application to Java 11 and Spring boot 2.1.2 and running into following error when trying to communicate over SOAP to an external partner. It is the Wss4jSecurityInterceptor that causes this issue. It work before when running java 8 and Spring Boot 1
REQUEST: ExampleSoapClient.sendRequest([javax.xml.bind.JAXBElement@5bba179f]).
ERROR: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.
org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.
at java.xml/com.sun.org.apache.xerces.internal.dom.ParentNode.internalInsertBefore(ParentNode.java:356)
at java.xml/com.sun.org.apache.xerces.internal.dom.ParentNode.insertBefore(ParentNode.java:287)
at java.xml/com.sun.org.apache.xerces.internal.dom.NodeImpl.appendChild(NodeImpl.java:237)
at org.apache.wss4j.dom.util.WSSecurityUtil.prependChildElement(WSSecurityUtil.java:314)
at org.apache.wss4j.dom.util.WSSecurityUtil.findWsseSecurityHeaderBlock(WSSecurityUtil.java:435)
at org.apache.wss4j.dom.message.WSSecHeader.insertSecurityHeader(WSSecHeader.java:165)
at org.apache.wss4j.dom.handler.WSHandler.doSenderAction(WSHandler.java:117)
at org.springframework.ws.soap.security.wss4j2.Wss4jHandler.doSenderAction(Wss4jHandler.java:63)
at org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor.secureMessage(Wss4jSecurityInterceptor.java:574)
at org.springframework.ws.soap.security.AbstractWsSecurityInterceptor.handleRequest(AbstractWsSecurityInterceptor.java:210)
at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:597)
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:378)
at com.example.domain.integration.provider.ExampleSoapClient.sendRequest(ExampleportSoapClient.java:61)
java 11 and Spring boot 2.1.2 upgrade
import com.sun.xml.wss.impl.callback.PasswordCallback;
import com.sun.xml.wss.impl.callback.UsernameCallback;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor;
import org.springframework.ws.transport.http.ClientHttpRequestMessageSender;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
public class ExampleSoapClient extends WebServiceGatewaySupport {
private Wss4jSecurityInterceptor wss4jSecurityInterceptor;
public ExampleSoapClient(Wss4jSecurityInterceptor wss4jSecurityInterceptor) {
wss4jSecurityInterceptor = new Wss4jSecurityInterceptor();
wss4jSecurityInterceptor.setValidationCallbackHandler(new ExampleCredentialsCallbackHandler());
wss4jSecurityInterceptor.setSecurementActions(WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.USERNAME_TOKEN);
/* Default Password encoding is digest, that is not supported by EP hence need to set need to set following password type. */
wss4jSecurityInterceptor.setSecurementPasswordType(WSConstants.PASSWORD_TEXT);
wss4jSecurityInterceptor.setSecurementUsernameTokenNonce(false);
wss4jSecurityInterceptor.setSecurementUsername("username");
wss4jSecurityInterceptor.setSecurementPassword("password");
//Note! this will help our external mock to not need any security implementation
wss4jSecurityInterceptor.setSecurementMustUnderstand(false);
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(40000);
requestFactory.setReadTimeout(40000);
setMessageSender(new ClientHttpRequestMessageSender(requestFactory));
}
public Object sendRequest(Object request) {
final WebServiceTemplate webServiceTemplate = getWebServiceTemplate();
ClientInterceptor[] interceptors = new ClientInterceptor[1];
interceptors[0] = wss4jSecurityInterceptor;
webServiceTemplate.setInterceptors((interceptors));
final SubmitDocument submitDocument = createRequest(request);
final SubmitDocumentResponse submitDocumentResponse = (SubmitDocumentResponse) webServiceTemplate.marshalSendAndReceive(endpoint, submitDocument);
return response;
}
}
class ExampleCredentialsCallbackHandler implements CallbackHandler {
public ExampleCredentialsCallbackHandler() {
}
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof UsernameCallback) {
handleUsernameCallback((UsernameCallback) callback);
} else if (callback instanceof PasswordCallback) {
handlePasswordCallback((PasswordCallback) callback);
} else {
throw new UnsupportedCallbackException(callback);
}
}
}
private void handleUsernameCallback(UsernameCallback callback) {
callback.setUsername("username");
}
private void handlePasswordCallback(PasswordCallback callback) {
callback.setPassword("password");
}
}
There is also a problem when use with new version saaj-impl (v1.4.0 or higher).
<dependency>
<groupId>com.sun.xml.messaging.saaj</groupId>
<artifactId>saaj-impl</artifactId>
<version>1.3.28</version>
</dependency>
Apparently there is a bug in the wss4j-ws-security-dom that spring pulls in. 2.2.0.
I updated to latest version 2.2.2 and it worked:
Also can downgrade to 2.0.6 and work.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With