Использование On-Logon триггеров в СУБД Postgres Pro Enterprise

3ea8465bfd2eb98f006543ef949d552f.jpg

Введение

Триггеры On-Logon хорошо знакомы разработчикам приложений для СУБД Oracle Database.
Они являются одним из видов триггеров событий базы данных, и автоматически срабатывают при подключении пользователя к БД.

Фактически, On-Logon триггер является блоком кода на языке программирования Oracle PL/SQL, который срабатывает на событие On-Logon (подключение пользователя к БД). Следует отметить, что при возникновении ошибки в On-Logon триггере, подключение пользователя к БД запрещается.

On‑Logon триггер удобно использовать для формирования контекста сессии,  либо для проведения нестандартных автоматических проверок пользователя перед началом сессии.

В Данной статье я расскажу о функциональности PostgreSQL, аналогичной тому, что предоставляет Oracle On Logon Trigger.

Первоначально, On-Logon триггеры появились в Postgres Pro Enterprise версии 14. Компания Postgres Pro передала свою реализацию этой технологии сообществу PostgreSQL и скоро они войдут и в open source версию СУБД PostgreSQL, доступную всем — 17-ый релиз, который будет выпущен в 2024 году.

В силу различия принятой в Oracle и PostgreSQL терминологии для события входа в систему, в PostgreSQL этот триггер называется On‑Login триггер.

Данный пример ярко характеризует модель развития СУБД PostgreSQL.
Идеи и их реализации, апробированные компаниями в коммерческих форках, передаются в open source. С другой стороны, компании точно также получают наработки open source в свой коммерческий форк. Это формирует устойчивую ситуацию взаимовыгодного сотрудничества коммерческих компаний и open source сообщества. Существующая практика уже доказала, что обычно эта схема более надёжная и долговечная, чем отдельные коммерческие компании без open source сообщества, или открытые продукты без коммерческой поддержки и развития.

On-Logon триггеры в СУБД Oracle

Рассмотрим следующий пример On-Logon триггера в СУБД Oracle Database.

Этот пример будет решать следующую задачу: для данного пользователя SCOTT разрешать подключение пользователя к БД только в рабочие часы (с 9:00 до 18:00), а также запрещать использование для подключения БД любых исполняемых файлов приложения кроме «hr.exe».

On-Logon триггер, решающий вышеописанную задачу в СУБД Oracle Database, будет иметь следующий вид:

CREATE OR REPLACE TRIGGER hr_logon_trigger
  AFTER LOGON ON DATABASE 
DECLARE
  v_cProgram constant varchar2(128 char) := 'hr.exe';
  v_xProgram          varchar2(128 char);
  v_xHour             int                := (EXTRACT(hour FROM systimestamp));
BEGIN                                                     
  IF user = 'SCOTT' THEN
   -- Проверяем что выполняемый файл hr.exe
    v_xProgram := sys_context('USERENV','CLIENT_PROGRAM_NAME');
    IF v_xProgram != v_cProgram THEN
      raise_application_error(-20000, 'Access denied from executable "' || v_xProgram || '"');
    END IF;

   -- Запретить вход в нерабочее время
    IF v_xHour not between 9 and 18 THEN
      raise_application_error(-20000, 'Access denied in NOT working hours');
    END IF;

  END IF;
END;
/

Trigger HR_LOGON_TRIGGER compiled

Проверяем наш триггер в СУБД Oracle, с помощью открытия соединения в утилите Oracle SQL*Plus:

C:\oracle\product\19.0.0\client_1\bin>sqlplus.exe scott/tiger@mydemosrv/orcl

SQL*Plus: Release 19.0.0.0.0 - Production on Sun Dec 01 14:25:54 2023
Version 19.21.0.0.0                                                                                                                                                                                                                                                                                                                                                                                                                   
Copyright (c) 1982, 2020, Oracle.  All rights reserved.    

ERROR:
ORA-04088: error during execution of trigger 'SYS.HR_LOGON_TRIGGER'
ORA-00604: error occurred at recursive SQL level 1
ORA-20000: Access denied from executable "sqlplus.exe"
ORA-06512: at line 10

Все работает штатно: подключение к БД с помощью утилиты sqlplus запрещено.
Для целей тестирования скопируем файл sqlplus.exe в hr.exe:

C:\oracle\product\19.0.0\client_1\bin>copy sqlplus.exe hr.exe                                                                                                                                                           
      1 file(s) copied.                          

Конечно, на реальном рабочем месте бизнес-пользователя, у него отсутствуют права на переименование файлов на его рабочем ПК.

Снова пытаемся открыть соединения с помощью нашей «новой» утилиты hr.exe:

C:\oracle\product\19.0.0\client_1\bin>hr.exe scott/tiger@mydemosrv/orcl

SQL*Plus: Release 19.0.0.0.0 - Production on Sun Dec 10 20:38:17 2023 Version 19.21.0.0.0

Copyright (c) 1982, 2020, Oracle.  All rights reserved.

Last Successful login time: Sun Dec 01 2023 14:28:42 +03:00

Connected to: Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.21.0.0.0

SQL> select to_char(sysdate,'hh24:mi') from dual;

TO_CH

12:38

Итак, наш On-Logon триггер в СУБД Oracle, автоматически срабатывает в момент подключения к БД и осуществляет все определенные в нем действия.

On-Login триггеры в СУБД Postgres Pro Enterprise

On-Login триггер в СУБД Postgres Pro Enterprise, так же как и в Oracle Database, является одним из видов триггеров событий базы данных (https://www.postgrespro.ru/docs/enterprise/14/event-trigger-database-login-example).
Данная функциональность впервые была добавлена еще в Postgres Pro Enterprise 14, и, конечно, доступна в последующих релизах этой СУБД.

Определим наш On-Login триггер решающий туже самую задачу: для данного пользователя разрешать подключение пользователя к БД только в рабочие часы с 9:00 до 18:00, а также запрещать использование для работы с БД любых исполняемых файлов кроме «hr.exe», но уже в среде СУБД Postgres Pro Enterprise.

On-Login триггер, решающий вышеописанную задачу в СУБД Postgres Pro Enterprise, будет иметь следующий вид:

--Создаем функцию выполняемую в триггере:
CREATE OR REPLACE FUNCTION check_session() RETURNS event_trigger 
  SECURITY DEFINER
  LANGUAGE plpgsql AS
$$
DECLARE
  v_cProgram constant text := 'hr.exe';
  v_xProgram          text;
  v_xHour             int  := EXTRACT('hour' FROM current_time);
BEGIN
  IF upper(quote_ident(session_user)) != 'SCOTT' THEN
    return;
  END IF;

   -- 1. Проверяем, что выполняемый файл hr.exe
    SELECT
      application_name
    INTO
      v_xProgram
    FROM
      pg_stat_activity 
    WHERE 
      pid = pg_backend_pid();

    IF v_xProgram != v_cProgram THEN
      RAISE EXCEPTION 'Access denied from executable "%"', v_xProgram;
    END IF;

    EXECUTE 'SET LOCAL TIME ZONE ''Europe/Moscow'';';

    -- 2. Запретить вход в нерабочее время
  IF v_xHour NOT BETWEEN 9 AND 18 THEN
    RAISE EXCEPTION 'Access denied in NOT working hours';
  END IF;
END;
$$
;
CREATE FUNCTION

-- Наконец, создаем сам On-Logon триггер:
CREATE EVENT TRIGGER check_session
  ON login
  EXECUTE FUNCTION check_session();
CREATE EVENT TRIGGER

Проверяем наш триггер в среде Postgres Pro Enterprise, с помощью открытия соединения в утилите psql:

postgres@demosrv:~$ psql -U scott -d demodb
psql: ошибка: подключиться к серверу через сокет "/tmp/.s.PGSQL.5432" не удалось: ВАЖНО:  Access denied from executable "psql"
КОНТЕКСТ:  функция PL/pgSQL check_session(), строка 22, оператор RAISE
postgres@demosrv:~$

Все работает штатно: подключение к БД с помощью утилиты psql запрещено.
Для целей тестирования скопируем файл файл psql в hr.exe:

  postgres@demosrv:/opt/pgpro/ent-15/bin$ cp ./psql hr.exe

И снова попытаемся открыть соединение с помощью «утилиты» hr.exe в нерабочее время:

postgres@demosrv:/opt/pgpro/ent-15/bin$ date
Ср дек 13 19:36:25 MSK 2023
postgres@demosrv:/opt/pgpro/ent-15/bin$ ./hr.exe -U scott -d demodb
hr.exe: ошибка: подключиться к серверу через сокет "/tmp/.s.PGSQL.5432" не удалось: ВАЖНО:  Access denied in NOT working hours
КОНТЕКСТ:  функция PL/pgSQL check_session(), строка 33, оператор RAISE

Наконец, подключаемся с помощью «утилиты» hr.rxe в рабочее время:

postgres@demosrv:/opt/pgpro/ent-15/bin$ date 
Пн дек 18 13:46:23 MSK 2023 
postgres@demosrv:/opt/pgpro/ent-15/bin$  ./hr.exe -U scott -d demodb 
hr.exe (15.5) Введите "help", чтобы получить справку.

demodb=>

On-Login триггер успешно сработал в СУБД Postgres Pro и все проверки успешно были выполнены!

Заключение

Поддержка в Postgres Pro Enterrise On-Logon триггеров, то есть триггеров события входа пользователя в систему, является важной функциональной возможностью СУБД Postgres Pro Enterprise.
Она востребована как при миграции с СУБД Oracle Database и MS SQL Server, так и для приложений, которые разрабатываются для СУБД Postgres Pro Enterprise «с нуля».

Снова хотелось бы напомнить, что поддержка On-Logon триггеров будет добавлена в следующий мажорный релиз open source СУБД PostgreSQL — в версию 17.

Игорь Мельников
Postgres Pro

© Habrahabr.ru