7

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.

Øyvind Bråthen
  • 59,338
  • 27
  • 124
  • 151

3 Answers3

7

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;
}
Adrian
  • 1,338
  • 8
  • 17
2

Validate a username and password against Active Directory?

With the search result should be able to query the groups for that user.

Community
  • 1
  • 1
Travis
  • 10,444
  • 2
  • 28
  • 48
  • This works if the user is a direct member of the requested group, but unfortunately doesn't work for nested group membership, which is very common in AD. – Adrian May 31 '11 at 17:16
0

The above mentioned IsMember function worked for me when checking existence of domain users on domain groups and local users and local groups, but it didn't work when checking existence of domain user on a local group such as IIS_IUSRS. I have modified it slightly to use the Members property of the group and looking to match of each user added with the SID of the given user.

Here is the code

private static bool IsMember(DirectoryEntry group, DirectoryEntry user)
{
    SecurityIdentifier userSId = new SecurityIdentifier((byte[])user.Properties["objectSid"].Value, 0);
    foreach (object member in (IEnumerable)group.Invoke("Members"))
        {
        using (var memberEntry = new DirectoryEntry(member))
                {
                    var groupSId = new SecurityIdentifier((byte[])memberEntry.Properties["objectSid"].Value, 0);
                    if (userSId.Equals(groupSId))
                    {
                        return true;
                    }
                }
    }

    return true;
}
Hamid Shahid
  • 4,486
  • 3
  • 32
  • 41