[ 2021-02-06 ]

Diferencia entre "Session User" y "Current User"

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