本サンプルでは、ドメインルートのディレクトリオブジェクトにバインドし、次のポリシーの値を取得してみます。
- パスワードの長さ
- パスワードの変更禁止期間
- パスワードの有効期間
- パスワードの履歴を記録する
- パスワードは複雑さの要件を満たす必要がある
- 暗号化を元に戻せる状態でパスワードを保存する
- アカウントのロックアウトの閾値
- ロックアウトカウンタのリセット
- ロックアウト期間
動作環境
- 動作環境 Windows 2003 (ドメイン環境)
- 開発環境 Visual Studio 2008 Professional
- .NET 3.5 (.NET 2.0 以上で動作します)
参考のURLです。
1 パスワードポリシーを持つディレクトリオブジェクト
パスワードのポリシーはドメインレベルのポリシーです。パスワードのポリシーを取得するには、スキーマクラスが domainDNS (objectClass=domainDNS) のディレクトリオブジェクトから取得します。このディレクトリオブジェクトのパスは RootDSE ディレクトリオブジェクトのdefaultNamingContext 属性値から得られます。つまり、ドメインのルートオブジェクトから取得できます。
2. パスワードの属性値を取得する
サンプルではルートオブジェクトにバインドし、パスワードのポリシーを取得します。プログラムでは次の属性値を取得します。
- パスワードの長さ
- パスワードの変更禁止期間
- パスワードの有効期間
- パスワードの履歴を記録する
- アカウントのロックアウトの閾値
- ロックアウトカウンタのリセット
- ロックアウト期間
/// <summary> /// パスワードの属性値を取得する /// </summary> public static void RetrievePasswordAttribute() { using (DirectoryEntry rootDSE = GetDirectoryEntry("RootDSE")) { // ドメインルートオブジェクトにパスワードのプロパティは格納されている // ので、回りくどいことをしなくても、LDAP://crm1.localのようにドメイン // のルートパスをを指定すれば取得できます。 string domainRoot = rootDSE.Properties["defaultNamingContext"].Value as string; using (DirectoryEntry rootEntry = GetDirectoryEntry(domainRoot)) { string[] policyAttributes = new string[]{ "maxPwdAge","minPwdAge", "minPwdLength", "lockoutDuration", "lockOutObservationWindow", "lockoutThreshold", "pwdHistoryLength" }; // rootEntryはobjectClassがdomainDNSのディレクトリオブジェクト DirectorySearcher searcher = new DirectorySearcher(rootEntry, null, policyAttributes, SearchScope.Base); SearchResult result = searcher.FindOne(); if (result != null) { // パスワードの長さ if (result.Properties.Contains("minPwdLength")) { Console.WriteLine("パスワードの長さ:" + result.Properties["minPwdLength"][0] + "文字以上"); } // パスワードの変更禁止期間 if (result.Properties.Contains("minPwdAge")) { // 64bit 整数型はLDAPでは負数として格納されている long tick = (long)result.Properties["minPwdAge"][0]; if (tick == long.MinValue) { tick = 0L; // 無期限 } else { tick = Math.Abs(tick); } Console.WriteLine("パスワードの変更禁止期間:" + new TimeSpan(tick).TotalDays + "日"); } // パスワードの有効期間 if (result.Properties.Contains("maxPwdAge")) { // 64bit 整数型はLDAPでは負数として格納されている long tick = (long)result.Properties["maxPwdAge"][0]; if (tick == long.MinValue) { tick = 0L; // 無期限 } else { tick = Math.Abs(tick); } Console.WriteLine("パスワードの有効期間:" + new TimeSpan(tick).TotalDays + "日"); } // パスワードの履歴を記録する if (result.Properties.Contains("pwdHistoryLength")) { Console.WriteLine("パスワードの履歴を記録する:" + result.Properties["pwdHistoryLength"][0] + "回"); } // パスワードは複雑さの要件を満たす必要がある // 暗号化を元に戻せる状態でパスワードを保存する // 上記2設定は pwdProperties 属性に格納されている // アカウントのロックアウトの閾値 if (result.Properties.Contains("lockoutThreshold")) { Console.WriteLine("アカウントのロックアウトの閾値:" + result.Properties["lockoutThreshold"][0] + "回ログオンに失敗"); } // ロックアウトカウンタのリセット if (result.Properties.Contains("lockOutObservationWindow")) { long tick = (long)result.Properties["lockOutObservationWindow"][0]; if (tick == long.MinValue) { tick = 0L; // 無期限 } else { tick = Math.Abs(tick); } Console.WriteLine("ロックアウトカウンタのリセット:" + new TimeSpan(tick).TotalMinutes + "分後"); } // ロックアウト期間 if (result.Properties.Contains("lockoutDuration")) { long tick = (long)result.Properties["lockoutDuration"][0]; if (tick == long.MinValue) { tick = 0L; // 無期限 } else { tick = Math.Abs(tick); } Console.WriteLine("ロックアウト期間:" + new TimeSpan(tick).TotalMinutes + "分"); } } } } } private static DirectoryEntry GetDirectoryEntry(string path) { path = "LDAP://" + path; return new DirectoryEntry(path, null, null, AuthenticationTypes.Secure); }
ディレクトリの属性値について
パスワードのポリシーを未定義にしても、パスワードポリシーのプロパティ値がとれます。ポリシーが未定義とは、定義しないというのではなく、現在のポリシーを上書きしないという意味。パスワードに関するポリシーはドメインレベルでのみ定義できます。そのため、ポリシーを定義してから未定義にすると、定義時の値が有効になります。
3. パスワードのポリシーを取得する
ルートディレクトリオブジェクトの pwdProperties 属性値からパスワードのプロパティを取得し、次のパスワードのポリシーを取得するサンプルを掲載します。
- パスワードは複雑さの要件を満たす必要がある
- 暗号化を元に戻せる状態でパスワードを保存する
/// <summary> /// プロパティの説明は以下のリンク参照 /// DOMAIN_PASSWORD_INFORMATION Structure /// http://msdn.microsoft.com/en-us/library/aa375371(VS.85).aspx /// </summary> [Flags] public enum PasswordProperty { DOMAIN_PASSWORD_COMPLEX = 1, DOMAIN_PASSWORD_NO_ANON_CHANGE = 2, DOMAIN_PASSWORD_NO_CLEAR_CHANGE = 4, DOMAIN_LOCKOUT_ADMINS = 8, DOMAIN_PASSWORD_STORE_CLEARTEXT = 16, DOMAIN_REFUSE_PASSWORD_CHANGE = 32 } public static void RetrievePasswordProperties() { using (DirectoryEntry rootDSE = GetDirectoryEntry("RootDSE")) { // ドメインルートオブジェクトにパスワードのプロパティは格納されている // ので、回りくどいことをしなくても、LDAP://crm1.localのようにドメイン // のルートパスをを指定すれば取得できます。 string domainRoot = rootDSE.Properties["defaultNamingContext"].Value as string; using (DirectoryEntry rootEntry = GetDirectoryEntry(domainRoot)) { string[] passwordProperties = new string[] { "pwdProperties" }; // rootEntryはobjectClassがdomainDNSのディレクトリオブジェクト DirectorySearcher searcher = new DirectorySearcher(rootEntry, null, passwordProperties, SearchScope.Base); SearchResult result = searcher.FindOne(); if (result != null) { if (result.Properties.Contains("pwdProperties")) { PasswordProperty property = (PasswordProperty) result.Properties["pwdProperties"][0]; Console.WriteLine(property); if ((property & PasswordProperty.DOMAIN_PASSWORD_COMPLEX) == PasswordProperty.DOMAIN_PASSWORD_COMPLEX) { Console.WriteLine("パスワードは、複雑さの要件を満たす必要がある:有効"); } else { Console.WriteLine("パスワードは、複雑さの要件を満たす必要がある:無効"); } if ((property & PasswordProperty.DOMAIN_PASSWORD_STORE_CLEARTEXT) == PasswordProperty.DOMAIN_PASSWORD_STORE_CLEARTEXT) { Console.WriteLine("暗号化を元に戻せる状態でパスワードを保存する:有効"); } else { Console.WriteLine("暗号化を元に戻せる状態でパスワードを保存する:無効"); } } } } } }
ADSIを使用するサンプルはスクリプトですが、次のサイトが参考になります。
スクリプト一覧 : Active Directory
http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/default.mspx
さんのコメント: さんのコメント: