Thursday 21 February 2013

Delegating Windows credentials to a WCF service from a load-balanced Web application: 403 Forbidden

I have a Web application that uses Windows Authentication to gather the client's credentials and then passes those credentials to a back-end Web service for delegation (so that the Web service can operate under those user's credentials).

This all works fine until you deploy it to an environment that uses load-balanced Web servers.

If you navigate to MyServerA.Domain then the credentials are accepted by the WCF service.

The same if you navigate to it's load-balanced peer, MyServerB.Domain.

However, if you go via the load-balanced DNS entry, e.g. MyLoadBalancer.Domain, the call to the Web service fails, with the old favourite:

2013-02-20 17:28:28,194 [5] ERROR TradeValidatorWebsite - The HTTP request was forbidden with client authentication scheme 'Negotiate'.
2013-02-20 17:28:28,194 [5] ERROR TradeValidatorWebsite - The remote server returned an error: (403) Forbidden.
2013-02-20 17:28:28,194 [5] ERROR TradeValidatorWebsite - Call stack follows:
2013-02-20 17:28:28,209 [5] ERROR TradeValidatorWebsite - 
Server stack trace: 
   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateAuthentication(HttpWebRequest request, HttpWebResponse response, WebException responseException, HttpChannelFactory factory)
   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory factory, WebException responseException, ChannelBinding channelBinding)
   at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

You don't get this error if you navigate to each server individually.

In the failure mode the authentication fails because the client identified to the server does not match the hostname of the machine.

This is described here: http://support.microsoft.com/kb/325608

Some other articles
http://blogs.msdn.com/b/crminthefield/archive/2012/10/03/kerberos-in-load-balanced-environments.aspx
http://support.citrix.com/article/CTX129314
http://support.microsoft.com/kb/907272 (good)
http://support.microsoft.com/kb/810572
http://support.microsoft.com/kb/929650 (very good, current)

http://technet.microsoft.com/en-us/library/ee176972.aspx a script to query for duplicates

Tuesday 19 February 2013

IE Compatibility View

I had a Intranet application that used Telerik's Kendo grid and it was causing some display problems in IE. I found that on some user's browsers it was displaying badly, whereas on mine it was fine.

Here are the summary of my findings:

Use IE's developer tools. Inspect the Browser Mode and Document Mode settings.
Browser Mode controls the User Agent string that is sent to the server identifying the client type.
Document Mode determines the layout mode that the browser uses.

When the page was being displayed badly the Browser Mode was set to IE9 Compatibility View.

Some users had Compatibility View turned on for all Intranet applications.

Adding the following to the application's Web.config will invite the browser to use a specific document mode.


   
    
    
   
  

Friday 15 February 2013

Kendo grid cultures

I had a Telerik kendo grid bound to a data service implemented via a Grid Controller.

When I upgraded the version of Kendo I noticed that after a row update, date rows were being either set as NULL or DateTime.MinValue. Furthermore, other dates were being set in US format (e.g. mm/dd/yyyy).

Clearly date ranges where the day component was > 12 were failing, a classic culture problem.
Yet my code still called kendo.culture("en-GB") in the document ready function as before.
Examining the kendo.cultures object I could see that the culture was en-US, despite my call above.

What was the problem? It transpires that when I created a new folder for the new version scripts, I neglected to copy the cultures subfolder. In that event calling kendo.culture("en-GB") fails gracefully, leaving you with a US culture.

Wednesday 6 February 2013

Aligining form label / inputs with CSS

The following (simple) CSS will help align label/input pairs in a form:

#dialog label {
    clear: left;
    float: left;
    width: 10em;
    padding-left: 3em;
}

#dialog input {
    float: left;
    margin-bottom: 1em;
}