I had an interesting afternoon today, trying to identify an issue that occurred while working on a user migration project.  This is a solution I have used for many apps that only support a single Domain/Naming context when in a distributed directory environment.  The benefits and issues with this for long term use will be for another post all together.

Some background on the plan, is that due to an acquisition, there is a planned migration from a legacy Active Directory domain, into a new Active Directory forest/domain.  Ultimately we want to use the same username from the OldDomain in the NewDomain, so that the user experience for the applications are pretty seamless to the users of the applications.  Many of these applications only require a username and a password which is used to BIND to an LDAP directory for a success/failure status, and then a possible query for any user metadata or groups.

Things to note:

  • A single Big Bang migration is not possible, and needs to be a phase migration of users
  • Many applications only support a simple BIND to a single LDAP directory
  • Users are domains in different forests (Sorry, no GCs )
  • User Names are unique between OldDomain and NewDomain

During this migration period, applications will need to authenticate and do LDAP queries for user information, but many of the applications only support 1 domain/Naming context.  They also only support Simple LDAP binds, and rarely a SASL bind among them.

One of the solutions for these single NC dependent applications, was to utilize Identity Life Cycle Manager (ILM) and Active Directory in Application Mode (ADAM) to give these applications the ability to authenticate users from multiple domains, but still provide a single BIND point.

This can be accomplished by using ILM to import the user data from OldDomain and NewDomain, and provision userProxy objects into an ADAM instance which becomes the central point of application Binding.   The userProxy object (it does not need to be userProxy, it just needs to support the msDS-bindProxy aux class) does not contain a password like a normal user object, but instead proxies the simple bind authentication request to the Active Directory Domain that the userProxy is linked too.  This linking is done by populating the objectSid property of the ADAM user with the SID of the parent AD user.  When the SIMPLE bind to ADAM for that username,  the request is sent to AD using the local Security API (More on this later).  You can read more about Bind Redirection for ADAM Proxy Objects here.  The benefit is that all your auditing/compliance/support is managed at the Active Directory level, and not at the ADAM level.  This avoids having to sync user passwords to ADAM, and all the issues that may arise with that.

The export/provision rules from ILM to ADAM can be summarized as:

  1. Filter out DISABLED users from entering the Metaverse.  This insures that we only have the enabled accounts, or the ones which could be used for authentication.
  2. If the same userName  is enabled in both domains,  Join on samAccountName.
  3. Set the NewDomain user data as a higher precedence for contribution.  This means if both user accounts are enabled,  the NewDomain data replaces OldDomain Data when exported to ADAM.
  4. The assumption is,  that NewDomain accounts are to be enabled once the user has been completely migrated and is actively using the NewDomain account for primary account.
  5. Since ADAM is keyed on samAccountName, only one account with the same name can be in the ADAM directory at one time.  The objectSid associated with that name will belong to the ENABLED account of the pair.
  6. The ADAM directory is in newDomain Domain.

So LDAP applications pointing to ADAM request the userName and the Password from the endUser.  Users in OldDomain who are yet to be migrated continue to use their existing userName and password and authenticate against OldDomain.  Users who have been migrated, and Enabled,  use the same userName and password, but authenticate toward NewDomain.   As long as the passwords are synced at time of Enabling the NewDomain user account, the transition can be seamless.  In the end,  all the users will be migrated to NewDomain, but the applications will be able to authenticate users from both domains, because they appear as single Domain when Binding.

Here is a quick example of how this works below. (I didn’t have Visio handy, so I had to user Power Point)

ILM ADLDS BindProxy Sync Diagram

ILM ADLDS BindProxy Sync Diagram

Now that I have tried to explain all of that (in a long winded way),  let me get back to the issue that was found out today.  The solution above has been working as designed with much success.  It has allowed the phased migration of users while the applications can authenticate users from both domains.

Today I receive a call that all of sudden the users are getting told they cannot logon when pointing to ADAM.   I quickly checked the users in ADAM and everything looked fine as far as user properties are concerned.   When using this solution I find it’s helpful to flow the string value of the Domain and Username that belong to the objectSid of the userProxy object because it may not be visually evident that what the ADAM user will proxy back as. (I usually create an attribute called parentADuser for this).  The user in question was showing a value of “OldDomainmyUser” since the user had not been migrated to newDomain yet, this seemed correct.  So I decided to check with ADfind, and the -resolveSids switch, which will translate the objectSid to the textual representation of the domain and user that matches that objectSid.  Instead of seeing “OldDomainmyUser” I now see “NewDomainmyUser”, but why?

I checked ILM and indeed the objectSid in the userProxy object was from OldDomainmyUser, but it resolved as “NewDomainmyUser”.   I checked to see if the newDomain user had been enabled since that SID would take precedence in the exporting to ADAM, but it indeed was Disabled.

So the oldDomain SID now translates to the NewDomain user, which means that when an authentication request comes in, it is being proxied to the NewDomain user, which is disabled. This would explain why the user could not logon.

So why was this happening?  It turns out that the migration team in an effort to pre-stage the migration had added the oldDomain SID to the sidHistory of the NewDomain user.   Now since ADAM uses the LSA API’s to authenticate the userProxy object,  it was sending the OldDomain SID, to the newDomain. the newDomain would realize it now has a user matching that SID (in sidHistory) and attempt to proxy the auth to the newDomain user.

The solution?   Remove sidHistory from disabled user accounts in NewDomain, until the user was ready to be migrated and enabled.  This means that Proxied Auth from ADAM would go to the oldDomain user account and not the disabled newDomain user account.  Of course this should have been tested by the migration team earlier, but it was an interesting hour or so today as I pieced together the puzzle to find out what was going on.

So what did I learn from this situation?  When using ADAM bind redirection,  to remember that the authentication uses the local security API of the ADAM server. This means it will attempt to resolve the SIDs from the Domain the server belongs too.  If sidHistory is contained on that user object in AD, for the SID from the foreign domain, it will authenticate to the local Domain first before going to the foreign domain.  This seems very logical when you think about it, but obviously it has implications when using this solution for a migration project.

I also learned it’s quite hard to summarize everything in a single Blog post, and still have it make sense.  :)

Comment posted by Jef

at 1/31/2008 6:10:00 PM

Jef

Peter,
Glad to hear from you after so long!  I sent you an invite on messenger.
I know it CAN be done, but unfortunately many vendors and developers don’t do it correctly. :(   My team gets stuck “making it work” and use this solution more often than I’d like too when we get stuck with a product the vendor is locked into a single naming context, or uses directory guessing techniques which have their own issue. :(
Maybe I should post a naughty list of vendors and products out there that don’t play well in a multi-domain environment…
Hope to hear from you!

September 06 10:54 PM
Comment posted by (namnlös)

at 1/31/2008 3:04:00 AM

(namnlös)

Hi jef,
I have done some migrations and I see that you mentioned that you cant bind two domains at the same time…I assume thats why you use the ADAM in the middle.
Actally you can bind more than one domain at the same time, I have som vbs that does the job if youre interested, both for user and group migration and for reACLing the file structures…
Second, if you like, add me to your MSN! mail is: firstnameLastname@hotmail.com FirstnameLastname = peterwestling
Have a nice day!

September 03 4:07 AM (http://banan-republiken.spaces.live.com/)
Comment posted by Jef

at 6/27/2008 12:18:00 AM

Jef

Dmitri,
I forgot to mention that as one of the options we had considered.  Doing so would not fit the migration timeline because oldDomain is going offline at seperation (in a few months) and we would have to move ADAM then, etc.   Also in my scenario oldDomain is not managed by the same group as newDomain, which could expose passwords over LDAP simple binds where SSL is not used, etc.  But yes, it would be viable since the oldDomain sid would be tried against oldDomain first :)
We did think about moving the ADAM box to the ROOT domain of the forest newDomain is in,  but it still resolves the oldDomain sid as newDomain which makes sense.
Thanks for the feedback.

June 27 12:18 PM
Comment posted by Dmitri Gavrilov [MSFT]

at 6/27/2008 11:31:00 AM

Dmitri Gavrilov [MSFT]

Just for completeness, another option is to join ADAM machine to the OldDomain. Of course, this option might not be feasible in many deployments.

June 27 11:31 AM

  • http://jeftek.com/164/upn-and-cross-forest-ldap-simple-binds/ UPN and cross-forest

    RE: ADAM, userProxy, and sidHistory: Not always what you expected
    Recently I was looking to help an application built on ColdFusion's CFLDAP module, which relied upon LDAP for "authentication", and could only be used with simple binds as a mechanism for presenting a username/password. I am working ain a multi

  • http://clintboessen.blogspot.com Clint Boessen [MVP]

    Thankyou very much for post Jef – it greatly helped me out.
    My recent post Exception- The Active Directory user wasnt found