Search code examples
javac#web-serviceswcfwsdl

Java web service client to consume a WCF service that needs header and body to be signed


The system we are working on comprise of the following applications: - A .Net WCF Security Token Service which can issue WSTrust access token. - A Java service that exposes a simple Ping operation. - A Java servlet that calls the STS to get a token and then uses it to access the service.

Requirements for the .Net WCF STS: - Message bodies of both requests and responses must be signed. - No encryption. - Must have timestamp and it must be signed. - Must use https.

To fulfill those requirements, we made a custom WCF web service whose custom binding is:

        var bindings = new BindingElementCollection();
        var transportBinding = new HttpsTransportBindingElement { RequireClientCertificate = false };
        var encodingBinding = new TextMessageEncodingBindingElement() { MessageVersion = MessageVersion.Soap12WSAddressing10 };
        MessageSecurityVersion version =
            MessageSecurityVersion
                .WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;

        var sec = SecurityBindingElement.CreateMutualCertificateBindingElement(version) as AsymmetricSecurityBindingElement;
        sec.MessageProtectionOrder = MessageProtectionOrder.EncryptBeforeSign;

        bindings.Add(sec);
        bindings.Add(encodingBinding);
        bindings.Add(transportBinding);

The service host is initialized like the below:

        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IWSTrust13SyncContract),
              new MyCustomBinding(), "/myendpoint");
        endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;

So far so good. We tested it with a .Net client and it works perfectly. For the Java part, the result is not that good. All the steps we have done so far are:

  1. In the Java service: Edit web service attributes:

    • Set secure service with “STS Issued Endorsing token” mechanism
    • Set KeyStore and TrustStore
  2. In servlet application

    • Add a web service client using the Java service's wsdl -> edit web service attribute
    • Set security: keystore and truststore
    • Set Security token service: endpoint, wsdl location, service name, port name, namespace and ws trust version

    • Add a web service client using the STS' wsdl -> edit web service attribute

    • In the Quality of Service tab, there is only the Transport section. The "Security" section is not there. (1)
  3. After setting all the above options, check in folder “Src/java/META - INF” there are wsit-client.xml and 2 service reference xml files as expected

    • I have checked the policy generated on xml files, all looks ok to me, it has the same policy as that of our STS’ wsdl. In details, it has:
    • AsymmetricBinding
    • SignedParts
    • TransportBinding
  4. The last step is to initiate the service port and invoke the operation as below Service_Service service = new Service_Service(); Service stub = service.getServicePort(); return stub.ping();

I expected that the message will be signed (both header and body) before sending to STS. However, actually, the message sent to STS is not signed. The STS throws an error: “The security header element 'Timestamp' with the '_1' id must be signed” (2)

If we change to use http instead of https for transport binding, the request message to STS is signed correctly. But the requirement is to use https.

Our questions are:

  • (1): is not having the security section in the QoS tab normal? Or are we doing anything wrong here?
  • (2): How to let Java sign the body and some other elements of the header when https is used?

Solution

  • It turned out that there is nothing wrong with the service as well as Java client. It was the exposed WSDL that caused all the trouble. Briefly speaking, WSDL had both AsymmetricBinding and TransportBinding elements which made the client confused when it tried to consume WSDL. After I removed the TransportBinding element from WSDL, Java client can be able to consume WSDL and generate correct requests with signatures.