I'm porting some code from System.DirectoryServices
to System.DirectoryServices.Protocols
due to the need to run on linux.
The majority of the code is fine but this little piece that retrieves tokenGroups
isn't coming across.
The original code reads:
using (var ldapObject = new DirectoryEntry(objectPath, username, password, AuthenticationTypes.Secure))
{
ldapObject.Options.Referral = ReferralChasingOption.All;
ldapObject.RefreshCache(new string[] { "tokenGroups" });
foreach (byte[] sid in ldapObject.Properties["tokenGroups"])
{
// Won't run on linux
var groupSID = new System.Security.Principal.SecurityIdentifier(sid, 0).ToString();
try
{
var group = this.GetSecurityGroupBySID(groupSID);
}
catch (Exception ex)
{
log.Warn($"Failed to get group with SID {groupSID}", ex);
}
}
}
Where objectPath
is of the form $"LDAP://{domainName}/{distinguishedName}"
My attempt looks like this:
public void GetExpandedGroups(string objectMail, LdapConnection ldapConnection)
{
var usersPath = "OU=active,OU=users,DC=path,DC=etc"; //Not real values
var filter = $"(&(objectClass = user)(!userAccountControl:1.2.840.113556.1.4.803:= 2)(mail={objectMail}))";
var request = new SearchRequest(usersPath, filter, SearchScope.Subtree, new string[] { "tokenGroups" });
request.Controls.Add(new SecurityDescriptorFlagControl(SecurityMasks.Dacl | SecurityMasks.Group | SecurityMasks.Owner));
var ldapObject = (SearchResponse)ldapConnection.SendRequest(request); // Error thrown here
foreach (byte[] sid in ldapObject.Entries[0].Attributes["tokenGroups"])
{
// Do stuff...
}
}
Whenever this runs I get an error, thrown. The stack trace and error response are below:
at System.DirectoryServices.Protocols.LdapConnection.<ConstructResponseAsync>d__57.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Threading.Tasks.ValueTask`1.get_Result()
at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)
at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request)
at LDAPTesting.Connectors.Protocols.GetExpandedGroups(String objectMail, LdapConnection ldapConnection) in C:\code\LDAPTesting\LDAPTesting\Connectors\Protocols.cs:line 62
at LDAPTesting.Connectors.Protocols.GetGroups() in C:\code\LDAPTesting\LDAPTesting\Connectors\Protocols.cs:line 103
at LDAPTesting.Program.Main(String[] args) in C:\code\LDAPTesting\LDAPTesting\Program.cs:line 17
00002120: SvcErr: DSID-031404CC, problem 5012 (DIR_ERROR), data 0
My thoughts are that I'm querying the wrong path but it looks to match the path that the original code requests on so I'm not sure what else I'm missing.
For anyone that comes along this, the solution is incredibly simple.
The SearchRequest
object needs to be of the scope Base. Really obvious when reading what the error message. So the line:
var request = new SearchRequest(usersPath, filter, SearchScope.Subtree, new string[] { "tokenGroups" });
Should instead read:
var request = new SearchRequest(usersPath, filter, SearchScope.Base, new string[] { "tokenGroups" });
I had a feeling that there would be an obvious and simple answer due to overlooking something and indeed there was!