WCF - WSHttpBinding and Clock Skew

28 January, 2009 · 4 minutes to read

WCF - WSHttpBinding and Clock Skew

I was deploying a WCF service and when testing it started to get the following error:

The security timestamp is invalid because its creation time ('2009-01-28T16:18:26.625Z') is in the future. Current time is '2009-01-28T16:11:40.173Z' and allowed clock skew is '00:05:00'.

A quick search of the internet threw light on what the problem was, by default in WCF the clocks on the client and server have to be within 5 minutes of each other. Now this can be controlled if all the machines involved are on the same network, but as soon as you start having clients on other networks, you will get them with bigger time differences than this. After another bit of searching I found that you can control the size of the allowed clock skew. However, you can't do this with the WSHttpBinding, you have to create a custom binding.

The problem then is that the documentation about doing this in web.config is pretty poor. With a custom binding you start with nothing about your connection set up and have to build it from scratch, which given the complexity of the possble binding is really difficult. I found several posts in newsgroups asking about it, but for a long time couldn't find a decent answer. Then I stumbled across http://social.msdn.microsoft.com/forums/en-US/wcf/thread/6554776e-4b05-427f-ad6f-5d72c6579746/ and discovered that you could programmatically create the binding, convert it to a custom binding and save it to a configuration file, which will then contain all the settings you need to duplicate your original binding, but within a custom binding where I could then set maxClockSkew.

The code I used is:
public static void Main(){     //Create the custom binding based on your original binding     WSHttpBinding binding = new WSHttpBinding();     binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;     binding.SendTimeout = new TimeSpan(0, 15, 0);     binding.MaxReceivedMessageSize = 65536000;     CustomBinding custom = new CustomBinding(binding);     //Set up the config file to save     Configuration machineConfig = ConfigurationManager.OpenMachineConfiguration();     ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();     fileMap.ExeConfigFilename = "out.config";     fileMap.MachineConfigFilename = machineConfig.FilePath;     Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);     config.NamespaceDeclared = true;     //Save the binding in the config file     ServiceContractGenerator scg = new ServiceContractGenerator(config);     string sectionName;     string configName;     scg.GenerateBinding(custom, out sectionName, out configName);     config.Save();}
So from my original binding specification

<wsHttpBinding>
    <binding name="SalamanderBinding" receiveTimeout="00:15:00"
            maxReceivedMessageSize="65536000">
            <security mode="Message">
                <message clientCredentialType="UserName"/>
            </security>
       <readerQuotas maxArrayLength="65536000"/> 
    </binding>
</wsHttpBinding>

I got the following custom binding

<customBinding>
    <binding name="SalamanderBinding">
        <transactionFlow transactionProtocol="WSAtomicTransactionOctober2004" />
        <security defaultAlgorithmSuite="Default" authenticationMode="SecureConversation"
            requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true"
            keyEntropyMode="CombinedEntropy" messageProtectionOrder="SignBeforeEncryptAndEncryptSignature"
            messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
            requireSecurityContextCancellation="true" requireSignatureConfirmation="false">
            <localClientSettings cacheCookies="true" detectReplays="true"
                replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
                replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
                sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="false"
                timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
            <localServiceSettings detectReplays="true" issuedCookieLifetime="10:00:00"
                maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
                negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
                sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
                reconnectTransportOnFailure="false" maxPendingSessions="128"
                maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
            <secureConversationBootstrap defaultAlgorithmSuite="Default"
                authenticationMode="UserNameForSslNegotiated" requireDerivedKeys="true"
                securityHeaderLayout="Strict" includeTimestamp="true" keyEntropyMode="CombinedEntropy"
                messageProtectionOrder="SignBeforeEncryptAndEncryptSignature"
                messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
                requireSecurityContextCancellation="true" requireSignatureConfirmation="false">
                <localClientSettings cacheCookies="true" detectReplays="true"
                    replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
                    replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
                    sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"
                    timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
                <localServiceSettings detectReplays="true" issuedCookieLifetime="00:15:00"
                    maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
                    negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
                    sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
                    reconnectTransportOnFailure="true" maxPendingSessions="128"
                    maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
            </secureConversationBootstrap>
        </security>
        <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
            messageVersion="Default" writeEncoding="utf-8">
            <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                maxBytesPerRead="4096" maxNameTableCharCount="16384" />
        </textMessageEncoding>
        <httpTransport manualAddressing="false" maxBufferPoolSize="524288"
            maxReceivedMessageSize="65536000" allowCookies="false" authenticationScheme="Anonymous"
            bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
            keepAliveEnabled="true" maxBufferSize="65536000" proxyAuthenticationScheme="Anonymous"
            realm=" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
            useDefaultWebProxy="true" />
    </binding>
</customBinding>

and I just needed to change the maxClockSkew values.

You do need to set the clock skew on the client and server sides.

Easy when you know how.

 

 

Richard Willis headshot

Written by Richard Willis

Managing Director / Founder

Richard started SalamanderSoft in 2007 after a successful career as a software developer. Wanting to start his own company and with experience in integrating school systems he set out to build the best integration system for schools and to exceed customer expectations. He starting out on his own, doing all the coding, support and sales until finally the growing number of customers meant he needed to start growing the team. He is still heavily involved in coding the core Integration Suite product in addition to running the company and being the first point of contact for prospective customers.

Copyright © 2020 SalamanderSoft Limited