Tuesday, January 19, 2010

Silverlight and WCF using ntlm authentication.


We have a Silverlight 3 application that makes use of wcf services in a standard 2 tier RIA application. As the application is to run on the client's intranet, available to all employees, windows authentication was the logical authentication mechanism.
Most of the samples that are available make this seem very simple and straight forward. Use a custom binding (to leverage binary message encoding for performance reasons) and set the httpTransport's authenticationScheme to Ntlm with IIS's authentication set to "Windows" and "anonymous" disabled. No Problem... or so we thought.

We just could not establish the identity of the client on the service. This is where a 3 month story starts with a support ticket logged with Microsoft the works..

Firstly the IIS would summarily deny any access to the service. Then we allow anonymous authentication on the service and obviously the identity on the current WCF OperationContext is not set. We eventually had a work-around where we injected the identity from the Silverlight’s host aspx page into Silverlight and then packaged the credentials as a custom header with each call. Not ideal, but time constraints where insane and we needed to get the first release out..

We logged a call with Microsoft to see if they could shed some light on the issue for us. We developed some sample application that low and behold worked without a hitch. We would run network traces, but for some or other reason the call from our application to the services would be stopped dead in its tracks with a 401 unauthorized. We configured IIS to only use Ntlm as the Negotiate with its default Kerberos scheme does cause problems, but to no avail.

So here is the kicker and something that is etched in my memory... I started looking at every trace I could throughout the application to determine exactly what happens in the application, start to finish, researching any and every step in detail.

I came across a single line in the start-up of the Silverlight client:
System.Net.WebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp);

The primary reason that this line was put in was to ease debugging of the service calls. This forces Silverlight to use its own HTTP request stack that understands valid Soap Faults where the default System.Net.Browser.WebRequestCreator.BrowserHttp will return you the notorious "NotFound" exception.

It turns out that in the msdn documentation there is a line that states "You can register an alternative HTTP stack using the RegisterPrefix method. Silverlight 3 provides the “client HTTP stack” which, unlike the “browser HTTP stack”, allows you to process SOAP-compliant fault messages. However, a potential problem of switching to the alternative HTTP stack is that information stored by the browser (such as authentication cookies) will no longer be available to Silverlight, and thus certain scenarios involving secure services might stop working, or require additional code to work.


So after about 3 months of blood sweat and endless phone calls from Microsoft support engineers one single line was the cause of our problems..

You’ve been warned.

1 comment:

  1. Let me get this straight which stack do I need to choose to get the authentication working?
    //Switch Stack (Silverlight Default is BrowserHttp) this enables us to get exception codes
    //WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);

    ReplyDelete