The Hoju Saram

Monday, January 08, 2007

.Net User Managable Access Control with AD User and Group Support.

For all articles relating to Domino to .Net conversion please see this post

Previously I posted about extending the SQLRoleProvider to allow for the use of AD groups.

This by itself is not that useful, so I have now created a project that uses this to show how to create a system for User-Managable Access Control with AD User and Group Support.

I have a zipped copy of this project available for dowload here.

The features that is project provides are:



  • SQL Roleprovider that supports AD group membership to determine application roles.

  • Access Control page to support the administration of users and groups and granting them application roles.

  • AD Search system to allow for the easy look-up of users and groups in the Active Directory and add them to the Access Control List


By using this system you can allow a specific group of users to manage access to the .net application themselves, as it supports AD group membership then the Access Control is very easy to use.

A couple of screen shots of the system in action are below.

Access Control List

Roles Tab

Searching Active Directory

To set it up you will firstly need to download the project, then install the standard .net SQLProvider system on your server . This can be found here, with additional set-up instructions in my previous post.

Once you have that set-up then you will need to run the additional SQL against the database found in the DBSetup folder of the project (this will add two new stored procedures to the standard SQLProvider database – you may need to alter the SQL permissions on these two stored procs to make them run in your environment).

After you have done that then you will need to alter the web.config of the project so that is matches your environment. You will need to adjust the connections string for the SQLRoleManagerConnection and some appsetting keys:

ADUser – this is the Domain\userid of the id used to query the Active directory when searching for users and groups

ADPasswd – this is the password of the ADUser

ADBrowsableDomains – this is a comma seperated list of all of the available domains in your environment.

DBRolesEdit – true or false to determine if the Access control Roles are editable. If you are implementing a system that uses static roles for access with a web.config setup like. Then set this to false. Otherwise set it to true to allow uses to update it.

ACLAdminRole – this is the Application Role that can edit the Access Control of the system. If the user ( or one of the users AD membership groups , if the user isn’t explicity listed ) is in this role then they can edit the ACL via the ACL.apsx page.

You will need to make sure that you have at least run the SQL statements

EXEC aspnet_Roles_CreateRole 'SQLProviderTest', '[ACLAdminRole]'
EXEC aspnet_UsersInRoles_AddUsersToRoles 'SQLProviderTest', ' YourDomain\YourId', '[ACLAdminRole]', 8

Once you have added yourself to the role that can edit the ACL (the value of the ACLAdminRole web.config key ) then you will be able to update the ACL.aspx page. You can then go to the default.aspx page and see which roles you are in.

For a better user experience I would suggest wrapping the content of the ACL.aspx page in a AJAX panel. I have purposely not done this because they are a variety of AJAX implemetations around, so this is up to you.

Happy Coding.

Labels: , ,

Wednesday, December 20, 2006

Extending SQLRoleProvider to Support Active Directory Group Membership.

This is a ASP 2.0 + solution, for ASP .Net Apps using Integrated Windows Authentication. Please note this post has been updated.

The System.Web.Security.SqlRoleProvider allows you to store and manage Roles for your .net web applications in an SQL Database. This is very useful for building ASP .Net application where you want to a group of “admin” end-users to be able manage who can access a system and what they can do. ( I will talk about building a AD integrated System access management system in a later blog, right now I will concentrate on the nuts and bolts).

Using the standard SQLProvider system roles are provided on a per user basis, so if you have thousands of users for the system then you would need to actually add each user individually. The whole point of this is to provide “end-user” system management, so I want to make it as easy as possible.

Then I thought that it would be much easier if I could extend the default SQLProfileprovider to support Active Directory groups. That way if a set of users where already defined in Active Directory group then all the “admin” users would need to do is grant that group the role in the application and that would give everyone in that group access, and keep the system far more manageable.

If you haven’t already used an SQL Roleprovider then you need to go the http://msdn2.microsoft.com/en-us/library/ms998314.aspx and follow the instructions related to the SQLRoleprovider. This will install a default installation of the Role provider database that integrates with the standard system.Web.Security.SqlRoleProvider. Make sure that if you run the stored procedures the application name matches the applicationName in the Providers Key in your web.config and make sure that the name you use is your Domain\User name.

So for example if I have AppName of SQLProviderTest a Role called Admin and my user is MYDOM\User1 so I issue the commands.

EXEC aspnet_Roles_CreateRole 'SQLProviderTest', 'Admin'
EXEC aspnet_UsersInRoles_AddUsersToRoles 'SQLProviderTest', ' MYDOM\User1', 'Admin', 8

And the web.config section would look something like this

<roleManager enabled="true" defaultProvider="SQLRoleProvider" cacheRolesInCookie="true"> <providers> <add name="SQLRoleProvider" type="System.Web.Security.SQLRoleProvider" connectionStringName="SqlRoleManagerConnection" applicationName="SQLProviderTest" /> </providers> </roleManager>


If you then compile and run default.aspx as specified in the instructions you it should display that you are in the role.

So we need to extend the standard SqlRoleProvider to support groups. Below is the code for the ADSQLRoleProvider class. To implement this do the following steps:

In visual studio create a App_Code folder under the root directory of your web project.


Add new class file in this folder called ADSQLRoleProvider.cs
Paste the following code into the class code file and save it.

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Security;
using System.Web;
using System.Security.Principal;

/// <summary>
/// Summary description for ADSQLRoleProvider
/// </summary>
public class ADSQLRoleProvider : System.Web.Security.SqlRoleProvider{

public ADSQLRoleProvider(){}

#region ADLookup & Support Methods

private string[] getusersADgroups(IIdentity User)
{

//HttpContext.Current.User;
WindowsIdentity Wident = (WindowsIdentity)User;
List<string> groups = new List<string>();

IdentityReferenceCollection UGroups = Wident.Groups;

foreach (IdentityReference Grp in UGroups)
{

NTAccount acc = (NTAccount)Grp.Translate(typeof(NTAccount));
groups.Add(acc.Value);
}

return groups.ToArray();

}
private string[] GetRolesForGroup(string groupname)
{
return base.GetRolesForUser(groupname);
}
#endregion

#region Extended SQLRoleProvider Methods
public override bool IsUserInRole(string username, string roleName)
{
if (base.IsUserInRole(username,roleName))
{
return true;
}
else
{
string[] Ugrps = getusersADgroups(HttpContext.Current.User.Identity);
string[] GroupsRoles;

foreach (string g in Ugrps)
{
GroupsRoles = GetRolesForGroup(g);
foreach (string grole in GroupsRoles)
{
if (grole == roleName)
{
return true;
}
}
}
}
return false;
}

public override string[] GetRolesForUser(string username)
{
System.Collections.Generic.List<string> roleList = new List<string>();

string[] ActualUserRoles = base.GetRolesForUser(username);

//Only do the next check if the username matches the current web user and the users roles are empty

if ((ActualUserRoles.Length == 0) && (username.ToLower() == HttpContext.Current.User.Identity.Name.ToLower()))
{

string[] Ugrps = getusersADgroups(HttpContext.Current.User.Identity);
string[] GroupsRoles;

foreach (string g in Ugrps)
{
GroupsRoles = GetRolesForGroup(g);
foreach (string grole in GroupsRoles)
{
if (!(roleList.Exists(delegate(string s) { return s == grole; })))
{
roleList.Add(grole);
}

}
}
return roleList.ToArray();
}
else
{
return ActualUserRoles;
}
}
#endregion
}



Open the web.config file and make sure that the original connection string for the Roleprovider database is correct.
Change the role provider section in the web.config to

<roleManager enabled="true" defaultProvider="ADSQLRoleProvider" cacheRolesInCookie="true"> <providers> <add name="ADSQLRoleProvider" type="ADSQLRoleProvider" connectionStringName="SqlRoleManagerConnection" applicationName="SQLProviderTest" /> </providers> </roleManager>

Compile the website to make sure you don’t get errors.

You have now update the application to use a custom sqlroleprovider that will first check for roles of a user, and if it doesn’t find any it will then check for any roles belonging to any Active Directory groups that user is a member of.

To test that this is working remove yourself from the role by running the stored proc aspnet_UsersInRoles_RemoveUsersFromRoles

For my example above this is

EXEC aspnet_UsersInRoles_RemoveUsersFromRoles 'SQLProviderTest', 'MYDOM\User1', 'Admin'

Re-run the application to make sure that you are not in any roles.

Now add a domain group that you are a member of to the Admin role. For my example the user MYDOM\User1 is a member of MYDOM\IT_Apps group so I will add that one with the Stored proc command

EXEC aspnet_UsersInRoles_AddUsersToRoles 'SQLProviderTest', ' MYDOM\IT_Apps', 'Admin', 8

If you run the application again you will see that you are in the role.

In up and coming blogging I will talk about how to build the user-front end to this, that allows users to search, select and assign roles to AD users and groups. This will allow you to build easy use managed applications with role based security. Some screen shots of what I am talking about are below:




Labels: , ,