Active Directoryのアカウントロックを検知する | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

Active Directoryでアカウントロックをした場合、AD上の「lockouttime」属性の値でロックの有無を検知できると思っていたんですけど、できないみたいですね。


ユーザがロックアウトしてるかどうかの判断@マイナーでもいいよね??


アカウントロックを解除したい場合、この属性値に「0」をセットすることでロックは解除されるようですが、AD上のグループポリシーでアカウントロックを自動解除する(例えば、ロック後に一定時間経過したらロックを解除する)場合、「lockouttime」の属性は「前回ロックした時刻(最終ロック時間)」が何時までも残ってしまうようです。

その他に、badpwdcount属性を使ってパスワードを間違えた回数を拾えば、グループポリシーに設定している閾値に達しているものはアカウントロックしているはず、という基準のものロジックを組み立ててみたりもしたのですが、このbadpwdcount属性はAD間で同期されるものではなくそのADローカルで管理されている属性のようです。


ってことでかなり途方にくれていたのですが、「msds-user-account-control-computed」という属性を調べればアカウントのロックアウトステータスなどを確認することができるようです。



ADのアカウントロック状態をLDAPを通して検知する


PHPで書いてしまいますが、LDAP使っているのでほかのプログラムでも置き換え可能です。


<?php
// ADサーバーのホスト
$host = "ldaps://192.168.0.100";

// ロックアウトをチェックする対象ユーザー名
$user = "username@testdomain.test";

// ADサーバーの管理者ユーザー
$adminId = "admin@testdomain.test";
$adminPass = "FooBar";

// LDAPに接続
$conn = ldap_connect($host, 636);
ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3);

// 管理者ユーザーでBIND
$auth = ldap_bind($conn, $adminId, $adminPass);

// msds-user-account-control-computed属性を検索
$ldapSearch = ldap_search($conn, "OU=Employee,OU=Users,DC=testdomain,DC=test", "userprincipalname=" . $user, array("msds-user-account-control-computed"));
$info = ldap_get_entries($conn, $ldapSearch);
$msds = $info[0]['msds-user-account-control-computed'][0];

// ロックアウトしているか検証
if (($info[0]['msds-user-account-control-computed'][0] & 16) === 16) {
    echo $user . "はロックアウト中" . PHP_EOL;
} else {
    echo $user . "はロックアウトしていません" . PHP_EOL;
}

ADへの認証方法やLDAPSを使う場合の設定などは前回書いた「PHPからActive Directoryに認証・パスワード変更する方法 」を参考にしてください。


属性の検索は一般的な方法ですが、ロックアウトの検証に関してはちょっと特殊で「msds-user-account-control-computed」の値と16の論理積が16の場合はアカウントロックしているという判断になります。


ms-DS-User-Account-Control-Computed attribute@Microsoft Developer Network


こちらに値についての説明が書かれていますが、「msds-user-account-control-computed」属性の値はその他のアカウントのステータスを表す数字との積み上げになっています。

アカウントロック(UF_LOCKOUT)を表す数値は16(16進でいう0x0010)となっていて、パスワードの有効期限切れ(UF_PASSWORD_EXPIRED)は8388608(16進でいう0x800000)となっています。

パスワードの有効期限切れかつアカウントロックしている場合の数字はこの足し算の「8388624」となり、このような場合でも論理積は16であるのでアカウントロックしているということがわかります。


予断ですが、ldap_searchは第3引数の検索フィルタに「array("*")」を指定すると全属性を引っ張ってこれるんですけど、その中に「msds-user-account-control-computed」属性はありません(全属性を引っ張ってこれるという思い違いをしていたみたい)。

なので、この属性はLDAPを通して取得できないんだと思い込んではまってました。