.NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~
-
Upload
michio-koyama -
Category
Technology
-
view
3.021 -
download
1
description
Transcript of .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~
![Page 1: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/1.jpg)
.NET から Active Directory データにアクセス
ユーザ情報の取得と表示
小山 三智男mitchin
![Page 2: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/2.jpg)
2
サンプルアプリケーション
開発環境• OS : Windows7(x64)• IDE : Visual Studio 2010 SP1• アプリ: Windows フォーム (.NET 4 Client Profile)
Web フォーム (.NET 4)クラスライブラリ (.NET 4 Client Profile)
実行環境• 単一ドメイン、単一サイト、単一サブネット• サーバ: Windows Server 2008 Standard SP1 (.NET 4)• クライアント: Windows XP SP3 (.NET 4 Client Profile)• IIS : Windows 認証
![Page 3: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/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://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/4.jpg)
4
主にどんなデータがあるの?
管理ツール「 Active Directory ユーザとコンピュータ」で管理する以下のオブジェクト• ユーザ• グループ• コンピュータ• 組織単位( OU)• プリンタ• 共有フォルダ
![Page 5: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/5.jpg)
5
サンプルアプリケーションの初期画面
ドメインを取得して画面下部に接続先を表示しています。
![Page 6: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/6.jpg)
6
ユーザリスト画面( Windows アプリ)
![Page 7: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/7.jpg)
7
ユーザリスト画面( Web アプリ)
![Page 8: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/8.jpg)
8
どうやって接続するの?
接続先によってプロバイダが異なります。
ドメインに接続する場合プロバイダ: LDAP(Lightweight Directory Access Protocol)書式例: LDAP://DC=virtual,DC=proceed,DC=local
ローカルに接続する場合プロバイダ: WinNT(Windows NT)書式例: WinNT://vpc-testclient1
![Page 9: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/9.jpg)
9
検索してユーザのリストを取得する
LDAP プロバイダで接続する場合• 接続するドメインや取得したユーザは DirectoryEntry オブジェクト• ユーザやグループを検索するのは DirectorySearcher オブジェクト• 複数の検索結果は SearchResultCollection として返される• SearchResult.GetDirectoryEntry メソッドで DirectoryEntry を取得• LDAP 書式のフィルター文字列( DirectorySearcher.Filter プロパティ)
は次のように指定(属性 = 値 をカッコで括る)• "(objectCategory=User)" -- ユーザ• "(&(objectCategory=Group)(name=De*))" -- De で始まるグループ• "(&(objectCategory=OrganizationalUnit)(name= 一課 )" -- 一課の
OU• "(&(objectCategory=PrintQueue)(!location= 本社 ) (|
(printColor=True)(printPagesPerMinute>=30)))" -- 本社以外でカラーか 1 分間に 30 枚以上印刷できるプリンタ
![Page 10: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/10.jpg)
10
ADSI のインターフェイス
基本インターフェイスは IADs インターフェイスで、各オブジェクトはこのインターフェイスを継承しています。
オブジェクトとそれに対応するインターフェイス
DirectoryEntry.NativeObject プロパティの値を上記インターフェイスにキャストできます。
ユーザ IADsUser
グループ IADsGroup
コンピュータ IADsComputer
組織単位( OU) IADsOU
プリンタ IADsPrintQueue
共有フォルダ
![Page 11: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/11.jpg)
11
クラスライブラリ側
ディレクトリ オブジェクトの種類を表す CategoryType 列挙体• User• Group• Computer• OrganizationalUnit• PrintQueue• Volume• ForeignSecurityPrincipal
※ 名前は検索時に指定する文字列と同じになるようにしています
![Page 12: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/12.jpg)
12
クラスライブラリ側
インターフェイスIDirectory(Directory オブジェクトのプロパティを定義 )IDomain( ドメインの Directory オブジェクトのプロパティを定義 )IUser(User オブジェクトの共通プロパティを定義 )IGroup(Group オブジェクトの共通プロパティを定義 )
クラスDirectoryObject(Directory オブジェクトを表す抽象基本クラス )DomainObject( ドメインの Directory オブジェクトを表す抽象基本クラ
ス )LocalUser( ローカルのユーザを表すクラス )DomainUser( ドメインのユーザを表すクラス )
![Page 13: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/13.jpg)
13
クラスライブラリ側
DirectoryAccess クラスに追加したパブリックなメンバGroupTokens プロパティ ( グループの PrimaryGroupToken/ 名前 のリス
ト )DisposeItems メソッド ( 使用されているリソースを解放 )FindDirectoryObject メソッド (Directory オブジェクトを検索 )GetBelongGroups メソッド ( 所属するグループを取得 )GetBelongPath メソッド ( 所属パスを取得 )GetUsers メソッド ( ユーザを取得 )
![Page 14: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/14.jpg)
14
フォーム側
Windows アプリの場合• ドメインユーザ用とローカルユーザ用の BindingSource のデータソース
に DomainUser クラス、 LocalUser クラスを指定• 詳細の各コントロールは BindingSource (クラス)のプロパティにバイ
ンド• ユーザの一覧を取得し BindingSource のデータソースに設定• BindingSource を一覧 ListBox のデータソースに設定• 選択したユーザの所属するグループを取得し 所属するグループ ListBox
のデータソースに設定
Web アプリの場合• DomainUser クラスをビジネスオブジェクトとする ObjectDataSource
を 3 つ用意• ユーザの一覧を取得するメソッドを指定したものを一覧 ListBox のデータ
ソースに指定• 選択したユーザの名前からユーザを検索するメソッドを指定したものを詳
細 FormView のデータソースに指定• 選択したユーザの所属するグループを取得するメソッドを指定したものを
所属するグループ ListBox のデータソースに指定
![Page 15: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/15.jpg)
15
ユーザ取得サンプルコード( VB )
Public Shared Function GetUsers( Of T As {DirectoryObject, IUser}) As IList(Of T) Dim users As New List(Of T)() Using root = GetRootEntry() ’ ルートの DirectoryEntry を取得 Dim filter = String.Format("(objectCategory={0})", CategoryType.User) Using searcher As New DirectorySearcher(root, filter) Using results = searcher.FindAll() For Each res As SearchResult In results users.Add(DirectCast(CreateInstance(res.GetDirectoryEntry()), T)) Next End Using End Using End Using Return usersEnd Function
※root は一般的には New DirectoryEntry(LDAP のルートパス ) をセットします※CreateInstance メソッドは DirectoryEntry から DirectoryObject を作成しま
す
![Page 16: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/16.jpg)
16
ユーザ取得サンプルコード( C# )
public static IList<T> GetUsers<T>() where T : DirectoryObject, IUser { var users = new List<T>(); using (var root = GetRootEntry()) { // ルートの DirectoryEntry を取得 var filter = String.Format("(objectCategory={0})", CategoryType.User); using (var searcher = new DirectorySearcher(root, filter)) { using (var results = searcher.FindAll()) { foreach (SearchResult res in results) { users.Add((T)CreateInstance(res.GetDirectoryEntry())); } } } } return users;}
※ root は一般的には new DirectoryEntry(LDAP のルートパス ) をセットします※CreateInstance メソッドは DirectoryEntry から DirectoryObject を作成しま
す
![Page 17: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/17.jpg)
17
所属するグループの取得はちょっと手間
• ユーザの所属するグループは IADsUser.Groups メソッドで取得• ただし、プライマリグループは含まれないので、別途取得する必要がある• そのためにはグループの primaryGroupToken が必要• primaryGroupToken はプロパティ( DirectoryEntry.Properties )にな
いので、ディレクトリストアからロードする必要がある• グループの primaryGroupToken =
ユーザの primaryGroupID なら、そのグループがユーザのプライマリグループ
![Page 18: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/18.jpg)
18
primaryGroupToken の取得と保持( VB )Private Shared Sub LoadGroupTokens(searcher As DirectorySearcher) searcher.Filter = String.Format( "(objectCategory={0})", CategoryType.Group) Using results = searcher.FindAll() For Each res As SearchResult In results Dim entry = res.GetDirectoryEntry() entry.Invoke("GetInfoEx", New Object() {"primaryGroupToken"}, 0) Dim token = Convert.ToInt32( entry.Properties.Item("primaryGroupToken").Value) GroupTokens.Add(token, entry.Properties.Item("cn").Value.ToString()) Next End UsingEnd Sub
DirectoryEntry.Invoke メソッド( IADs.GetInfoEx メソッドの呼出し)でプロパティをロードしています。
![Page 19: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/19.jpg)
19
primaryGroupToken の取得と保持( C# )Private static void LoadGroupTokens(DirectorySearcher searcher) { searcher.Filter = String.Format( "(objectCategory={0})", CategoryType.Group); using (var results = searcher.FindAll()) { foreach (SearchResult res in results) { var entry = res.GetDirectoryEntry(); entry.Invoke("GetInfoEx", new object[] { "primaryGroupToken" }, 0); var token = Convert.ToInt32( entry.Properties["primaryGroupToken"].Value); GroupTokens.Add(token, entry.Properties["cn"].Value.ToString()) } }}
DirectoryEntry.Invoke メソッド( IADs.GetInfoEx メソッドの呼出し)で
プロパティをロードしています。
![Page 20: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/20.jpg)
20
所属するグループの取得( VB )
Public Shared Function GetBelongGroups( user As IUser) As ReadOnlyCollection(Of String)
Dim groups As New List(Of String)()
’ 所属するグループ数分 ( プライマリグループ以外 ) For Each group As IADs In user.Native.Groups() groups.Add(group.Get("cn").ToString()) Next
If TypeOf user Is DomainUser Then ’ ドメインユーザの時 Dim primaryGroupId = DirectCast(user,
DomainUser).PrimaryGroupId groups.Add(GroupTokens.Item(primaryGroupId)) End If groups.Sort() Return groups.AsReadOnly()End Sub
![Page 21: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/21.jpg)
21
所属するグループの取得( C# )
public static ReadOnlyCollection<string> GetBelongGroups(IUser user) {
var groups = new List<string>();
// 所属するグループ数分 ( プライマリグループ以外 ) foreach (IADs group in user.Native.Groups()) { groups.Add(group.Get("cn").ToString()); }
if (user is DomainUser) { // ドメインユーザの時 var primaryGroupId = ((DomainUser)user).PrimaryGroupId; groups.Add(GroupTokens[primaryGroupId]); } groups.Sort(); return groups.AsReadOnly();}
![Page 22: .NETからActive Directoryデータにアクセス ~ユーザ情報の取得と表示~](https://reader036.fdocument.pub/reader036/viewer/2022081717/5499d3ecac79591d2e8b59c5/html5/thumbnails/22.jpg)
22
詳細は・・・
ブログにも書いてます。
ユーザやグループの検索http://blogs.wankuma.com/mitchin/archive/2013/06/26/327958.aspx
Active Directory 内のオブジェクトの検索指定http://blogs.wankuma.com/mitchin/archive/2013/06/28/327969.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/07/11/327999.aspx
ドメインユーザの画面への表示( Web アプリ)http://blogs.wankuma.com/mitchin/archive/2013/07/25/328019.aspx