Legal | Privacy
Restricting Data Access Using Virtual Private Database

Restricting Data Access Using Virtual Private Database

The goal of this tutorial is to show the power of using the Virtual Private Database capability to restrict access to certain data to certain users.

Approximately 30 minutes

This tutorial covers the following topics:

Place the cursor over this icon to load and view all the screenshots for this tutorial. (Caution: Because this action loads all screenshots simultaneously, response time may be slow depending on your Internet connection.)

Note: Alternatively, you can place the cursor over each individual icon in the following steps to load and view only the screenshot associated with that step.

The Virtual Private Database (VPD) enables data access control by user or by customer with the assurance of physical data separation. For Internet access, the Virtual Private Database can ensure that online banking customers see only their own accounts. The Web-hosting companies can maintain data of multiple companies in the same Oracle database, while permitting each company to see only its own data.

Within the enterprise, the Virtual Private Database results in lower costs of ownership in deploying applications. Security can be built once, in the data server, rather than in each application that accesses data. Security is stronger, because it is enforced by the database, no matter how a user accesses data. Security is no longer bypassed by a user accessing an ad hoc query tool or new report writer. The Virtual Private Database is a key technology that enables organizations to build hosted, Web-based applications. Indeed, many Oracle applications themselves use VPD to enforce data separation for hosting, including Oracle SalesOnline.com and Oracle Portal.

How the Virtual Private Database Works

The Virtual Private Database is enabled by associating one or more security policies with tables or views. Direct or indirect access to a table with an attached security policy causes the database to consult a function that implements the policy. The policy function returns an access condition known as a predicate (a WHERE clause), which the database appends to the user's SQL statement, thus dynamically modifying the user's data access.

You can implement VPD by writing a stored procedure to append a SQL predicate to each SQL statement that controls row-level access for that statement. For example, if John Doe (who belongs to Department 10) inputs the SELECT * FROM emp statement, then you can use VPD to add the WHERE DEPT = 10 clause. In this way, you use query modification to restrict data access to certain rows.

The Virtual Private Database ensures that, no matter how a user gets to the data (through an application, a report writing tool, or SQL*Plus), the same strong access control policy is enforced. In this way, VPD can help banks ensure that customers see only their own accounts, that telecommunications firms can keep customer records safely segregated, and that human resources applications can support their complex rules of data access to employee records.

 

Before starting this tutorial, you should have:

1.

Completed the Installing Oracle Database 10g on Windows Using Real Application Clusters (RAC) and Automated Storage Management (ASM) tutorial

OR

Completed the Installing Oracle Database 10g on Linux tutorial

 

2.

Downloaded and unzipped vpd.zip into your working directory (/home/oracle/wkdir)

 

Back to Topic List

In this tutorial, you create a set of users and roles to demonstrate how VPD works. To create users and roles, perform the following steps:

1.

Open a terminal window. Change directory to /home/oracle/wkdir. Start SQL*Plus with the /nolog option. In the SQL*Plus session, execute the following script:

@create_vpd_users_and_roles.sql

set echo off pagesize 20000
connect system/<password>
set echo off
prompt *** Create some end users.
prompt
prompt ***** Create STEVEN.KING@OSRD.COM (President)
create user "STEVEN.KING@OSRD.COM" identified by welcome1;
grant create session to "STEVEN.KING@OSRD.COM";
prompt
prompt ***** Create LOUISE.DORAN@OSRD.COM (Sales Rep)
create user "LOUISE.DORAN@OSRD.COM" identified by welcome1;
grant create session to "LOUISE.DORAN@OSRD.COM";
prompt
prompt ***** Create NEENA.KOCHHAR@OSRD.COM (AD_VP)
create user "NEENA.KOCHHAR@OSRD.COM" identified by welcome1;
grant create session to "NEENA.KOCHHAR@OSRD.COM";
prompt
prompt ***** Create SUSAN.MAVRIS@OSRD.COM (HR_REP)
create user "SUSAN.MAVRIS@OSRD.COM" identified by welcome1;
grant create session to "SUSAN.MAVRIS@OSRD.COM";
grant update on hr.employees to "SUSAN.MAVRIS@OSRD.COM";
prompt
prompt ***** Create ELENI.ZLOTKEY@OSRD.COM (Sales Manager)
create user "ELENI.ZLOTKEY@OSRD.COM" identified by welcome1;
grant create session to "ELENI.ZLOTKEY@OSRD.COM";
prompt
prompt ***** Create a role to get access to CUSTOMERS
drop role ots_role;
create role ots_role;
grant ots_role to public;
prompt
prompt ***** Grant object privileges to role ots_role
connect oe/oe
grant select on customers to ots_role;
prompt
prompt **** Update the email addresses of the users we just created
connect hr/hr
update employees set email='STEVEN.KING@OSRD.COM' where email='SKING';
update employees set email='LOUISE.DORAN@OSRD.COM' where email='LDORAN';
update employees set email='NEENA.KOCHHAR@OSRD.COM' where email='NKOCHHAR';
update employees set email='SUSAN.MAVRIS@OSRD.COM' where email='SMAVRIS';
update employees set email='ELENI.ZLOTKEY@OSRD.COM' where email='EZLOTKEY';

Move your mouse over this icon to see the image

 

 

In this tutorial, you use the EMPLOYEES and ORDERS tables. Describe what is in those tables. From a SQL*Plus session, execute the following script:

@describe_tables.sql

set pagesize 20000
connect oe/oe
prompt *** The ORDERS table:
desc orders
connect hr/hr
prompt
prompt *** The EMPLOYEES table:
desc employees

Move your mouse over this icon to see the image

Move your mouse over this icon to see the image

 

Currently, Eleni, a user, can connect to the CUSTOMERS table and see the credit_limit information for all customers (her customers and her colleague's). Perform the following:

1.

From a SQL*Plus session, execute the following script:

@select_customers_as_eleni.sql

set echo off pagesize 20000
prompt *** Connect as user ELENI.ZLOTKEY@OSRD.COM prompt (Account Manager with Employee ID 149)
set echo on
connect "ELENI.ZLOTKEY@OSRD.COM"/welcome1
select cust_last_name, cust_first_name, credit_limit, account_mgr_id from oe.customers order by account_mgr_id;
set echo off

Move your mouse over this icon to see the image

 

To restrict Eleni from viewing her colleague's customers credit_limit information, you need to create a policy function with a relevant column. Perform the following steps:

1.

From a SQL*Plus session, execute the following script:

@enable_vpd_policy.sql

set echo off pagesize 20000
connect system/<password>
set echo off
prompt *** Drop Policy in case there is one. prompt If there is none then an error is generated. Do not mind.
set echo on
begin
dbms_rls.drop_policy('oe','customers','accesscontrol_customers');
end;
/
set echo off
prompt
prompt *** Create policy function
set echo on
create or replace function f_policy_customers
-- Function must have the following parameters
(schema in varchar2, tab in varchar2)
-- Function will return a string that is used as a WHERE clause
return varchar2
as
v_employee_id number;
v_user varchar2(100);
-- out_string will be the return value. -- It is initialized to '1=2' because 'WHERE 1=2' -- means 'Nothing to access' and this can be combined -- with other conditions by OR
out_string varchar2(400) default '1=2 ';
begin
-- get session user
v_user := lower(sys_context('userenv','session_user'));
-- if session user is not SECUSER, -- then the connection is using a persionalized database user
-- if session user is SECUSER, -- then the connection is using an application user
if v_user != 'secuser' then
null;
else
v_user := lower(sys_context('userenv','proxy_user'));
end if;
-- Now get the employee ID of the user
begin
select employee_id into v_employee_id
from hr.employees where lower(email)=lower(v_user);
exception
when no_data_found then
v_employee_id:=0;
end;
-- Now generate the WHERE clause
out_string:=out_string||' or account_mgr_id = '||v_employee_id;
return out_string;
end;
/
set echo off
prompt
prompt *** The policy function must be accessible for all users
set echo on
grant execute on f_policy_customers to public;
set echo off
prompt
prompt *** Turn policy on
set echo on
begin
dbms_rls.add_policy('oe','customers','accesscontrol_customers', 'system','f_policy_customers',sec_relevant_cols=>'CREDIT_LIMIT');
end;
/
set echo off
prompt
prompt *** Grant SELECT privilege on hr.employees to PUBLIC (all users). prompt This is NOT RECOMMENDED to do in real world, prompt but shows the power of Virtual Private Database
set echo on
grant select on oe.customers to public;

Move your mouse over this icon to see the image

 

2.

Now that the policy has been applied, execute the same SELECT statement as Eleni to query customer credit limits. From a SQL*Plus session, execute the following script:

@select_customers_as_eleni.sql

set echo off pagesize 20000
prompt *** Connect as user ELENI.ZLOTKEY@OSRD.COM prompt (Account Manager with Employee ID 149)
set echo on
connect "ELENI.ZLOTKEY@OSRD.COM"/welcome1
select cust_last_name, cust_first_name, credit_limit, account_mgr_id from oe.customers order by account_mgr_id;
set echo off

Move your mouse over this icon to see the image

Notice that you only see the Eleni's customers now.

 

3.

If you perform another query without the credit_limit column, you get different results. From a SQL*Plus session, execute the following script:

@select_customers_as_eleni_wo_cl.sql

set echo off pagesize 20000
prompt *** Connect as user ELENI.ZLOTKEY@OSRD.COM prompt (Account Manager with Employee ID 149)
set echo on
connect "ELENI.ZLOTKEY@OSRD.COM"/welcome1
select cust_last_name, cust_first_name, account_mgr_id from oe.customers order by account_mgr_id;
set echo off

Move your mouse over this icon to see the image

 

When the policy is applied, a WHERE clause is added to the v$vpd_policy table. To view the policy, perform the following steps:

1.

From a SQL*Plus session, execute the following script:

@vpd_where_clause.sql
set echo off
connect system/<password>
set echo on
select policy, predicate as "predicate (WHERE clause)" from v$vpd_policy;

Move your mouse over this icon to see the image

 

In this case, you apply a policy so that Eleni can see all her customers and her colleague's customers. Only the credit limit for Eleni's colleague's customers will be blank. Perform the following steps:

1.

From SQL*Plus, execute the following script:

@enable_vpd_relevant_columns_filtering.sql
-- Function will return a string that is used as a WHERE clause
return varchar2
as
v_employee_id number;
v_user varchar2(100);
-- out_string will be the return value. -- It is initialized to '1=2' because 'WHERE 1=2' -- means 'Nothing to access' and this can be combined -- with other conditions by OR
out_string varchar2(400) default '1=2 ';
begin
-- get session user
v_user := lower(sys_context('userenv','session_user'));
-- if session user is not SECUSER, then the connection -- is using a persionalized database user
-- if session user is SECUSER, then the connection is using -- an application user
if v_user != 'secuser' then
null;
else
v_user := lower(sys_context('userenv','proxy_user'));
end if;
-- Now get the employee ID of the user
begin
select employee_id into v_employee_id
from hr.employees where lower(email)=lower(v_user);
exception
when no_data_found then
v_employee_id:=0;
end;
-- Now generate the WHERE clause
out_string:=out_string||' or account_mgr_id = '||v_employee_id;
return out_string;
end;
/
set echo off
prompt
prompt *** The policy function must be accessible for all users
set echo on
grant execute on f_policy_customers to public;
set echo off
prompt
prompt *** Turn policy on
set echo on
begin
dbms_rls.add_policy('oe','customers','accesscontrol_customers', 'system','f_policy_customers',sec_relevant_cols=>'CREDIT_LIMIT', sec_relevant_cols_opt => dbms_rls.ALL_ROWS);
end;
/
set echo off
prompt
prompt *** Grant SELECT privilege on hr.employees to PUBLIC (all users). prompt This is NOT RECOMMENDED to do in real world, but shows the power prompt of Virtual Private Database
set echo on
grant select on oe.customers to public;

Move your mouse over this icon to see the image

 

2.

Now you can test the policy by executing the select_customers_as_eleni.sql script again.

@select_customers_as_eleni.sql

set echo off pagesize 20000
prompt *** Connect as user ELENI.ZLOTKEY@OSRD.COM prompt (Account Manager with Employee ID 149)
set echo on
connect "ELENI.ZLOTKEY@OSRD.COM"/welcome1
select cust_last_name, cust_first_name, credit_limit, account_mgr_id from oe.customers order by account_mgr_id;
set echo off

Move your mouse over this icon to see the image

Scroll up to account manager ID 148.

Move your mouse over this icon to see the image

Notice that you now see Eleni's customers with their credit limits and all other customers with their credit limits blank.

 

In this tutorial, you've learned how to:

Enable a VPD Policy with Relevant Columns
View the Policy
Apply a VPD Policy with relevant Columns and Column Filtering

Back to Topic List

Back to Topic List

 

 

E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy