27
votes

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.

2
Is there a way to prevent being asked for credentials when using authorize? I'm using windows auth on an intranet site and need to secure by AD group and not prompt the user for credentials.Fireworks

2 Answers

33
votes

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

32
votes

It's no longer necessary to implement your own attribute for this functionality in ASP.NET MVC 3. The AspNetWindowsTokenRoleProvider works with Active Directory users and groups. To use this with AuthorizeAttribute you need to add the following to your web.config:

<authentication mode="Windows" />

<roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider">
   <providers>
      <clear />
      <add 
          name="AspNetWindowsTokenRoleProvider"
          type="System.Web.Security.WindowsTokenRoleProvider" 
          applicationName="/" />
   </providers>
</roleManager>

Then, on your controllers or action methods, you can refer to Active Directory Groups like so:

[Authorize(Roles = "YOURDOMAIN\\Group1, YOURDOMAIN\\Group2")]