Featured image of post Implementation of an Active Directory login

Implementation of an Active Directory login

After many years, it is still unclear how an Active Directory login differs from an LDAP login. Below are some examples of what steps need to be taken and what the potential pitfalls are

Long taking LDAP_MATCHING_RULE_IN_CHAIN

This particular LDAP query has been around for years, but it tends to take an exceptionally long time when run against a standard Active Directory (AD) environment. Recently, I wrote about a bug in Windows Server 2022 that was fixed, which relates to this issue. The query, once sent, returns a recursively resolved memberof attribute that includes all groups the user belongs to. I have encountered this query in several tools initially designed to work with a standard LDAP environment, which were later migrated to Active Directory. Presumably, it was intended as a straightforward method to adapt LDAP-authenticating tools to authenticate against AD. In my experience, this query took approximately 66 seconds to return a result. When run against the Global Catalog, it is significantly faster; however, it’s still not an ideal solution if performance is a priority.

1
2
3
4
5
6
7
8
    $memberOfGroups = @()
    $userid = "UserIdCn"
    $user = Get-ADObject -LDAPFilter "(cn=$userid)" -properties distinguishedName
    $userDn = $user.distinguishedName

    $ldapUser = Get-ADObject -LDAPFilter "(memberof:1.2.840.113556.1.4.1941:=$userDn)" 

    write-host $ldapUser

Manual way of group recursion

This is the simplest and easiest way to retrieve your recursive group memberships. While you have full control over the process, it’s important to note that it may involve making a significant number of queries to Active Directory. This overhead must be taken into account. However, this approach provides the flexibility to control the depth of your request. The example I’m providing is straightforward, but you can enhance this function with some recursion for better efficiency. My goal here was to keep it simple and demonstrate the basic concept.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    $memberOfGroups = @()
    $userid = "UserIdCn"
    $ldapUser = Get-ADObject -LDAPFilter "(cn=$userid)" -properties memberof

    foreach ($member in $ldapUser.memberof) {
        $memberOfGroups += $member
        $subGroup = get-ADObject -LDAPFilter "(distinguishedname=$member)" -properties memberof
        foreach ($member in $subGroup.memberof) {
            $memberOfGroups += $member
        }
    }
    write-host $memberOfGroups

Magic field tokenGroups

The tokenGroups attribute isn’t new, but because it is calculated on request, you might not have come across it. This attribute has been available since Windows Server 2000 and comes with specific requirements. It won’t work unless the Global Catalog is activated. Additionally, you need to perform your request using the distinguished name (DN) of the object (user) and set the search scope to “base.” When these conditions are met, the tokenGroups attribute will be populated with the recursively resolved SIDs of all the groups the user belongs to. This method is quite fast, taking only about 40 milliseconds. However, it only provides the object SIDs of your group memberships. If you need to resolve these SIDs into readable group names, you’ll need to follow up with additional queries or consider the next example.

1
2
3
4
5
6
7
8
    $memberOfGroups = @()
    $userid = "UserIdCn"
    $user = Get-ADObject -LDAPFilter "(cn=$userid)" -properties distinguishedName
    $userDn = $user.distinguishedName

    $ldapUser = Get-ADObject -LDAPFilter "(cn=$userid)" -Properties tokengroups -SearchScope base -SearchBase $userDn

    write-host $ldapUser.tokengroups

Tokengroups with resolved groupnames

This is the same approach as above, but with an additional step to retrieve all the group names from LDAP. While this method generates a significant number of queries, it is the only way to obtain the actual group names corresponding to the SIDs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    $memberOfGroups = @()
    $userid = "UserIdCn"
    $user = Get-ADObject -LDAPFilter "(cn=$userid)" -properties distinguishedName
    $userDn = $user.distinguishedName

    $ldapUser = Get-ADObject -LDAPFilter "(cn=$userid)" -Properties tokengroups -SearchScope base -SearchBase $userDn

    foreach ($tokenGroup in $ldapUser.tokengroups) {
        $ldapGroup = Get-ADObject -LDAPFilter "(objectsid=$($tokenGroup.value))" -Properties cn
        $memberOfGroups += $ldapGroup.cn
    }

    write-host $memberOfGroups

These are some examples on how to do the main part of simple ldap authentication against ad.

comments powered by Disqus
Developer / Inventor / Creator
Erstellt mit Hugo
Theme Stack gestaltet von Jimmy