Как определить все группы, к которым принадлежит пользователь (включая вложенные группы) В ActiveDirectory and.NET 3.5
у меня есть приложение, которое использует авторизацию ActiveDirecotry, и было решено, что оно должно поддерживать вложенные группы объявлений, например:
MAIN_AD_GROUP
|
|-> SUB_GROUP
|
|-> User
Итак, пользователь в not напрямую член MAIN_AD_GROUP
. Я хотел бы иметь возможность искать пользователя рекурсивно, ища группы, вложенные в MAIN_AD_GROUP
.
основная проблема в том, что я использую .NET 3.5 и есть ошибка в System.DirectoryServices.AccountManagement
в .NET 3.5, в котором метод UserPrincipal.IsMemberOf()
не будет работать группы с более 1500 пользователей. Поэтому я не могу использовать UserPrincipal.IsMemberOf()
и нет, я тоже не могу переключиться на .NET 4.
я работал над этой последней проблемой со следующей функцией:
private bool IsMember(Principal userPrincipal, Principal groupPrincipal)
{
using (var groups = userPrincipal.GetGroups())
{
var isMember = groups.Any(g =>
g.DistinguishedName == groupPrincipal.DistinguishedName);
return isMember;
}
}
но userPrincipal.GetGroups()
возвращает только те группы, непосредственным членом которых является пользователь.
как я могу заставить это работать с вложенными группами?
4 ответов
Решение #1
эта ошибка сообщает здесь, в Microsoft Connect вместе со следующим кодом, который работает вокруг этой проблемы, вручную повторяя PrincipalSearchResult<Principal>
возвращенные объекты, улавливая это исключение и продолжая:
PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();
var iterGroup = groups.GetEnumerator();
using (iterGroup)
{
while (iterGroup.MoveNext())
{
try
{
Principal p = iterGroup.Current;
Console.WriteLine(p.Name);
}
catch (NoMatchingPrincipalException pex)
{
continue;
}
}
}
решение #2
другое решение найти здесь избежать AccountManagement
класс, и используется System.DirectoryServices
API вместо:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;
namespace GetGroupsForADUser
{
class Program
{
static void Main(string[] args)
{
String username = "Gabriel";
List<string> userNestedMembership = new List<string>();
DirectoryEntry domainConnection = new DirectoryEntry(); // Use this to query the default domain
//DirectoryEntry domainConnection = new DirectoryEntry("LDAP://example.com", "username", "password"); // Use this to query a remote domain
DirectorySearcher samSearcher = new DirectorySearcher();
samSearcher.SearchRoot = domainConnection;
samSearcher.Filter = "(samAccountName=" + username + ")";
samSearcher.PropertiesToLoad.Add("displayName");
SearchResult samResult = samSearcher.FindOne();
if (samResult != null)
{
DirectoryEntry theUser = samResult.GetDirectoryEntry();
theUser.RefreshCache(new string[] { "tokenGroups" });
foreach (byte[] resultBytes in theUser.Properties["tokenGroups"])
{
System.Security.Principal.SecurityIdentifier mySID = new System.Security.Principal.SecurityIdentifier(resultBytes, 0);
DirectorySearcher sidSearcher = new DirectorySearcher();
sidSearcher.SearchRoot = domainConnection;
sidSearcher.Filter = "(objectSid=" + mySID.Value + ")";
sidSearcher.PropertiesToLoad.Add("distinguishedName");
SearchResult sidResult = sidSearcher.FindOne();
if (sidResult != null)
{
userNestedMembership.Add((string)sidResult.Properties["distinguishedName"][0]);
}
}
foreach (string myEntry in userNestedMembership)
{
Console.WriteLine(myEntry);
}
}
else
{
Console.WriteLine("The user doesn't exist");
}
Console.ReadKey();
}
}
}
использовать с документы MSDN:
этот метод поиска все группы рекурсивно и возвращает группы в которых пользователь является членом. Этот возвращаемый набор может также включать дополнительные группы, которые система считайте пользователя членом for целей авторизации.
группы, возвращаемые этим метод может включать группы из a различные объем и магазин чем главный. Для например, если Принципал-это объект AD DS, который имеет a DN of "СИЭН=спецотрядов в,DC=fabrikam,в постоянного тока=ком, возвращаемый набор может содержать группы что относятся к "СИЭН=NormalGroups в,DC=fabrikam,в постоянного тока=ком.
Я знаю, что это старый поток, но это лучший результат в Google, поэтому, если это кому-то поможет, вот что я придумал, который использует материал AccountManagement, но делает этот конкретный запрос намного проще.
public static class AccountManagementExtensions
{
public static bool IsNestedMemberOf(this Principal principal, GroupPrincipal group)
{
// LDAP Query for memberOf Nested
var filter = String.Format("(&(sAMAccountName={0})(memberOf:1.2.840.113556.1.4.1941:={1}))",
principal.SamAccountName,
group.DistinguishedName
);
var searcher = new DirectorySearcher(filter);
var result = searcher.FindOne();
return result != null;
}
}
эффективный способ-сделать один рекламный запрос, имея правильный фильтр DirectorySearcher, например
public bool CheckMemberShip(string userName)
{
bool membership = false;
string connection = "LDAP://"+YOURDOMAIN;
DirectoryEntry entry = new DirectoryEntry(connection);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=cn=GROUPNAME,OU=Groups,OU=ABC,OU=ABC,OU=IND,DC=ad,DC=COMPANY,DC=com)(|(sAMAccountName=" + userName + ")))";
SearchResult result = mySearcher.FindOne();
// No search result, hence no membership
if (result == null)
{
membership = false;
}
entry.Close();
entry.Dispose();
mySearcher.Dispose();
membership = true;
return membership;
}
вам нужно заменить YOURDOMAIN и GROUPNAME правильными значениями из вашего объявления.
нужно включить using System.DirectoryServices;