title: Is there a way to add a WSS4J interceptor for signing SOAP reqeust when using WS-SecurityPolicy approach?
body: <p>I am trying to create a <code>SOAP</code> client that follows <code>WS-SecurityPolicy</code>. The service requires <code>Timestamp</code>, <code>UsernameToken</code> and <code>Body</code> to be digitally signed in addition to encryption in the <code>SOAP</code> request.</p>
  
  <p>The Keystore for signing the request is not available as a file (<code>jks</code>/<code>pfx</code>). I am using a USB based token from which I can load the Keystore programmatically. The USB token does not allow export to a <code>pfx</code> file. </p>
  
  <p>Is there a way that I can override the Keystore used for signing using interceptors while using policy-based approach for WS-Security?</p>
  
  <p>Spring config for WS-SecurityPolicy is similar to the following:    </p>
  
  <pre class="lang-java prettyprint-override"><code>&lt;jaxws:client name="{http://cxf.apache.org}MyPortName"
        createdFromAPI="true"&gt;
        &lt;jaxws:properties&gt;
           &lt;entry key="security.callback-handler"
               value="interop.client.KeystorePasswordCallback"/&gt;
           &lt;entry key="security.signature.properties"
               value="etc/client.properties"/&gt;
           &lt;entry key="security.encryption.properties"
               value="etc/service.properties"/&gt;
           &lt;entry key="security.encryption.username"
               value="servicekeyalias"/&gt;
        &lt;/jaxws:properties&gt;
  &lt;/jaxws:client&gt;
  </code></pre>
  
  <p>Can this be configured along with an interceptor that will override the signature part? Instead of using the <code>security.signature.properties</code> in the above config I'd like to use an interceptor like below. Note: The code below uses libraries from <code>Spring-WS</code>. I am looking for analogous libs/classes from apache cxf that can be used for this case.</p>
  
  <pre class="lang-java prettyprint-override"><code>@Bean
  public Wss4jSecurityInterceptor securityInterceptor() throws Exception {
  
      Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
  
      String secAction = String.join(" ", WSHandlerConstants.USERNAME_TOKEN,WSHandlerConstants.TIMESTAMP,WSHandlerConstants.SIGNATURE);
  
      // set security actions
      securityInterceptor.setSecurementActions(secAction);
      // sign the request
      securityInterceptor.setSecurementUsername(config.getUsername());
      securityInterceptor.setSecurementPassword(config.getPassword());
      securityInterceptor.setSecurementPasswordType(WSConstants.PW_TEXT);
      securityInterceptor.setSecurementUsernameTokenNonce(true);
      securityInterceptor.setSecurementUsernameTokenCreated(false);
  
      Properties properties = new Properties();
      properties.setProperty("org.apache.ws.security.crypto.provider", "org.apache.wss4j.common.crypto.Merlin");
  
      Merlin crypto = (Merlin)CryptoFactory.getInstance(properties);
      crypto.setKeyStore(getKeyStore()); //This is my keystore fetched programmatically
      securityInterceptor.setSecurementSignatureKeyIdentifier("DirectReference");
      securityInterceptor.setSecurementSignatureCrypto(crypto);
  
      securityInterceptor.setSecurementSignatureParts("{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;" +
      "{Element}{http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/ws-securitypolicy.xsd}UsernameToken;" +
      "{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body");
  
      return securityInterceptor;
  }
  </code></pre>
  
  <p>I have tried using <code>Spring-WS</code>to implement the soap client using <code>Wss4jSecurityInterceptor</code> shown above. With that, the spring config shown first is not needed. </p>
  
  <pre class="lang-java prettyprint-override"><code>CommVerRequest request = new CommVerRequest();
  
              prepareRequest(pan, request);
  
              SOAPClient client = soapClientConfig.getSoapClient();
              CommVerResponse callResponse = client.call(request);
  
              /*CommVerResponse callResponse = port.verifyDetails(request);*/
  
  
              validationResponse = prepareResponse(callResponse);
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>@Bean
      public SOAPClient getSoapClient() throws Exception {
          SOAPClient soapClient = new SOAPClient();
          soapClient.setDefaultUri("https://foo.bar/CommVerService");
          ClientInterceptor[] interceptors = new ClientInterceptor[]{securityInterceptor()};
          soapClient.setInterceptors(interceptors);
  
          soapClient.setMarshaller(marshaller());
          soapClient.setUnmarshaller(marshaller());
  
          return soapClient;
      }
  </code></pre>
  
  <pre class="lang-java prettyprint-override"><code>@Bean
      public Jaxb2Marshaller marshaller() {
          Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
          marshaller.setContextPath("flatStub");
          return marshaller;
      }
  </code></pre>
  
  <p>However while calling the web service I get this error. </p>
  
  <pre class="lang-java prettyprint-override"><code>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 com.sun.org.apache.xerces.internal.dom.ParentNode.internalInsertBefore(ParentNode.java:357) ~[na:1.8.0_191]
      at com.sun.org.apache.xerces.internal.dom.ParentNode.insertBefore(ParentNode.java:288) ~[na:1.8.0_191]
      at com.sun.org.apache.xerces.internal.dom.NodeImpl.appendChild(NodeImpl.java:237) ~[na:1.8.0_191]
      at org.apache.wss4j.dom.util.WSSecurityUtil.prependChildElement(WSSecurityUtil.java:314) ~[wss4j-ws-security-dom-2.2.0.jar:2.2.0]
      at org.apache.wss4j.dom.util.WSSecurityUtil.findWsseSecurityHeaderBlock(WSSecurityUtil.java:435) ~[wss4j-ws-security-dom-2.2.0.jar:2.2.0]
      at org.apache.wss4j.dom.message.WSSecHeader.insertSecurityHeader(WSSecHeader.java:165) ~[wss4j-ws-security-dom-2.2.0.jar:2.2.0]
      at org.apache.wss4j.dom.handler.WSHandler.doSenderAction(WSHandler.java:117) ~[wss4j-ws-security-dom-2.2.0.jar:2.2.0]
      at org.springframework.ws.soap.security.wss4j2.Wss4jHandler.doSenderAction(Wss4jHandler.java:63) ~[spring-ws-security-3.0.6.RELEASE.jar:na]
      at org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor.secureMessage(Wss4jSecurityInterceptor.java:574) ~[spring-ws-security-3.0.6.RELEASE.jar:na]
      at org.springframework.ws.soap.security.AbstractWsSecurityInterceptor.handleRequest(AbstractWsSecurityInterceptor.java:210) ~[spring-ws-security-3.0.6.RELEASE.jar:na]
      at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:597) ~[spring-ws-core-3.0.7.RELEASE.jar:na]
      at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555) ~[spring-ws-core-3.0.7.RELEASE.jar:na]
      at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390) ~[spring-ws-core-3.0.7.RELEASE.jar:na]
      at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:383) ~[spring-ws-core-3.0.7.RELEASE.jar:na]
      at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:373) ~[spring-ws-core-3.0.7.RELEASE.jar:na
  </code></pre>