Преди да навлезем в подробности, благодаря на автора на разширението „кука за влизане“ за разработването и поддръжката му.
Много пъти, в упражнението за миграция на Oracle към Postgres, съм виждал използването на тригер за събитие на Oracle Database – СЛЕД ВХОДЯНЕ. Единственият му тип тригер за събитие на база данни/потребител на Oracle (LOGON), който се задейства, когато потребител се свърже с база данни, обикновено се използва за настройка на потребителската среда и изпълнение на функции, свързани със защитени роли на приложение.
Да кажем, например, че имаме потребител на приложение, където искахме да се свърже от приложението САМО а не от други програми или клиенти (Oracle/SQL*Plus). Това може да се постигне чрез създаване на тригер за събитие в базата данни СЛЕД ВХОДЯНЕ В Oracle.
Postgres поддържа повечето от стандартните тригери, но няма тригер AFTER LOGON. За заобикаляне, избрах login_hook
разширение, което свърши работата доста добре.
Нека видим какво ще преобразуваме от Oracle в Postgres с помощта на разширение. В Oracle има тригер, който не позволява на потребителите на приложението да се свързват към базата данни от други програми/клиенти (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;
От горния код става ясно, че MIGUSER
(потребител на приложение) е ограничен да се свързва чрез SQL*PLUS
клиент и всеки опит, който потребителят направи, ще доведе до следната грешка:
[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
За да заобиколим горното изискване, първо трябва да компилираме разширението login_hook
в Postgres. Стъпките са много прости като всяка друга компилация на разширения
--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
Сега всички сме готови да използваме това разширение. В нашия случай ще попречим на потребителя на приложението да използва Postgres клиент psql . За да направите това, използвайте функцията за шаблон, предоставена на login_hook
страница с разширение и я модифицирайте, за да улови името на приложението на клиента от pg_stat_activity прегледайте и го прекратете с помощта на pg_terminate_backend() системна функция. Забележка:Можете да използвате една и съща шаблонна функция за няколко цели, за да управлявате потребителя на приложението.
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;
Сега нека видим дали потребителят на приложението може да използва Postgres psql
за да се свържете с базата данни.
[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()
Готино. Ние сме в състояние да предотвратим връзките на потребителите на приложението от всяка друга програма/клиент в Postgres.
Благодаря.
– Рагав