Monday, July 04, 2011

Enabling conditional Basic HTTP authentication on a WCF OData service

Yes, a long title, but also something I was not able to find too easily using Google. Here’s the situation: for MyGet, we are implementing basic authentication to the OData feed serving available NuGet packages. If you recall my post Using dynamic WCF service routes, you may have deducted that MyGet uses that technique to have one WCF OData service serving the feeds of all our users. It’s just convenient! Unless you want basic HTTP authentication for some feeds and not for others…

After doing some research, I thought the easiest way to resolve this was to use WCF intercepting. Convenient, but how would you go about this? And moreover: how to make it extensible so we can use this for other WCF OData (or WebAPi) services in the future?

The solution to this was to create a message inspector (IDispatchMessageInspector). Here’s the implementation we created for MyGet: (disclaimer: this will only work for OData services and WebApi!)


 1 public class ConditionalBasicAuthenticationMessageInspector : IDispatchMessageInspector
 2 {
 3     protected IBasicAuthenticationCondition Condition { get; private set; }
 4     protected IBasicAuthenticationProvider Provider { get; private set; }
 5
 6     public ConditionalBasicAuthenticationMessageInspector(
 7         IBasicAuthenticationCondition condition, IBasicAuthenticationProvider provider)
 8     {
 9         Condition = condition;
10         Provider = provider;
11     }
12
13     public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
14     {
15         // Determine HttpContextBase
16         if (HttpContext.Current == null)
17         {
18             return null;
19         }
20         HttpContextBase httpContext = new HttpContextWrapper(HttpContext.Current);
21
22         // Is basic authentication required?
23         if (Condition.Evaluate(httpContext))
24         {
25             // Extract credentials
26             string[] credentials = ExtractCredentials(request);
27
28             // Are credentials present? If so, is the user authenticated?
29             if (credentials.Length > 0 && Provider.Authenticate(httpContext, credentials[0], credentials[1]))
30             {
31                 httpContext.User = new GenericPrincipal(
32                     new GenericIdentity(credentials[0]), new string[] { });
33                 return null;
34             }
35
36             // Require authentication
37             HttpContext.Current.Response.StatusCode = 401;
38             HttpContext.Current.Response.StatusDescription = "Unauthorized";
39             HttpContext.Current.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", Provider.Realm));
40             HttpContext.Current.Response.End();
41         }

Read more: Maarten Balliauw {blog}
QR: Enabling-conditional-Basic-HTTP-authentication-on-a-WCF-OData-service.aspx

Posted via email from Jasper-Net