netからactive directoryデータにアクセス ~グループ情報の取得と表示~
TRANSCRIPT
![Page 1: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/1.jpg)
.NET から Active Directory データにアクセス
グループ情報を表示する
小山 三智男mitchin
![Page 2: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/2.jpg)
2
サンプルアプリケーション
開発環境• OS : Windows7(x64)• IDE : Visual Studio 2010 SP1• アプリ: Windows フォーム (.NET 4 Client Profile)
Web フォーム (.NET 4) IE10クラスライブラリ (.NET 4 Client Profile)
実行環境• 単一ドメイン、単一サイト、単一サブネット• サーバ: Windows Server 2008 Standard SP1 (.NET 4)• IIS : Windows 認証• Windows クライアント: Windows 7 SP1 、 Windows XP
SP3• Web クライアント: IE10 、 IE8
![Page 3: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/3.jpg)
3
参照設定
• .NET から Active Directory の色々な情報にアクセスするために System.DirectoryServices アセンブリを参照する必要があります。
• ドメインやサイト関連は System.DirectoryServices. ActiveDirectory 名前空間にそれらを表すクラスがあり、 Active Directory の管理タスクを自動化するために使用されます。
• Active Directory 内のデータにアクセスするために使用されるのは System.DirectoryServices 名前空間で、オブジェクトをカプセル化する DirectoryEntry クラスやクエリを実行する DirectorySearcher クラスなどがあります。
• ADSI(Active Directory Services Interfaces) を使用してネイティブなオブジェクトを扱う場合は Active DS Type Libraryを参照する必要があります。
![Page 4: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/4.jpg)
4
主にどんなデータがあるの?
管理ツール「 Active Directory ユーザとコンピュータ」で管理する以下のオブジェクト• ユーザ• グループ• コンピュータ• 組織単位( OU)• プリンタ• 共有フォルダ
![Page 5: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/5.jpg)
5
サンプルアプリケーションの初期画面
ドメインを取得して画面下部に接続先を表示しています。
![Page 6: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/6.jpg)
6
グループリスト画面( Windows アプリ)
![Page 7: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/7.jpg)
7
グループリスト画面( Web アプリ)
![Page 8: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/8.jpg)
8
どうやって接続するの?
接続先によってプロバイダが異なります。
ドメインに接続する場合プロバイダ: LDAP(Lightweight Directory Access Protocol)書式例: LDAP://DC=virtual,DC=proceed,DC=local
ローカルに接続する場合プロバイダ: WinNT(Windows NT)書式例: WinNT://vpc-testclient1
これを引数にして DirectoryEntry のインスタンスを作成します。
![Page 9: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/9.jpg)
9
検索してグループのリストを取得する
LDAP プロバイダで接続する場合• 接続するドメインや取得したグループは DirectoryEntry オブジェクト• ユーザやグループを検索するのは DirectorySearcher オブジェクト• 複数の検索結果は SearchResultCollection として返される• SearchResult.GetDirectoryEntry メソッドで DirectoryEntry を取得• LDAP 書式のフィルター文字列( DirectorySearcher.Filter プロパティ)
は次のように指定(属性 = 値 をカッコで括る)• "(objectCategory=Group)" -- グループ• "(&(objectCategory=Group)(name=De*))" -- De で始まるグループ• "(&(objectCategory=Group)(groupType<=0)" -- セキュリティ グ
ループ• “(&(objectCategory=Volume)(!keywords=Sales)(|(uNCName=\\
testdc\*)(managedBy=CN=admin,OU= 管理部 ,DC=test,DC=local)))” -- キーワードに Sales がなく、 testdc 内にあるか admin が管理している共有フォルダ
![Page 10: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/10.jpg)
10
ADSI のインターフェイス
基本インターフェイスは IADs インターフェイスで、各オブジェクトはこのインターフェイスを継承しています。
オブジェクトとそれに対応するインターフェイス
DirectoryEntry.NativeObject プロパティの値を上記インターフェイスにキャストできます。
ユーザ IADsUser
グループ IADsGroup
コンピュータ IADsComputer
組織単位( OU) IADsOU
プリンタ IADsPrintQueue
共有フォルダ
![Page 11: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/11.jpg)
11
クラスライブラリ側
名前空間直下に追加したドメイングループのスコープタイプを表す DomainGroupScopeType 列挙体• BuiltInLocal = -2147483643• DomainLocal = -2147483644• Global = -2147483646• Universal = -2147483640
※ セキュリティグループの属性「 groupType 」の値と同じになるようにしています
既存のものについてはこちらのスライドを参照してくださいhttp://www.slideshare.net/mitchin227/display-user
![Page 12: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/12.jpg)
12
クラスライブラリ側に追加したクラス
LocalGroup ( ローカルのグループを表すクラス )プロパティ• Native (ADSI Group オブジェクトを取得 )
DomainGroup ( ドメインのグループを表すクラス )プロパティ• Native (ADSI Group オブジェクトを取得 )• Scope ( グループのスコープを取得 )• ScopeType ( グループのスコープタイプを取得 )• SecurityEnabled ( セキュリティグループかどうかを取得 )• Type ( グループの種類を取得 )
メソッド• FindByName ( データバインド用:グループを検索 )• GetGroups ( データバインド用:グループの一覧を取得 )
![Page 13: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/13.jpg)
13
クラスライブラリ側
DirectoryAccess クラスに追加したパブリックなメンバGetBelongPath メソッド ( 所属パスを取得 ) ※ オーバーロード
GetGroups メソッド ( グループを取得 )GetPrimaryGroupMemberEntries メソッド(PrimaryGroupToken を持つグループをプライマリグループとしているメンバの DirectoryEntry のコレクションを取得 )
PathToCn メソッド (LDAP パスの名前 ( オブジェクト名 ) を取得 )
![Page 14: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/14.jpg)
14
フォーム側( Windows アプリ)
• ドメイングループ用とローカルグループ用の BindingSource のデータソースに DomainGroup クラス、 LocalGroup クラスを指定
• 詳細の各コントロールは BindingSource (クラス)のプロパティにバインド
• グループの一覧を取得し BindingSource のデータソースに設定
• BindingSource を一覧 ListBox のデータソースに設定• ドメインの場合は選択したグループのメンバをメンバ ListView に表示
• ローカルの場合は選択したグループのメンバ名のコレクションをメンバ ListBox のデータソースに設定
• ドメインの場合は所属するグループを所属するグループListView に表示
![Page 15: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/15.jpg)
15
フォーム側( Web アプリ)
• DomainUser クラスをビジネスオブジェクトとする ObjectDataSource を 2 つ用意
• グループの一覧を取得するメソッドを指定したものを一覧 ListBox のデータソースに指定
• 選択したグループの名前からグループを検索するメソッドを指定したものを詳細 FormView のデータソースに指定
• BindingSource を一覧 ListBox のデータソースに設定• 選択したグループのメンバのデータソース用のテーブルを作成し、メンバ GridView のデータソースに設定してバインド
• 選択したグループの所属するグループのデータソース用のテーブルを作成し、所属するグループ GridView のデータソースに設定してバインド
![Page 16: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/16.jpg)
16
グループ取得サンプルコード( VB )
Public Shared Function GetGroups( Of T As {DirectoryObject, IGroup}) As IList(Of T) Dim groups As New List(Of T)() Using root = GetRootEntry() ’ ルートの DirectoryEntry を取得 Dim filter = String.Format("(objectCategory={0})",
CategoryType.Group) Using searcher As New DirectorySearcher(root, filter) Using results = searcher.FindAll() For Each res As SearchResult In results groups.Add(DirectCast(CreateInstance(res.GetDirectoryEntry()), T)) Next End Using End Using End Using Return groupsEnd Function※root は一般的には New DirectoryEntry(LDAP のルートパス ) をセット※CreateInstance メソッドは DirectoryEntry から DirectoryObject を作
成
![Page 17: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/17.jpg)
17
グループ取得サンプルコード( C# )
public static IList<T> GetGroups<T>() where T : DirectoryObject, IGroup { var grous = new List<T>(); using (var root = GetRootEntry()) { // ルートの DirectoryEntry を取得 var filter = String.Format("(objectCategory={0})",
CategoryType.Group); using (var searcher = new DirectorySearcher(root, filter)) { using (var results = searcher.FindAll()) { foreach (SearchResult res in results) { groups.Add((T)CreateInstance(res.GetDirectoryEntry())); } } } } return groups;}※root は一般的には new DirectoryEntry(LDAP のルートパス ) をセット※CreateInstance メソッドは DirectoryEntry から DirectoryObject を作
成
![Page 18: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/18.jpg)
18
ドメインのグループのスコープと種類
ドメインのグループにはスコープと種類があります。グループのスコープ•ビルトイン ローカル•ドメイン ローカル•グローバル•ユニバーサル
グループの種類•セキュリティ•配布
サンプルアプリでは DomainGroup クラスのコンストラクタ内で属性「 groupType 」の値からスコープと種類をプロパティにセットしています。
![Page 19: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/19.jpg)
19
メンバの表示はちょっと手間
• グループのメンバに含まれるのは ユーザ、グループ、コンピュータ、外部のセキュリティ プリンシパル
• メンバは IADsGroup.Members メソッドで取得し、ループで個々のメンバを処理
• ユーザやコンピュータのプライマリ グループになっていると、そのユーザやコンピュータはメンバに含まれないので、別途取得が必要
• 取得のしかたはユーザの所属するグループの取得と同様※11 ページの URL のスライド
の 17 ページ参照 • 外部のセキュリティ プリン
シパルは名前が SID 表記なので、読み取り可能な名前に変換
![Page 20: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/20.jpg)
20
メンバ名の取得サンプルコード( VB )
対象グループを group As IADsGroup とするとFor Each member As IADs In group.Members() Dim objectType = DirectCast([Enum].Parse(GetType(CategoryType), member.Class, True), CategoryType) ' ディレクトリ オブジェクトの種
類 ' 外部のセキュリティプリンシパルの時 If objectType = CategoryType.ForeignSecurityPrincipal Then Dim objectSid = DirectCast(member.Get("objectSid"), Byte()) Dim sid = New SecurityIdentifier(objectSid, 0) 'SID ' アカウントに変換 Dim account = DirectCast( sid.Translate(GetType(NTAccount)), NTAccount) 'account.Value または account.ToString() でメンバ名を取得 Else ' 外部のセキュリティプリンシパル以外の時 'member.Get(”cn”).ToString() でメンバ名を取得 End IfNext
![Page 21: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/21.jpg)
21
メンバ名の取得サンプルコード( C# )対象グループを IADsGroup group とするとforeach (IADs member in group.Members()) { var objectType = (CategoryType)Enum.Parse(typeof(CategoryType), member.Class, true); // ディレクトリ オブジェクトの種類 // 外部のセキュリティプリンシパルの時 if (objectType == CategoryType.ForeignSecurityPrincipal) { var objectSid = (byte[])member.Get("objectSid"); var sid = new SecurityIdentifier(objectSid, 0); //SID // アカウントに変換 var account = (NTAccount)sid.Translate(typeof(NTAccount)); //account.Value または account.ToString() でメンバ名を取得 } else { // 外部のセキュリティプリンシパル以外の時 //member.Get(”cn”).ToString() でメンバ名を取得 }}
![Page 22: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/22.jpg)
22
所属するグループの取得
• 所属するグループは属性「 memberOf 」で取得• DirectoryEntry なら Properties プロパティで、 IADs なら
GetEx メソッドで取得(どちらも引数は ” memberOf” )• Properties プロパティの項目の型は PropertyValueCollection• GetEx メソッドの戻り値は Object 型であるが、内部的には配列
が返される( memberOf の場合は文字列の配列)ので、 IEnumerable にキャストして ループで個々の要素を処理(値がない場合は例外がスローされる)
• 各要素の値は LDAP のパス形式(下記)CN=Administrators,CN=Builtin,DC=test,DC=local
参考: IADs の GetEx メソッドと Get メソッドGetEx メソッドの戻り値は内部的には配列になるが、 Get メソッドの戻り値は 複数の値の場合は配列、単一の値の場合は非配列になる単一の値しか持たない属性(前ページの objectSid など)を取得するなら Get メソッドを使用することでループ処理が不要になる
![Page 23: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/23.jpg)
23
所属するグループの取得サンプルコード
対象グループを group ( DirectoryEntry 型)とすると
VBFor Each groupPath As String In group.Properties.Item("memberOf") name = DirectoryAccess.PathToCn(groupPath) ' 名前を取得 path = DirectoryAccess.GetBelongPath(groupPath) ' 所属パスを取得Next
C#foreach (string groupPath in group.Properties["memberOf"]) { name = DirectoryAccess.PathToCn(groupPath); // 名前を取得 path = DirectoryAccess.GetBelongPath(groupPath); // 所属パスを取得}
![Page 24: NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~](https://reader035.vdocuments.net/reader035/viewer/2022081504/559221931a28abbe068b458a/html5/thumbnails/24.jpg)
24
詳細や関連情報はブログ等で
.NET から Active Directory にアクセスhttp://www.slideshare.net/mitchin227/active-directory-24695891
.NET から Active Directory データにアクセス ~ユーザ情報の取得と表示~http://www.slideshare.net/mitchin227/display-user
ユーザやグループの検索http://blogs.wankuma.com/mitchin/archive/2013/06/26/327958.aspx
SearchResultCollection クラスhttp://blogs.wankuma.com/mitchin/archive/2013/06/30/327977.aspx
ネイティブ ADSI オブジェクトhttp://blogs.wankuma.com/mitchin/archive/2013/07/01/327981.aspx
グループリスト画面、グループのスコープと種類http://blogs.wankuma.com/mitchin/archive/2013/08/21/328072.aspx
ドメインのグループ用のクラスhttp://blogs.wankuma.com/mitchin/archive/2013/08/24/328079.aspxhttp://blogs.wankuma.com/mitchin/archive/2013/08/25/328081.aspx