よくあるサンプルでは、ユーザをあらわすDirectoryEntryを作成して、プロパティの memberOf を使用すれば、自身が直接所属しているグループの完全識別名を取得できますが、その場合、グループがほかのグループに属している場合に、リカーシブに処理をする必要があります。今回は2通りの方法でユーザが所属するすべてのグループを取得してみます。方法として、tokenGroups 属性値から所属しているグループの SID を取得し、そこからグループ名を取得します。

動作確認環境

  • 動作環境: Windows 2003 Server (ドメイン環境)
  • 開発環境: Visual Studio 2008 Professional
  • .NET 3.5 SP1

.NET 2.0 以上で動作するはずです。

1. DirectorySearcher を使用してグループを取得する

LDAP のクエリを使用してグループをすべて取得する方法を掲載します。下記サンプルでは、ドメイン crm1.local ないの組織 CrmUsers 直下のユーザcrmuser03 の所属する全てのグループを列強するサンプルを掲載します。

public static void RetrieveGroupPattern1()
{

    StringBuilder builder = new StringBuilder();

    using (DirectoryEntry crmuser = GetDirectoryEntry("CN=crmuser03,OU=CrmUsers,DC=crm1,DC=local"))
    {
        crmuser.RefreshCache(new string[] { "tokenGroups" });

        builder.Append("(|");
        foreach (byte[] sid in crmuser.Properties["tokenGroups"])
        {
            // tokenGroupsの値をSID文字列に変換して、フィルタ条件に設定
              builder.AppendFormat("(objectSid={0})", ToObjectSidString(sid));
        }
        builder.Append(")");
    }
    using (DirectoryEntry searchRoot = GetDirectoryEntry("DC=crm1,DC=local"))
    {
        DirectorySearcher ds = new DirectorySearcher(searchRoot, builder.ToString());
        using (SearchResultCollection searchResultCollection = ds.FindAll())
        {
            foreach (SearchResult searchResult in searchResultCollection)
            {
                Console.WriteLine(searchResult.Properties["samAccountName"][0]);
            }
        }
                
     }
}
private static string ToObjectSidString(byte[] bytes)
{
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < bytes.Length; ++i)
    {
        builder.AppendFormat(@"\{0}", bytes[i].ToString("X2"));
    }
    return builder.ToString();
}
private static DirectoryEntry GetDirectoryEntry(string dn)
{
    return new DirectoryEntry("LDAP://" + dn, null, null, AuthenticationTypes.Secure);
}

tokenGroupsはconstructedな属性値のため、RefreshCacheを使用して、取得する必要があります。取得した全ての所属グループのSIDを DirectorySearcher のフィルタ条件(objectSid)にしています。

実行結果は次のようになります。

Domain Users
Users

2. IdentityReferenceCollection を使用してグループを取得する

tokenGroups 属性値の SIDから IdentityReferenceCollection.Translate メソッドを使用して System.Security.Principal.NTAccount 型 に変換してグループ名を列挙します。

public static void RetrieveGroupsPattern2()
{
    using (DirectoryEntry crmuser = GetDirectoryEntry("CN=crmuser03,OU=CrmUsers,DC=crm1,DC=local"))
    {
        crmuser.RefreshCache(new string[] { "tokenGroups" });

        IdentityReferenceCollection identityReferenceCollection = new IdentityReferenceCollection();
        foreach (byte[] tokenGroup in crmuser.Properties["tokenGroups"])
        {
            identityReferenceCollection.Add(new SecurityIdentifier(tokenGroup, 0));
        }

        identityReferenceCollection = identityReferenceCollection.Translate(typeof(NTAccount));
        foreach (NTAccount account in identityReferenceCollection)
        {
            Console.WriteLine(account.Value);
        }
    }
}

実行結果は次のようになります。

BULTIN\Users
CRM1\Domain Users

3. おわり

説明は以上です。 誤り等があればご指摘ください。