.NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~

Post on 30-Jun-2015

2.409 views 5 download

Transcript of .NETからActive Directoryデータにアクセス ~グループ情報の取得と表示~

.NET から Active Directory データにアクセス

グループ情報を表示する

小山 三智男mitchin

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

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を参照する必要があります。

4

主にどんなデータがあるの?

管理ツール「 Active Directory ユーザとコンピュータ」で管理する以下のオブジェクト• ユーザ• グループ• コンピュータ• 組織単位( OU)• プリンタ• 共有フォルダ

5

サンプルアプリケーションの初期画面

ドメインを取得して画面下部に接続先を表示しています。

6

グループリスト画面( Windows アプリ)

7

グループリスト画面( Web アプリ)

8

どうやって接続するの?

接続先によってプロバイダが異なります。

ドメインに接続する場合プロバイダ: LDAP(Lightweight Directory Access Protocol)書式例: LDAP://DC=virtual,DC=proceed,DC=local

ローカルに接続する場合プロバイダ: WinNT(Windows NT)書式例: WinNT://vpc-testclient1

これを引数にして DirectoryEntry のインスタンスを作成します。

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 が管理している共有フォルダ

10

ADSI のインターフェイス

基本インターフェイスは IADs インターフェイスで、各オブジェクトはこのインターフェイスを継承しています。

オブジェクトとそれに対応するインターフェイス

DirectoryEntry.NativeObject プロパティの値を上記インターフェイスにキャストできます。

ユーザ IADsUser

グループ IADsGroup

コンピュータ IADsComputer

組織単位( OU) IADsOU

プリンタ IADsPrintQueue

共有フォルダ

11

クラスライブラリ側

名前空間直下に追加したドメイングループのスコープタイプを表す DomainGroupScopeType 列挙体• BuiltInLocal = -2147483643• DomainLocal = -2147483644• Global = -2147483646• Universal = -2147483640

※ セキュリティグループの属性「 groupType 」の値と同じになるようにしています

既存のものについてはこちらのスライドを参照してくださいhttp://www.slideshare.net/mitchin227/display-user

12

クラスライブラリ側に追加したクラス

LocalGroup ( ローカルのグループを表すクラス )プロパティ• Native (ADSI Group オブジェクトを取得 )

DomainGroup ( ドメインのグループを表すクラス )プロパティ• Native (ADSI Group オブジェクトを取得 )• Scope ( グループのスコープを取得 )• ScopeType ( グループのスコープタイプを取得 )• SecurityEnabled ( セキュリティグループかどうかを取得 )• Type ( グループの種類を取得 )

メソッド• FindByName ( データバインド用:グループを検索 )• GetGroups ( データバインド用:グループの一覧を取得 )

13

クラスライブラリ側

DirectoryAccess クラスに追加したパブリックなメンバGetBelongPath メソッド ( 所属パスを取得 ) ※ オーバーロード

GetGroups メソッド ( グループを取得 )GetPrimaryGroupMemberEntries メソッド(PrimaryGroupToken を持つグループをプライマリグループとしているメンバの DirectoryEntry のコレクションを取得 )

PathToCn メソッド (LDAP パスの名前 ( オブジェクト名 ) を取得 )

14

フォーム側( Windows アプリ)

• ドメイングループ用とローカルグループ用の BindingSource のデータソースに DomainGroup クラス、 LocalGroup クラスを指定

• 詳細の各コントロールは BindingSource (クラス)のプロパティにバインド

• グループの一覧を取得し BindingSource のデータソースに設定

• BindingSource を一覧 ListBox のデータソースに設定• ドメインの場合は選択したグループのメンバをメンバ ListView に表示

• ローカルの場合は選択したグループのメンバ名のコレクションをメンバ ListBox のデータソースに設定

• ドメインの場合は所属するグループを所属するグループListView に表示

15

フォーム側( Web アプリ)

• DomainUser クラスをビジネスオブジェクトとする ObjectDataSource を 2 つ用意

• グループの一覧を取得するメソッドを指定したものを一覧 ListBox のデータソースに指定

• 選択したグループの名前からグループを検索するメソッドを指定したものを詳細 FormView のデータソースに指定

• BindingSource を一覧 ListBox のデータソースに設定• 選択したグループのメンバのデータソース用のテーブルを作成し、メンバ GridView のデータソースに設定してバインド

• 選択したグループの所属するグループのデータソース用のテーブルを作成し、所属するグループ GridView のデータソースに設定してバインド

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 を作

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 を作

18

ドメインのグループのスコープと種類

ドメインのグループにはスコープと種類があります。グループのスコープ•ビルトイン ローカル•ドメイン ローカル•グローバル•ユニバーサル

グループの種類•セキュリティ•配布

サンプルアプリでは DomainGroup クラスのコンストラクタ内で属性「 groupType 」の値からスコープと種類をプロパティにセットしています。

19

メンバの表示はちょっと手間

• グループのメンバに含まれるのは ユーザ、グループ、コンピュータ、外部のセキュリティ プリンシパル

• メンバは IADsGroup.Members メソッドで取得し、ループで個々のメンバを処理

• ユーザやコンピュータのプライマリ グループになっていると、そのユーザやコンピュータはメンバに含まれないので、別途取得が必要

• 取得のしかたはユーザの所属するグループの取得と同様※11 ページの URL のスライド

の 17 ページ参照 • 外部のセキュリティ プリン

シパルは名前が SID 表記なので、読み取り可能な名前に変換

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

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() でメンバ名を取得 }}

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 メソッドを使用することでループ処理が不要になる

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); // 所属パスを取得}

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