TodoList: access_control は必要無かった2007年01月03日 09時43分17秒

アクセス制限の実験をしてみる。

何に制限をかけようかと迷ったが、所属団体 (Organization) にすることにした。一般ユーザに、勝手に作られても困るので、編集は特権階級のみが出来ることにする。


class OrganizationController < ApplicationController
  scaffold :organization
  include AccessControl
  #access_control :all, :if => false
  access_control :show, :list, :if => true
  access_control :new, :edit, :destroy, :role => 'admin'
end

admin ユーザの uyota でアクセスすると問題ないが、user 権限を持つ uyota_user で http://localhost:3000/todo/list にアクセスしても表示されない。log/development.log を覗いてみる。

まず、以下のログが見つかった。


Processing OrganizationController#list (for 127.0.0.1 at 2006-12-29 13:07:30) [GET]
  Session ID: be7119e0113bed0af55c46c5b02b5a3b
    Parameters: {"action"=>"list", "controller"=>"organization"
    required_perm is organization/list
      ESC[4;36;1mPermission Load (0.010409)ESC[0m   ESC[0;1mSELECT DISTINCT permissions.*
      FROM permissions, roles,
       permissions_roles, users_roles,
        users
        WHERE users.id = 2
        AND users.id = users_roles.user_id
        AND users_roles.role_id = roles.id
        AND roles.id = permissions_roles.role_id
        AND permissions_roles.permission_id = permissions.id
        AND permissions.controller = 'organization'
        AND permissions.action = 'list'
        ESC[0m
  ESC[4;35;1mPermission Columns (0.010521)ESC[0m   ESC[0mSHOW FIELDS FROM permis
  sionsESC[0m
    ESC[4;36;1mPermission Load (0.005501)ESC[0m   ESC[0;1mSELECT * FROM permissions
  WHERE (permissions.`controller` = 'organization' AND permissions.`action`
= 'list' ) LIMIT 1ESC[0m
    Redirected to http://localhost:3000/user/home

http://localhost:3000/organization/list へのアクセス権限を調べている様である。アクセス権限が無いと判断されて、user/home に転送されているそうだ。

その後に、


Processing UserController#home (for 127.0.0.1 at 2006-12-29 13:07:31) [GET]
  Session ID: be7119e0113bed0af55c46c5b02b5a3b
    Parameters: {"action"=>"home", "controller"=>"user"}
    required_perm is user/home
      ESC[4;35;1mPermission Load (0.040347)ESC[0m   ESC[0mSELECT DISTINCT permissions.*
FROM permissions, roles,
 permissions_roles, users_roles,
  users
  WHERE users.id = 2
  AND users.id = users_roles.user_id
  AND users_roles.role_id = roles.id
  AND roles.id = permissions_roles.role_id
  AND permissions_roles.permission_id = permissions.id
  AND permissions.controller = 'user'
  AND permissions.action = 'home'

とあった。こちらは user/home へのアクセス制限を調べていて、権限があると判断されていた。

ログの中で、今まで覗いたことが無いテーブルがあるのに気が付いた。login_engine と user_engine がたくさんテーブルを作るので、どんなテーブルがあるのかは気にしていなかった。users や roles などのテーブルは、気になったときに見ていたが permissions は覗いたことはない。

今までの中では、一番レコードの数が多いが以下のが SQL の結果だ。


mysql> select * from permissions;
+----+------------+--------------------------+-------------+
| id | controller | action                   | description |
+----+------------+--------------------------+-------------+
|  1 | role       | new                      | NULL        |
|  2 | role       | list                     | NULL        |
|  3 | role       | edit                     | NULL        |
|  4 | role       | destroy                  | NULL        |
|  5 | role       | index                    | NULL        |
|  6 | role       | show                     | NULL        |
|  7 | permission | new                      | NULL        |
|  8 | permission | list                     | NULL        |
|  9 | permission | edit                     | NULL        |
| 10 | permission | destroy                  | NULL        |
| 11 | permission | index                    | NULL        |
| 12 | permission | show                     | NULL        |
| 13 | user       | delete                   | NULL        |
| 14 | user       | new                      | NULL        |
| 15 | user       | list                     | NULL        |
| 16 | user       | forgot_password          | NULL        |
| 17 | user       | restore_deleted          | NULL        |
| 18 | user       | delete_user              | NULL        |
| 19 | user       | logout                   | NULL        |
| 20 | user       | edit                     | NULL        |
| 21 | user       | change_password_for_user | NULL        |
| 22 | user       | edit_user                | NULL        |
| 23 | user       | signup                   | NULL        |
| 24 | user       | show                     | NULL        |
| 25 | user       | edit_roles               | NULL        |
| 26 | user       | login                    | NULL        |
| 27 | user       | home                     | NULL        |
| 28 | user       | change_password          | NULL        |
| 29 | todo       | new                      | NULL        |
| 30 | todo       | list                     | NULL        |
| 31 | todo       | edit                     | NULL        |
| 32 | todo       | destroy                  | NULL        |
| 33 | todo       | create                   | NULL        |
| 34 | todo       | index                    | NULL        |
| 35 | todo       | show                     | NULL        |
| 36 | todo       | update                   | NULL        |
+----+------------+--------------------------+-------------+
36 rows in set (0.01 sec)

permissions.controller に organization が無いのが、少なくても一つの原因のようだ。

さて、permission を作らなければいけないのは分かった。なお、この SQL と同じ結果は http://localhost:3000/permission/list で見られる。つまり http://localhost:3000/permission/new で新しいレコードを作れるわけだ。しかし、面倒臭い。もちろん、そんなことはやってられない。なんとかして自動で生成する方法を見つけねば。

ここで不思議に思ったのが todo は入っていることだ。そこで、ruby script/generate controller organization をやっていなかったために無いのかと思い調べてみると、ユーザの所属先を作る時にやっていた。

そうなると、怪しいのは user_engine となる。そこで、vendor/plugins/user_engine/README を読むと、


% rake sync_permissions
(in /export/home/uyota/rails/Todo)

をやると、このアクセス制限のレコードが作られると書いてあった。このコマンドはレコードを消すことは絶対無いそうだ。

同様にして、http://localhost:3000/organization/list が表示される様になるまで、log/development.log の SQL を追跡した。最終的には http://localhost:3000/role/edit/3 にて、organization の中の list が選ばれていないといけないようだ。roles テーブルの id=3 は User だ。

つまり、user_engine がページ毎のアクセス制御はやってくれているわけだ。ただ単に、organization/edit などのページにアクセスさせたくないのであれば、user_engine で事が足りていたのだ。user_engine の README でも、読み直すことにする。しかし、:if などの条件によるアクセス制御には興味があるので、また後で access_control を試すかも知れない。

前回次回