Similar to the problem in the following MSDN thread: http://social.msdn.microsoft.com/Forums/en-MY/csharplanguage/thread/4c9fea6c-1d0a-4733-a8ac-e3b78d10e999
I am trying to verify whether or not a given user is a member of a group, and our existing functional solutions are too slow (13-16 seconds) and I'm trying to speed it up. I currently have:
public bool IsMemberAD(string userName, string groupName)
{
var pc = new System.DirectoryServices.AccountManagement.PrincipalContext(System.DirectoryServices.AccountManagement.ContextType.Domain);
var user = System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(pc, System.DirectoryServices.AccountManagement.IdentityType.SamAccountName,
userName.ToLower());
var group = System.DirectoryServices.AccountManagement.GroupPrincipal.FindByIdentity(pc, groupName);
if (group == null || user == null) return false;
return user.IsMemberOf(group);
}
What makes this interesting is that it only returns an error when the user is not in the group directly, but rather a member of a group that is within the target group.
For example:
Steve and Sam are two users, and GroupParent and GroupChild are two groups. Steve and GroupChild are members of GroupParent. Sam is a member of GroupChild. If I call this function on (Steve, GroupParent), it returns true. If I call it on (Sam, GroupParent), I get an error. If I call it on ("fdkjskghkf", GroupParent) it returns false.
I linked an article above with similar issues, but his solution did not work for me, I still got the same error. Ideas?
Thanks to Jon Theriault here the following code fixed this problem for me.
string strName = System.Security.Principal.WindowsIdentity.GetCurrent().Name; // "MW\\dalem"
// This is here because of a .Net error that gets 0x80005000 on "isUser = user.IsMemberOf(groupU);"
string domainName = strName.Split('\\')[0];
var pc = new PrincipalContext(ContextType.Domain, domainName);
I remember when I wrote similar code I did run into some strange issues. I'm not sure exactly why your call is failing but you can turn your problem around and do something like:
return group.GetMembers(true).Contains(user);
Can you try somethig like this :
public bool IsMemberAD(string userName, string groupName)
{
PrincipalContext context = new PrincipalContext(ContextType.Domain, "WM2008R2ENT:389", "dc=dom,dc=fr", "jpb", "pwd");
/* Retreive the user principal
*/
UserPrincipal user = UserPrincipal.FindByIdentity(context, userName);
if (user == null) return false;
/* Retreive the group principal
*/
GroupPrincipal targetGroup = GroupPrincipal.FindByIdentity(context, groupName);
if (targetGroup == null) return false;
/* Look for all the groups a user belongs to
*/
PrincipalSearchResult<Principal> allGroups = user.GetAuthorizationGroups();
var grp = (from g in allGroups
where g.Sid == targetGroup.Sid
select g).FirstOrDefault();
return (!(grp == null));
}
If anyone is interested. Using DirectorySearcher with the following filter is approx 60% faster.
string filter = string.Format("(&(distinguishedName={1})(memberof:1.2.840.113556.1.4.1941:={0}))", dnOfUser, dnOfGroup);
The filter will traverse upwards and not just the parent of the user.
GetAuthorizationGroups() does not find nested groups.
To really got all groups a given user is member of included nested groups try this:
using System.Security.Principal
private List<string> GetGroups(string userName)
{
List<string> result = new List<string>();
WindowsIdentity wi = new WindowsIdentity(userName);
foreach (IdentityReference group in wi.Groups)
{
try
{
result.Add(group.Translate(typeof(NTAccount)).ToString());
}
catch (Exception ex) { }
}
result.Sort();
return result;
}
Use Try/Catch because I had some exceptions in a very large AD (half a million objects) with 2 out of 200 groups because my some SIDs (Translate does SID -> Name conversion) were no longer available. In our huge AD is only takes < 1 second.
User contributions licensed under CC BY-SA 3.0