Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Group Claim Augmentation does not work if display name is different from SamAccountName for Group #134

Closed
NaveenKanukuntla opened this issue Nov 5, 2020 · 11 comments
Assignees

Comments

@NaveenKanukuntla
Copy link

When I try to provide access to users using an AD Group. My AD Group name is 'IT-DepartmentName'. But the display name is 'Department Name'.

So, while logging in, although claims augmentation is completed successfully, it does not match my group SamAccountName. Since during claims augmentation, it resolves to group display name and I never get access to the site due to the mis-match in Group display name vs Group SamAccountName.

@Yvand
Copy link
Owner

Yvand commented Nov 10, 2020

You can set what attribute is used to create group claims, and by default it's the samAccountName: Go to Central Administration > Security > LDAPCP Claim types configuration.
You can also double check how LDAPCP creates groups claims by filtering SharePoint logs on product/area "LDAPCP" (enable verbose to see individual groups)

@Yvand Yvand self-assigned this Nov 10, 2020
@Yvand Yvand added the Issue label Nov 10, 2020
@NaveenKanukuntla
Copy link
Author

NaveenKanukuntla commented Nov 10, 2020

Thanks for your reply Yvan. I have debugged the code and I can see that the code is retrieving the memberOf property from Active Directory for logged in user.

The MemberOf property looks something like this for each attribute :
image

As you can see in the picture, it pulls distinguished name, strips the string and extracts just the name of the group from it.

If I do a lookup for this group in AD using PowerShell. This is what I get. I can never search it using the name, I must use the SamAccountName.
image

And this what I can see from the ULS Logs, which is how groups are augmented during initial login.
image

As you can see from the first screenshot, I am part of NAPP_FIM_SP-SPAdmin Group, but since the augmentation is done using name of the group and not the samaccountname (SP-SPAdmin), I get access denied.

image

Here is the block of code that does Group Augmentation :

claimValue = OperationContext.GetValueFromDistinguishedName(value);
if (String.IsNullOrEmpty(claimValue)) { continue; }

                                        string groupDomainName, groupDomainFqdn;
                                        OperationContext.GetDomainInformation(value, out groupDomainName, out groupDomainFqdn);
                                        if (!String.IsNullOrEmpty(groupCTConfig.ClaimValuePrefix) && groupCTConfig.ClaimValuePrefix.Contains(ClaimsProviderConstants.LDAPCPCONFIG_TOKENDOMAINNAME))
                                        {
                                            claimValue = groupCTConfig.ClaimValuePrefix.Replace(ClaimsProviderConstants.LDAPCPCONFIG_TOKENDOMAINNAME, groupDomainName) + claimValue;
                                        }
                                        else if (!String.IsNullOrEmpty(groupCTConfig.ClaimValuePrefix) && groupCTConfig.ClaimValuePrefix.Contains(ClaimsProviderConstants.LDAPCPCONFIG_TOKENDOMAINFQDN))
                                        {
                                            claimValue = groupCTConfig.ClaimValuePrefix.Replace(ClaimsProviderConstants.LDAPCPCONFIG_TOKENDOMAINFQDN, groupDomainFqdn) + claimValue;
                                        }
                                    }
                                    else
                                    {
                                        claimValue = value;
                                    }

                                    SPClaim claim = CreateClaim(groupCTConfig.ClaimType, claimValue, groupCTConfig.ClaimValueType, false);
                                    groups.Add(claim);

         /// <summary>
        /// Return the value from a distinguished name, or an empty string if not found.
        /// </summary>
        /// <param name="distinguishedNameValue">e.g. "CN=group1,CN=Users,DC=contoso,DC=local"</param>
        /// <returns>e.g. "group1", or an empty string if not found</returns>
        public static string GetValueFromDistinguishedName(string distinguishedNameValue)
        {
            int equalsIndex = distinguishedNameValue.IndexOf("=", 1);
            int commaIndex = distinguishedNameValue.IndexOf(",", 1);
            if (equalsIndex != -1 && commaIndex != -1)
            {
                return distinguishedNameValue.Substring(equalsIndex + 1, commaIndex - equalsIndex - 1);
            }
            else
            {
                return String.Empty;
            }
        }

Here is my LDAPCP Claims Configuration
image

@Yvand
Copy link
Owner

Yvand commented Nov 10, 2020

Hi @NaveenKanukuntla, your analysis is perfectly correct:
In this code path, LDAPCP uses the DistinguishedName of the group to set its claim value, regardless of what is set in the claims mapping table.
The reason for this design is that the LDAP object available here is the user. The only info LDAPCP has about the groups is their DistinguishedName values in property memberof of the user.
To actually set the claim value of groups with their samAccountName, LDAPCP would need to do 1 additional LDAP query for each group, which may have a significant impact on performance.

A possible alternative is to get the groups using method LDAPCP.GetGroupsFromActiveDirectory(), which should set the claim value of group with their samAccountName. For that you need to check the option "Use .NET helper (for Active Directory only)" in LDAPCP global configuration page. Did you consider it?

@NaveenKanukuntla
Copy link
Author

Hi @Yvand . Thanks for the quick reply. I initially started using .NET Helper setting.

But, it looks like that method does not use secure authentication, the authentication type is set to None. Hence any calls to my directory simply fails to query anything or maybe the filter is incorrect.

See the ULS logs below after setting the setting to use .NET Helper method.
image

As you can see, it completes the query in 0ms, which does not seem normal to me. Like you said, I figured that I will have to do one additional query if I use 'Query this Server' setting instead of 'Use .NET helper' setting.

@Yvand
Copy link
Owner

Yvand commented Nov 10, 2020

You can configure a secure connection using the authentication options (check boxes) in the LDAP connection section, at the top of LDAPCP global configuration page (you will need to delete and re-add the connection)

@NaveenKanukuntla
Copy link
Author

NaveenKanukuntla commented Nov 10, 2020

Hi @Yvand .

I created it multiple times. Still it did not work, hence switched back to Query LDAP Server option.

I was debugging the code to see what was going on. In LDAPCP.cs, I noticed you put a comment. See below line.

// BUG: Filters must be set in an object created in this method (to be bound to current thread), otherwise filter may be updated by multiple threads
List<LDAPConnection> ldapServers = new List<LDAPConnection>(this.CurrentConfiguration.LDAPConnectionsProp.Count);

the ldapServers object is empty, hence the query is failing since there are no LDAP servers to query.

CurrentConfiguration.LDAPConnectionsProp.Count object does show a count = 1, but the instantiation of the object(new List<LDAPConnection>) is not working. It is empty after the debugger goes to next line.

image

What filter were you inferring to when you said // BUG: Filters must be set in an object created in this method ?
Any idea, why it would fail to instantiate ?

EDIT : I figured what was going on, the foreach loop following the line mentioned above

 foreach (LDAPConnection ldapServer in this.CurrentConfiguration.LDAPConnectionsProp.Where(x => x.EnableAugmentation))
                    {
                        ldapServers.Add(ldapServer.CopyConfiguration());
                    }

Even though i saved the connection with 'Enable augmentation' never gets saved into my persistedobject store in SharePoint.
Hence there is nothing to iterate over as the statement relies on connections where EnableAugmentation = true.

image

Now I have to figure out why it would not save my augmentation setting.

@Yvand
Copy link
Owner

Yvand commented Nov 12, 2020

I did a very quick test of the augmentation, and the logs confirm that the authentication is secured, using the the authentication options that I checked when I added the connection:

11/12/2020 09:34:34.25	powershell_ise.exe (0x1CE4)	0x1A74	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] Starting augmentation for user '[email protected]'.	a9b123b3-9f4b-0001-78ca-b550c7b8d601
11/12/2020 09:34:34.28	powershell_ise.exe (0x1CE4)	0x184C	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] Getting AD groups of user "[email protected]" from AD domain "contoso.local" (authenticate as "contoso\spcontentaccess" with AuthenticationType "SimpleBind, Signing, Sealing").	

Can you compare with your own logs?

@NaveenKanukuntla
Copy link
Author

NaveenKanukuntla commented Nov 12, 2020

I tried to do exactly what you said and this time i selcted both 'Query this Server' and 'Use .NET Helper'.
I have configured 4 domains to look for.

I see the following in logs

11/12/2020 10:59:17.77	w3wp.exe (0x3B20)	0x0F7C	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] Getting AD groups of user "User1" from AD domain "contoso.com" (authenticate as "contoso\superadmin" with AuthenticationType "SimpleBind").	
11/12/2020 10:59:17.77	w3wp.exe (0x3B20)	0x12C8	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] Getting AD groups of user "User1" from AD domain "fabrikam.com" (authenticate as "fabrikam\superadmin" with AuthenticationType "SimpleBind").	
11/12/2020 10:59:17.77	w3wp.exe (0x3B20)	0x25A4	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] Getting AD groups of user "User1" from AD domain "tailspin.com" (authenticate as "fabrikam\superadmin" with AuthenticationType "SimpleBind").	
11/12/2020 10:59:17.77	w3wp.exe (0x3B20)	0x1968	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] Getting AD groups of user "User1" from AD domain "acme.com" (authenticate as "fabrikam\superadmin" with AuthenticationType "SimpleBind").	
11/12/2020 10:59:17.79	w3wp.exe (0x3B20)	0x25A4	LDAPCP	Augmentation	1337	Unexpected	[LDAPCP] Unexpected error occurred while getting AD groups of user "User1" using UserPrincipal.GetAuthorizationGroups() from AD domain "tailspin.com" (authenticate as "fabrikam\superadmin" with AuthenticationType "SimpleBind").: System.DirectoryServices.DirectoryServicesCOMException: The user name or password is incorrect.  , Callstack:    at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)     at System.DirectoryServices.DirectoryEntry.Bind()     at System.DirectoryServices.DirectoryEntry.get_SchemaEntry()     at System.DirectoryServices.AccountManagement.ADStoreCtx.IsContainer(DirectoryEntry de)     at System.DirectoryServices.AccountManagement.ADStoreCtx..ctor(DirectoryEntry ctxBase, Boolean ownCtxBase, String username, String password, ContextOptions options)     at System.DirectoryServices.AccountManagement.PrincipalContext.CreateContextFromDirectoryEntry(DirectoryEntry entry)     at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()	
11/12/2020 10:59:17.79	w3wp.exe (0x3B20)	0x25A4	LDAPCP	Augmentation	1337	Medium	[LDAPCP] Got and processed 0 group(s) for user "User1" in 8 ms from AD domain "tailspin.com" (authenticate as "fabrikam\superadmin" with AuthenticationType "SimpleBind").	
11/12/2020 10:59:17.79	w3wp.exe (0x3B20)	0x1968	LDAPCP	Augmentation	1337	Unexpected	[LDAPCP] Unexpected error occurred while getting AD groups of user "User1" using UserPrincipal.GetAuthorizationGroups() from AD domain "acme.com" (authenticate as "fabrikam\superadmin" with AuthenticationType "SimpleBind").: System.DirectoryServices.DirectoryServicesCOMException: The user name or password is incorrect.  , Callstack:    at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)     at System.DirectoryServices.DirectoryEntry.Bind()     at System.DirectoryServices.DirectoryEntry.get_SchemaEntry()     at System.DirectoryServices.AccountManagement.ADStoreCtx.IsContainer(DirectoryEntry de)     at System.DirectoryServices.AccountManagement.ADStoreCtx..ctor(DirectoryEntry ctxBase, Boolean ownCtxBase, String username, String password, ContextOptions options)     at System.DirectoryServices.AccountManagement.PrincipalContext.CreateContextFromDirectoryEntry(DirectoryEntry entry)     at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()	
11/12/2020 10:59:17.79	w3wp.exe (0x3B20)	0x1968	LDAPCP	Augmentation	1337	Medium	[LDAPCP] Got and processed 0 group(s) for user "User1" in 9 ms from AD domain "acme.com" (authenticate as "fabrikam\superadmin" with AuthenticationType "SimpleBind").	
11/12/2020 10:59:17.79	w3wp.exe (0x3B20)	0x12C8	LDAPCP	Augmentation	1337	Medium	[LDAPCP] Got and processed 0 group(s) for user "User1" in 19 ms from AD domain "fabrikam.com" (authenticate as "fabrikam\superadmin" with AuthenticationType "SimpleBind").	
11/12/2020 10:59:18.07	w3wp.exe (0x3B20)	0x0F7C	LDAPCP	Augmentation	1337	Medium	[LDAPCP] Got and processed 3 group(s) for user "User1" in 289 ms from AD domain "contoso.com" (authenticate as "contoso\superadmin" with AuthenticationType "SimpleBind").	b9f58c9f-5529-8055-4170-cc0aa629cbb3
11/12/2020 10:59:18.07	w3wp.exe (0x3B20)	0x0F7C	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] LDAP queries to get group membership on all servers completed in 290ms	b9f58c9f-5529-8055-4170-cc0aa629cbb3
11/12/2020 10:59:18.07	w3wp.exe (0x3B20)	0x0F7C	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] Added group 'contoso\Domain Users', claim type 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' to user 'User1'	b9f58c9f-5529-8055-4170-cc0aa629cbb3
11/12/2020 10:59:18.07	w3wp.exe (0x3B20)	0x0F7C	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] Added group 'contoso\Users', claim type 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' to user 'User1'	b9f58c9f-5529-8055-4170-cc0aa629cbb3
11/12/2020 10:59:18.07	w3wp.exe (0x3B20)	0x0F7C	LDAPCP	Augmentation	1337	Verbose	[LDAPCP] Added group 'contoso\IT_Department', claim type 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' to user 'User1'	b9f58c9f-5529-8055-4170-cc0aa629cbb3
11/12/2020 10:59:18.07	w3wp.exe (0x3B20)	0x0F7C	LDAPCP	Augmentation	1337	Medium	[LDAPCP] User 'User1' was augmented with 3 groups	b9f58c9f-5529-8055-4170-cc0aa629cbb3

As you can see, if I select both 'Query this Server' and 'Use .NET Helper'. I see these unexpected errors for username and password that was used to connect to these 4 domains. I have verified it multiple times and the username or password is not incorrect.

Hence I chose 'Query this LDAP Server' and unchecked 'Use .NET Helper' option. Then I do get the groups but they do not match because of the name vs samaccountname difference.

One thing to note is user1 is local to domain contoso.com.

@Yvand
Copy link
Owner

Yvand commented Nov 16, 2020

I see that all connections are made with AuthenticationType "SimpleBind", while I guess you set something more secure?
To confirm if that's the actual issue, you can run the script below that gets group membership just like LDAPCP does when "Use .NET Helper" is set.
You only need to set variables at the top:

Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ldapUser = "contoso\spfarm"
if (!$ldapPassword) { $ldapPassword = Read-Host "Enter the password (will appear in clear text)" }
$userToAugment = "yvand"
$domainFQDN = "contoso.local"
# domainContainer must be set, otherwise UserPrincipal.FindByIdentity throsws error 0x80005000 (tested only in AD)
$domainContainer = "DC=contoso,DC=local"
$contextOptions = [System.DirectoryServices.AccountManagement.ContextOptions] "Negotiate, Signing, Sealing" # Encrypted connection, traffic unreadable in network analyzer
$contextOptions = [System.DirectoryServices.AccountManagement.ContextOptions] "SimpleBind" # LDAP traffic is in clear text
$contextType = [System.DirectoryServices.AccountManagement.ContextType]::Domain

$principalContext = $null
$principalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext ($contextType, $domainFQDN, $domainContainer, $contextOptions, $ldapUser, $ldapPassword)
if ($principalContext -ne $null -and [String]::IsNullOrEmpty($principalContext.ConnectedServer) -eq $false) {
    $principalContext
    $user = $null
    $user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($principalContext, $userToAugment)
    $groups = $user.GetAuthorizationGroups()

    # The foreach group calls an enumerator that does separate LDAP binds for each group
    foreach($group in $groups) {
        $group.SamAccountName
    }
}

@stale
Copy link

stale bot commented Dec 16, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Dec 16, 2020
@stale stale bot closed this as completed Dec 23, 2020
@rurikon
Copy link

rurikon commented Sep 7, 2021

Yvand, you commented earlier that "A possible alternative is to get the groups using method LDAPCP.GetGroupsFromActiveDirectory(), which should set the claim value of group with their samAccountName."

I was looking at the following lines in the code of GetGroupsFromActiveDirectory():

string claimValue = adGroup.Name;

claimValue = groupCTConfig.ClaimValuePrefix.Replace(ClaimsProviderConstants.LDAPCPCONFIG_TOKENDOMAINNAME, groupDomainName) + adGroup.Name;

claimValue = groupCTConfig.ClaimValuePrefix.Replace(ClaimsProviderConstants.LDAPCPCONFIG_TOKENDOMAINFQDN, groupDomainFqdn) + adGroup.Name;

To me this looks like it's using Name and not samAccountName. Would it be possible to modify this to look at whatever is set in the claim types configuration page?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants