使用Wss4jSecurityInterceptor会抛出WRONG_DOCUMENT_ERR:与创建该节点的节点不同,该节点在另一文档中使用

时间:2019-02-13 09:47:02

标签: java spring-boot soap-client

我正在将应用程序升级到Java 11和Spring boot 2.1.2,并在尝试通过SOAP与外部合作伙伴通信时遇到以下错误。导致此问题的原因是Wss4jSecurityInterceptor。在运行Java 8和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和Spring boot 2.1.2升级

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");
}

}

3 个答案:

答案 0 :(得分:5)

显然,spring引入了wss4j-ws-security-dom中的一个错误。2.2.0。

我更新到最新的版本2.2.2,并且有效:

答案 1 :(得分:2)

也可以降级到2.0.6并开始工作。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web-services</artifactId>
    <version>2.0.6.RELEASE</version>
</dependency>

答案 2 :(得分:0)

与新版本的saaj-impl(v1.4.0或更高版本)一起使用时,也会出现问题。

<dependency>
    <groupId>com.sun.xml.messaging.saaj</groupId>
    <artifactId>saaj-impl</artifactId>
    <version>1.3.28</version>
</dependency>