2020年12月30日水曜日

アクセス制御の実装サンプル解説(3) - ファセット検索

 こちらの記事の継続です。

ファセット検索ページの追加


アプリケーションにファセット検索のページを追加します。アプリケーション・ビルダーからページの作成を実行します。


ページ・タイプコンポーネントに含まれるレポートをクリックします。


ファセット検索をクリックします。


ページ名は任意ですが、以下ではファセット検索を指定しています。に進みます。


ナビゲーションのプリファレンス新規ナビゲーション・メニュー・エントリの作成を選択します。新規ナビゲーション・メニュー・エントリはページ名と同一のファセット検索になるので、そのままにして、へ進みます。


表/ビューの名前としてPAC_TASKS(表)を選択します。

それ以外はデフォルトの設定とします。データ・ソースはローカル・データベース、ソース・タイプは表、表示形式はレポートです。ファセットとして生成される列は、PROJECT_ID(number)、ASSIGNED_TO(number)、STATUS(varchar2)、COST(number)、BUDGET(number)の5つです。確認して作成をクリックします。画面が小さい場合、開くダイアログが小さく、ファセットとして選択される列の一覧が下部に隠れている場合があります。画面をスクロールすることで確認できます。


ページが作成されたら、実行して作成されたファセット検索のページを確認します。サインインする従業員は誰でも構いません。


ファセット検索のページが表示されます。保存されているデータの全件である73件がリストされています。


ページ作成ウィザードによってファセット検索がページとして作成される場合、ソースとなる表に参照制約が設定されていると、その参照先を共有コンポーネントにLOVとして作成した上で、レポートの列とファセットがLOVを元に表示するように自動的に構成されます。今回は表PAC_TASKSをソースとして指定しています。ページ作成ウィザードは、列PROJECT_ID(レポート上はProject)には表PAC_PROJECTSのPROJECT_NAMEの値を、列ASSIGNED_TOには表PAC_EMPLOYEESのEMPLOYEE_NAMEの値を表示するようにレポートを作成しています。

共有コンポーネントLOVを開くと、PAC_EMPLOYEES.EMPLOYEE_NAMEPAC_PROJECTS.PROJECT_NAMEの2つのLOVが作成されていることが確認できます。


以上でファセット検索のページの追加は完了しました。

検索結果のアクセス制限


ファセット検索のリスト表示には、リージョンとしてクラシック・レポートが使用されています。このリストされる内容を今回の要件である
  1. 管理者ロールを持っていれば、すべてのタスクが一覧される。
  2. 管理者以外は、自分が所属している部門のタスクのみが一覧される。
という条件で制限します。宣言的に認可スキームを設定するとリスト表示が変わる、といった機能はありません。SQLを記述することで制限を加えます。

ページ作成直後のファセット検索の検索結果を表示するリージョンのソースは、表PAC_TASKSが設定されています。


以下のWHERE句を設定することで、今回の要件を達成できます。
:G_IS_ADMINISTRATOR = 'Y'
or
assigned_to in (
    select employee_id from pac_employees where group_name = :G_GROUP_NAME
)

WHERE句の中で、あらかじめ設定したアプリケーション・アイテムを使うことでSQLの記述を簡単にしています。

さて、アプリケーション・アイテムを設定する際に、セッション・ステート保護制限付き - ブラウザから設定不可とするように指示しています。

ブラウザから、これらのアプリケーション・アイテムを変更できると、管理者ロールなしで他部門のタスクを参照することができる穴があることになります。一般にSQLを文字列処理により生成することをせず、バインド変数を使用することでSQLインジェクション攻撃を防ぐことができる、と言われていますが、それだけではないことに注意が必要です。

先ほどのWHERE句の設定で要件は達成していますが、部門名がレポートに含まれていないので結果の確認がしにくいです。そのため、ソースの設定を以下のSQLに変更します。表PAC_EMPLOYEESを結合して、列GROUP_NAMEの表示を追加しています。

select PROJECT_ID,
       TASK_ID,
       TASK_NAME,
       ASSIGNED_TO,
       STATUS,
       START_DATE,
       END_DATE,
       COST,
       BUDGET,
       e.GROUP_NAME
from PAC_TASKS t join PAC_EMPLOYEES e 
    on t.assigned_to = e.employee_id
where :G_IS_ADMINISTRATOR = 'Y'
or
e.GROUP_NAME = :G_GROUP_NAME

結果を確認してみましょう。

管理者ロールを持つ従業員でサインインすると、73件全件、リスト表示されます。Group Nameも複数の部門がリストされていることが確認できます。

例えば、経理部の一般従業員でサインインすると、経理部のみの16件がリストされること確認できます。


これで、レポートのアクセス制御が実装されたことが確認できました。

コンポーネント毎のセキュリティ - 認可スキームの働き


ページ、リージョン、その他、ほとんどすべてのコンポーネントはセキュリティのプロパティを持っており、認可スキームを設定することができます。今回のファセット検索の制御には使用していません。では、いつ使うのか?という疑問はあるかと思います。

認可スキームを設定して動作を確認してみましょう。

最初にクラシック・レポートの列GROUP_NAMEに設定して効果を確認します。管理者ロールがない場合、部門つまりGROUP_NAMEは、サインインした従業員の部門に一致するので表示する必要がなく、管理者ロールを持った従業員のみに意味のある情報です。

GROUP_NAME認可スキーム管理権限に設定します。


管理者ロールを持たない従業員でサインインし効果を確認すると、列GROUP_NAMEが表示されていないことが確認できます。管理者ロールがあれば、表示されます。



画面に表示されるコンポーネントにたいしての認可スキームの効果は、そのコンポーネントの表示/非表示です。サーバー側の条件でも同等の設定は可能ですが、認可スキームによって表示/非表示を決定できる場合は、そちらを使う方が合理的です。

ほとんど意味はありませんが、挙動をより理解するため、検索結果のリージョンの認可スキーム管理権限にしてみます。


管理者ロールのない従業員でサインインすると、検索結果のレポート自体が表示されなくなります。管理者ロールがあれば表示されます。


今後の作業に支障がでるので、こちらの設定は元に戻しておきましょう。

画面表示に関するコンポーネントへの認可スキームの効果は以上です。

表示ではなく、アプリケーションの操作に関するコンポーネントの場合は違った効果になります。

ファセット検索ページのプロパティに含まれる認可スキーム管理権限に設定し、確認してみます。


管理者ロールのない従業員がファセット検索のページをアクセスすると、以下のように権限が不十分です。というエラーが発生し、ファセット検索にアクセスできません。(アプリケーション・ビルダーを開いていない場合、技術情報の部分は表示されません。)


管理者ロールがある従業員であれば、アクセスが許可されます。このようにエラーが発生するとアプリケーションの操作ができなくなるので、基本的にはタブを閉じるかブラウザを終了し、再度、新規にセッションを開始しサインインし直す必要があります。

通常はこのようなエラーをアプリケーションの利用者に経験させるのは望ましくないため、保護されているページへのナビゲーションも同時に抑制することが望まれます。今回の例でいえば、サイド・メニューのファセット検索のエントリを非表示にします。

共有コンポーネントナビゲーション・メニューからデスクトップ・ナビゲーション・メニューを開き、ファセット検索のエントリの、認可スキーム管理権限にします。


管理者ロールのない従業員でサインインすると、ファセット検索のメニュー自体が表示されないことが確認できます。


ナビゲーション・パスがなければ、保護されているページに対するアクセスは、本来許されていない直接URLを編集するといった方法によるので、エラーの発生によってタブを閉じる、ブラウザを終了するといった作業を要求することになるのは妥当な結果でしょう。

ファセット検索でのアクセス制御の実装についての説明は以上です。

次は対話モード・レポートとフォームを実装します。

検索結果のリージョンとファセット検索のページ、それと、ナビゲーション・メニューに設定した認可スキームは管理権限から、元の設定の無い状態- 選択 -または- 認可の必要なし -へ戻しておきましょう。