Introduction
This article will guide you through the best practices and method of using LDAP Active Directory as your user store for credentials and account information in your web applications or portal that you will develop in C# or VB.Net.
A traditional approach creating user store is storing the users in a database and managing them there. But what if your have a company portal and you already use Active Directory? Or what if you want to make it easy on yourself and leverage some of the Active Directory or ADAM features such as account expirations, password policies, connectivity to Exchange, etc? what if you already have a set of users that you are hosting in Active Directory and now you want to build a website or portal for those users without managing two sets of accounts? This is when this article will be helpful.
When developing a web portal that uses Active Directory users, there are a few things that you need to consider in your web application?
- How will your web application communicate with Active Directory?
- How will you authenticate against Active Directory?
- How do you allow users to self-register into the portal?
- How will users be able to change their passwords or reset their passwords?
- How will the users be able to update their profile information such as email?
- How will the portal administrators be able to assign permissions for users?
- How will administrators be able to add users to certain Active Directory groups without going into Active Directory Users and Groups?
A special application called the .Net Active Directory Wrapper has been developed that helps address this specific need and this article will show you how easy it is to interact with Active Directory using this module and to do the various tasks. The .Net Active Directory Wrapper uses ADSI and System.DirectoryServices Namespace to perform its functions.
Authentication
When building your own custom app that leverages Active Directory users, probably the first step you need to do is authenticate those users that are logging in.
There are two ways you can authenticate a user.
- Pass through authentication - here you find out who the user is from their windows session. Based on that logged in user, your application can decide whether to give the user access or not. No need for the user to input any username or password here.
- Logging in using a login form - here the user has to input the user name and password explicitly into a form. Your application will grab that information and authenticate based on the credentials inputted.
Windows Pass through authentication
Here you find out who the user is from their windows session. Based on that logged in user, your application can decide whether to give the user access or not. No need for the user to input any username or password here.
Usually this means the user is on the same domain as the portal application's web server.
To find out who the user is from the windows session, you can use the following code:
LDAPManager.CurrentUser()
this will return a string with the user's account in the following format: domain\username
if you wish to get the ADObject of that User to pull, say the email address of that user. Use the following line.
ADUser oUser = LDAPManager.GetCurrentUser();
string email = oUser.email;
Forms Authentication
In forms authentication, the user is manually inputting their credentials (username and password) into a login form. Use the authentication method if the user is not part of the same domain as the web server.
The process of authenticating a user involves a few subtle steps. You need to keep a few things in mind when doing this.
- What domain is the user logging into?
- Are the inputted credentials correct (meaning username and password)
- Is the account expired?
- If incorrect logon, you may want return the user with the reason of failure. Were they bad credentials or was the account expired?
In this .Net Active Directory Wrapper module, all steps listed above are available in one function as follows.
LDAPManager.Login(username, password);
The response from the above function returns true if the login is successful and false if not successful. If false, the response indicates why the logon is not successful, either because the account it was a bad username and password or it is an expired account.
User Registration / Account Creation
Most portal applications allow users to register in order access their portal or certain parts of the portal. For example, eBay requires you to browse and search for products but in order to buy something you must register first and create an account.
.Net Active Directory allows users to register easily. The registration involves asking for 3 necessary components:
- Username
- Password
- Email
The registration process may also require you to include additional information about yourself such as address, phone number, etc..
But the minimum core is username, password and email.
LDAPManager.CreateUser(username, password, email); OR
LDAPManager.CreateUser(username,password, email, location);
After creation of the user then you can update that user's properties such as the address and phone numbers as follows:
ADObject oUser = new ADUser();
oUser.StreetAddress = "streetaddress";
oUser.Phone1 = "1112223333";
oUser.CommitChanges();
Password Management
Password Management addresses two password management features
- Forgot Username and Password (password resets)
- Changing password
Forgotten Password
In most applications when a user forgets his/her password they are prompted with a form where they fill in the email address or their username and a link will be sent to that user's email address that allows them to reset their password and pick a new one.
This is provided that the email address is a unique identifier for the user account in Active Directory. You may also choose for them to input their usernames or sAmAccountName.
The email link that gets generated will have a unique id (usually a GUID) encoded into the URL. When the user clicks on the link in their email, the server checks to see if the GUID matches the GUID that it issued to that user, therefore confirming that the user trying to change the password is the same user that requested the password change. (Just a way of confirming the user requesting the password in fact owns that email address).
This is easily doable with the .Net Active Directory Wrapper as follows:
{LOGIC TO CHECK IF GUIDs MATCH}
{if match then}
ADUser oUser = New ADUser("[email protected]"); //finds the object from AD with that email
Try{
oUser.ChangePassword("newpassword");
}
{end if}
Change Password
Changing password is also a classic functionality in any fully baked application. The user in this case chooses to change his password for any reason, maybe he had it shared with his girl friend and now they broke up. Usually here the user is presented with a form that has three fields.
- Old Password field
- New Password
- Confirm New Password
The logic here should be as follows:
- If the old password is correct then
- If the new password field = the new password field then
- If the password meets minimum requirements, then
- Change password
Condition 1 and 2 above need to be handled by the application. Condition 3 can be handled by Active Directory (or whatever LDAP system you're using).
Condition 1 and 2 are easily available in the .Net Active Directory Wrapper module as follows:
ADUser oUser = New ADUser("janderson");
Try{
oUser.ChangePassword("oldpassword","newpassword1","newpassword2");
}
Catch{
{code: tell user password did not change successfully because of e.message}
}
User Profile Management
In your portal, you will probably need to add the functionality for your users or subscribers to be able to go in and update their personal information and profiles. Some of the common profile properties are:
- Account Login
- Email
- Personal Street Address, City, Country, Zip
- Business Street Address, City, Country, Zip
- Primary Phone number
- Secondary Phone number
- Title
In .Net Active Directory Wrapper, you are able to easily read and write that information to the user object as follows:
Try{
oUser.mail = "rjonhson"; //set the user's email
oUser.commit; // saves the changes to Active Directory
}
Advanced Profile Management
Option 1 - Use Active Directory
You may ask us ok, what if we need to store information about that user that is Active Directory does not support such as "Hobby" or "How did you hear about us?" Little do people know that you can actually store as many "attributes" as you wish in an Active Directory object usually by changing the user schema class. But more simply this could be done in another way.
This is also done using .Net Active Directory Wrapper as follows:
Try{
oUser.Properties["Hobby"] = "singing,fishing"; //where hobby is whatever new attribute you want.
oUser.Commit;
}
Keep in mind that if you decide to add new attributes that Active Directory does not use by default, you will need to document and plan the new attributes prior to actually using them, much like you would plan a database table.
Option 2 - User SQL Table
The other option of storing additional information about a user may also be storing that user information in a database table like SQL Server.
You will need a way to map the account in Active Directory to the table row that hosts the rest of the profile. There is probably no better choice to use than the username or the "sAMAccountName"
Account Cancellations
A portal user may decide to cancel his account or subscription. What you may wish to do with the users' Active Directory account may vary depending on what you are looking for. If a user opts to cancel what will you do with their Active Directory account?
- Delete the Account from Active Directory
- Lock the Account
- Or Lock the Account, take some action, the delete the Account?
Active Directory Wrapper allows you to easily delete or lock the account. This is done with the following lines of code.
Try{
LDAPManager.DeleteUser("domain\user");
}
OR
If you wish
Try{
LDAPManager.LockUserAccount("domain\user");
}
Permissions
Your portal application will probably need to be permission sensitive. You need your application to be able to restrict permissions on its sites, objects, or artifacts depending on who the user is, and there is no better way of leveraging Active Directory groups to do that.
Let's say for instance that you have a site and you only allow the users that belong to the "Administrators" group to enter that site. How do you enforce that security on the page?
Another tricky part of this is what if group B is in the Administrator group and user1 is in group B?
In that case you would want user1 to be able to see the page.
The best way to do this to run the security check on the ON LOAD event of that page. Let's take a look:
On Load{
If (LDAPManager.IsInGroup("domain\userid", "groupname")) {
{CODE: Display the Administration Page}
}
Else{
{CODE: redirect to Access Denied Page}
}
}
Another function that will come in handy is the IsCurrentUserInGroup. This function will use the current user that is logged into the windows desktop session and see if they are in the group. You would simply have to replace the function above with the following:
LDAPManager.IsCurrentUserInGroup("groupname");
Note that this function returns the effective group that the user is in as we mentioned above. By "effective" we mean the following.
If the user is a member of group A and group A is a member of group B. then the user is "effectively" a member of group B.
The IsInGroup function returns true if User.IsInGroup("B") is executed.
Active Directory Groups Management
Portal Administrators need to be able to create Active Directory groups without going into Active Directory. A web interface for viewing, creating and deleting groups needs to be put in place.
Using .Net Active Directory Wrapper, this could be done easily via the following methods.
Creating Groups
To create a group simply pass the group name you wish to create to the CreateGroup function as a string. The group will be a global security group and the location of the group will default to the Users container
LDAPManager.CreateGroup("groupname");
There is also the option of adding that group in a specific OU.
LDAPManager.CreateGroup("groupname","OUName");
This function works provided that that there is only one OU with that name. If more OUs exist you can use the path to where you wish to create that group as follows:
LDAPManager.CreateGroup("groupname", "LDAP://CN=User1,CN=users,DC=domain,DC=com");
Add User to a group
Adding a user to a group will often be necessary in Active Directory and has many applications.
You may have few key groups in your Active Directory. Here's an example:
- Portal Administrators - user's that manage permissions, accounts, content, etc...
- Viewers - users that just see content
- Power Users - users that can add content and manager a subset of users.
Adding users to the various groups could be done easily in .Net Active Directory Wrapper as follows:
LDAPManager.AddUserToGroup("domain\user","groupname") //where groupname is the common name of the object
oUser.AddToGroup("PowerUsers");
Note that the function above will execute immediately and there is no need to use the commitchanges function to add the use to the group.
The other method is to use the AddUsers from the ADGroup object.
ADGroup oGroup("PowerUsers");
oGroup.AddUsers("User1");
if you wish to pass many users at once you can use:
oGroup.AddUsers(new string[] { "John", "Mike", "Sandeep" });
Deleting Users from a Group
Obviously if you can add users to a group you must also be able to remove users.
oGroup.RemoveUsers("username");
or to remove a group of users
oGroup.RemoveUsers(new string[] { "John", "Mike", "Sandeep" });
Deleting a Group
Deleting an Active Directory group without going into Active Directory Users and Computers will probably be an important task for an administrator to do. You can easily code this in your application as follows:
LDAPManager.DeleteGroup("groupname");
Or you can also use the method found in the ADGroup object.
ADGroup oGroup = new ADGroup("mygroup");
oGroup.Delete();
Listing Members of a Group
When administering your portal, you will probably want to know who is in the "Powerusers" or any group per say.
In order to find out who thedirect members of a group are use:
oGroup.Members();
This function will return an ArrayList of all the usernames that are found in that group.
Listing all "effective" members of a Group
oGroup.Members will list the users that belong that group. But consider this scenario:
you have group A that has user1, user2 and user3 and group B it.
In group B you have user 3 and user 4.
"Effectively", User 3 and User 4 are technically also belong to group A because group B in A. and this scenario can get much more complicated.
To find out all the effective members of a group use
oGroup.EffectiveMembers();
This will return an array list of all the users in the group, and all the users in the sub groups, and what group they map to.
Arralist will look as follows:
User1 |
Group A |
User2 |
Group A |
User3 |
Group A |
User4 |
Group B |
User 5 |
Group B |
Auditing Permissions
This allows you to see what groups a user in part of in Active Directory.
LDAPManager.FindMembership("user1");
This will list all the groups, that a user is a member of directly and indirectly.
Or
oUser.FindMemberships()