ActiveDirecotry認証を使用するアプリケーションがあり、ネストされたADグループをサポートする必要があると判断されました。例:
_MAIN_AD_GROUP
|
|-> SUB_GROUP
|
|-> User
_
したがって、ユーザーは_MAIN_AD_GROUP
_のメンバーではない直接メンバーではありません。 _MAIN_AD_GROUP
_にネストされたグループを検索して、ユーザーを再帰的に検索できるようにしたいと思います。
主な問題は、.NET 3.5を使用していて、.NET 3.5の_System.DirectoryServices.AccountManagement
_にバグがあり、メソッド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()
は、ユーザーが直接メンバーであるグループのみを返します。
ネストされたグループでこれを機能させるにはどうすればよいですか?
このバグは報告されています ここでは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;
}
}
}
別の回避策 ここにあります は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();
}
}
}
代わりにUserPrincipal.GetAuthorizationGroups()
を使用してください-その MSDN docs から:
このメソッドは、すべてのグループを再帰的に検索し、ユーザーがメンバーであるグループを返します。返されるセットには、システムがユーザーを承認目的でメンバーと見なす追加のグループが含まれる場合もあります。
このメソッドによって返されるグループには、プリンシパルとは異なるスコープおよびストアのグループが含まれる場合があります。たとえば、プリンシパルが「CN = SpecialGroups、DC = Fabrikam、DC = com」のDNを持つAD DSオブジェクトである場合、返されるセットには、「CN = NormalGroups、DC = Fabrikam、DC = com。
私はこれが古いスレッドであることを知っていますが、これは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フィルターを使用して単一のADクエリを実行することです。
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をADからの正しい値に置き換える必要があります。
ソース: 。NET/C#とLDAPを使用してActive Directory内のユーザーのグループメンバーシップを再帰的に取得する方法(Active Directoryへのヒットが2つだけではない)
using System.DirectoryServices;
を含める必要があります