Рассмотрим для примера такую ситуацию: PL/SQL-код приложения состоит из нескольких слоев: слой доступа к данным, слой бизнес-логики и слой обеспечивающий презентационный уровень. Одним словом, есть набор PL/SQL-пакетов и типов реализующих доступ к таблицам, есть PL/SQL-объекты которые содержат в себе бизнес-логику и есть код реализующий визуальный интерфейс приложения (например: пользовательский код в формах APEX).
При этом код, отвечающий за интерфейс пользователя, имеет право вызывать только процедуры бизнес-логики, и не может напрямую обращаться к слою доступа к данным, иначе это может привести нарушению логической целостности данных.В настоящий момент, стандартными средствами СУБД, невозможно реализовать декларативную проверку на возможность вызова PL/SQL-процедур только в определенном месте.
Для решения этой задачи нам на помощь приходит опция Data Vault. Мы можем создать правило на команду EXECUTE и далее в функции проверки этого правила, проанализировав стек вызовов PL/SQL, разрешить или запретить вызов соответствующей процедуры.
Давайте посмотрим, как все это работает.В моем приложении работу с репозитарием объектов инкапсулирует объектный тип TObjectRepository. К этому объектному типу непосредственно могут обращаться только следующих три объектных типа:
- TPersistent - абстрактный тип, его наследники обладают свойством сохранять и читать свое состояние из БД;
- TDictionary - инкапсулирует работу с справочниками, в связи с особой ролью системных справочников, может напрямую обращаться к API поддержки репозитория;
- TGroup - инкапсулирует функционал группировки объектов в группы, тоже напрямую может работать с фабрикой объектов.
Для начала создадим функцию осуществляющую проверку возможности вызова:
где функция getWhoCallMe анализируя стек вызовов (с помощью системной функции DBMS_UTILITY.FORMAT_CALL_STACK), возвращает имя PL/SQL-объекта из которого была вызвана текущая проверяемая процедура.
create or replace function pcl4.check_valid_call return pls_integer is
begin
if pcl_service.getWhoCallMe in ('PCL4.TPERSISTENT','PCL4.TDICTIONARY','PCL4.TGROUP') then
return 1;
end if;
return 0;
end;
/
show errors;
grant execute on check_valid_call to dvsys;
Также не забываем дать права на выполнение функции проверки пользователю DVSYS, поскольку выполнение проверки будет происходит из под него.
Конечно, было бы более правильнее, если бы условие проверки в функции check_valid_call не было бы жестко зашито в код, а читалось из отдельной таблицы. Но сути примера это не меняет.
SQL> connect dvpcl/*****
Connected.
SQL>
SQL> declare
2 v_xRule_set_name varchar2(90 char) := 'Проверка вызова PL/SQL-объекта в разрешённом месте';
3 v_xRule_name varchar2(90 char) := 'CHECK_API_LAYER';
4 begin
5 --Создаем набор правил
6 dvsys.dbms_macadm.create_rule_set(rule_set_name => v_xRule_set_name
7 ,description => null
8 ,enabled => dvsys.dbms_macutl.g_yes
9 ,eval_options => dvsys.dbms_macutl.g_ruleset_eval_all
10 ,audit_options => dvsys.dbms_macutl.g_ruleset_audit_off
11 ,fail_options => dvsys.dbms_macutl.g_ruleset_fail_show
12 ,fail_message => 'Вызов в данном месте НЕ разрешен'
13 ,fail_code => -20002
14 ,handler_options => dvsys.dbms_macutl.g_ruleset_handler_off
15 ,handler => null);
16 -- Создаем правило - указываем код проверки:
17
18 dvsys.dbms_macadm.create_rule(rule_name => v_xRule_name
19 ,rule_expr => 'PCL4.CHECK_VALID_CALL = 1');
20
21 -- Добавляем вновь созданное правило к нашему набору
22 dvsys.dbms_macadm.add_rule_to_rule_set(rule_set_name => v_xRule_set_name
23 ,rule_name => v_xRule_name);
24
25 -- Указываем критерии проверки: выполнение (EXECUTE) объектного типа (TOBJECTREPOSITORY) содержащегося в определенной схеме (PCL4)
26 dvsys.dbms_macadm.create_command_rule(command => 'EXECUTE'
27 ,rule_set_name => v_xRule_set_name
28 ,object_owner => 'PCL4'
29 ,object_name => 'TOBJECTREPOSITORY'
30 ,enabled => dvsys.dbms_macutl.g_yes);
31 commit;
32 end;
33 /
PL/SQL procedure successfully completed.
SQL>
Обратите внимание, что проверка будет производится только к вызовам объектного типа TObjectRepository, место вызова остальных PL/SQL-объектов никак не проверяется!
Таким образом, мы можем явно определить PL/SQL-объекты, вызов которых возможен только в определенном месте.
SQL> conn pcl4/*****
Connected.
SQL> create or replace procedure test_dv1 is
2 v_xObject TPersistent;
3 begin
4 v_xObject := TObjectRepository.getObjectById(12345) ;
5 end;
6 /
Procedure created.
SQL> show errors;
No errors.
SQL>
SQL> exec test_dv1;
BEGIN test_dv1; END;
*
ERROR at line 1:
ORA-01031: insufficient privileges
ORA-06512: at "PCL4.TOBJECTREPOSITORY", line 248
ORA-06512: at "PCL4.TEST_DV1", line 4
ORA-06512: at line 1
SQL>
Здесь важно отметить, что проверка производится именно в момент вызова, а не компиляции вызывающего PL/SQL-блока.
В общем случае, проверки не ограничиваются только командой выполнения (EXECUTE), вы можете реализовать хитроумные проверки практически для любой команды СУБД.
Комментариев нет:
Отправить комментарий