I have WPF application that has a login form. I would like to make all existing windows users that belong to some specific group able to log into my application.
So what I need is a way after the user have given his username and password to see if this is a user, belonging to the wanted group, and that the password is correct. The feedback I can use to decide if the user gets logged in or not.
If you need to find out if the user has membership to some AD group, you will need to use the group's SID if the user is not a "direct" member of the group (i.e. the user is a member of a nested group which itself is a member of the 'desired' AD group).
(I've used this for years, but long ago lost the link to where I found it. I believe there's actually a simpler way to check for nested groups in DirectoryServices 4.0, but I have not used it).
If you're using .NET 3.5 (as indicated in the link from Travis), you can check the user's credentials like this:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain)
{
if (pc.ValidateCredentials(username, password))
{
/* Check group membership */
}
}
If you are not using .NET 3.5, you can still check the credentials like this:
var user = new DirectoryEntry("", username, password)
try
{
user.RefreshCache();
/* Check group membership */
}
catch (DirectoryServicesCOMException ex)
{
/* Invalid username/password */
}
finally
{
user.Close();
}
Then, to check, the AD group membership, use the following:
var user = new DirectoryEntry("", username, password);
var searcher = new DirectorySearcher();
searcher.Filter = "(&(objectCategory=group)(samAccountName=" + YourGroupName + "))";
var group = searcher.FindOne();
if (group != null && IsMember(group.GetDirectoryEntry(), user))
/* User is a direct OR nested member of the AD group */
The IsMember helper method:
static bool IsMember(DirectoryEntry group, DirectoryEntry user)
{
group.RefreshCache(new string[] { "objectSid" });
SecurityIdentifier groupSID =
new SecurityIdentifier((byte[])group.Properties["objectSid"].Value, 0);
IdentityReferenceCollection refCol;
user.RefreshCache(new string[] { "tokenGroups" });
IdentityReferenceCollection irc = new IdentityReferenceCollection();
foreach (byte[] sidBytes in user.Properties["tokenGroups"])
{
irc.Add(new SecurityIdentifier(sidBytes, 0));
}
refCol = irc.Translate(typeof(NTAccount));
PropertyValueCollection props = user.Properties["tokenGroups"];
foreach (byte[] sidBytes in props)
{
SecurityIdentifier currentUserSID = new SecurityIdentifier(sidBytes, 0);
if (currentUserSID.Equals(groupSID))
{
return true;
}
}
return false;
}