CakePHP Auth でパスワード変更フォームの暗号化周り(暗号化されずに登録される場合など)

Authコンポーネントでパスワード変更フォーム作ったら
保存した時に暗号化されなかったり、暗号化された
パスワードが入力欄に入ったりしたので備忘録。

■現象
【1つ目】
 Authコンポーネント使用後、パスワード変更フォームで
 パスワード入力して保存すると、DB側にはパスワードが
 裸のまま保存される(「aaa」と入力したらそのまま保存)。

 ※ユーザー新規登録画面からユーザー名と
  パスワードを入力した場合はちゃんと暗号化(ハッシュ化)
  されて保存される。

【2つ目】
 パスワード入力欄のvalueが暗号化されたパスワードが
 入ってるため、そのまま保存するとハッシュ化後の
 パスワードが二重に暗号化して保存されてしまう。

■原因
【1つ目】 
 パスワード変更時は暗号化されないっぽい。

【2つ目】
 DB保存のパスワードが暗号化後の値のため、
 当然そのまま引っ張ってきてしまっている。
 (ちなみに暗号化を戻す復号化して表示みたいなのはできない)

■対策
【1つ目】
 パスワード変更時に$this->Auth->hashPasswords($this->data)で
 丸ごと暗号化をかけてDB保存する。

【2つ目】
 パスワード入力欄をデフォ空白にしておき、
 「新しいパスワード」みたいなフォームにする。
 空白だったらパスワード変更なし、
 空白以外だったらパスワード変更あり とする。
 (但し、そうすると今度はバリデーションに引っかかるが、
  ここでは設けない)

■対策後のソース(UsersController) RESOLUTION Source
    function edit() {
        $id = $this->Auth->User(‘id’);

        if (!$id && empty($this->data)) {
            $this->Session->setFlash(‘ユーザーが見つかりません’, ‘flash_message’, array(‘result’ => ‘error’));
            $this->redirect(array(‘action’ => ‘edit’));
        }

        if ($id && !empty($this->data)) {
            // パスワード入力欄が空白だったら配列削除  delete array if empty the password input form
            if (empty($this->data[‘User’][‘password’])) {
                unset($this->data[‘User’][‘password’]);
            }

            // userのidとusernameを定義しないと暗号化されない hashing need both username and password
            $this->data[‘User’] += array(
                ‘id’ => $this->Auth->User(‘id’),
                ‘username’ => $this->Auth->User(‘username’),
            );

            // AuthのhashPasswords関数でパスワードを暗号化してから保存 hashing password
            if ($this->User->save($this->Auth->hashPasswords($this->data))) {
                $this->Session->setFlash(‘変更内容を保存しました’, ‘flash_message’, array(‘result’ => ‘success’));
                //$this->redirect(array(‘action’ => ‘edit’));
            } else {
                $this->Session->setFlash(‘変更内容を保存できませんでした。もう一度実行してみてください。’, ‘flash_message’, array(‘result’ => ‘error’));
            }
        }

        if (empty($this->data)) {
            $this->data = $this->User->read(null, $id);
        }
    }

■参考サイト
 5.2.5.4 hashPasswords
 CakePHP 1.3 API – hashPasswords
 cakePHP | Authコンポーネントのパスワード暗号化に対応する

■for English
I have problem two things that change password page on CakePHP Auth component.

[CAUSE]
1. I couldn’t save hashing password.
2. password form show the hashing password.

[RESOLUTION]
1. use hassPassword class.
   $this->Auth->hashPasswords($this->data)
2.  set blank password form then check the form. check the my source.

CakePHPのACLで権限一覧を見る時のMySQLクエリー

# MySQLクエリー – パーミッション一覧
SELECT
  aros_acos.id AS aros_acos_id,
  aros.model,
  groups.name,
  acos.alias,
  acos.lft,
  acos.rght,
  aros_acos._create,
  aros_acos._read,
  aros_acos._update,
  aros_acos._delete
FROM
  aros_acos
LEFT JOIN aros   ON aros_acos.aro_id = aros.id
LEFT JOIN acos   ON aros_acos.aco_id = acos.id
LEFT JOIN groups ON aros.foreign_key = groups.id
;

↓↓↓ こんな感じの結果になる ↓↓↓

aros_acos_id model name alias lft rght _create _read _update _delete
115 Group users edit 81 82 1 1 1 1
97 Group administrators logout 51 52 -1 -1 -1 -1
98 Group administrators view 47 48 -1 -1 -1 -1

CakePHP 1.3.x のACLサンプルプログラム

結論から書くと、勉強用や参考になるかなと思い、
CakePHPのACLサンプルプログラムを
ダウンロードできるようにgithubへアップしました。

I uploaded to GitHub CakePHP ACL sample programs
for study.

■GitHubサンプルプログラム(GitHub sample programs)
  256hax/CakePHP-1.3.x-ACL-samples – GitHub

アクセスしたら左上の [ZIP] ボタンを押して
ダウンロードできます。
そのあと、同じページに「README」が
書いてありますので、それをご参照ください。

■経緯
CakePHPのACLをチュートリアルをもとに
実装していたが、ややこしいうえに自分のやり方が
悪いのか、ちゃんと動作しなかった。
幸いにもエンジニアの人が解説したブログが
たくさんあったので、なんとか動くようになった。
ただ、意外にも「ダウンロードしてすぐ動かせる」
っていうファイル群が見つからなかったので、
ACLのサンプルプログラムを丸ごとアップしてみようと思う。

■参考サイト
 ACL を制御するシンプルなアプリケーション :: 開発例 :: マニュアル :: 1.3コレクション
 CakePHP ACL – アクセス制御リストを攻略する | hijiriworld Web Creators
 CakePHP – ACLの権限管理を超簡単にするプラグイン『Plugin ACL』 – 高橋です
 cakePHP チュートリアル「ACL を制御するシンプルなアプリケーション」 その1 – SystemGathering
 CakePHP – Auth component loop redirect 

■リダイレクト無限ループについて
 CakePHP 1.3.x のACLチュートリアルを実装後、
 UsersControllerの「$this->Auth->allow(‘*’);」を
 外すと、どのページにアクセスしても
 リダイレクトループ(ページ転送がループ)してしまい
 ダメだった。結局、下記のようにし、あとは
 パーミッションで対応(但し、下記方法が合ってるか不明)。

function beforeFilter() {
parent::beforeFilter();
//$this->Auth->allow(‘*’); 
if(isset($this->params[‘requested’])) {
$this->Auth->allow($this->action);
}
}
 
 

 あと、CakePHPチュートリアルの パーミッションの手動設定
 追加のみ実行可能で、変更はできないようで、
 色々いじったところ、混乱してハマった。

 なので、 ACL Plugin を使ったほうが確実。