En esta breve publicación voy a trata de explicar dos conceptos que en muchas oportunidades suelen confundirse (o por lo menos no quedan del todo claros). Estoy hablando de “session user” y “current user”.
En bases de datos Oracle, durante el tiempo de vida de una sesión, es muy probable que el usuario conectado utilice privilegios de diferentes usuarios. Esto sucede muy a menudo y de manera transparente (en el detrás de escena de la sesión).
En todo momento, mientras esté viva la sesión, podemos identificar dos usuarios prinicpales: el usuario de sesión (“session user”) y el usuario actual (“current user”). Estas dos identidades pueden referirse al mismo usuario o pueden ser diferentes de acuardo al privilegio que se esté utilizando.
Veamos primero de que se trata cada uno de estos conceptos y posteriormente voy a usar un ejemplo para tratar de ilustrarlo.
Session user: Es el usuario con el que fue iniciada la sesión en la base de datos. Este usuario permanece sin cambios durante el tiempo de vida de la sesión. A veces se denomina también usuario de inicio de sesión. Podemos conocer cuál es, utilizando la función sys_context con el namespace USERENV(que hace referencia a la sesión actual) y el parámetro SESSION_USER: SYS_CONTEXT ('USERENV', 'SESSION_USER').
Si, por ejemplo, nos conectamos a la base de datos como USERS1, entonces el usuario de sesión será USERS1.
Current user: Es el usuario cuyos privilegios están actualmente activos. Este usuario puede cambiar a lo largo del tiempo de vida de la sesión. Podemos saber cuál es “current user” en determinado momento utilizando también la función sys_context con USERENV, pero en este caso con el parámetro ‘CURRENT_USER’:
SYS_CONTEXT ('USERENV', 'CURRENT_USER').
Por ejemplo, si el usuario USER1 está ejecutando un procedimiento almacenado propiedad del usuario USER2, durante el tiempo que dure la ejecución del mismo, el usuario actual será USER2 y el usuario de sesión permanecerá sin cambios como USER1.(Cuando un usuario ejecuta un procedimiento o función, del cual no es propietario, y al cual se le han otorgado permisos de ejecución, los privilegios del owner del procedimiento o función son activados).
Veamos cómo funciona esto con un ejemplo:
Voy a preparar primero un escenario de prueba donde utilizaré tres usuarios distintos:
- USER1
- USER2
- USER3
USER1 lo voy a utilizar como usuario de validación (desde el cual voy a realizar las verificaciones), en el usuario USER2 voy a crear dos procedures, PROC1 que devuelve “session_user” y “current_user” directamente ejecutando la función SYS_CONTEXT y otro, PROC2, que lo hace llamando a dos funciones propiedad del usuario USER3 que también utilizan SYS_CONTEXT para retornar los valores del session y el current.
Creación de usuarios:
CREATE USER user1 IDENTIFIED BY Oracle1;
CREATE USER user2 IDENTIFIED BY Oracle1;
CREATE USER user3 IDENTIFIED BY Oracle1;
Permisos:
GRANT CREATE SESSION TO user1;
GRANT CREATE SESSION, CREATE PROCEDURE TO user2;
GRANT CREATE SESSION, CREATE PROCEDURE TO user3;
Aquí voy a crear las funciones en el usuario USER3 que devuelven session_user y current_user usando SYS_CONTEXT.
SQL> CONN user3
Enter password: ***********
Connected.
SQL> CREATE OR REPLACE FUNCTION get_session_user
RETURN varchar2
IS
BEGIN
RETURN SYS_CONTEXT('USERENV', 'SESSION_USER');
END;
/
Function created.
SQL> CREATE OR REPLACE FUNCTION get_current_user
RETURN varchar2
IS
BEGIN
RETURN SYS_CONTEXT('USERENV', 'CURRENT_USER');
END;
/
Function created.
Grant de ejecución a USER2 sobre las dos funciones.
SQL> GRANT EXECUTE ON get_session_user TO user2;
Grant succeeded.
SQL> GRANT EXECUTE ON get_current_user TO user2;
Grant succeeded.
Con el usuario USER2 voy a crear dos procedimientos, uno muestra SESSION_USER y CURRENT_USER utilizando SYS_CONTEXT. El otro procedimiento llama a las funciones de USER3 (get_session_user y get_current_user) para mostrar lo mismo.
SQL> CONN user2
Enter password: ***********
Connected.
SQL> CREATE OR REPLACE PROCEDURE proc1 AS
2 BEGIN
3 DBMS_OUTPUT.PUT_LINE('Session user is ' || SYS_CONTEXT('USERENV', 'SESSIO N_USER'));
4 DBMS_OUTPUT.PUT_LINE('Current user is ' ||SYS_CONTEXT('USERENV', 'CURREN T_USER'));
5 END;
6 /
Procedure created.
SQL> CREATE OR REPLACE PROCEDURE proc2 AS
2 BEGIN
3 DBMS_OUTPUT.PUT_LINE('Session user is ' || user3.get_session_user);
4 DBMS_OUTPUT.PUT_LINE('Current user is ' || user3.get_current_user);
5 END;
6 /
Procedure created.
Por último, conectado con el usuario USER1, voy a verificar los resultados:
Conexión con USER1:
SQL> CONN user1
Enter password:
Connected.
Verificación “session user” y “current user” con la funcion SYS_CONTEXT:
SESSION_USER:
SQL> SET SERVEROUTPUT ON
SQL> EXEC DBMS_OUTPUT.PUT_LINE('Session user is ' || SYS_CONTEXT('USERENV', 'SESSION_USER'));
Session user is USER1
PL/SQL procedure successfully completed.
CURRENT_USER:
SQL> EXEC DBMS_OUTPUT.PUT_LINE('Current user is ' || SYS_CONTEXT('USERENV', 'CURRENT_USER'));
Current user is USER1
PL/SQL procedure successfully completed.
Como podemos ver en este caso ambos coinciden.
Ahora, ejecuto el proc1 propiedad del usuario user2
SQL> EXEC user2.proc1;
Session user is USER1
Current user is USER2
PL/SQL procedure successfully completed.
En este caso, "session user" continúa siendo USER1 pero el "current" pasa a ser USER2, puesto que es el owner del procedure.
Por último ejecuto el procedure proc2 del usuario USER2, este a su vez llama a las funciones get_session_user y get_current_user del USER3.
SQL> EXEC user2.proc2;
Session user is USER1
Current user is USER3
PL/SQL procedure successfully completed.
Aquí podemos ver que el “session user” permanece como USER1 pero el “current” pasa a ser USER3, ya que el procedimiento PROC2 del usuario USER2 llama una función del usuario USER3.
Conclusión:
En el ejemplo queda claro como el "session user" siempre se mantiene y el "current user" puede ir variando de acuerdo a los privilegios que se vayan utilizando durante la vida de la sesión.
No hay comentarios:
Publicar un comentario