Tuesday, February 16, 2010

How to use Custom RoleProvider in WCF?

First thing is to add reference to the System.Web.dll assembly to your WCF project. Then create a class which inherits from RoleProvider. You’ll also need to add the System.Web.Security namespace. Then you can use the CTRL+dot trick so that VS generates all the methods for you. You’ll end up with something like this:

public class MyRoleProvider : RoleProvider
{
 
    public override void AddUsersToRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }
 
    public override string ApplicationName
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }
 
    public override void CreateRole(string roleName)
    {
        throw new NotImplementedException();
    }
 
    public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
    {
        throw new NotImplementedException();
    }
 
    public override string[] FindUsersInRole(string roleName, string usernameToMatch)
    {
        throw new NotImplementedException();
    }
 
    public override string[] GetAllRoles()
    {
        throw new NotImplementedException();
    }
 
    public override string[] GetRolesForUser(string username)
    {
        throw new NotImplementedException();
    }
 
    public override string[] GetUsersInRole(string roleName)
    {
        throw new NotImplementedException();
    }
 
    public override bool IsUserInRole(string username, string roleName)
    {
        throw new NotImplementedException();
    }
 
    public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
    {
        throw new NotImplementedException();
    }
 
    public override bool RoleExists(string roleName)
    {
        throw new NotImplementedException();
    }
}

Now, you’ll need to provide actual implementation for all of these methods. That’s up to you.

Next, you need to configure your config file. Add following to the system.web section of your configuration file:

<system.web>
    <roleManager enabled ="true">
 
        <providers>
            <add  name="MyRoleProvider" type="ReducingComplexity.MyRoleProvider, ReducingComplexityRoleProvider"/>
        </providers>
    </roleManager>
</system.web>

Now you’ll need to link this role provider to your services services. You will use serviceBehavior for this. For example, if you have service behavior defined like this:

<behaviors>
    <serviceBehaviors>
        <behavior name="MyServis.MyStandardBehavior">
            <serviceAuthorization roleProviderName="MyRoleProvider" principalPermissionMode="UseAspNetRoles"></serviceAuthorization>
        </behavior>
    </serviceBehaviors>
</behaviors>

Using the <serviceAuthorization>, I set roleProviderName with the name of my role provider as defined under <roleManager> node. Also, principalPermissionMode need to be set to UseAspNetRoles. That’s pretty much it. It’s that simple.

Now it’s possible to use both declarative security framework:

[PrincipalPermission(SecurityAction.Demand,Role = "Customer")]
public List<Order> GetOrders(int customerId)
{
}

or for example Thread.CurrentPrincipal.IsInRole() method.

public List<Order> GetOrders(int customerId)
{
    if (Thread.CurrentPrincipal.IsInRole("Customer")) 
    {
        // get customer orders 
    }
    else 
    {
        // permission denied
    }
}

WCF rocks!!!

Still, there is something I really don’t like. It is the fact that RoleProvider is considered to belong to ASP.NET(hence the need to add reference to System.Web.dll assembly). This is kind of unnatural, and I would like to see the role providers moved to some other assembly, for example System.Security.dll.

2 comments: