Introduction

Windows Communication Foundation provides tons of methods to authenticate users' check for authorization based on
the service type that it's quite confusing to implement simple form based authentication and role based authorization for WCF REST 4.0.

Note: This article assumes that the WCF REST service is hosted with
the ASP.NET application and shares the same web.config. Make sure that Form Authentication is enabled in
the web.config file.

Background

There are many ways to authenticate and authorize a user in a WCF Service, but in this example, the authentication cookie will already be created by
the login page and that will be used by subsequent requests made to the REST service for authorization.

Using the Code

A typical way to authorize a user for a specific role is to use the Principal Permission attribute. Something like this:

But even though after the user is authenticated using Membership provider and HTTPContext.Current.User.Identity and the context is available at service level, the principal permission attribute always throws a security exception.

The reason for that is the principal permission attribute checks for System.Threading.Thread.CurrentPrincipal.Identity and not for
the HTTPContext Identity.

To solve this problem, we have to create a Custom Principal and Authorization Policy for
the WCF Service. Then this policy will be hooked with the WCF REST Service using ServiceBehaviour.

If you look closely, the custom principal is created using the HTTPContext Identity that was created after
the user is authenticated using membership provider and the authentication cookie is set after validating the user. Something like this:

FormsAuthentication.SetAuthCookie(username, false);

Attach Authorization Policy to WCF

This can be done by creating a service behavior in the web.config file. But here, I have created
a custom service behavior by implementing IServiceBehavior and attaching the authorization policy to it.

That's all. Now we can add the PrincipalPermission attribute to any web method and authorize
the user for a specific role. We can also implement a custom PrincipalPermission attribute to control the granularity of authorization.

Note: We can also create an Authentication service to validate
the user name password and create an authentication cookie after validation. Here, the assumption is that WCF REST is hosted with
the Web application and therefore shares the context.

Let me know if there is any better way to achieve the same thing without providing user name and password at each request.

Share

About the Author

I work as a freelance consultant and is passionate about taking challenges in latest technology.
I am a solution architect and trainer with 9+ years experience in designing, developing and maintaining enterprise wide application using latest technology like SharePoint 2010, MOSS 2007, Business Intelligence, SQL Server 2008, Reporting Service, Analysis Service and Integration service.

This seems like the solution to our problem. We are using forms authentication and need to control who has access to the various part of our REST web service based on the roles they have in AD. I implemented the code as shown here. The problem is that when it reaches...

return Roles.IsUserInRole(role)

in the CustomPrincipal class, it throws the error "Method is only supported if the user name parameter matches the user name in the current Windows Identity."

We are tapping directly into AD and our roleManger per web.config is...

I admit this area is not my expertise and have to believe I'm missing something someone more experienced would notice directly. Do we need to establish the custom policy under behaviors in web.config? If so, I'm having some trouble with syntax on that. Or is it something else? I will continue to hammer away at this, but any insight you can offer would be greatly appreciated.

Hello,
Its been a while, i have worked on this solution but few things to note here that this solution override System.Threading.Thread.CurrentPrincipal.Identity. And since you are using WindowsToken it might be possible that it checks for Windows Identity instead. Can you check what is the value of your Thread, HTTPContext and Windows Identity.

Though you have mentioned you are using Form based authentication, are you sure? I mean what is your Identity provider? My guess is that you are using Windows auth instead of Form.

Thanks for the response! I added my answer below from a window I left open, and if I had refreshed I would have seen you response first.

I went down the route you suggest. This link shows (table 4) that when using integrated Windows authentication in IIS and Forms Auth in your code, you will never get HttpContext and WindowsIdentity to be the same thing. This led me to try some things with impersonation, which worked--I was getting HttpContext and WindowsIdentity to be the same user. But I was still getting the error on IsUserInRole, which led me to the discovery that under Windows Token role provider, it simply doesn't work, which led me to my work around.

I found the problem, and came up with a work around. The obstacle is that we are using Windows Token role provider, which according to this (and a few other folks) makes IsUserInRole inaccessible. So my IsInRole method now looks like this: