如何检查用户是否属于AD组和嵌套组?

发布于 2024-08-29 14:30:42 字数 1323 浏览 1 评论 0原文

我有一个使用 Windows 身份验证并实现我们自己的 RoleProvider 的 ASP.NET 3.5 应用程序。

问题是我们希望将对一组页面的访问限制为几千个用户,而不是逐个输入所有这些页面,我们发现它们属于 AD 组。

如果我们针对特定用户检查成员资格的公共组是它的直接成员,那么答案很简单,但我遇到的问题是,如果该组是另一个组的成员,然后是另一个组的成员,那么我的代码总是返回 false。

例如:假设我们要检查User是否是组E的成员,但User不是*E的直接成员”,她是“A”的成员,“B”的成员实际上是E的成员,因此用户是*E的成员”

解决方案之一尽管它给出了正确的答案,但我们的速度非常慢

using (var context = new PrincipalContext(ContextType.Domain))
  {
    using (var group = GroupPrincipal.FindByIdentity(context, IdentityType.Name, "DL-COOL-USERS"))
    {
      var users = group.GetMembers(true); // recursively enumerate

      return users.Any(a => a.Name == "userName");
    }
  }

原始的解决方案以及我试图使用.NET 3.5 System.DirectoryServices.AccountManagement进行工作,并且当用户是相关组的直接成员时它确实可以工作如下如下所示:

public bool IsUserInGroup(string userName, string groupName)
{
  var cxt = new PrincipalContext(ContextType.Domain, "DOMAIN");
  var user = UserPrincipal.FindByIdentity(cxt, IdentityType.SamAccountName, userName);

 if (user == null)
  {       
    return false;
  }


  var group = GroupPrincipal.FindByIdentity(cxt, groupName);

  if (group == null)
  {        
    return false;
  }

  return user.IsMemberOf(group);
}

底线是,即使组嵌套在许多级别中,我们也需要检查成员资格。

多谢!

I have an ASP.NET 3.5 application using Windows Authentication and implementing our own RoleProvider.

Problem is we want to restrict access to a set of pages to a few thousand users and rathern than inputing all of those one by one we found out they belong to an AD group.

The answer is simple if the common group we are checking membership against the particular user is a direct member of it but the problem I'm having is that if the group is a member of another group and then subsequently member of another group then my code always returns false.

For example: Say we want to check whether User is a member of group E, but User is not a direct member of *E", she is a member of "A" which a member of "B" which indeed is a member of E, therefore User is a member of *E"

One of the solutions we have is very slow, although it gives the correct answer

using (var context = new PrincipalContext(ContextType.Domain))
  {
    using (var group = GroupPrincipal.FindByIdentity(context, IdentityType.Name, "DL-COOL-USERS"))
    {
      var users = group.GetMembers(true); // recursively enumerate

      return users.Any(a => a.Name == "userName");
    }
  }

The original solution and what I was trying to get to work, using .NET 3.5 System.DirectoryServices.AccountManagement and it does work when users are direct members of the group in question is as follows:

public bool IsUserInGroup(string userName, string groupName)
{
  var cxt = new PrincipalContext(ContextType.Domain, "DOMAIN");
  var user = UserPrincipal.FindByIdentity(cxt, IdentityType.SamAccountName, userName);

 if (user == null)
  {       
    return false;
  }


  var group = GroupPrincipal.FindByIdentity(cxt, groupName);

  if (group == null)
  {        
    return false;
  }

  return user.IsMemberOf(group);
}

The bottom line is, we need to check for membership even though the groups are nested in many levels down.

Thanks a lot!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

滥情稳全场 2024-09-05 14:30:42

解决方案 1:使用 web.config 限制访问

由于您使用的是 ASP.NET,限制访问的更简单的解决方案是在 web.config 中进行设置,示例如下:

<configuration>
  <location path="protected/url/path">
    <system.web>
      <authorization>
        <allow roles="DOMAIN\group"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>
</configuration>

有关详细信息: http://msdn.microsoft.com/en-us/library/wce3kxhd.aspx 和 < a href="http://msdn.microsoft.com/en-us/library/b6x6shw7.aspx" rel="nofollow noreferrer">http://msdn.microsoft.com/en-us/library/b6x6shw7.aspx 。

解决方案 2:更快地实现 IsUserInGroup

我在 .NET 2.0 应用程序中使用的代码在与您的类似的大森林中运行良好。

static bool IsUserInGroup(DirectoryEntry user, string groupName)
{
    user.RefreshCache(new string[] {"tokenGroups"});
    for (int i = 0; i < user.Properties["tokenGroups"].Count; i++) {
        SecurityIdentifier sid = new SecurityIdentifier((byte[]) user.Properties["tokenGroups"][i], 0);
        try {
            NTuser nt = (NTuser) sid.Translate(typeof(NTuser));
            if (nt.Value.ToLower().EndsWith("\\" + groupName.ToLower())) {
                return true;
            }
        } catch (IdentityNotMappedException) {
            continue;
        }
    }

    return false;
}

Solution 1: Use web.config to restrict access

Since you are using ASP.NET, a lot simpler solution to restrict access is by setting it up in web.config, example as follows:

<configuration>
  <location path="protected/url/path">
    <system.web>
      <authorization>
        <allow roles="DOMAIN\group"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>
</configuration>

For more info: http://msdn.microsoft.com/en-us/library/wce3kxhd.aspx and http://msdn.microsoft.com/en-us/library/b6x6shw7.aspx.

Solution 2: A faster implementation of IsUserInGroup

A code I used in a .NET 2.0 application, works well in a big forest comparable to yours.

static bool IsUserInGroup(DirectoryEntry user, string groupName)
{
    user.RefreshCache(new string[] {"tokenGroups"});
    for (int i = 0; i < user.Properties["tokenGroups"].Count; i++) {
        SecurityIdentifier sid = new SecurityIdentifier((byte[]) user.Properties["tokenGroups"][i], 0);
        try {
            NTuser nt = (NTuser) sid.Translate(typeof(NTuser));
            if (nt.Value.ToLower().EndsWith("\\" + groupName.ToLower())) {
                return true;
            }
        } catch (IdentityNotMappedException) {
            continue;
        }
    }

    return false;
}
安人多梦 2024-09-05 14:30:42

好吧,我不得不跳出这个框架来思考,幸运的是,通过研究 AD,我们发现所有 3000 多名必须查看这些页面的人在自定义 AD 属性中共享一个关键字。所以我所要做的就是从 AD 加载对象并查找它。最终的效果客户非常满意!目前这似乎是一个有点肮脏的解决方案,但一如既往,它工作得很好,我们必须继续做其他事情!

目前,我们正在进行试点计划,我们希望出现任何错误并得到通知,以便我们采取行动。

public static bool IsEmployeeCoolEnoughToSeePages(string userName)
{
  if (string.IsNullOrEmpty(userName))
  {
    throw new ArgumentNullException("Current user's Username cannot be null");
  }

  using (var searcher = new DirectorySearcher(("LDAP://YOURDOMAIN.com")))
  {
    searcher.Filter = string.Format("(&(objectCategory=user)(samAccountName={0}))", ariseUserName);
    SearchResultCollection searchResultCollection = searcher.FindAll();

    if (searchResultCollection.Count == 1)
    {
      var values = searchResultCollection[0].Properties["title"];

      if (values.Count == 1)
      {
        return values[0].ToString().StartsWith("_COOLNES_");
      }
    }

    return false;
  }
}

Well, I had to think outside the square with this one and fortunately by looking into AD we discovered that all the 3000+ people that had to see the pages share a keyword in a custom AD property. So all I had to do is load the object from AD and look this up. End result client is very happy! It seems like a bit of a dirty solution at the moment but as always this is working perfectly and we have to move on onto other things!

At the moment we are going on with this with a pilot program and any errors that we get we want them to bubble up and be notified so we can act on it.

public static bool IsEmployeeCoolEnoughToSeePages(string userName)
{
  if (string.IsNullOrEmpty(userName))
  {
    throw new ArgumentNullException("Current user's Username cannot be null");
  }

  using (var searcher = new DirectorySearcher(("LDAP://YOURDOMAIN.com")))
  {
    searcher.Filter = string.Format("(&(objectCategory=user)(samAccountName={0}))", ariseUserName);
    SearchResultCollection searchResultCollection = searcher.FindAll();

    if (searchResultCollection.Count == 1)
    {
      var values = searchResultCollection[0].Properties["title"];

      if (values.Count == 1)
      {
        return values[0].ToString().StartsWith("_COOLNES_");
      }
    }

    return false;
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文