はじめに
OAC(Oracle Analytics Cloud)のセマンティック・モデルでは、接続プールの設定を使用してデータソースに接続します。
通常、接続プールでは特定のユーザー名とパスワードが指定されているので、セマンティック・モデルを経由してデータソースに接続する際は、すべてのOACユーザーが同じユーザーでアクセスすることになります。
このようなケースにおいても、Oracle Databaseの仮想プライベートデータベース(VPD)を使用して行レベルセキュリティを実現することができます。
本記事で実現すること:
- Autonomous Database(ADB)にある特定の表に行レベルセキュリティを設定する
- OACにログインするユーザーごとに参照できる範囲(行)を制限する
- 対象のOACユーザーがどの行を参照できるかは、ADBの表で管理する
- OACのセマンティック・モデルで実現する
サンプルデータの準備
※ SQLの実行には、SQL Developerを使用しました。
次の記事で使用した、ADBUSERユーザーを流用します。
ADBにADBUSERが存在しない場合は作成します。
※適切なパスワードを指定してください。
CREATE USER adbuser IDENTIFIED BY "************";
GRANT DWROLE TO adbuser;
alter user adbuser quota unlimited on data;
ADBUSERで接続して、SHサンプルスキーマを利用してテスト用のデータを作成します。
CREATE TABLE adbuser.sales AS SELECT * FROM sh.sales WHERE prod_id in (13,14,15) ROWNUM <= 10000;
CREATE TABLE adbuser.products AS SELECT * FROM sh.products;
仮想プライベートデータベース(VPD)の設定
VPD用の管理者ユーザーの作成
この記事で作成したVPD用のユーザーである VPDADMIN を使用します。
存在しない場合は、作成します。コンテキストを作成できる権限も付与します。
CREATE USER vpdadmin IDENTIFIED BY "************";
GRANT DWROLE TO vpdadmin;
GRANT CREATE ANY CONTEXT TO vpdadmin;
alter user vpdadmin quota unlimited on data;
VPDADMINで接続します。
OACユーザーがどの行を参照できるかを管理する表を作成し、データをインサートします。
OAC_USER列にOACのユーザー名を、SECURITY_VALUE列にそのユーザーが検索可能なPROD_IDの値をインサートしました。
CREATE TABLE VPDADMIN.SECURITY_TABLE
(
OAC_USER VARCHAR2(30),
SECURITY_VALUE NUMBER
);
insert into vpdadmin.security_table(oac_user,security_value) values('OACUSER1',13);
insert into vpdadmin.security_table(oac_user,security_value) values('OACUSER2',14);
アプリケーション・コンテキストの作成
Oracle Databaseのアプリケーション・コンテキストは、セッションごとの「属性(キー=値)」を保持し、SQLやPL/SQLから参照できる仕組みです。ユーザーやアプリの状態(役割、地域、テナントID、機能フラグなど)をDB側で一貫して扱うために使われます。
ここでは、OACから通知されるOACユーザー名を保持するために使用します。
CREATE OR REPLACE CONTEXT OAC_CTX USING VPDADMIN.OAC_CTX_PKG;
CREATE OR REPLACE PACKAGE VPDADMIN.OAC_CTX_PKG
IS
PROCEDURE set_ctx(OACUSER VARCHAR2);
END;
/
CREATE OR REPLACE PACKAGE BODY VPDADMIN.OAC_CTX_PKG
IS
PROCEDURE set_ctx(OACUSER VARCHAR2)
IS
BEGIN
DBMS_SESSION.SET_CONTEXT('OAC_CTX', 'OACUSER', OACUSER);
END;
END;
/
GRANT EXECUTE on VPDADMIN.OAC_CTX_PKG to adbuser;
VPDポリシー関数の作成
次に、行レベルセキュリティを適用するためのポリシー関数を作成します。
CREATE OR REPLACE FUNCTION VPDADMIN.vpd_policy_function (
object_schema IN VARCHAR2,
object_name IN VARCHAR2
) RETURN VARCHAR2 AS
v_oac_user_name VARCHAR2(100);
v_security_value NUMBER;
BEGIN
-- OACユーザー名を取得
v_oac_user_name := upper(SYS_CONTEXT('OAC_CTX', 'OACUSER'));
-- security_tableから該当するセキュリティ値を取得
BEGIN
SELECT security_value INTO v_security_value
FROM VPDADMIN.security_table
WHERE oac_user = v_oac_user_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- security_tableに該当ユーザーが存在しない場合、アクセスを禁止
RETURN '1=0';
END;
-- PROD_ID列の値がセキュリティ値と一致する行のみ許可
RETURN 'PROD_ID = ' || TO_CHAR(v_security_value);
END vpd_policy_function;
/
VPDポリシーの設定
表にポリシーを適用します。
BEGIN
DBMS_RLS.ADD_POLICY(
object_schema => 'adbuser',
object_name => 'SALES',
policy_name => 'sales_vpd_policy',
function_schema => 'VPDADMIN',
policy_function => 'vpd_policy_function',
statement_types => 'SELECT',
policy_type => DBMS_RLS.CONTEXT_SENSITIVE
);
END;
/
※参考:ポリシーの削除
BEGIN
DBMS_RLS.DROP_POLICY(
object_schema => 'adbuser',
object_name => 'SALES',
policy_name => 'sales_vpd_policy'
);
END;
/
SQL Developerでテスト
adbuserで接続して、検索できるかどうかテストしてみます。
結果は0件です。
表の所有者であるadbuserにもVPDが適用されており、adbuserは何の権限も持たないからです。
セマンティックモデルの設定
セマンティックモデラーで、セマンティックモデルを作成します。
システム接続の作成
システム接続を作成します。
「新規」ボタンから「接続」をクリックします。
接続定義を設定します。
「システム接続」をオンにしておきます。
物理レイヤーの作成
「新規」ボタンから「セマンティック・モデル」をクリックします。
任意の名前を入力して「作成」をクリックします。
「空のモデルで開始」をクリックします。
「MyDatabase」をダブルクリックし、「一般」タブのデータベースタイプを「Oracle Autonomous Data Warehouse」にします。
「表」タブに移動し、「SALES」「PRODUCTS」をドラッグ&ドロップします。
結合を追加します。
PROD_ID列同士で結合を定義し、「追加」をクリックします。
ここまでは、通常通りの設定です。
接続プールでのスクリプトの設定
「拡張」タブに移動し、「仮想プライベートデータベース」をオンにします。
「接続プールタブ」に移動します。
「詳細ビュー」を表示して、接続スクリプト「問合せ前に実行」を追加します。
次のコードを設定します。行端の「;」を忘れないでください。
CALL VPDADMIN.OAC_CTX_PKG.set_ctx('VALUEOF(NQ_SESSION.USER)');
有効化されていることを確認します。
スクリプトが設定されていても、有効化されていないと実行されません。
残りを定義して保存
セマンティックモデルの残りの部分(論理レイヤー、プレゼンテーション・レイヤー)を設定し、デプロイします。
動作確認
デプロイしたサブジェクト領域を使用して、ワークブックを作成しました。
OACUser1でテスト
PROD_ID(すなわち製品ID)が13のデータしか検索されていません。
当然ながら、OAC側で検索条件は何も設定していません。
VPDの対象となっているSALES表を避けて、PRODUCTS表だけを検索するようにすると(この例では、販売数量や販売金額を除外)、たくさんの行が検索されました。
これを避けるには、PRODUCTS表に対してもVPDを設定する必要があります。
OACUser2でテスト
ログアウトして、OACUser2でログインし直しました。
「製品ID」が14の行だけが検索されました。
おわりに
セマンティックモデルを経由してデータベースに接続するとき、通常は指定したユーザーで接続することになるので、データベースから見るとどのOACユーザーが接続しているのかを識別できません。
今回は、OACセマンティックモデルの接続プールの「問合せ前に実行」スクリプトを使用して、ADBに「自分が何者か」についての情報を引き渡すことで、同じユーザーでログインしているのに、実際に使用しているOACユーザーが誰かを識別することができました。
参考情報

















