CakePHP 2 で ActiveDirectory に LDAP 認証する
CakePHP 2 で ActiveDirectory に LDAP 認証してみました。Auth コンポーネントはカスタムの認証ロジックを簡単に組み込めるようになっています。 CakePHP のバージョンは 2.3.2 です。
公式の Auth コンポーネントを使用したユーザー認証方法です。カスタムの認証方法についても紹介されています。
コントローラーの作成
まず、 app\Controller\UsersController.php を作成し、下記のように記述します。 13 行目以外は通常の Auth コンポーネントを使ったものと同じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?php App::uses('AppController', 'Controller'); class UsersController extends AppController { var $uses = array("Member"); var $components = array('Auth'); public function index() { $this->redirect(array('action' => 'login')); } function beforeFilter() { $this->Auth->authenticate = array('Ldap'); $this->Auth->loginRedirect = array('controller' => 'Applications', 'action' => 'index'); } public function login() { if ($this->request->is('post')) { $this->Session->delete('Auth.redirect'); $loggedin = $this->Auth->login(); if ($loggedin) { return $this->redirect($this->Auth->redirect()); } else { $this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth'); } } } public function logout() { $this->Auth->logout(); } } ?> |
ビューの作成
同じくビューも作成しておきます。これも通常の Auth コンポーネントを使うときと違いはありません。とりあえず app\View\Users に login.ctp と logout.ctp を作成しておけば充分でしょう。
1 2 3 4 5 6 7 |
<?php echo $this->Session->flash('auth'); echo $this->Form->create('User', array('action' => 'login')); echo $this->Form->input('username'); echo $this->Form->input('password'); echo $this->Form->end('Login'); ?> |
1 |
<?php echo __('Logged out'); ?> |
カスタムコンポーネントの作成
次に本題の LDAP 認証を行なうコンポーネントを作成します。 app\Controller\Component\Auth\LdapAuthenticate.php を作成し、下記のように記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<?php App::uses('BaseAuthenticate', 'Controller/Component/Auth'); class LdapAuthenticate extends BaseAuthenticate { public function authenticate(CakeRequest $request, CakeResponse $response) { // LDAP認証 $user = $this->_ldapAuth($request['data']['User']); //debug($user); return $user; } // LDAP認証を行なうメソッド function _ldapAuth($request) { $username = $request['username']; $password = $request['password']; // パスワードが空ならfalse if ($password == "") return false; $LDAP_HOST = "ldap://localhost"; $LDAP_PORT = 389; $LDAP_ADMIN_DN = "管理者のアカウント"; $LDAP_ADMIN_PASSWORD = "管理者のパスワード"; $LDAP_SEARCH_OU = "OU(組織単位)の指定"; // 接続 $ds = ldap_connect($LDAP_HOST, $LDAP_PORT); if (!$ds) return false; // 認証方法を変更 if (ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) { // 管理権限でバインドしてみる if (ldap_bind($ds, $LDAP_ADMIN_DN, $LDAP_ADMIN_PASSWORD)) { // 渡されたユーザ名を検索 $sr = ldap_search($ds, $LDAP_SEARCH_OU, "samaccountname=".$username); //エントリを取得 $info = ldap_get_entries($ds, $sr); // dn(ドメイン名前)が取得できてかつイニシャルがセットされていれば if (isset($info[0]["dn"]) && isset($info[0]["initials"]) && $info[0]["initials"] > 0) { $ret = array("name" => $username); // 名前(フルネーム) $ret["fullname"] = $info[0]["name"][0]; // イニシャル $ret["id"] = $info[0]["initials"][0]; // グループ $ret["groups"] = array(); foreach ($info[0]["memberof"] as $val) { // CNの値をgroupsに追加 if (preg_match("/CN=(\w+)/", $val, $matches)) { $ret["groups"][] = $matches[1]; } } // パスワード認証 if (@ldap_bind($ds, $info[0]["dn"], $password)) { ldap_close($ds); return $ret; } } } } ldap_close($ds); return false; } } ?> |
authenticate メソッドの $request にユーザーが入力したアカウントが入ってきますので、これを使って ActiveDirectory に問い合わせます。
_ldapAuth メソッドは勝手に定義したものなので名前はなんでもかまいません。この中で認証を行ない、失敗すれば false 、成功すれば LDAP で取得したユーザー情報を連想配列で返します。
ldap_connect の前の設定変数には、サーバーや認証に使う管理者の情報を設定しておきます。
変数名 | 説明 | 値の例 |
---|---|---|
$LDAP_HOST | LDAP サーバーのアドレス | ldap://localhost | $LDAP_ADMIN_DN | 管理者のアカウント | cn=Administrator,cn=Users, dc=test,dc=co,dc=jp |
$LDAP_ADMIN_PASSWORD | 管理者のパスワード | $LDAP_SEARCH_OU | 検索するOU(組織単位) | ou=TestOU,dc=test, dc=co,dc=jp |
基本的な流れは次の通りです。
- ldap_connect でサーバーに接続
- ldap_bind 管理者権限でバインド(ログインみたいなもん)
- ldap_search でユーザー名を検索
- ldap_get_entries でユーザーエントリーを取得
- ldap_bind ユーザー名とパスワードでバインド
最後の ldap_bind が成功すればパスワードが OK ということなので、認証 OK にする。
ユーザーが属しているグループは memberof に格納されているので、 CN 部分を抜きだしてやればグループの一覧が取得できます。
最後までお読みいただきありがとうございました m(_ _)m