1. Documentación en Tahiti -> Oracle Database, 11g Release 2 (11.2) -> Masters Book List -> Security Guide -> 6 Using Application Contexts to Retrieve User Information
2. Un contexto o contexto de aplicación no es más que un conjunto de pares nombre-valor que la base de datos almacena en memoria. Se identifica por una etiqueta, a partir de la cual se puede acceder al array de pares nombre-valor. Una aplicación crear y utilizar estos contextos para el control de acceso que hemos visto en el objetivo anterior o para reforzar la seguridad de la propia aplicación ya que el contexto está protegido por un procedimiento y no un usuario.
Lo más probable es que el verdadero propósito que hay detrás de este objetivo es reforzar el control de acceso utilizando contextos, así que vamos a hacer un ejercicio completo que combina contextos y control de acceso con VPD.
El ejercicio que vamos a hacer está sacado de la documentación practicamente integro ya que es muy interesante.
-- Creamos un usuario que será el administrador de las políticas VPD de nuestra BD CREATE USER SYSADMIN_VPD IDNTIFIED BY "sysadmin_vpd"; GRANT CREATE SESSION, CREATE ANY CONTEXT, CREATE PROCEDURE, CREATE TRIGGER, ADMINISTER DATABASE TRIGGER TO sysadmin_vpd IDENTIFIED BY "sysadmin_vpd"; GRANT EXECUTE ON DBMS_SESSION TO sysadmin_vpd; GRANT EXECUTE ON DBMS_RLS TO sysadmin_vpd; -- Creamos dos usuarios con los que vamos a realizar las pruebas GRANT CREATE SESSION TO tbrooke IDENTIFIED BY tbrooke; GRANT CREATE SESSION TO owoods IDENTIFIED BY owoods; -- Creamos un tabla de prueba en el esquema SCOTT con dos registros ALTER USER SCOTT ACCOUNT UNLOCK IDENTIFIED BY "scott"; CONNECT scott/scott DROP TABLE CUSTOMERS CASCADE CONSTRAINTS; CREATE TABLE customers ( cust_no NUMBER(4), cust_email VARCHAR2(20), cust_name VARCHAR2(20)); INSERT INTO customers VALUES (1234, 'TBROOKE', 'Thadeus Brooke'); INSERT INTO customers VALUES (5678, 'OWOODS', 'Oberon Woods'); COMMIT; -- Damos permisos de SELECT al administrador VPD GRANT SELECT ON customers TO sysadmin_vpd; -- Creamos otra tabla de pedidos DROP TABLE ORDERS_TAB; CREATE TABLE orders_tab ( cust_no NUMBER(4), order_no NUMBER(4)); INSERT INTO orders_tab VALUES (1234, 9876); INSERT INTO orders_tab VALUES (5678, 5432); INSERT INTO orders_tab VALUES (5678, 4592); -- Damos permisos de SELECT a los usuarios que hemos creado GRANT SELECT ON orders_tab TO tbrooke; GRANT SELECT ON orders_tab TO owoods; -- Creamos el contexto con el administrador VPD CONNECT SYSADMIN_VPD/sysadmin_vpd CREATE OR REPLACE CONTEXT orders_ctx USING orders_ctx_pkg; -- Creamos el paquete PL/SQL que fija el contexto de aplicación -- La parte más importante es la fijación del contexto con "SET_CONTEXT" CREATE OR REPLACE PACKAGE orders_ctx_pkg IS PROCEDURE set_custnum; END; / CREATE OR REPLACE PACKAGE BODY orders_ctx_pkg IS PROCEDURE set_custnum AS custnum NUMBER; BEGIN SELECT cust_no INTO custnum FROM SCOTT.CUSTOMERS WHERE cust_email = SYS_CONTEXT('USERENV', 'SESSION_USER'); DBMS_SESSION.SET_CONTEXT('orders_ctx', 'cust_no', custnum); EXCEPTION WHEN NO_DATA_FOUND THEN NULL; END set_custnum; END; / -- Definimos un TRIGGER que se lance al inicio de sesión en la BD CREATE TRIGGER set_custno_ctx_trig AFTER LOGON ON DATABASE BEGIN sysadmin_vpd.orders_ctx_pkg.set_custnum; END; / -- Comprobamos que el contexto se aplica correctamente a los usuarios creados CONN tbrooke/tbrooke SELECT SYS_CONTEXT('orders_ctx', 'cust_no') custnum FROM DUAL; -- Ahora creamos la política que limita el acceso de los usuarios a sus propios pedidos -- Nos logamos como el admin. VPD CONN SYSADMIN_VPD/sysadmin_vpd -- Creamos la función que añade el predicado de control de los pedidos CREATE OR REPLACE FUNCTION get_user_orders( schema_p IN VARCHAR2, table_p IN VARCHAR2) RETURN VARCHAR2 AS orders_pred VARCHAR2 (400); BEGIN orders_pred := 'cust_no = SYS_CONTEXT(''orders_ctx'', ''cust_no'')'; RETURN orders_pred; END; / -- Creamos la política VPD BEGIN DBMS_RLS.ADD_POLICY ( object_schema => 'scott', object_name => 'orders_tab', policy_name => 'orders_policy', function_schema => 'sysadmin_vpd', policy_function => 'get_user_orders', statement_types => 'select'); END; / -- Es hora de probar que funciona correctamente -- Primero comprobamos que podemos ver todos los registros como el administrador VPD SELECT * FROM SCOTT.ORDERS_TAB; -- Nos conectamos con los otros usuarios para validar la política CONNECT tbrooke/tbrooke SELECT * FROM SCOTT.ORDERS_TAB; -- Validamos el segundo usuario -- Cualquier otro usuario no vería ningún registro en la tabla (con permiso SELECT) CONNECT owoods/owoods SELECT * FROM SCOTT.ORDERS_TAB; -- Limpiamos los objetos y usuarios creados CONN SCOTT/scott DROP TABLE ORDERS_TAB; DROP TABLE CUSTOMERS; CONNECT / AS SYSDBA DROP CONTEXT orders_ctx; DROP USER sysadmin_vpd CASCADE; DROP USER tbrooke; DROP USER owoods;