PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

AFTER LOGON(Oracle) trigger no PostgreSQL com extensão – login_hook


Antes de entrar em detalhes, obrigado ao autor da extensão 'login hook' por desenvolvê-lo e mantê-lo.

Muitas vezes, no exercício de migração do Oracle para o Postgres, vi o uso do gatilho Oracle Database Event – ​​AFTER LOGON ON. É um tipo de gatilho de evento de banco de dados/usuário Oracle (LOGON) que é acionado quando um usuário se conecta a um banco de dados, normalmente usado para definir o ambiente do usuário e executar funções associadas a funções de aplicativo seguras.

Digamos, por exemplo, que temos um usuário de aplicativo ao qual queríamos que ele se conectasse a partir do aplicativo SOMENTE e não de nenhum outro programa ou cliente (Oracle/SQL*Plus). Isso pode ser feito criando um gatilho de evento de banco de dados AFTER LOGON ON no Oracle.

O Postgres suporta a maioria dos gatilhos padrão, mas não há nenhum gatilho AFTER LOGON. Para contornar isso, selecionei login_hook extensão que fez o trabalho muito bem.

Vamos ver o que vamos converter de Oracle para Postgres com a ajuda da extensão. Existe um gatilho no Oracle que impede que os usuários do aplicativo se conectem ao banco de dados de outros 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;

A partir do código acima, fica claro que MIGUSER (usuário do aplicativo) está restrito a se conectar via SQL*PLUS cliente e qualquer tentativa que o usuário fizer resultará no seguinte erro:
[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 contornar o requisito acima, primeiro precisamos compilar a extensão login_hook em Postgres. Os passos são muito simples como qualquer outra compilação de extensão
--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

Agora, estamos prontos para usar essa extensão. No nosso caso, evitaremos que o usuário da aplicação use o cliente Postgres psql . Para fazer isso, use a função de modelo fornecida no login_hook página de extensão e modifique-a para capturar o nome do aplicativo do cliente de pg_stat_activity visualize e encerre-o usando pg_terminate_backend() função do sistema. Nota:Você pode usar a mesma função de modelo para várias finalidades para gerenciar o usuário do aplicativo.
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;

Agora, vamos ver se o usuário do aplicativo pode usar o Postgres psql para se conectar ao banco de dados.
[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 impedir a conexão dos usuários do aplicativo de qualquer outro programa/cliente no Postgres.

Obrigada.

–Raghav