Search code examples
c#.netwpfwindows-authentication

Using Windows Authentication inside my own login form


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.


Solution

  • 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;
    }