It’s been a year and one of the most popular posts in this blog still today is How To: Secure your ASP.NET MVC application and use Active Directory as the Membership Provider. In that post I promised to write about how to use Active Directory groups to restrict access to controller actions to make your application even more secure by consolidating access based in already defined groups in Active Directory (AD). I finally got to it and here it is.

Remember that if you are not already using Active Directory as your membership provider in your application, you need to first follow the steps described in the first post mentioned above.

In a business, the use of Active Directory to organize user and computer accounts is very common. When we create new web applications for that business it is likely that we want to have some access control to certain areas of the application. For example, let’s say that you have a web application that helps accounting and customer support get details about a certain customer such as reports, invoice details, account information, etc… In such application there is a good chance that accounting and customer service employees will have different access to different areas in the application.

The Example

Here is an example of what such a task will look like in the controller of your MVC application:

 public ActionResult DeactivateMembership(Membership model)
 {
    // your business logic here
    return View("DeactivateMembership", model);
 }

And here is what is going to look like with an attribute that will only allow users in the customer service group to execute such task

[AuthorizeAD(Groups = Constants.CSgroup)]
 public ActionResult DeactivateMembership(Membership model)
 {
    // your business logic here
    return View("DeactivateMembership", model);
 }

The custom AuthorizeAD attribute

The custom attribute labeled AuthorizeAD is what makes this happen, below is the declaration of this custom attribute that access Active Directory to determine if an specific user or group within AD has access to a defined controller action:

namespace Application.Filters
{
public class AuthorizeADAttribute : AuthorizeAttribute
{
    public string Groups { get; set; }
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (base.AuthorizeCore(httpContext))
        {
           /* Return true immediately if the authorization is not 
           locked down to any particular AD group */
           if (String.IsNullOrEmpty(Groups))
               return true;

           // Get the AD groups
           var groups = Groups.Split(',').ToList();

           // Verify that the user is in the given AD group (if any)
           var context = new PrincipalContext(
                                 ContextType.Domain, 
                                 "yourdomainname");

           var userPrincipal = UserPrincipal.FindByIdentity(
                                  context,
                                  IdentityType.SamAccountName,
                                  httpContext.User.Identity.Name);

           foreach (var group in groups)
           if (userPrincipal.IsMemberOf(context, 
                IdentityType.Name, 
                group))
               return true;
        }
         return false;
}

protected override void HandleUnauthorizedRequest(
AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
             var result = new ViewResult();
             result.ViewName = "NotAuthorized";
             result.MasterName = "_Layout";
             filterContext.Result = result;
        }
        else
             base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

The code above overrides the AuthorizeCore call which allow us to customize the authorization check so we can use the Active Directory in our domain.

The implementation

To limit access to controller actions you will use the new custom attribute like this:

[AuthorizeAD(Groups = Constants.CSgroup)]

Where Constant.CSGroup is just a constant value I created that translates to the actual name of the AD group. This can also be used to aggregate two or more AD groups as one value if needed. In the class below I set the value of CSgroup to be the name of two different AD groups in my domain, the csr group and csr_leads group:

public static class Constants
    {
        /// <summary>
        /// CS - Customer support and customer support leads
        /// </summary>
        public const string CSgroup = "csr, csr_leads";
}

If you don’t need to do this then you can use the custom attribute by simply providing the name of your AD group, a user name or the name of a Role within your Active Directory:

// Only give access to a group
[AuthorizeAD(Groups = "yourADgroup")]


// Give access to a group and a user
[AuthorizeAD(Groups = "yourADgroup", Users = "someuser")]

// Give access to a Role
[AuthorizeAD(Roles = "Admin")]
 

That’s it! Hope this is helpful for you and as always, if you have a recommendation, a comment or question please use the comment’s section below.