Example Schema I often use the EMP and DEPT tables for test and demonstration purposes. Both these tables are owned by the SCOTT user, together with two less frequently used tables: BONUS and SALGRADE. Execute the below code snippets to create and seed the EMP and DEPT tables in your own schema. The BONUS and SALGRADE tables are included as well, but are commented out. The DDL (data definition language) part creates the tables, the DML (data manipulation language) part inserts the data. DDL create table dept( deptno number(2,0), dname varchar2(14), loc varchar2(13), constraint pk_dept primary key (deptno) create table emp( empno number(4,0), ename varchar2(10), job varchar2(9), mgr number(4,0), hiredate date, sal number(7,2), comm number(7,2), deptno number(2,0), constraint pk_emp primary key (empno), constraint fk_deptno foreign key (deptno) references dept (deptno) /* create table bonus( ename varchar2(10), job varchar2(9), sal number, comm number create table salgrade( grade number, losal number, hisal number */ DML insert into dept values(10, 'ACCOUNTING', 'NEW YORK' insert into dept values(20, 'RESEARCH', 'DALLAS' insert into dept values(30, 'SALES', 'CHICAGO' insert into dept values(40, 'OPERATIONS', 'BOSTON'
7839,'KING','PRESIDENT',null, to_date('17-11-1981','dd-mm-yyyy'), 5000, null, 10 7698, 'BLAKE', 'MANAGER', 7839, to_date('1-5-1981','dd-mm-yyyy'), 2850, null, 30 7782, 'CLARK', 'MANAGER', 7839, to_date('9-6-1981','dd-mm-yyyy'), 2450, null, 10 7566, 'JONES', 'MANAGER', 7839, to_date('2-4-1981','dd-mm-yyyy'), 2975, null, 20 7788, 'SCOTT', 'ANALYST', 7566, to_date('13-jul-87','dd-mm-rr') - 85, 3000, null, 20 7902, 'FORD', 'ANALYST', 7566, to_date('3-12-1981','dd-mm-yyyy'), 3000, null, 20 7369, 'SMITH', 'CLERK', 7902, to_date('17-12-1980','dd-mm-yyyy'), 800, null, 20 7499, 'ALLEN', 'SALESMAN', 7698, to_date('20-2-1981','dd-mm-yyyy'), 1600, 300, 30 7521, 'WARD', 'SALESMAN', 7698, to_date('22-2-1981','dd-mm-yyyy'), 1250, 500, 30 7654, 'MARTIN', 'SALESMAN', 7698, to_date('28-9-1981','dd-mm-yyyy'), 1250, 1400, 30 7844, 'TURNER', 'SALESMAN', 7698, to_date('8-9-1981','dd-mm-yyyy'), 1500, 0, 30
7876, 'ADAMS', 'CLERK', 7788, to_date('13-jul-87', 'dd-mm-rr') - 51, 1100, null, 20 7900, 'JAMES', 'CLERK', 7698, to_date('3-12-1981','dd-mm-yyyy'), 950, null, 30 7934, 'MILLER', 'CLERK', 7782, to_date('23-1-1982','dd-mm-yyyy'), 1300, null, 10 /* insert into salgrade values (1, 700, 1200 insert into salgrade values (2, 1201, 1400 insert into salgrade values (3, 1401, 2000 insert into salgrade values (4, 2001, 3000 insert into salgrade values (5, 3001, 9999 */ commit; Example 1: Definer and Invoker Rights Definer right is the default because it is very hard to manage privileges with invoker rights. You would have to analyze what the procedure is using and granularly assign privileges to users who need to execute the procedure. Pendant in the unix world: setuid bit. One of the worst enemies of security best practices. SQL>connect scott SCOTT>create or replace procedure scott.definer_give_raise_to_all(raise_amount_number) IS BEGIN update scott.emp set sal=sal+raise_amount; commit; END; /
SCOTT>grant execute on scott.definer_give_raise_to_all to ron; Grant succeeded. ron does not have update privilege on scott.emp; SQL>connect ron RON>update scott.emp set sal=sal+10; * ERROR at line 1: ORA-01031: insufficient privileges RON>exec scott.definer_give_raise_to_all(10 PL/SQL procedure successfully completed. SQL>connect scott SCOTT>create or replace procedure scott.invoker_give_raise_to_all(raise_amount_number) AUTHID CURRENT_USER IS BEGIN update scott.emp set sal=sal+raise_amount; commit; END; / SCOTT>grant execute on scott.invoker_give_raise_to_all to ron; Grant succeeded. SQL>connect ron RON>exec scott. invoker_give_raise_to_all(10 BEGIN scott. invoker_give_raise_to_all(10 END; * ERROR at line 1: ORA-01031: insufficient privileges ORA-06512: at "SCOTT.INVOKER_GIVE_RAISE_TO_ALL", line7 ORA-06512: at line 1 SQL>connect scott SCOTT>grant update on scott.emp to ron; Grant succeeded. SQL>connect ron RON>exec scott. invoker_give_raise_to_all(10 PL/SQL procedure successfully completed.
Example 2: Secure Application Roles Goal: Provide access to scott.emp for users whose name is in ename and who are managers. Step 1: Define View and grant privileges SQL>connect scott SCOTT>create view emp_job as (select ename, job from emp View created. SCOTT>grant select on emp_job to blake, james; Grant succeeded. SCOTT>-- revoke access to the base table SCOTT>revoke select on emp from blake,james; Step 2: Create secure application role and grant object privileges SQL>create role manager_role identified using access_control_policy; Role created. SQL>grant select on scott.emp to manager_role; Grant succeeded. only a procedure can activate the role SQL>set role manager_role; * ERROR at line 1: ORA-28201: Not enough privileges to enable application role "MANAGER_ROLE" Step 3: Build the procedure that assigns the role. It looks up the currently logged on user in the emp_job view. If it is a manager it sets the role granting access to the table. SCOTT> create or replace procedure access_control_policy authid current_user AS v_user varchar2(50 v_job varchar2(50 BEGIN -- get the user from the context v_user := lower((sys_context('userenv','session_user'))
-- get the job description select job into v_job from scott.emp_job where lower(ename) = v_user; -- if we are a manager then set the role if v_job = 'MANAGER' then dbms_session.set_role('manager_role' else null end if; END access_control_policy; / Step 4: grant execute privileges to the appropriate users SCOTT>grant execute on access_control_policy to blake, james; Step 5: test manually SCOTT>select * from emp_job; ENAME JOB --------------------------- BLAKE MANAGER JAMES CLERK SQL>connect blake BLAKE>exec scott.access_control_policy; PL/SQL procedure successfully completed. BLAKE>select * from session_roles; ROLE ---------------------------- MANAGER_ROLE BLAKE>select max(sal) from scott.emp; MAX(SAL) ---------------------------- 5030 SQL>connect james JAMES>exec scott.access_control_policy; PL/SQL procedure successfully completed. JAMES>select * from session_roles; ROLE ---------------------------- CONNECT JAMES>select max(sal) from scott.emp; * ERROR at line 1: ORA-00942: table or view does not exist
Example 3a: Virtual Private database with Application Context Depending on the deptno of the database user the query to emp should return results or not. create an Application Context SQL>create context ctx_ex using sec_mgr.ctx_ex_mgr; SQL> ctx_ex : Namespace, ctx_ex_mgr: Namespace Manager SQL> create a lookup table SQL>create table lookup_dept as select ename username, deptno from emp; SQL> create the namespace manager SQL>create or replace package ctx_ex_mgr 1 as 2 procedure set_deptno; 3 procedure clear_deptno; 4 end; 5 / SQL> SQL>create or replace package body ctx_ex_mgr 1 as 2 procedure set_deptno 3 as 4 l_deptno number; 5 begin 6 select deptno into l_deptno from lookup_dept 7 where username = sys_context('userenv','session_user' 8 dbms_session.set_context(namespace=>'ctx_ex', 9 attribute=>'deptno', 10 value=>'l_deptno' 11 end set_deptno; 12 procedure clear_deptno 13 as 14 begin 15 dbms_session.clear_context(namespace=>'ctx_ex', 16 attribute=>'deptno' 17 end clear_deptno; 18 end ctx_ex_mgr; 19 / set the application context during logon automatically SQL>create or replace trigger set_user_deptno 1 after logon on database 2 begin
3 sec_mgr.ctx_ex_mgr.set_deptno; 4 exception 5 when no data found 6 then 7 null; 8 end; 9 / SQL> implement security policy manually create a view which restricts the user query to records within his dept. SQL>create or replace view my_dept_ctx 1 as 2 select * from emp where deptno=sys_context('ctx_ex','deptno'
Example 3b: Virtual Private database with Row Level security Depending on the deptno of the database user the query to emp should return results or not. define a predicate for the query rewriting SQL>create or replace function rls_dept(obj_owner in varchar2, 1 obj_name in varchar2) 2 return varchar2 3 as 4 deptno number; 5 predicate varchar2(200 6 begin 7 deptno:=sys_context('ctx_ex','dept' 8 if deptno is null then 9 predicate := '1=2'; 10 else 11 predicate := 'deptno=' deptno; 12 end if 13 return(predicate 14 end rls_dept; 15 / the delivered predicate value will be attached as where clause now create the VPD policy and attach it to the EMP table SQL>begin 1 dbms_rls.add_policy( 2 object_schema='scott', 3 object_name='emp', 4 policy_name='restrict_dept_policy', 5 function_schema='scott', 6 policy_function='rls_dept' 7 end; 8 / create another context for maintaining deptno SQL>create context ctx_ex2 using sec_mgr.set_ctx_ex2; SQL>create or replace procedure set_ctx_ex2 1 ( 2 deptno in number 3 ) 4 is 5 begin 6 dbms_session.set_context('ctx_ex2','dept',deptno 7 end; 8 / test the policy without setting the context SQL>select * from emp; No rows selected.
this is because of the '1=2' predicate which will used for the query rewrite; with context setting SQL>exec set_ctx_ex2(20 SQL>select * from emp; all rows with dept=20 becaue of the predicate deptn=20