24
.NET かか Active Directory かかかかかかかか かかかかかかかかかかか かか かかか mitchin

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

Embed Size (px)

Citation preview

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

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

グループ情報を表示する

小山 三智男mitchin

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

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データにアクセス ~グループ情報の取得と表示~

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データにアクセス ~グループ情報の取得と表示~

4

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

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

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

5

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

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

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

6

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

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

7

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

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

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データにアクセス ~グループ情報の取得と表示~

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データにアクセス ~グループ情報の取得と表示~

10

ADSI のインターフェイス

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

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

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

ユーザ IADsUser

グループ IADsGroup

コンピュータ IADsComputer

組織単位( OU) IADsOU

プリンタ IADsPrintQueue

共有フォルダ

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

11

クラスライブラリ側

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

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

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

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

12

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

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

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

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

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

13

クラスライブラリ側

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

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

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

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

14

フォーム側( Windows アプリ)

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

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

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

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

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

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

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

15

フォーム側( Web アプリ)

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

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

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

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

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

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

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データにアクセス ~グループ情報の取得と表示~

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データにアクセス ~グループ情報の取得と表示~

18

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

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

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

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

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

19

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

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

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

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

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

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

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

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

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データにアクセス ~グループ情報の取得と表示~

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データにアクセス ~グループ情報の取得と表示~

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データにアクセス ~グループ情報の取得と表示~

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データにアクセス ~グループ情報の取得と表示~

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