Active Directory组查找功能失败

时间:2009-12-02 14:44:38

标签: asp.net active-directory

帮助!我一直在尝试编写一个函数来确认用户在Active Directory组中的成员资格,并且如果该成员恰好在该组中,它会起作用,如果该用户不在,则会抛出异常。

这是功能:

private bool IsUserMemberOfGroup(string user, string group)
{
  using (var ctx = new PrincipalContext(ContextType.Domain))
  using (var groupPrincipal = GroupPrincipal.FindByIdentity(ctx, group))
  using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, user))
  {
    if (groupPrincipal == null)
    {
      return false;
    }
    else
    {
      return userPrincipal.IsMemberOf(groupPrincipal);
    }
  }
}

这是YSOD:

'/'应用程序中的服务器错误。

未知错误(0x80005000)

描述:执行当前Web请求期间发生了未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的更多信息。

异常详情:

System.Runtime.InteropServices.COMException:未知错误(0x80005000)

来源错误:

     
 
Line 34:         else
Line 35:         {
Line 36:           return userPrincipal.IsMemberOf(groupPrincipal);
Line 37:         }
Line 38:       }
   

我不知道它是否相关,但是当我单步执行该函数时,groupPrincipal.Members.Count抛出类型为“System.NullReferenceException”的异常,Count.Base显示一个异常,并显示消息“Object reference not not设置为对象的实例“。

到底发生了什么事?当某人不是会员时,为什么名为IsMemberOf的bool不会返回false?

谢谢,

丹尼尔

3 个答案:

答案 0 :(得分:4)

我认为你可以简化一些事情:

private bool IsUserMemberOfGroup(string user, string group)
{
  using (var ctx = new PrincipalContext(ContextType.Domain))
  using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, user))
  {
      PrincipalSearchResult<Principal> result = userPrincipal.GetGroups();

      GroupPrincipal groupPrincipal = 
           result.Where(g => g.SamAccountName == groupName).FirstOrDefault();

      return (groupPrincipal != null);
  }
}

userPrincipal.GetGroups()将为您提供该用户的所有组成员身份(包括主要组和嵌套组成员身份)的明确列表;然后搜索您感兴趣的群组的列表,例如通过samACcountName或其他一些属性。

如果您在PrincipalSearchResult<Principal>返回的GetGroups()中找到了您要查找的群组,那么您的用户就是该群组的成员。

您可以使用此功能为自己保存至少一个“FindByIdentity”。

答案 1 :(得分:1)

对marc_s的代码进行了一次小修改,我有:

using (var ctx = new PrincipalContext(ContextType.Domain)) 
using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, user)) 
using (var groupPrincipal = GroupPrincipal.FindByIdentity(ctx, group))
{
     if (userPrincipal == null) return false;
     if (groupPrincipal == null) return false;

     PrincipalSearchResult<Principal> result = userPrincipal.GetGroups(); 
     Principal grp = result.Where(g => g.Sid == groupPrincipal.Sid).FirstOrDefault(); 
     return (grp != null);
}

比较Sid似乎比比较SamAccountName更可靠。

答案 2 :(得分:0)

我们的设置中有一些毒药组导致某些用户失败而其他用户失败。其他建议答案中的“FirstOrDefault”逻辑可能帮助我们躲避毒药群,但这并不能保证。

对于遇到此问题的其他人,我们有两条建议。首先检查组名中是否有任何带正斜杠的组(实际的组名,而不是“pre-windows 2000”名称,它将用下划线替换它)。如果您可以重命名可能解决问题的所有此类组...它对我们有用。

这种解决方法也适用于我们:

/// <summary>
/// This does a recursive group search for the given user or computer principal.
/// </summary>
public IEnumerable<Principal> GetGroups(Principal principal)
{
    return GetGroups(null, principal);
}

private IEnumerable<Principal> GetGroups(HashSet<SecurityIdentifier> ancestorPrincipalSids, Principal parentPrincipal)
{
    try
    {
        //enumerate this here so errors are thrown now and not later
        //if the current group name has a forward-slash, I think this 
        //will always error here
        var groups = parentPrincipal.GetGroups().ToArray();
        if (groups == null)
        {
            return Enumerable.Empty<Principal>();
        }

        //keep track of all ancestors in the group hierarchy to this point
        //so that we can handle circular references below
        var newAncestors = new HashSet<SecurityIdentifier>(ancestorPrincipalSids ?? Enumerable.Empty<SecurityIdentifier>());
        newAncestors.Add(parentPrincipal.Sid);

        return groups
            .Concat(groups
                .Where(g => !newAncestors.Contains(g.Sid)) //handle circular references
                .SelectMany(g => GetGroups(newAncestors, g)));
    }
    catch
    {
        return Enumerable.Empty<Principal>();
    }
}
相关问题