1
votes

I've been struggling with this problem for quite a bit of time, and have not been able to solve it yet, despite looking around everywhere.

Scenario details (code, config and other stuff is posted at the end):

  1. WCF Web Service (.NET 4), exposing two endpoints: one unsecured and one secured using Message Security and UserName authentication (using Membership infrastructure) -- No Transport Security.
  2. Both endpoints use MTOM encoding; all classed referred to by the WSDL are marked with the MessageContract attribute, and members with MessageBodyMember attribute.
  3. Configuration on WCF bindings has 'establishSecurityContext' and 'negotiateServiceCredential' set to false.
  4. WCF service protected with a self-signed certificate for encryption purposes.
  5. Attempting access from Java client using Apache CXF 2.5.1. I have setup the certificate into a KeyStore accesible from the classpath.

The results:

  1. Accessing the Web Service from a .NET client works fine
  2. Accessing the unsecured endpoint from Apache CXF works fine both with and without MTOM encoding.
  3. Accessing the secured endpoint (without MTOM) from Apache CXF works fine. CXF tracing indicates that the encryption/decryption process is carried on normally.
  4. Once MTOM was activated in WCF, the problem arose. We were able to determine that in the WCF side, the reception of the message, its processing and generation/encryption of the response happens normally.
  5. It is during the reception of the message in CXF that the problem happens. It looks to us that CXF is not deserializing the MTOM attachment properly before trying to decrypt the message; hence, the decryption logic founds that the message still has an element to decrypt in the response, but founds an empty element to decrypt and fails. We tried to add a RECEIVE phase interceptor to initialize attachments, to no avail (fails trying to find the boundary marker in the multipart response).
  6. Using Fiddler, we found that the response looks well formed, with an attachment referred

CODE/CONFIG/STUFF:

Web.Config (shortened for clarity):

  <system.serviceModel>
    <!-- Services -->
    <services>
      <service name="TestServices.Services.TestService" behaviorConfiguration="TestService.Basic">
        <!-- Plain (unsecured) endpoint -->
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="TestService.Basic" name="TestService.Basic"
                  contract="TestServices.Interfaces.ITestService" bindingNamespace="http://searchtechnologies.com/cpa/wcfinterop"/>
        <!-- Secure endpoint -->
        <endpoint address="/secure" binding="wsHttpBinding" bindingConfiguration="TestService.Secure" name="TestService.Secure"
                  contract="TestServices.Interfaces.ITestService" bindingNamespace="http://searchtechnologies.com/cpa/wcfinterop"/>
      </service>
    </services>
    <!-- Bindings -->
    <bindings>
      <wsHttpBinding>
        <binding name="TestService.Basic" messageEncoding="Mtom">
          <security mode="None">
            <message clientCredentialType="None"/>
            <transport clientCredentialType="None"/>
          </security>
        </binding>
        <binding name="TestService.Secure" messageEncoding="Mtom">
          <security mode="Message">
            <message clientCredentialType="UserName" establishSecurityContext="false" negotiateServiceCredential="false"/>
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <!-- Behaviors -->
    <behaviors>
      <serviceBehaviors>
        <behavior name="TestService.Basic">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceCredentials>
            <serviceCertificate storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" findValue="equiros-PC2.search.local"/>
            <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="SqlProvider"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>

The Java client code (portions omitted for clarity):

  private static void secureTest() {
    try {
      logger.debug("Secure test starting. Instatiating service");
      // service instantiation
      TestService service = new TestService();
      ITestService port = service.getTestServiceSecure();
      // request creation
      BasicRequest request = objectFactory.createBasicRequest();
      request.setStringData("String data");
      request.setIntegerData("Integer data");
      // setup logging
      setupInterceptors(port);
      // setup security & binding
      setupBinding(port);
      // service call
      logger.debug("Attempting service call");
      BasicResponse response = port.simpleOperation(request);
      logger.debug("Call success!!!");
      logger.debug(String.format("Response data: str: %1$s; int: %2$s",
          response.getStringData(), response.getIntegerData()));
    } catch (Exception e) {
      logger.error("Error during service invocation", e);
    }
  }

  private static void setupInterceptors(ITestService port) {
    Client proxy = JaxWsClientProxy.getClient(port);
    proxy.getInInterceptors().add(new LoggingInInterceptor());
    proxy.getOutInterceptors().add(new LoggingOutInterceptor());
  }

  private static void setupBinding(ITestService port) {
    javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider) port;
    SOAPBinding binding = (SOAPBinding) bp.getBinding();
    binding.setMTOMEnabled(true);
    Map<String, Object> context = bp.getRequestContext();
    context.put("ws-security.username", "systemadmin");
    context.put("ws-security.password", "Pass@word1");
    context.put("ws-security.encryption.properties",
        "clientKeystore.properties");
    context.put("ws-security.encryption.username", "serviceKey");
  }

The error trace (decryption phase only):

[main] DEBUG org.apache.ws.security.components.crypto.CryptoFactory  - Using Crypto Engine [class org.apache.ws.security.components.crypto.Merlin]
[main] DEBUG org.apache.ws.security.util.Loader  - Trying to find [clientKeystore.jks] using sun.misc.Launcher$AppClassLoader@2a340e class loader.
[main] DEBUG org.apache.ws.security.components.crypto.Merlin  - The KeyStore clientKeystore.jks of type jks has been loaded
[main] DEBUG org.apache.ws.security.processor.TimestampProcessor  - Found Timestamp list element
[main] DEBUG org.apache.ws.security.message.token.Timestamp  - Current time: 2012-02-07T22:52:22.852Z
[main] DEBUG org.apache.ws.security.message.token.Timestamp  - Timestamp created: 2012-02-07T22:52:22.641Z
[main] DEBUG org.apache.ws.security.message.token.Timestamp  - Timestamp expires: 2012-02-07T22:57:22.641Z
[main] DEBUG org.apache.ws.security.message.token.Timestamp  - Validation of Timestamp: Everything is ok
[main] DEBUG org.apache.ws.security.message.token.DerivedKeyToken  - DerivedKeyToken: created : element constructor
[main] DEBUG org.apache.ws.security.message.token.DerivedKeyToken  - DerivedKeyToken: created : element constructor
[main] DEBUG org.apache.ws.security.processor.ReferenceListProcessor  - Found reference list element
[main] DEBUG org.apache.ws.security.processor.ReferenceListProcessor  - Found data reference: _3
[main] DEBUG org.apache.ws.security.processor.X509Util  - Sym Enc Algo: http://www.w3.org/2001/04/xmlenc#aes256-cbc
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Getting XMLCipher with transformation
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Constructing XMLCipher...
[main] DEBUG org.apache.xml.security.algorithms.JCEMapper  - Request for URI http://www.w3.org/2001/04/xmlenc#aes256-cbc
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - cipher._algorithm = AES/CBC/ISO10126Padding
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Initializing XMLCipher...
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - opmode = DECRYPT_MODE
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Processing source element...
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypting element...
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypting to ByteArray...
[main] DEBUG org.apache.xml.security.utils.ElementProxy  - setElement("KeyInfo", "null")
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Encrypted octets:
x1eLqhngbuRTq2XJIkcTdzyu1UFb4eV0kwno04/w4yW0HiY6RyYa7OHqniV63aaxgZPxm0NOK2ZUgjggtkM0O9myJ6ZJOFxCLmqREjQMD+mFW+WuTSEZ5cgc3SFule3MmryqoStNLsmzM8t5yaT3drF1ctT7DJQnV6W858WwpD+Dw+WYmO0RaUlgsfbTnWiBvCZ8yyCzvgmZTMGr8y9LXnwaw+FsspReuMpcIOsqU9LE5u5uW5ZJglgn5cv/8XWikD3TwNzqL+7qAVN8R6WnXgUmb1DuX5lx4cyxlwcLnkfOQKbGrwGvKJUY47ohAgKH
[main] DEBUG org.apache.xml.security.algorithms.JCEMapper  - Request for URI http://www.w3.org/2001/04/xmlenc#aes256-cbc
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - JCE Algorithm = AES/CBC/ISO10126Padding
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypted octets:
<BasicResponse xmlns="http://searchtechnologies.com/cpa/wcfinterop/data"><DateTimeData>0001-01-02T00:00:00</DateTimeData><IntegerData>Integer data</IntegerData><StringData>String data</StringData></BasicResponse>
[main] DEBUG org.apache.ws.security.processor.ReferenceListProcessor  - Found data reference: _6
[main] DEBUG org.apache.ws.security.processor.X509Util  - Sym Enc Algo: http://www.w3.org/2001/04/xmlenc#aes256-cbc
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Getting XMLCipher with transformation
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Constructing XMLCipher...
[main] DEBUG org.apache.xml.security.algorithms.JCEMapper  - Request for URI http://www.w3.org/2001/04/xmlenc#aes256-cbc
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - cipher._algorithm = AES/CBC/ISO10126Padding
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Initializing XMLCipher...
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - opmode = DECRYPT_MODE
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Processing source element...
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypting element...
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypting to ByteArray...
[main] DEBUG org.apache.xml.security.utils.ElementProxy  - setElement("KeyInfo", "null")
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Encrypted octets:

[main] DEBUG org.apache.xml.security.algorithms.JCEMapper  - Request for URI http://www.w3.org/2001/04/xmlenc#aes256-cbc
[main] DEBUG org.apache.xml.security.encryption.XMLCipher  - JCE Algorithm = AES/CBC/ISO10126Padding
Feb 07, 2012 4:52:22 PM org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor handleMessage
WARNING: 
org.apache.ws.security.WSSecurityException: The signature or decryption was invalid
    at org.apache.ws.security.processor.ReferenceListProcessor.decryptEncryptedData(ReferenceListProcessor.java:298)
    at org.apache.ws.security.processor.ReferenceListProcessor.decryptDataRefEmbedded(ReferenceListProcessor.java:159)
    at org.apache.ws.security.processor.ReferenceListProcessor.handleReferenceList(ReferenceListProcessor.java:93)
    at org.apache.ws.security.processor.ReferenceListProcessor.handleToken(ReferenceListProcessor.java:60)
    at org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:396)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:249)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:85)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
    at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:799)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1627)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1494)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1402)
    at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:47)
    at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:195)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:649)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:533)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:463)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:366)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:319)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:88)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134)
    at $Proxy33.simpleOperation(Unknown Source)
    at com.searchtechnologies.wcfinterop.TestServiceClient.secureTest(TestServiceClient.java:74)
    at com.searchtechnologies.wcfinterop.TestServiceClient.main(TestServiceClient.java:32)
Caused by: java.lang.ArrayIndexOutOfBoundsException
    at java.lang.System.arraycopy(Native Method)
    at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(Unknown Source)
    at org.apache.xml.security.encryption.XMLCipher.decryptElement(Unknown Source)
    at org.apache.xml.security.encryption.XMLCipher.doFinal(Unknown Source)
    at org.apache.ws.security.processor.ReferenceListProcessor.decryptEncryptedData(ReferenceListProcessor.java:296)
    ... 26 more

Feb 07, 2012 4:52:22 PM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
WARNING: Interceptor for {http://searchtechnologies.com/cpa/wcfinterop}TestService#{http://searchtechnologies.com/cpa/wcfinterop}SimpleOperation has thrown exception, unwinding now
org.apache.cxf.binding.soap.SoapFault: The signature or decryption was invalid
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.createSoapFault(WSS4JInInterceptor.java:643)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:308)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:85)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
    at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:799)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1627)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1494)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1402)
    at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:47)
    at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:195)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:649)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:533)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:463)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:366)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:319)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:88)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134)
    at $Proxy33.simpleOperation(Unknown Source)
    at com.searchtechnologies.wcfinterop.TestServiceClient.secureTest(TestServiceClient.java:74)
    at com.searchtechnologies.wcfinterop.TestServiceClient.main(TestServiceClient.java:32)
Caused by: org.apache.ws.security.WSSecurityException: The signature or decryption was invalid
    at org.apache.ws.security.processor.ReferenceListProcessor.decryptEncryptedData(ReferenceListProcessor.java:298)
    at org.apache.ws.security.processor.ReferenceListProcessor.decryptDataRefEmbedded(ReferenceListProcessor.java:159)
    at org.apache.ws.security.processor.ReferenceListProcessor.handleReferenceList(ReferenceListProcessor.java:93)
    at org.apache.ws.security.processor.ReferenceListProcessor.handleToken(ReferenceListProcessor.java:60)
    at org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:396)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:249)
    ... 21 more
Caused by: java.lang.ArrayIndexOutOfBoundsException
    at java.lang.System.arraycopy(Native Method)
    at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(Unknown Source)
    at org.apache.xml.security.encryption.XMLCipher.decryptElement(Unknown Source)
    at org.apache.xml.security.encryption.XMLCipher.doFinal(Unknown Source)
    at org.apache.ws.security.processor.ReferenceListProcessor.decryptEncryptedData(ReferenceListProcessor.java:296)
    ... 26 more

[main] ERROR com.searchtechnologies.wcfinterop.TestServiceClient  - Error during service invocation
java.lang.NullPointerException
    at com.sun.xml.internal.messaging.saaj.soap.impl.ElementImpl.addTextNode(ElementImpl.java:439)
    at com.sun.xml.internal.messaging.saaj.soap.ver1_2.Fault1_2Impl.setFaultRole(Fault1_2Impl.java:323)
    at com.sun.xml.internal.messaging.saaj.soap.ver1_2.Fault1_2Impl.setFaultActor(Fault1_2Impl.java:559)
    at org.apache.cxf.jaxws.JaxWsClientProxy.createSoapFault(JaxWsClientProxy.java:219)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:152)
    at $Proxy33.simpleOperation(Unknown Source)
    at com.searchtechnologies.wcfinterop.TestServiceClient.secureTest(TestServiceClient.java:74)
    at com.searchtechnologies.wcfinterop.TestServiceClient.main(TestServiceClient.java:32)

As you can see, it looks like when CxF tries to decode the element which references the attachment, it finds its contents empty, and fails.

Any help will be deeply appreciated.

Couldn't post the WSDL because of size constraints. Available on request if necessary.

Regards,

Eduardo Quiros-Campos

1

1 Answers

1
votes

As far as I known, CXF does not support completely MTOM when signature is enable : it doesn't sign or encrypt the attachments. As WCF do sign or encryt attachments, it won't work. See http://cxf.547215.n5.nabble.com/Signature-digest-mismatch-when-NET-supplies-MTOM-attachment-td3270961.html and https://issues.apache.org/jira/browse/CXF-3687.