ASP .NET MVC Forms authorization with Active Directory groups

dnatoli picture dnatoli · Dec 3, 2010 · Viewed 34.4k times · Source

I'm attempting to authenticate using users and groups in ASP.NET MVC against Active Directory.

I have put the following attribute on all my classes (except the account class):

[Authorize (Roles="SubcontractDB Users")]

This group is found under OU=Area->OU=Groups->OU=Company->CN=SubcontractDB in active directory. I'm assuming I also need to setup a RoleManager in web.config which I've attempted to do as follows:

<roleManager defaultProvider="ADRoleProvider">
  <providers>
    <clear />
        <add name="ADMembershipProvider" 
             type="System.Web.Security.ActiveDirectoryMembershipProvider" 
             connectionStringName="ADConnectionString" 
             attributeMapUsername="sAMAccountName" />
  </providers>
</roleManager>

My connection string is:

    <add name="ADConnectionString" 
         connectionString="LDAP://blah.com:389/DC=blah,DC=wateva,DC=com"/>

Obviously I'm doing it wrong as this doesn't work. All I want to do is allow access to users that are a member of a certain group in AD.

Answer

dnatoli picture dnatoli · Dec 8, 2010

So I ended up implementing my own authorize attribute and using that:

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<string>();

            // Verify that the user is in the given AD group (if any)
            var context = new PrincipalContext(ContextType.Domain, "server");
            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;
      }
   }
}

And then I can simply use the following above controllers or functions

Using Application.Filters;
...
[AuthorizeAD(Groups = "groupname")]

NB: You could simply use new PrincipalContext(ContextType.Domain); however there is a bug in .NET 4.0 that throws a (0x80005000) error at userPrincpal.IsMemberOf(...). See here for details.

If you would like to know how to redirect to another page based on failed authorization, check my answer here: Adding an error message to the view model based on controller attribute in ASP.NET MVC