A Division of Technology Associates International Corporation
Maximo Blog

Using Active Directory to manage your web application security

October 24, 2007 in C#, Programming Techniques by Michael Chrisman 0 Comments

The one common thing all applications have in is some type of security. Even the simplest of applications have at least some type of “administration” functionality. The most common and easiest way to setup up security is to 1) create users, 2) create groups, 3) assign users to those groups, and 4) in your application, enable/disable functionality based on those groups. What you end up with is a User table that has UserIDs and Passwords (plus other stuff), a group table with group ID/names, and a join table where users and groups “joined”. Of course then you have to create three admin screens for these tables. The last part is some type of procedure for approving and adding users to the system and to each group.

Although this works well, it does have some problems. The first is that users often use the same UserID/password as their network account. If you store the password in plain text, then this is a GIANT security hole. Too many people without the right security rights can access this data. Of course, then you have to encrypt the password and that adds another level of complexity to your application. Next issue is the process for adding users to the system. This often falls to the developers, who have no idea if a user should be a basic user to an administrator in the system. The last is what I think is the biggest overlooked security hold in medium to large companies. That is, when an employee leaves the company, their network account is disabled/deleted, but rarely are the user’s accounts in every application removed. That means if a user was an Admin in an application and they leave on less than good terms, they could give their userid/password to their “buddy” and the buddy could raise havoc in the application and it would not be traceable to them.

So how do we solve these issues? All of these problems could be solved with lots of procedures and extra code. But why do that when all of these problems have already been solved. Instead of doing a lot of extra work, you can push the work off onto already existing functionality: The Active Directory. If you think about it, it’s the perfect solution. The Active Directory already manages all your users; it is setup to handle groups; there are already procedures in place for adding users and adding users to groups, and when a user leaves the company, the Active Directory is the first place they are deactivated/deleted. Another thing is that groups are usually “owned” by an end user and it is up to them to “OK” new users to that group. So basically by using the Active Directory to manage your application security, you can push all the work and management off onto other people and off your project.

Now, even though we have the Active Directory managing our users and groups, we still have to program what those groups can do in our application. The following example shows how to setup your WEB (ASP.Net) application to check if the current user is a member of a given group. You will then have to enable/disable functionality based on that. If you want to do this for client server applications, then you will have to do some work on the security class (remove all the impersonation stuff). The following examples are in C#.

(Note on SQL Server integrated security. If you use SQL Server’s Integrated security, then you can use the same groups you created for the application and assign rights accordingly. That way, when a user is added to the group, they will not only have rights in your application, but also in the database.)

OK, let’s get started with some code. The first step is to setup the environment. Here are the prerequisites:

  1. The IIS web server must be setup for “Trusted for Delegation” in the Active Directory.
  2. All users must already be in the Active Directory.
  3. This does not work on LARGE Active Directories as it take too long to search the tree.

Next you have to set the Web server to handle the “Authorization” part of security (that is validating the user is who they say they are). Follow these steps:

  1. Open the IIS Admin tool
  2. Open up the Web Sites and navigate to your web site
  3. Right click on it and select “Properties”
  4. Click on the “Directory Security” tab.
  5. In the “Anonymous Access and Authentication Control: Area, click on the Edit Button.
  6. Uncheck the “Anonymous Access” check box and check the “Integrated Windows Authentication”

IISAdmin screen

Click OK twice.

Now we need to create some groups in the Active Directory for our application. At minimum you should create a “MyAppUsers” and a “MyAppAdmin”. If you have other group needs, create them also. When you have them created, be sure to denote a User of the application as the Group owner. This allows the users of the system to manage and “own” the application. One thing nice about the Active Directory is that you can nest these groups. You can make the “admin” group a member of the “users” group. Next assign users to these groups. All of this information is should have been figured out when you did your security analysis for your application.

Next, now the web server is setup to authenticate the user automatically, but we need to know what the user ID is. Here is the code for that:


   1:  UserID = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_USER"].ToString();

Next we need the magic class. You can just add this to your web page (be sure to remove the Namespace and class statements), add it as a class in your project (rename the namespace to match your namespace) or add it to a new project.


   1:  using System;
   2:  using System.Security.Principal;
   3:  using System.DirectoryServices;
   4:  
   5:  namespace ADAppSecurity
   6:  {
   7:      // be sure to add a reference to System.DirectoryServices in you project.
   8:      // Integrated web security must be enabled and anonymous turned off
   9:      // 
  10:      public class ADAppSecurity
  11:      {
  12:          /// [summary]
  13:          /// This method will determine if a user is a member of a group within the Active directory
  14:          /// This is the public interface to this class
  15:          /// [/summary]
  16:          /// [param name="domainName"]The domain to search[/param]
  17:          /// [param name="groupName"]The group to search in[/param]
  18:          /// [param name="userName"]The userID of the user[/param]
  19:          /// [param name="User"]The User principal from the web page[/param]
  20:          /// [returns]True if the user is a member of the group, False otherwise. Also returns false for errors[/returns]
  21:          public bool IsMemberOfAD(string domainName, string groupName, string userName, IPrincipal User)
  22:          {
  23:              // this class is setup for use in ASP.Net apps and since the user running IIS rarely has rights to to
  24:              // the domain (and shouldn't have access to it), we have to impersonate the user so we can access
  25:              // the activie domain. 
  26:              WindowsImpersonationContext impersonationUser;
  27:              impersonationUser = ((WindowsIdentity)User.Identity).Impersonate();
  28:  
  29:              DirectoryEntry directory = new DirectoryEntry("LDAP://" + domainName);
  30:  
  31:              bool RetVal = IsMemberOf(groupName, userName, directory);
  32:  
  33:              impersonationUser.Undo(); // all done, so we stop impersonating
  34:  
  35:              return (RetVal);
  36:  
  37:          }
  38:  
  39:          /// [summary]
  40:          /// Determines if the given user is a member of the domain.
  41:          /// [/summary]
  42:          /// [param name="groupName"]The user group.[/param]
  43:          /// [param name="userName"]The user name.[/param]
  44:          /// [param name="directory"]A Container for the active directory[/param]
  45:          /// [returns]True if the user is a member of the domain, False otherwise.[returns]
  46:          private bool IsMemberOf(string groupName, string userName, DirectoryEntry directory)
  47:          {
  48:              try
  49:              {
  50:                  if (userName.IndexOf("\") > -1)
  51:                  {
  52:                      return (IsMemberOf(groupName, userName.Substring(userName.IndexOf("\") + 1, userName.Length - userName.IndexOf("\") - 1), directory));
  53:  
  54:                  }
  55:  
  56:                  DirectorySearcher srch = new DirectorySearcher("(CN=" + groupName + ")");
  57:  
  58:                  srch.SearchRoot = directory;
  59:                  srch.SearchScope = SearchScope.Subtree;
  60:                  SearchResultCollection coll = srch.FindAll();
  61:  
  62:                  if (coll.Count == 0)
  63:                  {
  64:                      return (false);
  65:                  }
  66:                  else
  67:                  {
  68:                      foreach (SearchResult rs in coll)
  69:                      {
  70:                          ResultPropertyCollection resultPropColl = rs.Properties;
  71:  
  72:                          foreach (Object memberColl in resultPropColl["member"])
  73:                          {
  74:                              DirectoryEntry gpMemberEntry = new DirectoryEntry("LDAP//" + memberColl);
  75:  
  76:                              PropertyCollection userProps = gpMemberEntry.Properties;
  77:  
  78:                              object obVal = userProps["sAMAccountName"].Value;
  79:                              if (null != obVal)
  80:                              {
  81:                                  if (userName.ToLower().Equals(obVal.ToString().ToLower()))
  82:                                      return (true);
  83:                                  else
  84:                                  {
  85:                                      // Recure call incase member is a group
  86:                                      if (IsMemberOf(obVal.ToString(), userName, directory))
  87:                                          return (true);
  88:                                  }
  89:                              }
  90:                          }
  91:                      }
  92:                  }
  93:              }
  94:              catch (Exception)
  95:              {
  96:                  // an error occured, just ignore it.
  97:              }
  98:              return (false);
  99:          }
 100:      }
 101:  }

The final step is to check if the current user is a member of the a certain group. Obviously you will need to “hard code” the group names. I recommend that you place them in something that is someone easy to change (like the web.config) as every once in a while, those in charge of Active Directories like to change their naming schemes. Here is how you would check for access rights (in this example, the domain is “foobar.com”; and the group is “MyAppAdmin”:


   1:  ADAppSecurity ADObject = new ADAppSecurity();
   2:  
   3:  if (ADObject.IsMemberOfAD(“foobar.com”, “MyAppAdmin”, UserID, Page.User))
   4:  {
   5:      // User is a member
   6:  }

Basically, that is it. Everywhere in your app where you need to check for security rights, just use the above if statement.

It’s not that hard to use the active directory to manage your web application security and it has so many benefits.

Post a Comment

Remember my personal information.
Notify me of follow-up comments?

We don't know if you're a human. Confirm below: