.NET 3.5 から ユーザ管理用のクラスをまとめた名前空間 AccountManagement が追加されています。PrincipalContext や UserPrincipal クラスを使用すると、タイプセーフな方法で、ユーザの名前やログイン日付による検索、ユーザの情報やロック状態の取得、解除等様々なユーザ管理テスクを間単に行えるようになります。AccountManagement名前空間のクラスを使用するには、System.DirectoryServices.AccountManagement.dllへの参照を追加するのを忘れないでください。同様にSystem.DirectoryServices 名前空間のクラスはSystem.DirectoryServices.dllの参照が必要です。

AccountManagement 名前空間の説明のリンクを掲載しておきます。

System.DirectoryServices.AccountManagement 名前空間の概要
http://msdn.microsoft.com/ja-jp/library/bb384379.aspx

1. LDAPの接続

PrincipalContext を使用すると簡単に、LDAPに接続する準備を行えます。PrincipalContext を作成するサンプルの一つを掲載します。詳細な説明はMSDNを参照してください。サンプルでは、test.localドメインのコンテナUsersを処理対象のルートパスとして、初期化しています。

PrincipalContext ctxt = new PrincipalContext(ContextType.Domain, "test.local", "OU=Users,DC=test,DC=local");

System.DirectoryServices 名前空間で該当する処理はActiveDirectoryにバインドして、DirectoryEntryを作成処理が該当します。サンプルでは、実行ユーザの視覚情報を使用して、ADにバインドするサンプルを掲載しています。

string connectionString = "LDAP://test.local/OU=Users,DC=test,DC=local";

DirectoryEntry entry= new DirectoryEntry(connectionString, null, null, AuthenticationTypes.Secure);
object o = entry.NativeObject;

1.1 ユーザの検索

ユーザの検索はFindByメソッドを使用して行えます。

UserPrincipal user = UserPrincipal.FindByIdentity(ctxt, IdentityType.SamAccountName, "user1");

同じことをSystem.DirectorySevices のクラスを使用すると次のようになります。result は、SearchResult型のインスタンスで、result.GetDirectoryEntry メソッドを使用して、検査結果のディレクトリエントリを取得できます。

DirectoryEntry searchRoot = GetSearchRoot(); // 検索のルートパスを表すDirectoryEntry
using (DirectorySearcher ds = new DirectorySearcher(searchRoot))
{
     string filter = "(&(objectClass=user)(sAMAccountName=user1))";
     ds.Filter = filter;
     ds.SizeLimit = 1;
     result = ds.FindOne();
}

1.2 ユーザの検証

user1という名前のユーザのパスワードがあっているかを検証します。検証処理の注意点ですが、パスワードの有効期限が切れている、ロックアウトされている、次回パスワード変更が必要の場合、いずれも検証が失敗します。ChangePasswordの場合は、ロックアウト以外では処理を行うことができます。

if (ctxt.ValidateCredentials("user1", "password"))
{
    MessageBox.Show("OK!!");
}
else
{
   MessageBox.Show("DAME");
}

同様の処理を既存のDirectoryEntry クラスで行おうとする場合、次のようになります。指定されたユーザ、パスワード情報でDirectoryEntryにバインドできるかで検証します。

string userId = "user1";
string currentPassword = "passowrd";
string connectionString = "LDAP://test.local/OU=Users,DC=test,DC=local";

DirectoryEntry entry= new DirectoryEntry(connectionString, userName, password, AuthenticationTypes.Secure);
object o = entry.NativeObject;

同様のことをDirectoryEntryを使用すると次のようにInvokeを呼び出します。

DirectoryEntry entry = GetChangeUser(); // 変更対象ユーザ取得
entry.Invoke("ChangePassword", oldPassword, newPassword);

1.3 パスワードの変更

パスワードの変更は、UserPrincipalのChangePasswordメソッドを使用します。

user.ChangePassword("oldpassword11", "newpassword12");

DirectoryEntry を使用する場合は、ChangePasswordをInvokeします。アカウントが変更できないに設定されていたり、ロックアウトされている以外はパスワードを変更できます。パスワードの有効期限切れや初回パスワード変更が必要な場合も旧パスワードがあっていればパスワードを変更できます。

entry.Invoke("ChangePassword", oldPassword, newPassword);

1.4 パスワードの設定

user.SetPassword("newpassword33");

DirectoryEntry を使用する場合は、ChangePasswordと同様にInvokeを呼び出します。ただし、旧パスワードは必要ありませんが、ChangePasswordと異なり、Administratorのような高い権限が必要となります。

entry.Invoke("ChangePassword", oldPassword, newPassword);

1.5 ユーザのロック解除

UserPrincipal user = UserPrincipal.FindByIdentity(ctxt, IdentityType.SamAccountName, "lockeduser");
if (user.IsAccountLockedOut())
{
    user.UnlockAccount();
}

DirectoryEntry を使用す場合は、InvokeGet,InvokeSet を使用しまます。サンプルではロックされているかを調べる例を刑咲いています。

// ロックされているかを調べるユーザのDirectoryEntry取得
DirectoryEntry user = GetLockCheckUser(); 
bool locked = (bool) user.InvokeGet("IsAccountLocked")

2. まとめ

今回の説明は以上です。誤りなどがありましたら、ご指摘ください。

AccountManagement 名前空間にはユーザ管理タスクを簡単にするクラスが追加されています。UserPrincipal クラスは紹介していること意外でも様々な機能があります。MSDNのドキュメントを参照していただければと思います。