Área de Tecnologías de la Información y las Comunicaciones Aplicadas
Área de Tecnologías de la Información y las Comunicaciones Aplicadas Universidad de Murcia
Área de Tecnologías de la Información y las Comunicaciones Aplicadas
ATICA arrow DBCONNECTOR arrow SQL - Contextos
21.09.2017
 
 
SQL - Contextos Imprimir E-mail

¿Qué es un contexto (o namespace)?

Un contexto Oracle (o contexto de aplicación o también namespace), es algo así como una agrupación de variables globales. Oracle permite crear contextos (con el privilegio CREATE ANY CONTEXT), y dentro de cada contexto se pueden definir atributos (similares a variables globales), de forma que una vez que le asigno valor a un atributo lo tendré disponible en cualquier momento dentro de la misma sesión (incluso entre sesiones si defino el contexto como global). Otra sesión puede tener un valor diferente para el mismo atributo anterior.

Para crear un contexto, primero tengo que crear un paquete que me permita definir atributos para dicho contexto (proporcionando seguridad a la citada definición de atributos); de modo que no puedo definir atributos en un contexto ejecutando directamente DBMS_SESSION.SET_CONTEXT (obtendría un error "ORA-01031 Privilegios Insuficientes"), sino que tengo que hacerlo desde el paquete del contexto, por ejemplo:

create or replace package pkg_ctx_prueba as

  procedure name_value(n varchar2, v varchar2);
end;
/

create or replace package body pkg_ctx_prueba as
  procedure name_value(n varchar2, v varchar2) as
  begin
    -- Si ejecutas DBMS_SESSION.SET_CONTEXT a mano, obtendrás un error:
    -- ORA-01031: insufficient privileges
    dbms_session.set_context('CTX_PRUEBA',n,v);
  end;
end;
/

Ahora puedes crear el contexto, y después, desde cualquier sesión, usar el contexto creando atributos para consultarlos posteriormente con SYS_CONTEXT:

SQL> create context ctx_prueba using pkg_ctx_prueba;
Context created.

SQL> exec pkg_ctx_prueba.name_value('email','micorreo@um.es');
PL/SQL procedure successfully completed.

SQL> exec pkg_ctx_prueba.name_value('dni','12345678X');
PL/SQL procedure successfully completed.

SQL> select sys_context('CTX_PRUEBA','email') from dual;
SYS_CONTEXT('CTX_PRUEBA','EMAIL')
--------------------------------------------------------------------------------
micorreo@um.es

SQL> select sys_context('CTX_PRUEBA','dni') from dual;
SYS_CONTEXT('CTX_PRUEBA','DNI')
--------------------------------------------------------------------------------
12345678X

SI queremos que los atributos del contexto sean globales a todas las sesiones, de modo que el valor de un atributo establecido por una sesión, sea visto por las demás, al crear el contexto hay que incluir la opción "ACCESSED GLOBALLY":

create context ctx_prueba using pkg_ctx_prueba ACCESSED GLOBALLY;

Podemos obtener todos los atributos de contexto de una sesión de la vista SESSION_CONTEXT; y en el caso de usar contextos globales, a partir de GLOBAL_CONTEXT.

Si trabajamos con contextos globales, podemos usar los parámetros USERNAME y CLIENT_ID de DBMS_SESSION.SET_CONTEXT (en el paquete del contexto), de modo que si indicamos un valor de USERNAME distinto de NULL, sólo dicho usuario de BD podrá acceder al citado contexto global. Si indicamos el CLIENT_ID, sólo podrá acceder la sesión que haya puesto dicho valor de CLIENT_ID mediante DBMS_SESSION.SET_IDENTIFIER (si se usan los 2, USERNAME y CLIENT_ID, se deberán cumplir las 2 condiciones):

dbms_session.set_context('CTX_PRUEBA',n,v,'USUARIO_DATASOURCE', u);

Si sustituimos la línea correspondiente del procedure del paquete PKG_CTX_PRUEBA (más arriba) por la línea del ejemplo anterior, sólo podrá acceder al contexto global CTX_PRUEBA el usuario de BD USUARIO_DATASOURCE, siempre que use el CLIENT_ID con el valor que tuvo en la llamada anterior, supongamos que "u = 12345":

dbms_session.set_identifier(12345);

Por tanto, en una aplicación web, se debería usar un contexto global, de modo que cuando un usuario se conecte a la aplicación se ejecutará el paquete que define los atributos de contexto para SU sesión, pasándole como parámetro el identificador de sesión (CLIENT_ID). Y cada vez que haya que acceder a una tabla que tenga asociada una política de seguridad (o varias), hay que identificar la sesión que va a hacer la operación con DBMS_SESSION.SET_IDENTIFIER(identificador_de_sesión).

En el manual oficial de Oracle tienes un ejemplo de uso de un Contexto Global para una Aplicación Web.


¿Qué es USERENV?

USERENV es un contexto o namespace predefinido, que podríamos llamar contexto del sistema, a través del cual Oracle define automáticamente muchos atributos asociados a la sesión de usuario; por ejemplo el usuario conectado, a través del atributo CURRENT_USER (de hecho la función del sistema USER no es más que una llamada a "SYS_CONTEXT('USERENV', 'CURRENT_USER')".

¿Qué es CLIENT_IDENTIFIER?

Dentro del contexto USERENV, Oracle proporciona el atributo CLIENT_IDENTIFIER, que inicialmente está vacío (NULL) y que normalmente se usa en aplicaciones web para identificar al usuario conectado a la aplicación web  en cuestión (por ejemplo, guardando el DNI o email del usuario conectado, o el identificador de las sesión web), o para definir algún aspecto relativo a dicho usuario útil en el control de acceso a los datos por parte del citado usuario (por ejemplo, el departamento al que pertenece el usuario, de forma que pueda ser usado como predicado en las consultas/actualizaciones para restringirle el acceso y que acceda sólo a los datos de su departamento); aunque esto último es mejor hacerlo a través de atributos de un nuevo contexto.

Los atributos de los contextos Oracle (incluido CLIENT_IDENTIFIER), se usan también para implementar políticas de control de acceso a los datos dentro de la propia BD, usándolos de forma conjunta a Oracle Virtual Private Database.

¿Se puede usar CLIENT_IDENTIFIER en un triger de Auditoria de BD?

Otra posible aplicación sería la identificación del usuario de cualquier aplicación web, a la hora de hacer la auditoría de BD (en los triggers en cuestión).

Aunque el valor de CLIENT_IDENTIFIER no persiste entre sesiones diferentes (su valor sólo está accesible para una misma sesión de BD), sería relativamente sencillo asignarle el identificador de usuario en cada llamada a BD, mediante el método "setClientIdentifier()" del interfaz "oracle.jdbc.OracleConnection", o similar (seguro que nuestros expertos en desarrollo web JEE tendrán más claro en qué punto hacer dicha llamada, según se use Hibernate con o sin JPA, etc), de forma que la BD pueda usarlo en los triggers de auditoría. Además, en la vista V$SESSION existe una columna que muestra siempre el valor de CLIENT_IDENTIFIER, con lo que en Sistemas siempre sabrían qué usuario REAL es el que está haciendo cada operación de las que están sucediendo en la BD en tiempo real (OJO, no confundir con V$SESSION.CLIENT_INFO que normalmente se utiliza para identificar el módulo o formulario de la aplicación que se está ejecutando en cada momento, y que se rellena con "DBMS_APPLICATION_INFO").

De forma que aquellas aplicaciones que ya tienen triggers de auditoría de BD, sólo tendrían que sustituir "USER" por "nvl(sys_context('USERENV','CLIENT_IDENTIFIER'), USER)" (así la auditoría seguiría cogiendo el usuario del datasource correspondiente mientras no se identifique al usuario real mediante CLIENT_IDENTIFIER). Ejemplo desde SQL:
SQL> select nvl(sys_context('USERENV','CLIENT_IDENTIFIER'), USER) from dual;
NVL(SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER'),USER)
--------------------------------------------------------------------------------
FUNDEWEB

SQL> exec dbms_session.set_identifier('usuario@um.es')
PL/SQL procedure successfully completed.

SQL> select nvl(sys_context('USERENV','CLIENT_IDENTIFIER'), USER) from dual;
NVL(SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER'),USER)
--------------------------------------------------------------------------------
usuario@um.es

Última modificación ( 12.12.2014 )
 
Área de Tecnologías de la Información y las Comunicaciones Aplicadas
Volver al incio del documento Volver al inicio del documento
Área de Tecnologías de la Información y las Comunicaciones Aplicadas