James
James

Reputation: 2009

Active Directory RoleProvider - Principal.IsMemberOf throws PrincipalOperationException

I have created the following method in a custom Active Directory RoleProvider:

public override string[] GetRolesForUser(string username)
{
    ArrayList results = new ArrayList();
    using (var principalContext = new PrincipalContext(
             ContextType.Domain, null, domainContainer))
    {
        var user = UserPrincipal.FindByIdentity(
             principalContext, IdentityType.SamAccountName, username);
        foreach (string acceptibleGroup in GroupsToInclude)
        {
            GroupPrincipal adGroup = GroupPrincipal.FindByIdentity(
                 principalContext, acceptibleGroup);
            if (user.IsMemberOf(adGroup))
                results.Add(acceptibleGroup);
        }
    }
    return results.ToArray(typeof(string)) as string[];
}

It only checks against a white list of roles which are used in my application. The problem is that if the user is not a member of one of the roles, I get a PrincipalOperationException when the

if (user.IsMemberOf(adGroup))

line is executed. I would expect this to simply return `false if the user is not in the group. What is going wrong here?

EDIT: As and aside, if I call user.GetAuthorizationGroups() and attempt to loop through the results, I get a COMException - The specified directory service attribute or value does not exist.

Upvotes: 2

Views: 2440

Answers (2)

Harvey Kwok
Harvey Kwok

Reputation: 11873

Both Principal.IsMemberOf() and user.GetAuthorizationGroups() are using tokenGroups attribute to determine the group membership.

You need to make sure the account you used to run the program is added to Builtin\Windows Authorization Access Group in order to access tokenGroups attribute.

See this MSDN KB for more details.

Upvotes: 3

James
James

Reputation: 2009

I have managed to work around this problem with the following:

public override string[] GetRolesForUser(string username) 
{ 
    ArrayList results = new ArrayList(); 

    using (PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, null, domainContainer))
        {
            UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, username);
            foreach (string acceptibleGroup in GroupsToInclude)
            {
                GroupPrincipal p = GroupPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, acceptibleGroup);
                if (p.GetMembers().Contains(user))
                    results.Add(acceptibleGroup);
            }
        } 

    return results.ToArray(typeof(string)) as string[]; 
}

However it is not exactly efficient as it pulls all the members of a group back. I am sure there is a better solution to my problem and hopefully someone will post it here!

Upvotes: 1

Related Questions