How to:Mix Active Directory and Custom Authentication

How to:Mix Active Directory and Custom Authentication

Old forum URL: forums.lhotka.net/forums/t/1230.aspx


DeHaynes posted on Friday, September 15, 2006

Requirements

In my company I am dealing with three situations when it comes to Business Objects (BOs).

1.      I want to authenticate to Active Directory (AD) when inside my company Wide Area Network (WAN).  

2.      I have 700 - 7000 users who also need access to the same BOs via the Internet.  I do not want to the headache of maintaining those users in Active Directory, so I need to use Custom Authentication on the Intranet.

3.      Finally I know my user base will ask, "Why can't we access the data via the Internet?"  So I need to have Active Directory Authentication via the Internet as well.

 

The final result is that I need my BOs to be able to authenticate via Custom and Active Directory Authentication on the fly.

 

CHOICES

            Following the framework outline, I needed to create my own Identity and Principal objects which inherit from ReadOnlyBase, and implement the IIdentity interface.  I planned to follow the blueprint that Rockford used in his book. 

            When looking at how Rockford implemented his objects, I deduced that there are two distinct things happening, Authentication and Group Membership. 

 

Authentication

I only found one way to authenticate someone directly.  It required Interopt Services and importing functions from some windows DLLs.  I felt that this method was rather messy.

Another way I found to authenticate was to do a query against AD using the DirectorySearcher and providing it with the user’s credentials.  If the domain, username or password weren’t correct, it would throw an exception. 

Group Membership

During my research into how to authenticate with AD, I found WindowsIdentity and WindowsPrincipal in the System.DirectoryServices namespace.  I saw that there is a WindowsPrincipal().IsInRole("") method.  This could tell me if an AD user was in an AD group.  I also saw that there was a WindowsIdentity.Groups property that returned an IdentityReferenceCollection.  So I could use these to implement in the CanRead(), CanWrite(), etc functions in my BOs.  I did have one concern though. 

Rockford, in his example, loads all the groups for a particular user into the Identity class.  I didn’t know if the WindowsIdentity did the same thing.  I am under somewhat of a time crunch, so I decided to just follow the same process and load the AD groups into my custom Identity. 

            In addition, I found another method to get the groups a user belongs to and that was by doing a query against AD with the DirectorySearcher.  Since I already was going to use this to authenticate a user, I might as well use it to get the groups.

Implementation

            I needed to create the custom Identity and Principal objects to implement my authentication system.  My Principal object is exactly like the one in the book.  I changed very little of it except where it is required to work with my system.  All the real implementation was in the Identity object.

As far as the Identity object, the first thing I did was add a new field to the Criteria class inside my custom ANBOIdentity.  I also added some code to parse a Username or Domain passed in the form of <Username>\<Domain> or <Username>/<Domain>.  I also allow the user to supply a domain in the LDAP format.

Next I modified the DataPortal_Fetch(Criteria criteria) method of the Identity class. This method works two different ways.  If the domain field is an empty string, then it assumes that they want to use Custom Authentication.  If the domain field contains a value it assumes they want to use AD authentication.  So based on that, it goes to the appropriate system (SQL or AD), validates the user and loads the groups they are a member of into the Identity.

The code for the Custom Authentication part of DataPortal_Fetch is exactly the same as Rockford’s example except modified to work with my setup. 

The code for AD Authentication begins with the assumption that authentication fails.  It then proceeds through the following steps. 

1.      It creates the DirectorySearcher which requires the help of two private functions to make the parameters.  The parameters are the DLAPEntry, username which it puts in the format <domain>\<username> and the password.   

2.      Sets the search filter to look for our user.

3.      Specifies that we are only looking for the “memberOf” property

4.      Then executes a search

If the search fails, it will most likely cause an exception. 

In all my testing, I never saw a situation where result was null that didn’t cause an exception.  The reason I am keeping the null test is because that is how kit was in the example I looked at.

You can see that the class catches three exceptions.  The “Logon Failure” ones happen if a username or password is not valid.  The “A referral was returned” occurs if the domain is not valid.  The last exception occurs if a user is valid but belongs to no groups. 

Once a user is validated, the method loops through the “memberOf” properties and adds them to the _roles list.

At this point you use the unmodified framework authentication system.

 

Conclusion

            I attached a copy of my ANBOPrincipal and ANBOIdentity classes to this post in a zipped file.  Well, I hope this helps somebody.  It was fun to figure out.

 

 

 

 

 

 

 

tiago replied on Saturday, September 16, 2006

DeHaynes:

I attached a copy of my ANBOPrincipal and ANBOIdentity classes to this post in a zipped file.  Well, I hope this helps somebody.  It was fun to figure out.

You helped me :)

If an application is exposed both internally and on the Web we need AD and custom authentication.

I couldn't find the attachement though.

Cheers

Tiago

DeHaynes replied on Saturday, September 16, 2006

Sorry about that, I am a noob at this board.  I edited my original message and put it back.

tiago replied on Saturday, September 16, 2006

Tks

DansDreams replied on Monday, September 18, 2006

Thanks for sharing this.  I won't need this functionality for another six months or so, but I've added this to my favorites to look at then as a starting point.

IMO this is a feature that will just be taken for granted by the users and must be there for a combination smart client + asp.net environment.  At the same time is way cool for us that know what's going on behind the scenes.  :)

Copyright (c) Marimer LLC