Search code examples
c#soapws-security

Remove timestamp element from ws-security headers created by WCF


I am consuming an old Java web service from WCF that requires the request in the form:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header>
        <wsse:Security mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss- wssecurity-secext-1.0.xsd">
            <wsse:UsernameToken wsu:Id="xxx" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-ssecurity-utility-1.0.xsd">
                <wsse:Username>username</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        ...
    </s:Body>
</s:Envelope>

Using the following config hack "works" but I don't want the username and password exposed in config:

<binding name="bindingName">
      <security mode="Transport">
        <transport clientCredentialType="Certificate" />
      </security>
</binding>
...
<endpoint address="https://endpoint address"
      binding="basicHttpBinding" bindingConfiguration="bindingName"
      contract="contract"
      name="bindingName">

    <headers>
        <wsse:Security mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss- wssecurity-secext-1.0.xsd">
            <wsse:UsernameToken wsu:Id="UsernameToken-8293453" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-ssecurity-utility-1.0.xsd">
                <wsse:Username>username</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
    </headers>
</endpoint>

What I want to use is something along the lines of:

<binding name="bindingName">
    <security mode="TransportWithMessageCredential">
        <transport clientCredentialType="Certificate" />
        <message clientCredentialType="UserName" />
    </security>
</binding>

But this generates the timestamp element in the security element, which the java webservice borks on.

What I need to do is remove the timestamp from the XML it generates or have some sort of custom binding to do it for me.

I tried creating custom credentials, but this only changed the usernameToken element.

I have already looked at many, many SO questions (many from 2007 and earlier) including the following with no joy:

What is the best, simplest and most elegant way to remove the timestamp element.

Thanks in advance


Solution

  • Found the answer on Kristian Kristensen's blog post about his woes in integrating to a Java AXIS 1.X and WSS4J web service.. So much simpler and easier than the hacks I was trying previously.

    You can solve this with a simple custom binding in App.config as so:

    BUGFIX - there is a bug in previous version - forgot to add certificate in httpTransport

    <system.serviceModel>
        <bindings>
            <customBinding>
                <binding name="CustomBindingName">
                    <security authenticationMode="UserNameOverTransport" includeTimestamp="false">
                        <secureConversationBootstrap />
                    </security>
                    <textMessageEncoding messageVersion="Soap11" />
                    <httpsTransport useDefaultWebProxy="false" requireClientCertificate="true" />
                </binding>
            </customBinding>
        </bindings>
    
        <client>
            <endpoint address="<endpoint address>" 
                binding="customBinding"
                bindingConfiguration="CustomBindingName"
                contract="<contract goes here>"
                name="EndpointName" />
    
        </client>
    </system.serviceModel>
    

    This gives the correct SOAP ws-security header without the timestamp that confused the java server just by calling this code

    var client = new [clientType]();
    
    client.ClientCredentials.ClientCertificate.Certificate = [certificate];
    
    client.ClientCredentials.UserName.UserName = [UserName];
    client.ClientCredentials.UserName.Password = [Password];
    
    System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
    
    // TODO wrap in try catch
    client.Open();
    
    var result = client.[action](new [RequestType] { ... });
    

    Further Reading: