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:
- 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.
- If the same userName is enabled in both domains, Join on samAccountName.
- 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.
- 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.
- 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.
- 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)
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 “OldDomain\myUser” 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 “OldDomain\myUser” I now see “NewDomain\myUser”, but why?
I checked ILM and indeed the objectSid in the userProxy object was from OldDomain\myUser, but it resolved as “NewDomain\myUser”. 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
September 06 10:54 PM
Comment posted by (namnlös)
at 1/31/2008 3:04:00 AM
September 03 4:07 AM
Comment posted by Jef
at 6/27/2008 12:18:00 AM
June 27 12:18 PM
Comment posted by Dmitri Gavrilov [MSFT]
at 6/27/2008 11:31:00 AM
June 27 11:31 AM