WCF and fixing client/host time issues (MaxClockSkew) quickly
I have noticed that some of my WCF clients suddenly had issues connecting. These were the exceptions:
The security timestamp is stale because its expiration time is in the past. An error occurred when verifying security for the message
The problem was that the server time had a difference of +/- 10 min. with the clients that had problems. Since these clients are not part of the domain at all we had a problem, since WCF only allows a 5 min. difference.
This could "easely" be solved with:
But this is only supported by custom bindings. Custom binding doesn’t support properties like readerQuotas … so this creates a new problem. You could for example add tcpTransport in your custom binding but here again not all the properties are available. And I’m actually not a fan of having to rewrite all my bindings.
That’s why I liked the following solution (note, this is only when you host your service in an application/service):
ServiceHost service = new ServiceHost(typeof(Calculator)); Binding currentBinding = service.Description.Endpoints.Binding;
With this code we get our current binding (presuming the endpoints and bindings are in the App.config).
Then we just have to update the current binding with a custom binding:
// Set the maximum difference in minutes int maxDifference = 300; // Create a custom binding based on an existing binding CustomBinding myCustomBinding = new CustomBinding(currentBinding); // Set the maxClockSkew var security = myCustomBinding.Elements.Find<SymmetricSecurityBindingElement>(); security.LocalClientSettings.MaxClockSkew = TimeSpan.FromMinutes(maxDifference); security.LocalServiceSettings.MaxClockSkew = TimeSpan.FromMinutes(maxDifference); // Set the maxClockSkew var secureTokenParams = (SecureConversationSecurityTokenParameters)security.ProtectionTokenParameters; var bootstrap = secureTokenParams.BootstrapSecurityBindingElement; bootstrap.LocalClientSettings.MaxClockSkew = TimeSpan.FromMinutes(maxDifference); bootstrap.LocalServiceSettings.MaxClockSkew = TimeSpan.FromMinutes(maxDifference); // Update the binding of the endpoint service.Description.Endpoints.Binding = myCustomBinding;
The only thing we had to do is create a custom binding based on an existing binding.
After that we adapted the
maxClockSkew on the required objects and then injected the new binding back to the endpoint.
If you have multiple endpoints you should apply this on all your endpoints.