Saturday, 13 October 2012

Implementing Role Based Access Control on ACS - Part 2


This is a continuation of previous post. Please refer the below link to know more about previous post - Implementing Role Based Access Control on ACS.

Adding Role claim using ACS portal

As we know already (from previous post), when generating rules for public identities using Generate button on ACS portal under a Rule Groups, it does not contain a claim - Role. This is because, the public identities (such as Google, Live, Yahoo etc.,) will not have information about what role the user assigned. But when we use identities such as ADFS, that will provide the role of the user. As we are not using ADFS now, we need to add it manually by using ACS portal or programmatically.

So, I am planning to add Role claim for the public identities we added in previous section (in previous post). The role of each identity (email id) will be as per the table mentioned below.

Identity ProviderEmail IdRole
Google Idpm.thirumalai@gmail.comAccountant
Live Idpm.thirumalai@live.comManager
Yahoo Idthirumalai_pm@yahoo.co.inEmployee

Step 1: Switch to ACS portal for the ACS namespace created and select the Role Group hyperlink from the left panel. Select the Role Group of RBAC Test relying party application.

Step 2: Add a new rule by clicking Add hyperlink and provide the information to Role claim for Google identity as below.



Step 3: Add Role claim for the Yahoo provider the same way done in previous step.


Step 4: To add Live Id in the Rule, we can't use the Email Id of the user. This is because, when using Live Id as identity provider in ACS, the output claims of the user will not contains the Email Id of the user. So, to identify the user, alternatively we can use a claim called nameidentifier, which is one of a claim (a 44 letter string) in output claims.

Important to know here is, the nameidentifier will be different for the same Live Id when the relying party application are different. It means, when I login with my Live Id on a Relying party application, ACS provides an unique id which will be different from the other relying party application when I login. So know what is the unique id for the relying party application we created for this applicaton, we need to login with the Live id and verify the returned claims.

The nameidentifier (http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier) provide the unique identifier.


Step 5: Add the Live Id rule with the nameidentifier value.


Step 6: If we run the project now, the screen shows the list of claims which includes the Role claim.

Changing the Application for RBAC

The main aim of this RBAC is to restrict the user accessing modules/screen/functions which are not authorized to them. For Example – In our example application, the Home screen accesible by all user. But the Employee screen can only be able to access the users who has Employee role and restrict screens which are not authorized such as Accountant and Manager.

Step 1: To know whether the user is in a particular role of not, we can use User.IsInRole(RoleName). To implement the RBAC for Employee screen, change the Employee.aspx.cs code load event as below
protected void Page_Load(object sender, EventArgs e)
{
    ContentPlaceHolder cph = (ContentPlaceHolder)this.Master.FindControl("MainContent");
    if (User.IsInRole("Employee"))
    {
        ClaimsInfo claimsInfo = new ClaimsInfo();
        cph.Controls.Add(claimsInfo);
    }
    else
    {
        AccessDenied claimsInfo = new AccessDenied();
        cph.Controls.Add(claimsInfo);
    }
}
As per the code it checks whether the user is in Employee role. if yes, it will show the page otherwise it will show the access denied message.

Step 2:Same way, change same type of code in Accountant.aspx.cs and Manager.aspx.cs classes.

Step 3:Run the code and verify the output.



As per the picture above, I logged in with my gmail id which is assigned to Accountant role. So when I access Manager screen, it shows access denied message.

Adding Role claim using code

Configuring the role in the ACS portal is little bit difficult. Instead we can do the same from the code itself. This allows us to keep a database about the user and their role information.

In this implementation, I am going to add an XML file which contains details about the users and their role.
Step 1: Add an XML file (UserData.xml) in the project and add the xml script as below.
<?xml version="1.0" encoding="utf-8" ?>
<Users>
  <User Id="mailid1@gmail.com">
    <Role>Accountant</Role>
  </User>
  <User Id="Xh5IflqFPavPjPGLQSIMP7Ua1wnQja5J7mPElWnmd3w=">
    <Role>Manager</Role>
  </User>
  <User Id="mailid2@yahoo.co.in">
    <Role>Employee</Role>
  </User>
</Users>
Step 2: Add a class file in the project with class name as ClaimsTransformationModule. The code of the class as below.
public class ClaimsTransformationModule : ClaimsAuthenticationManager
{
    public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal)
    {
        if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated == true)
        {
            ClaimCollection claimCollection = ((IClaimsIdentity)incomingPrincipal.Identity).Claims;
            Dictionary<string, string> tempClaims = new Dictionary<string, string>();

            foreach (Claim claim in claimCollection)
                tempClaims.Add(claim.ClaimType, claim.Value);

            if (tempClaims["http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider"] != null)
            {
                string strIdentifier = string.Empty;


                if (tempClaims["http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider"] == "uri:WindowsLiveID")
                    strIdentifier = tempClaims["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"];
                else
                    strIdentifier = tempClaims["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"];

                XPathDocument userData = new XPathDocument(ConfigurationManager.AppSettings["DataPath"].ToString() + @"/UserData.xml");

                XPathNavigator nav = userData.CreateNavigator().SelectSingleNode("//User[@Id='" + strIdentifier + "']");

                if (nav != null)
                {
                    ((IClaimsIdentity)incomingPrincipal.Identity).Claims.Add(new Claim(ClaimTypes.Role, nav.Select("User").Current.SelectSingleNode("Role").InnerXml));
                }
                else
                    ((IClaimsIdentity)incomingPrincipal.Identity).Claims.Add(new Claim(ClaimTypes.Role, "Guest"));
            }
        }
        return incomingPrincipal;
    }
}
This code looks at the user email id (Google, Yahoo) or the unique identifier (Live Id) and adds the role of the user in the claim based on the xml data.

Note: This code require the path of the xml file. So need to add the path of the file in the appSettings.

Step 2: We have added the ClaimsTransformationModule by inheriting ClaimAuthenticationManager class. We also need to change the Web.Config setting to look at this file while on the authentication process.

So, Add the claimsAuthenticationManager node under the microsoft.identityModel\service node.


Step 3: Delete the added rules from the Rule groups of the relying party application.

Step 4: Now run the application and verify the output.

Step 5: When login with email id which is not present in the xml data it will be considered as Guest role.



Adding ADFS as Identity Provider and using it

When we use ADFS as Identity Provider in ACS, ACS itself provides Role claim addition to the other claims. So we can use it as we have use the same above code ie., User.IsInRole(RomeName).

For adding ADFS identity provider with ACS, refer the below post.
Configuring ACS for consuming ADFS and using in Web Application

download the source code of this implementation here.

0 Responses to “Implementing Role Based Access Control on ACS - Part 2”

Post a Comment