2020年12月31日木曜日

アクセス制御の実装サンプル解説(6) - 認可スキーム

 こちらの記事の継続で、本シリーズの最後の記事になります。

今までは認可スキームありきで、各種のページ・タイプへアクセス制御を実装してきました。この記事では、認可スキームについて説明します。

認可スキームは共有コンポーネントとして登録されます。登録済みの認可スキームを確認してみましょう。共有コンポーネントから認可スキームを開きます。

コントリビューション権限リーダー権限管理権限の3つが登録済みです。

この認可スキームはアプリケーション作成ウィザード機能で、アクセス制御チェックを入れているとウィザードによって、アプリケーションに作成されます。

または、ページ作成ウィザードページ・タイプとして機能を選択し、アクセス制御を追加することもできます。

横道にそれますが、導入されたアクセス制御のコンポーネントはビルド・オプション機能: アクセス制御に紐づけられています。

共有コンポーネントビルド・オプションがあります。

これを開くと、ビルド・オプションの一覧が確認できます。アプリケーション作成ウィザード、ページ作成ウィザードで追加できる機能は(ログイン・ページを除き)、ビルド・オプションに紐づけられています。機能: アクセス制御をクリックして開いてみます。

アクセス制御に関連するコンポーネントの確認や、無効化(ステータス除外へ変更)、機能の削除(コンポーネントの削除)が可能であることがわかります。

さて、認可スキームです。実体が分かりやすいのはリーダー権限です。こちらを開いてみます。


リーダー権限は、スキーム・タイプとしてはブールを戻すPL/SQLファンクションとして実装されています。


スキーム・タイプは他に以下の種類があります。
  • EXISTS SQL問合せ
  • NOT EXISTS SQL問合せ
  • ブールを戻すPL/SQLファンクション
  • ロールまたはグループ内にある
  • ロールまたはグループ内にない
  • 式1のアイテムがNOT NULL
  • 式1のアイテムがNULL
  • 式1のアイテムの値 != 式2
  • 式1のアイテムの値 = 式2
  • 式1のプリファレンスの値 != 式2
  • 式1のプリファレンスの値 = 式2
これらは還元すると、ブールを戻すPL/SQLファンクションになります。つまり、真偽値を返すPL/SQLファンクションが認可スキームです。戻り値がTRUEであればアクセスが許可され、FALSEであればアクセスが許可されません。

この認可スキームとなるファンクションが呼び出されるタイミングが評価ポイントであり、認可スキームの検証の頻度が高いとパフォーマンス面ではマイナスになりますが、権限の変更の反映が早くなります。

例えば認可スキームの検証セッションごとに1回であると、サインインした後、再度サインインするまで権限の状態は変わりません。一般にOracle APEXのアプリケーションではサインアウトを意図的に行うことは少ないので、セッションのタイムアウトまで一旦許可されたアクセス権限は、そのまま維持されることになります。

ページ・ビューごとに1回であれば、サインアウト/サインインを行うことなく、新たにページを表示するたびにアクセス権限が評価され、変更された権限が適用されます。

リーダー権限として定義されているコードを見てみましょう。
if nvl(apex_app_setting.get_value(
   p_name => 'ACCESS_CONTROL_SCOPE'),'x') = 'ALL_USERS' then
    -- allow user not in the ACL to access the application
    return true;
else
    -- require user to have at least one role
    return apex_acl.has_user_any_roles (
        p_application_id => :APP_ID, 
        p_user_name      => :APP_USER);
end if;

アプリケーション定義ACCESS_CONTROL_SCOPEALL_USERSであればTRUEを返す、それ以外はapex_acl.has_user_any_rolesの結果(何かロールが登録されていればTRUE)を返しています。

次にコントリビューション権限を見てみましょう。

コントリビューション権限スキーム・タイプとして、ロールまたはグループ内にあるが設定され、タイプアプリケーション・ロール名前管理者、コントリビュータとなっています。つまり、ユーザーがアプリケーション・ロールとして管理者かコントリビュータ・ロールを持っているとコントリビューション権限がTRUEとなります。

今回の要件では、管理者はデータの編集を行なわず(自分が担当者の場合に限定)、コントリビューション権限は持たないことにしているので、名前から管理者を除きます。

管理権限は、こちらの名前管理者のみ(アプリケーション・ロールとして管理者を持っている)の認可スキームです。コントリビューション権限と大差ないので確認は省きます。

次に、アプリケーション・ロールの設定を確認します。共有コンポーネントからアプリケーション・アクセス制御を開きます。

アプリケーションに登録されているアプリケーション・ロールユーザー・ロール割当てとして、ユーザーに割り当てられたアプリケーション・ロールを確認することができます。


共有コンポーネントアプリケーション・アクセス制御を開いて、ユーザー・ロール割当てを実施するには、Oracle APEX開発環境にログインする必要があります。つまりOracle APEXの開発者アカウントが必要ですが、機能としてアクセス制御がアプリケーションに組み込んであれば、サイド・メニューの管理よりアクセス制御の設定を変更したり、ユーザーへのアプリケーション・ロールの追加/削除をすることができます。


機能: アクセス制御によって提供されるアクセス制御は、これを導入しないとアプリケーションのアクセス制御ができない、といったものではありません。

そうではなく、以下の作業をアプリケーションに行います。
  • アプリケーション・ロールとして、管理者、コントリビュータ、リーダーを登録する。
  • アプリケーション定義にACCESS_CONTROL_SCOPEを登録し、ACL_ONLYを設定する。
  • 認可スキームとして管理権限(アプリケーション・ロールの管理者を持っている)、コントリビューター権限(アプリケーション・ロールの管理者かコントリビュータを持っている)、リーダー権限(アプリケーション定義がALL_USERSであるか、または、何かひとつでもアプリケーション・ロールを持っている)の3つを登録する。
  • 管理権限を持ったユーザーによって、アプリケーション定義ACCESS_CONTROL_SCOPEの変更と、ユーザーへのアプリケーション・ロールの割当てを可能とする画面を、アプリケーションに登録する。

アプリケーションを開発する側としては、自力で同様の機能をアプリケーションに組み込むこともできますが、提供されている機能が開発するアプリケーションの要件を満足するのであれば、わざわざ開発する必要はなく、そのまま利用することで開発工数の削減になります。アプリケーション自体に組み込まれた設定であるため、組み込まれた後の認可スキームやページは自由に改変可能です。

ウィザードのよって組み込まれるアクセス制御の機能は、そのアプリケーションに閉じた作業です。複数のアプリケーションに跨ったアプリケーション・ロールの登録やユーザーへのロールの割り当てといった機能は含まれていません。そのような機能が必要な場合は、認可スキームを作成する必要があります。

伝統的な企業アプリケーションであれば、LDAPを認証/認可のためのサーバーとして使用していることが多いと思います。Oracle APEXではLDAPの扱いを容易にするためのAPI、APEX_LDAPを提供しています。これらのAPIを使った認可スキームの実装については、また記事を改めて行えたらと思います。

今回の認可に関するシリーズは以上になります。