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

LdapAdapter: Keep track of already processed groups to account for circular references #38817

Merged
merged 1 commit into from
Dec 9, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public static async Task RetrieveClaimsAsync(LdapSettings settings, ClaimsIdenti

if (!settings.IgnoreNestedGroups)
{
GetNestedGroups(settings.LdapConnection, identity, distinguishedName, groupCN, logger, retrievedClaims);
GetNestedGroups(settings.LdapConnection, identity, distinguishedName, groupCN, logger, retrievedClaims, new HashSet<string>());
}
else
{
Expand Down Expand Up @@ -96,8 +96,10 @@ public static async Task RetrieveClaimsAsync(LdapSettings settings, ClaimsIdenti
}
}

private static void GetNestedGroups(LdapConnection connection, ClaimsIdentity principal, string distinguishedName, string groupCN, ILogger logger, IList<string> retrievedClaims)
private static void GetNestedGroups(LdapConnection connection, ClaimsIdentity principal, string distinguishedName, string groupCN, ILogger logger, IList<string> retrievedClaims, HashSet<string> processedGroups)
{
retrievedClaims.Add(groupCN);

var filter = $"(&(objectClass=group)(sAMAccountName={groupCN}))"; // This is using ldap search query language, it is looking on the server for someUser
var searchRequest = new SearchRequest(distinguishedName, filter, SearchScope.Subtree);
var searchResponse = (SearchResponse)connection.SendRequest(searchRequest);
Expand All @@ -109,18 +111,26 @@ private static void GetNestedGroups(LdapConnection connection, ClaimsIdentity pr
logger.LogWarning($"More than one response received for query: {filter} with distinguished name: {distinguishedName}");
}

var group = searchResponse.Entries[0]; //Get the object that was found on ldap
string name = group.DistinguishedName;
retrievedClaims.Add(name);
Copy link
Contributor Author

@RoadTrain RoadTrain Dec 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, we use a group Common Name (CN, like SomeGroup) as a claim name. In this particular instance, a Distinguished Name (DN, like CN=SomeGroup,DC=domain,DC=com) was used instead, which I think is incorrect.
Possibly a typo, was introduced in #25075

var group = searchResponse.Entries[0]; // Get the object that was found on ldap
var groupDN = group.DistinguishedName;

processedGroups.Add(groupDN);

var memberof = group.Attributes["memberof"]; // You can access ldap Attributes with Attributes property
if (memberof != null)
{
foreach (var member in memberof)
{
var groupDN = $"{Encoding.UTF8.GetString((byte[])member)}";
var nestedGroupCN = groupDN.Split(',')[0].Substring("CN=".Length);
GetNestedGroups(connection, principal, distinguishedName, nestedGroupCN, logger, retrievedClaims);
var nestedGroupDN = $"{Encoding.UTF8.GetString((byte[])member)}";
var nestedGroupCN = nestedGroupDN.Split(',')[0].Substring("CN=".Length);

if (processedGroups.Contains(nestedGroupDN))
{
// We need to keep track of already processed groups because circular references are possible with AD groups
return;
}

GetNestedGroups(connection, principal, distinguishedName, nestedGroupCN, logger, retrievedClaims, processedGroups);
}
}
}
Expand Down