【问题标题】:Active Directory group lookup function failingActive Directory 组查找功能失败
【发布时间】:2009-12-02 14:44:38
【问题描述】:

帮助!我一直在尝试编写一个函数来确认用户在 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 显示异常消息“对象引用不设置为对象的实例”。

这到底是怎么回事?当某人不是成员时,为什么名为 IsMemberOf 的布尔值不会返回 false?

谢谢,

丹尼尔

【问题讨论】:

  • 什么是“用户”和“组”??
  • 抱歉,这些是(例如)“domain\\user_SAMAccountName”和“domain\\group_SAMAccountName”。

标签: asp.net active-directory


【解决方案1】:

我认为你可以简化一下:

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 或其他一些属性。

如果您在GetGroups() 返回的PrincipalSearchResult&lt;Principal&gt; 中找到您要查找的组,那么您的用户就是该组的成员。

你可以用这个至少为自己节省一个“FindByIdentity”调用。

【讨论】:

  • 嗯...那行得通。我不确定为什么该代码有效而我的无效,但它确实有效。奇怪的。感谢您的快速回复!
  • 遗憾的是,我们发现此代码仅适用于您尝试查询的 AD 组位于 LDAP 树的根目录中。将安全组放在 AD 树中的任何其他位置都会导致调用崩溃。它只会返回 True - 绝不会返回 False。 (错误只是崩溃)。
【解决方案2】:

对 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 更可靠。

【讨论】:

    【解决方案3】:

    我们的设置中有一些毒组,这导致某些用户失败,但其他用户却没有。其他建议答案中的“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>();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多