General
==============================
This is a short example of implementation of Oracle VPD - Virtual Personal Database.
==============================
VPD Overview
==============================
From Oracle docs:
Virtual private database (VPD) enables to enforce security, to a fine level of granularity, directly on tables, views, or synonyms.
Because security policies are attached directly to tables, views, or synonyms and automatically applied whenever a user accesses data, there is no way to bypass security.
When a user directly or indirectly accesses a table, view, or synonym protected with a VPD policy, the server dynamically modifies the SQL statement of the user.
The modification creates a
WHERE
predicate returned by a function implementing the security policy. The statement is modified dynamically, transparently to the user, using any condition that can be expressed in or returned by a function.
VPD policies can be applied to SELECT, INSERT, UPDATE, INDEX, and DELETE statements.
The VPD is implemented via DBMS_RLS package.
==============================
Implementation Example
==============================
Per each table, there is a dedicated function, which returns a predicate.
The implementation of the function is below.
In this function, there is a reference to privileged users, that are listed inside an applicative table DB_PRIV_USERS.
For these privileged users the returned predicate is NULL.
For other users, the predicate is being built from another applicative table, DB_PRODUCT_USERS.
DBA_POLICIES
SELECT object_name,
policy_group,
policy_name,
pf_owner, package,
function,
sel, ins, upd, enable
FROM DBA_POLICIES
WHERE rownum < 11;
OBJECT_NAME POLICY_GROUP POLICY_NAME PF_OWNER PACKAGE FUNCTION SEL INS UPD ENABLE
------------------- ------------ ----------- -------- ------- -------------------- --- --- --- ------
DAILY_PROD_AGG SYS_DEFAULT PROD_POL01 DWNG BUILD_PRD1_PREDICATE YES YES YES YES
REP_DAILY_VISITORS SYS_DEFAULT PROD_POL01 DWNG BUILD_PRD1_PREDICATE YES YES YES YES
DAILY_PROD_TRAFFIC SYS_DEFAULT PROD_POL02 DWNG BUILD_PRD2_PREDICATE YES YES YES YES
REP_DAILY_PROD SYS_DEFAULT PROD_POL02 DWNG BUILD_PRD2_PREDICATE YES YES YES YES
DAILY_PROD_ABANDONED SYS_DEFAULT PROD_POL03 DWNG BUILD_PRD3_PREDICATE YES YES YES YES
DAILY_USER_AGG SYS_DEFAULT PROD_POL03 DWNG BUILD_PRD3_PREDICATE YES YES YES YES
DAILY_CONCAT_PROD SYS_DEFAULT PROD_POL03 DWNG BUILD_PRD3_PREDICATE YES YES YES YES
DWH_PROD SYS_DEFAULT PROD_POL04 DWNG BUILD_PRD4_PREDICATE YES YES YES YES
DAILY_PROD_ORIG SYS_DEFAULT PROD_POL04 DWNG BUILD_PRD4_PREDICATE YES YES YES YES
PROD_COUNTER_DATA SYS_DEFAULT PROD_POL04 DWNG BUILD_PRD4_PREDICATE YES YES YES YES
FUNCTION BUILD_PRD1_PREDICATE
CREATE OR REPLACE FUNCTION BUILD_PRD1_PREDICATE (obj_schema VARCHAR2,
obj_name VARCHAR2)
RETURN VARCHAR2
IS
v_predicate VARCHAR2(2000);
v_userName VARCHAR2(30);
v_cnt PLS_INTEGER;
v_productList VARCHAR2(200);
CURSOR prd_cur IS
SELECT PRODUCT_ID
FROM DB_PRODUCT_USERS
WHERE USERNAME = SYS_CONTEXT('USERENV', 'SESSION_USER');
BEGIN
SELECT COUNT(*)
INTO v_cnt
FROM DB_PRIV_USERS
WHERE USERNAME = SYS_CONTEXT('USERENV', 'SESSION_USER');
IF (v_cnt > 0) THEN
v_predicate := NULL;
ELSE
v_cnt := 0;
FOR i IN prd_cur LOOP
v_cnt := v_cnt + 1;
IF (v_cnt > 1) THEN
v_productList := v_productList ||',';
END IF;
v_productList := v_productList || ''''||i.product_id||'''';
END LOOP;
IF (v_cnt = 0) THEN
v_predicate := '1=2';
ELSIF (v_cnt = 1) THEN
v_predicate := 'PRODUCT_ID = ' || v_productList;
ELSE
v_predicate := 'PRODUCT_ID IN (' || v_productList || ')';
END IF;
END IF;
RETURN v_predicate;
END BUILD_PRD1_PREDICATE ;
DB_PRODUCT_USERS
SELECT * FROM DB_PRODUCT_USERS WHERE ROWNUM < 11;
USERNAME PRODUCT_ID
----------------- ------------
USER_A 008
USER_B 057
USER_C 030
USER_D 001
USER_E 557
USER_F 053
USER_G 062
USER_H 562
USER_K 011
USER_L 064
DB_PRIV_USERS
SELECT * FROM DB_PRIV_USERS;
USERNAME DESCRIPTION
----------------- -------------------------
SYSTEM DBA User
MANAGER DBA User
ADMIN_PORTAL User for internal portal
This article on Oracle VPD is incredibly informative! Just like Skynode optimizes my gaming experience, understanding VPD can enhance data security and user access control in databases.
ReplyDelete