当初は U2A 、つまり「ユーザーID(と、アクセスレベル)を元に対応するACL IDを取得する」インデックスを作成する予定だった。これについては諸々の思考の後も変わらない。但しインデックスではなく、「ACLキャッシュ」という独立した概念となり、daoやidxとしては実装されない。恐らく、yb直下、つまりYakiBiki内の機能を横断する位置づけとなるだろう。まぁ実際、YakiBikiのデータ操作の殆どに関わってくるので、この扱いでも良いだろう。
ACLキャッシュは、次のような機能を提供する。
現在既に、ACL IDに対応するDataIDを取得する"A2D"インデックスが存在する。これとACLキャッシュを組み合わせることで、次の手順で、アクセスが許可されるデータIDを取得可能になる。
例えばトップ画面になるであろう一覧表示であれば、この結果とカテゴリやキーワード検索のインデックス取得結果を併せ、更新ソートインデックスにフィルタとして適用することで、現在ログイン中のユーザーがアクセス可能なデータの検索結果を取得できる。
また、編集画面や単一表示画面などある一つのIDに対して追跡したい場合は、逆にデータを先に取得しそのACL-IDが、1.の結果に含まれているかで対象となる操作のallow/denyを判別可能となる。
ACLキャッシュはあくまでもキャッシュである為、ユーザー・グループ・ACLに変更が生じた場合適宜再構築する必要がある。
具体的にどのタイミングで再構築が必要となるのか。その前にまず、ユーザー・グループ・ACLに変更が生ずるタイミングを確認する。
以上が変更タイミングとなる。注意点として、ACLのupdateには例えばPolicy(Negative/Positive)だけの修正や、権限リストだけの修正も含まれる。
さて、ここで実際にACLキャッシュが「無効」となり、再構築が必要となるタイミングを絞り込んでみる。結論から言うと以下に絞り込まれる。
以下に、これら以外がなぜ除外されたのか理由を述べる。
ちなみに、delete { user | group } の処理には当然 add / remove も含まれている。しかし、処理のI/Fとしてメソッド(ロジック)を分割してしまっている為、別タイミングとして挙げている。
またACLのcreateタイミングに於いては、create時点で既に権限リストが初期データとして渡される可能性がある為、再構築の要有りと判断している。
各ACLキャッシュ再構築タイミングでの詳細を述べる前に、ACLデータを以下にして「キャッシュ」にconvertするのかその概要を、現状の段階でメモしておく。
まず、ACLデータの構成を改めて確認する。
アクセスレベル とはアクセス権限を表す整数値・・・今のところは、である。現時点では以下の3つのうちいずれかの値を取る。
policyは二つの値を持つ。 Positive と Negative である。POSI/NEGAとも省略する。以下に、policyがどのように権限リストの評価に影響するのかをまとめてみる。
次のような権限リストを想定してみる。
権限リストの評価に於いては、一旦グループを、その所属するユーザーに展開する。従って上記リストは次のように変形される。
このように、一つのUserIDに対して、グループを展開したことにより複数のアクセスレベルが同居する事になる。この優先順位を決定するのがpolicyとなる。
なお、権限リスト中のアイテムの上下関係は優先順位とは影響しない。つまり、上下関係は処理上なんら意味を持たない。
Positive policy とは一言で言えば、要求されたアクセスレベル 以上が一つでもあれば許可 するポリシーである。
Negative policy とは一言で言えば、要求されたアクセスレベル 未満が一つでもあれば拒否 するポリシーである。
ACLデータと実際の許可・拒否の判定基準は上記のような評価によって定められる。今のところは。
ACLキャッシュの原理は、ACLデータに登録されているユーザーの分だけ、上記評価結果を何らかの物理ファイルとしてキャッシュしておく仕組みである。
基本的には他のインデックス系と似たようなデータファイル構造を取る。
cache/ acl/ 1.idx (UserID = 1) 2.idx (UserID = 2) 3.idx (UserID = 3) ...
#ACLID,LEVEL|OK_NG&LEVEL|OK_NG&LEVEL|OK_NG&... 100,1|1&2|0 200,1|0&2|0 300,1|1&2|1 ...
なおLEVELについては、"0"は登録されない。LEVEL 0 は評価時に使われる。外部から「Level0についてこのユーザーが許可されているACLを取得したい」というケースはあり得ない。なぜなら、Level0はアクセス禁止を表しているからである。
概要 | 入力 | 出力 |
---|---|---|
許可されるACL ID群の取得 | ユーザーID, アクセスレベル | 一つ以上のACL ID |
ユーザーと関わるACL ID群の無条件取得 | ユーザーID | 一つ以上のACL ID |
ユーザーIDのエントリの作成, 削除 | ユーザーID | 処理の成否 |
キャッシュの新規作成・更新 | ユーザーID, ACL ID | 処理の成否 |
キャッシュの削除 | ユーザーID, ACL ID | 処理の成否 |
(以上は現時点での暫定予想。)
ACLキャッシュの原理と、権限リストとpolicyの評価の仕組みを踏まえた上で、各再構築タイミングにおける処理の詳細を考えてみる。
その前に、処理の簡略化のため、新たに G2A という1:Nインデックスを追加する。これは、 アクセスレベルに関わらず 権限リストに登録されているグループと、ACL IDを結びつけるためのものである。詳細は後述。
まずユーザーを削除できるための条件を確認しておく。そのユーザーがownerとなっているGroup, Category, Data, Acl が全て0件となっていることが必須条件である。実際はこの条件を満たすための確認作業が面倒くさいため、結局、ステータスを「ログイン禁止」にして無効化する措置が採られるとは思うのだけれど・・・。さておき。
グループの削除条件は特に無い。なぜならグループIDが他と関係するのは、UserIDとのリレーションと、このACL権限リストだけだからである。
これについては先に例を挙げた方が分かりやすい。ユーザーがグループより脱ける場合、グループに入る場合のそれぞれを考えてみる。
以下のような権限リストを持つACLを考えてみる。
ここで、user1がgroup1から脱けるとする。その場合、 キャッシュとして 影響するのは、user1のエントリのみである。user2が、user1と同じくgroup1に所属しているが、 user2の評価結果はなんら変化しない。 このため、キャッシュを更新するのはuser1のエントリに絞ることが可能となる。
以下のような権限リストを持つACLを考えてみる。
ここで、user2がgroup1に入るとする。その場合、 キャッシュとして 影響するのは、user2のエントリのみである。user1やuser3が、同じくgroup1に所属しているが、 user1, user3の評価結果はなんら変化しない。 このため、キャッシュを更新するのはuser2のエントリに絞ることが可能となる。
addもremoveも、次のような処理で共通になることが分かった。
まだまだ悩みまくっていた時のメモ。
ここから大分変わってしまっていて、ACL絡みのインデックスも今では acl_to_data の1つしかない。
U2AやG2Aは結局不要となってしまって消えた。
ACLの再構築タイミングは殆どそのまま。
ACLの評価については、現時点では yb_AclCache クラスの normalize_permlist() と evaluate() メソッドに集約されている。仕様についてはテストケースを参照。まぁ評価の内実については上記メモからあまり変わっていない。グループからユーザを展開して、衝突についてはPolicyで解決するという流れ。
alpha-2の段階ではACLがグループの操作やカテゴリ操作、記事スレッドの操作にも及んでいたのだけれど、面倒くさくなったので alpha-3の時にマスタ管理は個別のroleに持たせて、記事スレッドの概念も削除。記事の作成権限を別途roleに含ませる事でその辺を管理するように直したりしている。
コメント