※ 本記事は2017年3月13日に公開されたものです。

さて今回は仮想プライベートデータベースを利用してアプリケーションユーザーごとのアクセス制御を実現してみましょう。
アプリケーションユーザー名の識別には、このブログの第14回「実際の利用者をデータベースに伝播する ~ セッション情報」で紹介したクライアント識別子(Client Identifier)を利用します。

では、データベースに必要な設定をおこなっていきます。
まずはアプリケーションが利用するデータベースユーザーの作成です。今回はAPP1USERというユーザーを作成して、APP1.TESTTAB表へのアクセス権限を付与します。

create user app1user identified by oracle;
grant create session to app1user;
grant select on app1.testtab to app1user; 

上記ユーザーの作成はアプリケーション用のユーザーに簡単なパスワードをつけている悪い例です。

次にファイングレインアクセスコントロールのポリシーファンクションの変更です。
今回は接続ユーザーがAPP1USERの場合には、アプリケーションユーザー(クライアント識別子)のデータのみ戻す設定をおこないます。フローチャートは省略しますが、ファンクションには以下の赤字の2行を追加するだけです。

create or replace function app1.vpdfunc
  (v_schema varchar2, v_objname varchar2)
  return varchar2
is begin
  if upper(sys_context('userenv','session_user')) = 'PUKU' then
    if sys_context('userenv','ip_address') = '10.185.155.180' and
       sys_context('userenv','client_program_name') like 'sqlplus%' then
      return '1=1';
    else
      return '0=1';
    end if;
  elsif upper(sys_context('userenv','session_user')) = 'APP1USER' then
    return 'name = upper(sys_context(''userenv'',''client_identifier''))';
  else
    return 'name = upper(sys_context(''userenv'',''session_user''))';
  end if;
end;
/ 

では実際にアクセスしてみましょう。
まずはAPP1USERでデータベースに接続します。

SQL> connect app1user/oracle@appdb
接続されました。

ログイン直後のデフォルトの状態では、クライアント識別子に値は設定されていません(NULLが設定されています)。

SQL> select sys_context('userenv','client_identifier') from dual;
SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER')
--------------------------------------------------------------------------------

クライアント識別子に値が設定されていない場合、APP1.TESTTAB表にアクセスしてもファイングレインアクセスコントロールによって条件「NAME = ”」が付加されますので結果は戻りません。

SQL> select * from app1.testtab;
レコードが選択されませんでした。 

次にクライアント識別子をSATOに設定します。SQL*Plus上でクライアント識別子を設定するには、DBMS_SESSIONパッケージのSET_IDENTIFIERプロシージャ(12cR2英語マニュアル12cR1日本語マニュアル)を実行します。

SQL> execute dbms_session.set_identifier('sato')
PL/SQLプロシージャが正常に完了しました。 

クライアント識別子に値が正しく設定されたことを確認します。

SQL> select sys_context('userenv','client_identifier') from dual;
SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER')
--------------------------------------------------------------------------------
sato 

クライアント識別子にSATOという値が設定されている場合、ファイングレインアクセスコントロールによって「NAME = ‘SATO’」という条件が付加されますので、1行の結果が戻ります。

SQL> select * from app1.testtab;
NAME
----------------
SATO 

次にクライアント識別子をITOに設定し、値を確認します。

SQL> execute dbms_session.set_identifier('ito')
PL/SQLプロシージャが正常に完了しました。
SQL> select sys_context('userenv','client_identifier') from dual;
SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER')
--------------------------------------------------------------------------------
ito 

現在はクライアント識別子がITOという値に設定されているため、先ほどとは異なる結果が戻ります。

SQL> select * from app1.testtab;
NAME
----------------
ITO 

クライアント識別子をクリアするにはDBMS_SESSIONパッケージのCLEAR_IDENTIFIERプロシージャ(12cR2英語マニュアル12cR1日本語マニュアル)を実行します。プロシージャを実行すると、クライアント識別子の値は設定されていない状態となり、表を検索しても結果は戻らなくなります。

SQL> execute dbms_session.clear_identifier
PL/SQLプロシージャが正常に完了しました。
SQL> select sys_context('userenv','client_identifier') from dual;
SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER')
--------------------------------------------------------------------------------
SQL> select * from app1.testtab;
レコードが選択されませんでした。

次回はいよいよWEBアプリケーションでアプリケーションユーザーごとのアクセス制御を実装します。

「もくじ」にもどる