Детальний контроль доступу і контексти програми. Частина 3, Інтеграція додатків і даних, Бази даних, статті

Частина 2


Для здійснення цього завдання використовуються таблиці EMP_BASE_TABLE і HR_REP. Тоді виникає питання “навіщо використовувати таблицю EMP_BASE_TABLE та подання EMP, якщо можна просто виконати select * from emp_base_table? “З двох причин:




  1. Дані таблиці службовців використовуються для реалізації політики безпеки.

  2. Ця таблиця зчитується при створенні контексту програми.

Для того, щоб прочитати дані про службовця, необхідно встановити значення контексту програми, для того, щоб встановити значення контексту програми, необхідно прочитати дані про службовця. Це проблема курки і яйця. Одним з варіантів її вирішення є створення уявлення, яким будуть користуватися всі програми (подання EMP) і реалізація безпеки цього подання. Для здійснення цього завдання політика безпеки буде користуватися вихідної таблицею EMP_BASE_TABLE. З таблиці EMP_BASE_TABLE можна дізнатися, хто є менеджером деякого відділу, і хто підпорядковується деякого користувачеві. Додаток і кінцеві користувачі ніколи не будуть звертатися до таблиці EMP_BASE_TABLE – вона буде використовуватися тільки політикою безпеки. Після цього створюється процедура установки значень контексту:



SQL> – це процедура, “несе відповідальність” за 
SQL> – створення контексту програми. Вона реалізує
SQL> – політику шляхом установки привілеїв,
SQL> – виданих користувачеві в контексті програми.

SQL> create or replace
  2  procedure set_role( p_roleName in varchar2 default null )
  3  as
  4      l_empno       number;
  5      l_cnt      number;
  6      l_roleName varchar2(40) default upper(p_roleName);
  7  begin
  8      if ( sys_context( “Hr_App_Ctx”, “RoleName” ) is NOT NULL )
  9      then
10 – переривання запиту. Зміна ролі вимагає зміни
11 – предиката, пов’язаного із запитом. Через кешування курсора
12 – в клієнтському додатку не можна гарантувати, що
13 – не існує інших вже розібраних запитів з
14 – предикатами з поточної ролі.
15 – Якщо, наприклад, роль вже встановлена ​​в значення MGR і
16 – розібрано декілька запитів, а тепер спробувати
17 – змінити роль на EMP, то розібрані запити все ще
18 – будуть використовувати предикати MGR, а не EMP.
19 raise_application_error (-20001, “Рольужеустановлена”);
20      end if;
21
22 – Так як використовується користувач СЕСІЇ, а не ПОТОЧНИЙ
25 – користувач і, крім того, empno поточного користувача
23 – використовується досить часто, то він буде зберігатися в цьому
24 – Контексті. Користувач СЕСІЇ – це ім’я приєднаного в
26 – даний момент користувача. ПОТОЧНИЙ користувач – це ім’я
27 – користувача, який має привілеями на виконання
28 – запиту, їм може бути власник процедури,
29– Тобто не приєднаних користувач!
30      select empno into l_empno
31        from emp_base_table
32       where ename = sys_context( “userenv”, “session_user”);
33
34      dbms_session.set_context( “Hr_App_Ctx”, “Empno”, l_empno );
35
36      if ( l_roleName = “EMP” )
37      then
38 – будь-хто може скористатися роллю EMP
39          dbms_session.set_context( “Hr_App_Ctx”, “RoleName”, “EMP” );
40      elsif ( l_roleName = “MGR” )
41      then
42 – перевіримо, чи є користувач MGR (менеджером),
43 – якщо ні, то видамо повідомлення про помилку і перервемо виконання.
44– Користувач може спробувати знову.
45          select count(*) into l_cnt
46            from dual
47           where exists
48             ( select NULL
49             from emp_base_table
50                where mgr = to_number(sys_context(“Hr_App_Ctx”,”Empno”))
51             );
52          if ( l_cnt = 0 )
53          then
54 raise_application_error (-20002, “Винеменеджер”);
55          end if;
56          dbms_session.set_context( “Hr_App_Ctx”, “RoleName”, “MGR” );
57      elsif ( l_roleName = “HR_REP” )
58      then59 – перевіримо, чи є користувач HR_REP, якщо ні,
60 – видамо повідомлення про помилку і перервемо виконання.
61    – Користувач може спробувати знову.
62          select count(*) into l_cnt
63            from dual
64           where exists
65             ( select NULL
66             from hr_reps
67                where username = sys_context( “userenv”, “session_user” )
68             );
69
70          if ( l_cnt = 0 )
71          then
72 raise_application_error (-20002, “Винеконтролер”);
73          end if;
74          dbms_session.set_context( “Hr_App_Ctx”, “RoleName”, “HR_REP” );
75      else
76 raise_application_error (-20003, “Роль” / / l_roleName / /
77 “неможливо розпізнати”);
78      end if;
79  end;
80  /
Procedure created.

SQL> grant execute on set_role to public
  2  /
Grant succeeded.

Отже, до цього моменту зроблено: створена процедура, яка приймає ім’я ролі у вигляді параметра. На початку цієї процедури забезпечується, щоб атрибут RoleName ще не був встановлений. Так як в політиці безпеки повертатимуться різні предикати, що залежать від значення RoleName, то не можна дозволяти користувачеві змінювати його роль, якщо вона вже встановлена. Якщо допустити зміну ролі, то може виникнути проблема, пов’язана з кешуванням курсора і ‘old’-предикатами. Далі подивимося на EMPNO поточного користувача. Ця процедура виконує дві операції:



  1. Перевіряє, чи є користувач службовцям – при отриманні помилки “NO DATA FOUND”, стає відомим, що він не службовець. Тому значення його контексту ніколи не будуть встановлені, а сам користувач не побачить ніяких даних.

  2. Поміщає часто використовується значення в контекст програми. Тепер через EMPNO поточного користувача можна швидко отримати доступ до таблиці EMP – це буде реалізовано в предикатной функції, описаної нижче.

Далі процедура переходить до перевірки, чи дозволено поточному користувачеві отримати роль, яку він запитує. Кожен, хто запитує роль EMP, може встановити її. Тільки той, хто дійсно керує іншими людьми, може встановити роль MGR. Тільки той, про кого є дані в таблиці HR_REPS, може встановити роль HR_REP.


Далі створимо об’єкт контексту програми бази даних і зв’яжемо його з тільки що створеної процедурою SET_HR_APP_DEPT:



SQL> – Створення контексту програми. Ім’я контексту –
SQL> – HR_APP_CTX. Процедура, з якою він пов’язаний в даному випадку –
SQL> – це SET_ROLE

SQL> create or replace context Hr_App_Ctx using SET_ROLE
  2  /
Context created.

Отже, тепер створені контекст з ім’ям Hr_App_Ctx і процедура для його установки. Важливо мати на увазі, що, так як контекст пов’язаний з процедурою Set_Role, то вона є єдиним засобом установки значень контексту. Якщо, наприклад, спробувати встановити в цьому контексті RoleName з метою отримання доступу до заборонених даними, то виявиться, що зробити це не можна:



SQL> REM Виконання наступних далі операцій буде перервана. 
SQL> REM Це показує, що процедура dbms_session.set_context
SQL> REM може встановити контекст Hr_App_Ctx тільки через процедуру
SQL> REM SET_ROLE

SQL> exec dbms_session.set_context( “Hr_App_Ctx”, “RoleName”, “MGR” );
BEGIN dbms_session.set_context( “Hr_App_Ctx”, “RoleName”, “MGR” ); END
*
ERROR at line 1:
ORA-01031: прівілегійнедостаточно
ORA-06512: at “SYS.DBMS_SESSION”, line 55
ORA-06512: at line 1

Цей атрибут контексту відповідає за безпеку. Значення контексту можна встановити тільки через процедуру. В цьому випадку гарантується, що, якщо значення й існує, то воно перевірено і встановлено. Тепер для тестування логіки процедури спробуємо виконати збережену процедуру під різними користувачами і подивимося, які ролі можна встановити і які значення існують в контексті.



SQL> grant select on sys.v_$context to rls_smith;
Grant succeeded.

SQL> connect rls_smith/rls_smith
Connected.

SQL> set serveroutput on
SQL> show user
USER is “RLS_SMITH

SQL> exec rls.set_role( “Mgr” )
BEGIN rls.set_role( “Mgr” ); END;

*
ERROR at line 1:
ORA-20002: Ви не менеджер
ORA-06512: at “RLS.SET_ROLE”, line 53
ORA-06512: at line 1

До цього часу можна було побачити, що процедура доступна RLS_SMITH, але не дозволяє йому встановити контекст ‘MGR’ до тих пір, поки він фактично не стане менеджером. Якщо тепер подивитися на цей контекст через динамічне представлення v $ context, то можна побачити:



SQL> select * from v$context;

NAMESPACE  ATTRIBUTE  VALUE
———- ———- —–
HR_APP_CTX EMPNO      7369

що RLS_SMITH дійсно міг отримати список номерів його службовців, але не атрибут RoleName. Тепер повторимо операцію з RoleName, задавши правильне значення для RLS_SMITH:



SQL> exec rls.set_role( “emp” )
PL/SQL procedure successfully completed.

SQL> select * from v$context;

NAMESPACE  ATTRIBUTE  VALUE
———- ———- —–
HR_APP_CTX ROLENAME   EMP
HR_APP_CTX EMPNO      7369

Можна побачити, що тепер все працює, як очікувалося. RLS_SMITH може отримати номер його службовця і атрибут RoleName, встановлений в контексті HR_APP_CTX. Для подальшого тестування логіки виконаємо:

SQL> exec rls.set_role( “emp” )
BEGIN rls.set_role( “emp” ); END;

*
ERROR at line 1:
ORA-20001: Роль вже встановлена
ORA-06512: at “RLS.SET_ROLE”, line 18
ORA-06512: at line 1

SQL> select * from v$context;

NAMESPACE  ATTRIBUTE  VALUE
———- ———- —–
HR_APP_CTX ROLENAME   EMP
HR_APP_CTX EMPNO      7369

Результат показує, що логіка не дозволяє користувачеві змінити його роль після того, як вона вже встановлена, далі буде видно, що в контексті залишаються колишні значення. Це повідомлення про помилку не критично, воно означає тільки те, що не можна змінити роль під час сесії.


Далі приєднаємося різними користувачами, переглянемо результати роботи процедури і розглянемо різні способи отримання значень контексту сесії:



SQL> connect rls_blake/rls_blake
Connected.

SQL> exec rls.set_role( “mgr” )
PL/SQL procedure successfully completed.

SQL> set serveroutput on
SQL> declare
  2      l_AppCtx     dbms_session.AppCtxTabTyp;
  3      l_size        number;
  4  begin
  5      dbms_session.list_context( l_AppCtx, l_size );
  6      for i in 1 .. l_size loop
  7          dbms_output.put( l_AppCtx(i).namespace // “.” );
  8          dbms_output.put( l_AppCtx(i).attribute // ” = ” );
  9          dbms_output.put_line( l_AppCtx(i).value );
10      end loop;
11  end;
/

HR_APP_CTX.ROLENAME = MGR
HR_APP_CTX.EMPNO = 7698

PL/SQL procedure successfully completed.

На цей раз приєднаємося як RLS_BLAKE, завідувач відділом 30. Коли RLS_BLAKE викликає процедуру Set_Role з параметром RoleName = ‘MGR’, видно, що контекст встановлений правильно: він – менеджер, і кількість його службовців встановлено. Крім того, цей тест показує, як переглянути пари значень атрибутів в контексті сесії за допомогою пакета dbms_session.list_context. Функції цього пакета може викликати будь користувач (так як відбувається звернення до подання sys.v $ context, яке використовувалося раніше), тому всі користувачі можуть використовувати такий метод для перевірки значень контексту сесії.


Тепер, так як контекст сесії встановлений належним чином, можна підготуватися до створення процедури політики безпеки. Ця процедура буде викликатися засобами бази даних під час їх роботи для формування динамічного предиката. Динамічний предикат обмежує такі можливості користувача, як читання і запис.



SQL> – створимо предикатний пакет (пакет для генерації умови where)
SQL> – додатки HR. Для створення унікального умови where кожній
SQL> – операції SELECT / INSERT / UPDATE / DELETE повинна відповідати
SQL> – окрема функція.

SQL> create or replace package hr_predicate_pkg
  2  as
  3     function select_function( p_schema in varchar2,
  4                               p_object in varchar2 ) return varchar2;
  5
  6     function update_function( p_schema in varchar2,
  7                               p_object in varchar2 ) return varchar2;
  8
  9     function insert_delete_function( p_schema in varchar2,
10   p_object in varchar2 ) return varchar2;
11  end;
12  /

Для кожної операції мова маніпулювання даними (Data Manipulation Language – DML) напишемо предикати, трохи відрізняються один від одного. Кожна DML-операція буде підкорятися своїм правилам. Це дозволить пропозицією DELETE бачити набір даних (в даному прикладі менший), що відрізняється від набору даних, видимого при виконанні пропозиції SELECT. Далі показана реалізація тіла пакета HR_PREDICATE_PKG:



SQL> create or replace package body hr_predicate_pkg
  2  as
  3
  4  g_app_ctx constant varchar2(30) default “Hr_App_Ctx”;
  5
  6  g_sel_pred varchar2(1024) default NULL;
  7  g_upd_pred varchar2(1024) default NULL;
  8  g_ins_del_pred varchar2(1024) default NULL;
  9
10
11  function select_function( p_schema in varchar2,
12                    p_object in varchar2 ) return varchar2
13  is
14  begin
15
16      if ( g_sel_pred is NULL )
17      then
18          if ( sys_context( g_app_ctx, “RoleName” ) = “EMP” )
19          then
20          g_sel_pred := “empno = sys_context(“”Hr_App_Ctx””,””EmpNo””)”;
21
22          elsif ( sys_context( g_app_ctx, “RoleName” ) = “MGR” )
23          then
24          g_sel_pred :=
25             ” empno in ( select empno
26                    from emp_base_table
27                   start with empno =
28                          sys_context(“”Hr_App_Ctx””,””EmpNo””)
29                 connect by prior empno = mgr)”;
30
31          elsif ( sys_context( g_app_ctx, “RoleName” ) = “HR_REP” )
32          then
33          g_sel_pred := “deptno in
34                   ( select deptno
35                       from hr_reps
36                      where username =
37                      sys_context(“”userenv””,””session_user””) )”;
38
39          else
40 raise_application_error (-20005, “Рольнеустановлена”);
41          end if;
42      end if;
43
44      return g_sel_pred;
45  end;
46
47  function update_function( p_schema in varchar2,
48                    p_object in varchar2 ) return varchar2
49  is
50  begin
51      if ( g_upd_pred is NULL )
52      then
53          if ( sys_context( g_app_ctx, “RoleName” ) = “EMP” )
54          then
55          g_upd_pred := “1=0”;
56
57          elsif ( sys_context( g_app_ctx, “RoleName” ) = “MGR” )
58          then
59          g_upd_pred :=
60             ” empno in ( select empno
61                    from emp_base_table
62                   where mgr =
63                       sys_context(“”Hr_App_Ctx””,””EmpNo””) )”;
64
65          elsif ( sys_context( g_app_ctx, “RoleName” ) = “HR_REP” )
66          then
67          g_upd_pred := “deptno in
68                   ( select deptno
69                       from hr_reps
70                      where username =
71              sys_context(“”userenv””,””session_user””) )”;
72
73          else
74 raise_application_error (-20005, “Рольнеустановлена”);
75          end if;
76      end if;
77
78      return g_upd_pred;
79  end;
80
81  function insert_delete_function( p_schema in varchar2,
82                       p_object in varchar2 ) return varchar2
83  is
84  begin
85      if ( g_ins_del_pred is NULL )
86      then
87          if ( sys_context( g_app_ctx, “RoleName” ) in ( “EMP”, “MGR” ) )
88          then
89          g_ins_del_pred := “1=0”;
90          elsif ( sys_context( g_app_ctx, “RoleName” ) = “HR_REP” )
91          then
92          g_upd_pred := “deptno in
93                   ( select deptno
94                       from hr_reps
95                      where username =
96                  sys_context(“”userenv””,””session_user””) )”;
97          else
98 raise_application_error (-20005, “Рольнеустановлена”);
99          end if;
100      end if;
101      return g_ins_del_pred;
102  end;
103
104  end;
/
Package body created.

Раніше, без Детального Контролю Доступу використання однієї таблиці з описаними вище трьома предикатами можна було досягти за допомогою 3-х уявлень – по одному на кожну операцію SELECT, UPDATE і INSERT / DELETE. Детальний Контроль Доступу дозволяє скоротити кількість об’єктів до однієї таблиці з динамічним предикатом.


Згадайте логіку, описану раніше:



 11  function select_function( p_schema in varchar2,
 12                    p_object in varchar2 ) return varchar2
 13  is
 14  begin
 15
 16      if ( g_sel_pred is NULL )
 17      then 
логіка для присвоєння значення g_sel_pred,
– Глобальної змінної, оголошеної в тілі пакету
 
42      end if;
 43
 44      return g_sel_pred;
 45  end;

У цій функції мінлива g_sel_pred встановлюється в непорожнє значення точно один раз за сесію. Якщо при попередньому виклику цієї предикатной функції предикат вже встановлено – він просто повертається знову. У цьому є дві переваги:



Останній етап цього процесу полягає у зв’язуванні предикатів з кожною DML-операцією і самої таблицею EMP. Далі показана реалізація цієї операції:



SQL> – Додамо політику до подання EMP. Кожна функція пакета
SQL> – HR_PREDICATE_PKG зв’язується з таблицею для виконання операцій
SQL> – SELECT / INSERTUPDATE / DELETE. При INSERT і UPDATE встановимо прапор
SQL> – “update_check” взначеніе TRUE. Це дуже схоже на створення
SQL> – вистави з “CHECK OPTION”
SQL> – У цьому випадку забезпечується, що дані, створювані в базі
SQL> – даних, – це ті дані, які користувач може
SQL> – побачити.

SQL> begin
  2     dbms_rls.add_policy
  3     ( object_schema   => “RLS”,
  4       object_name     => “EMP”,
  5       policy_name     => “HR_APP_SELECT_POLICY”,
  6       function_schema => “RLS”,
  7       policy_function => “HR_PREDICATE_PKG.SELECT_FUNCTION”,
  8       statement_types => “select” );
  9  end;
10  /

PL/SQL procedure successfully completed.

 SQL> begin
  2     dbms_rls.add_policy
  3     ( object_schema   => “RLS”,
  4       object_name     => “EMP”,
  5       policy_name     => “HR_APP_UPDATE_POLICY”,
  6       function_schema => “RLS”,
  7       policy_function => “HR_PREDICATE_PKG.UPDATE_FUNCTION”,
  8       statement_types => “update” ,
  9       update_check    => TRUE );
 10  end;
 11  /

 PL/SQL procedure successfully completed.

SQL> begin
  2     dbms_rls.add_policy
  3     ( object_schema   => “RLS”,
  4       object_name     => “EMP”,
  5       policy_name     => “HR_APP_INSERT_DELETE_POLICY”,
  6       function_schema => “RLS”,
  7       policy_function => “HR_PREDICATE_PKG.INSERT_DELETE_FUNCTION”,
  8       statement_types => “insert, delete” ,
  9       update_check    => TRUE );
 10  end;
 11  /

 PL/SQL procedure successfully completed.

Таким чином, з кожною DML-операцією зв’язується різна предикатна функція. Коли користувач запитує дані таблиці EMP, до запиту буде приєднуватися предикат, сформований пакетної функцією hr_predicate_pkg.select. Коли користувач оновлює таблицю, буде використовуватися пакетна функція update і так далі.


Тепер протестуємо додаток. Для цього створимо пакет HR_APP. Цей пакет являє собою додаток. У нього входять функції для виконання:



Приєднаємося різними користувачами з різними ролями і простежимо за поведінкою нашого застосування. Це дозволить побачити, як працює детальний контроль доступу .


Нижче показана специфікація програми:



SQL> create or replace package hr_app
  2  as
  3      procedure listEmps;
  4
  5      procedure updateSal;
  6
  7      procedure deleteAll;
  8
  9      procedure insertNew( p_deptno in number );
 10  end;
 11  /

Package created.

Телопакета:
SQL> create or replace package body hr_app
  2  as
  3
  4  procedure listEmps
  5  as
  6      l_AppCtx     dbms_session.AppCtxTabTyp;
  7      l_size       number;
  8  begin
9 dbms_output.put_line (“—— КонтекстСессіі ———-“);
 10      dbms_session.list_context( l_AppCtx, l_size );
 11      for i in 1 .. l_size loop
 12          dbms_output.put( l_AppCtx(i).namespace // “.” );
 13          dbms_output.put( l_AppCtx(i).attribute // ” = ” );
 14          dbms_output.put_line( l_AppCtx(i).value );
 15      end loop;
 16
17 dbms_output.put_line (“—— Данниетабліци Emp, коториеможноувідеть —–“);
 18      for x in ( select ename, sal, dname
 19               from emp, dept
 20              where emp.deptno = dept.deptno )
 21      loop
 22          dbms_output.put_line( x.ename // “,” // x.sal // “,” // x.dname );
 23      end loop;
 24  end;
 25
 26
 27  procedure updateSal
 28  is
 29  begin
 30      update emp set sal = 9999;
31 dbms_output.put_line (sql% rowcount / / “строкобновлено”);
 32  end;
 33
 34  procedure deleteAll
 35  is
 36  begin
 37      delete from emp where empno <> sys_context( “Hr_app_Ctx”, “EMPNO” );
38 dbms_output.put_line (sql% rowcount / / “строкудалено”);
 39  end;
 40
 41  procedure insertNew( p_deptno in number ) 
 42  as
 43  begin
 44      insert into emp ( empno, deptno, sal ) values ( 123, p_deptno, 1111 );
 45  end;
 46
 47  end hr_app;
 48  /

Package body created.

 SQL> grant execute on hr_app to public
 2  /
Grant succeeded.

Отже, “додаток” створено. Процедура listEmps показує всі записи, які можна побачити через подання EMP. Процедура updateSal оновлює кожен запис, до якої можна отримати доступ. Процедура deleteAll видаляє кожен запис, до якої можна отримати доступ, за винятком записи, що ідентифікує користувача. Процедура insertNew створює нового службовця в заданому відділі. Ця програма просто тестує все DML-операції над поданням EMP, які можна було б виконати.

Частина 4


Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*