sql >> Base de Datos >  >> RDS >> PostgreSQL

Desencadenador DESPUÉS DE INICIO DE SESIÓN (Oracle) en PostgreSQL con extensión – login_hook

Antes de entrar en detalles, gracias al autor de la extensión 'login hook' por desarrollarla y mantenerla.

Muchas veces, en el ejercicio de migración de Oracle a Postgres, he visto el uso del activador de eventos de la base de datos de Oracle:DESPUÉS DE INICIAR SESIÓN. Es un tipo de disparador de evento de usuario/base de datos de Oracle (INICIO DE SESIÓN) que se activa cuando un usuario se conecta a una base de datos, por lo general se usa para configurar el entorno del usuario y realizar funciones asociadas con roles de aplicaciones seguras.

Pongamos, por ejemplo, que tenemos un usuario de aplicación donde queremos que se conecte desde la aplicación SOLO y no de ningún otro programa o cliente (Oracle/SQL*Plus). Esto se puede lograr mediante la creación de un desencadenador de eventos de base de datos DESPUÉS DE INICIAR SESIÓN en Oracle.

Postgres es compatible con la mayoría de los disparadores estándar, pero no hay un disparador DESPUÉS DEL INICIO DE SESIÓN. Para solucionarlo, seleccioné login_hook extensión que hizo el trabajo bastante bien.

Veamos qué vamos a convertir de Oracle a Postgres con la ayuda de la extensión. Hay un activador en Oracle que evita que los usuarios de la aplicación se conecten a la base de datos desde otros programas/clientes (sqlplus).

CREATE OR REPLACE TRIGGER program_restrict
AFTER LOGON ON DATABASE
BEGIN
    FOR x IN (SELECT username, program FROM SYS.v_$session WHERE audsid = USERENV ('sessionid'))
    LOOP
    IF LTRIM (RTRIM (x.username)) = 'MIGUSER' AND UPPER(substr(x.program,1,7)) = 'SQLPLUS'
    THEN
      raise_application_error(-20999,'Not authorized to use in the Production environment!');
    END IF;
    END LOOP;
END program_restrict;

Del código anterior, está claro que MIGUSER (usuario de la aplicación) está restringido para conectarse a través de SQL*PLUS cliente y cualquier intento que haga el usuario resultará en el siguiente error:

[oracle@rrr ~]$ rlsqlplus miguser/miguser
... <trimmed banner>
ERROR:
ORA-04088: error during execution of trigger 'SYS.PROGRAM_RESTRICT'
ORA-00604: error occurred at recursive SQL level 1
ORA-20999: Not authorized to use in the Production environment!
ORA-06512: at line 6
ORA-06512: at line 6

Para solucionar el requisito anterior, primero debemos compilar la extensión login_hook en Postgres. Los pasos son muy simples como cualquier otra compilación de extensiones

--Download zip/Git clone the extension
https://github.com/splendiddata/login_hook

-- Set the pg_config in your path
[root@node1-centos8 ~]# export PATH=/usr/pgsql-13/bin:$PATH

-- change to login_hook directory and run make/make install
[root@node1-centos8 ~]# cd login_hook
[root@node1-centos8 login_hook]# make
[root@node1-centos8 login_hook]# make install

-- add the login_hook.so to session_preload_libraries and restart the database

[root@node1-centos8 ~]# grep -i session_preload /var/lib/pgsql/13/data/postgresql.conf
session_preload_libraries = 'login_hook'
[root@node1-centos8 ~]# systemctl restart postgresql-13.service

-- connect to the database and create the extension
[postgres@node1-centos8 ~]$ psql
psql (13.1)
Type "help" for help.

postgres=# create extension login_hook;
CREATE EXTENSION

Ahora, estamos listos para usar esta extensión. En nuestro caso, evitaremos que el usuario de la aplicación utilice el cliente de Postgres psql . Para hacer esto, use la función de plantilla provista en el login_hook página de extensión y modifíquela para capturar el nombre de la aplicación del cliente de pg_stat_activity verlo y terminarlo usando pg_terminate_backend() función del sistema. Nota:Puede usar la misma función de plantilla para varios propósitos para administrar el usuario de la aplicación.

CREATE OR REPLACE FUNCTION login_hook.login() RETURNS VOID LANGUAGE PLPGSQL AS $$
DECLARE
    ex_state   TEXT;
    ex_message TEXT;
    ex_detail  TEXT;
    ex_hint    TEXT;
    ex_context TEXT;
	rec record;
BEGIN
	IF NOT login_hook.is_executing_login_hook()
	THEN
	    RAISE EXCEPTION 'The login_hook.login() function should only be invoked by the login_hook code';
	END IF;
	
	BEGIN
    for rec in select pid,usename,application_name from pg_stat_activity where application_name ilike 'psql%'
    loop
          if rtrim(rec.usename) = 'miguser' and rtrim(rec.application_name) = 'psql' then
            raise notice 'Application users(%) restricted to connect with any clients(%)',rec.usename,rec.application_name;
            perform pg_terminate_backend(rec.pid);
          end if;
    end loop;
	EXCEPTION
	   WHEN OTHERS THEN
	       GET STACKED DIAGNOSTICS ex_state   = RETURNED_SQLSTATE
	                             , ex_message = MESSAGE_TEXT
	                             , ex_detail  = PG_EXCEPTION_DETAIL
	                             , ex_hint    = PG_EXCEPTION_HINT
	                             , ex_context = PG_EXCEPTION_CONTEXT;
	       RAISE LOG e'Error in login_hook.login()\nsqlstate: %\nmessage : %\ndetail  : %\nhint    : %\ncontext : %'
	               , ex_state
	               , ex_message
	               , ex_detail
	               , ex_hint
	               , ex_context;
    END	;       
END$$;

-- Give exeuction grant on the function. 
GRANT EXECUTE ON FUNCTION login_hook.login() TO PUBLIC;

Ahora, veamos si el usuario de la aplicación puede usar Postgres psql para conectarse a la base de datos.

[postgres@node1-centos8 ~]$ psql -U miguser -d postgres -p 5432
NOTICE:  Application users(miguser) restricted to connect with any clients(psql)
psql: error: FATAL:  terminating connection due to administrator command
CONTEXT:  SQL statement "SELECT pg_terminate_backend(rec.pid)"
PL/pgSQL function login_hook.login() line 20 at PERFORM
SQL statement "select login_hook.login()

Frio. Podemos evitar que los usuarios de la aplicación se conecten desde cualquier otro programa/cliente en Postgres.

Gracias.

–Raghav