Query LDAP (Active Directory) and retrieve a list of the specified user group memberships (optimized for performance).
using System;
using System.DirectoryServices;
namespace LdapTools
{
public static class LdapHelper
{
private const string LdapRootPath = "LDAP://DC=abc,DC=corp,DC=net";
private const string LdapMemberOfProperty = "memberOf";
private const string LdapPersonSearchFilter = "(&((&(objectCategory=person)(objectClass=user)))(sAMAccountName={0}))";
/// <summary>
/// Query LDAP and attempt to retrieve a list of the specified
/// <paramref name="username"/>'s group memberships
/// using the "memberOf" property. (note: optimized for performance).
/// </summary>
/// <param name="username">The LDAP user name.</param>
/// <exception cref="ArgumentNullException">
/// Thrown when the specified parameter for <paramref name="username"/>
/// is null, empty, or contains only whitespace characters.
/// </exception>
/// <exception cref="NullReferenceException">
/// Thrown when the LDAP <see cref="T:System.DirectoryServices.SearchResult"/>
/// returns null.
/// </exception>
/// <returns>
/// An <see cref="System.Array"/> of strings containing the
/// <paramref name="username"/>'s group memberships.
/// </returns>
public static string[] GetUserGroups(string username)
{
if (string.IsNullOrWhiteSpace(username))
{
throw new ArgumentNullException("username",
"User name cannot be null, empty " +
"or contain only whitespace characters.");
}
// check username for domain prefix (e.g.: "DOMAIN\USERNAME" => "USERNAME"),
// and remove if found:
username = username.IndexOf('\\') == -1 ? username : username.Split('\\')[1];
string[] groups = {};
using (var de = new DirectoryEntry(LdapRootPath))
{
// ------------------------------------------------------------------------------------
// Authentication Type Flags:
// https://msdn.microsoft.com/en-us/library/system.directoryservices.authenticationtypes(v=vs.110).aspx
// ------------------------------------------------------------------------------------
// AuthenticationTypes.ReadonlyServer = writable server not required (serverless binding)
// AuthenticationTypes.Secure = request secure authentication (also the default)
// AuthenticationTypes.FastBind = query only base adsi interface for performance boost
// ------------------------------------------------------------------------------------
de.AuthenticationType =
AuthenticationTypes.ReadonlyServer |
AuthenticationTypes.Secure |
AuthenticationTypes.FastBind;
using (var ds = new DirectorySearcher(de))
{
ds.Filter = string.Format(LdapPersonSearchFilter, username);
ds.PropertiesToLoad.Add(LdapMemberOfProperty);
ds.SearchScope = SearchScope.Subtree;
SearchResult sr = ds.FindOne();
if (sr == null || sr.Properties == null)
{
throw new NullReferenceException(string.Format(
"Failed to find \"{0}\" in LDAP, or user does not " +
"have any associated group memberships.",
username)
);
}
int memberOfCount = sr.Properties[LdapMemberOfProperty].Count;
Array.Resize(ref groups, memberOfCount);
for (int i = 0; i <= memberOfCount - 1; i++)
{
string distinguishedName = sr.Properties[LdapMemberOfProperty][i].ToString();
int equalsIndex = distinguishedName.IndexOf("=", 1, StringComparison.Ordinal);
if (equalsIndex == -1)
{
break;
}
int commaIndex = distinguishedName.IndexOf(",", 1, StringComparison.Ordinal);
groups[i] = distinguishedName.Substring(equalsIndex + 1)
.Substring(0, commaIndex - equalsIndex - 1);
}
}
}
return groups;
}
}
}