Recently while working through a domain migration with a client, the question came up if the NetScaler LDAP authentication could be set to ignore disabled accounts. The NetScaler Gateway was serving two domains, and the migrated accounts were going to have the same username in both domains. The accounts would be pre-staged in the target domain, and then disabled in the source domain once the user migration was completed. I did find a way to do it, and past the break I'll tell you how as well as explain a bit about how the NetScaler does LDAP searches.
The main issue I was confronted with is that users had never been required to select a domain when logging in remotely. The client did not want users to have to change their process, so we had to make it transparent to both users that had been migrated and those who were still in the source domain. By pre-populating target accounts, there was going to be a viable user account in each domain. So the source domain had to be first in the list of domains to attempt authentication against. Within the primary authentication policies on the NetScaler Gateway, the source domain policy was given a priority of 80 and the target domain policy was given a priority of 90. So the source domain would be checked first. Now once a user was migrated they would be using their account in the target domain, and their source domain account would be disabled. So we needed the source domain policy to ignore disabled accounts and move on to the target domain policy and try to authenticate against that. The magic in this case is with the Search Filter in the LDAP server object.
The Search Filter is what the NetScaler Gateway uses to search LDAP to try and find a user object. The Search Filter is combined with the Server Logon Name Attribute to form an LDAP query that is submitted to the LDAP server. You can observe the process if you SSH into the NetScaler, drop to the shell, and run 'cat /tmp/aaad.debug'. That file is a direct pipe into the aaa process, so it does not save any content locally. You could pipe it to the screen or to a file to capture the output as authentication attempts are made.
Let's say I am user nedtest01 on source.local. When I submit my username and password, the NetScaler creates an LDAP query like this:
ns_ldap_search Searching for
<<(samAccountName=nedtest01)>> from base
<<dc=source,dc=local>>
It's just looking for a user object with a matching samAccountName. Anything you add to the Search Filter is included as an & portion of the LDAP query. A quick search for locating disabled accounts in Active Directory will find you this wonderful string:
(userAccountControl:1.2.840.113556.1.4.803:=2)
All that gobbledygook simply refers to any account that is disabled in AD. By placing a '!' on the front, the property is negated and so by placing this in the Search Filter:
!(userAccountControl:1.2.840.113556.1.4.803:=2)
I now get this LDAP search:
ns_ldap_search Searching for
<<(& (samAccountName=nedtest01)
(!(userAccountControl:1.2.840.113556.1.4.803:=2)))>> from base
<<dc=source,dc=local>>
Since my account is disabled post migration, the search will come back with no results, and the NetScaler will move on to the next LDAP authentication source. Hooray!
Labels: Active Directory, Citrix, LDAP, NetScaler, NetScaler Gateway