Детальный контроль доступа и контексты приложения. Часть 4
Том Кайт
Часть 3
Теперь присоединимся различными пользователями и протестируем функциональность приложения.
SQL> -- Присоединимся как служащий, у которого нет способности управлять.
SQL> connect rls_adams/rls_adams
Connected.
SQL> -- Сначала попробуем стать менеджером
SQL> -- Мы не являемся менеджером, поэтому стать им SQL> -- не разрешается 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
Таким образом, результат показывает, что нельзя получить роль, не предназначенную для текущего пользователя. Чтобы убедиться, что ни к каким данным нет доступа, попробуем теперь запросить что-нибудь, и посмотрим, что произойдет:
SQL> -- теперь посмотрим, что произойдет при попытке выполнить SQL> -- что-нибудь без получения роли
SQL> exec rls.hr_app.listEmps ------ КонтекстСессии ---------- HR_APP_CTX.EMPNO = 7876 ------ Данные таблицы Emp, которые можно увидеть ----- BEGIN rls.hr_app.listEmps; END;
*
ERROR at line 1: ORA-28112: ошибка при выполнении функции политики ORA-06512: at "RLS.HR_APP", line 18 ORA-06512: at line 1
Появилось сообщение об ошибке. Это сообщение возникло, потому что так написана предикатная функция:
function select_function( p_schema in varchar2, p_object in varchar2 ) return varchar2
is begin
if ( g_sel_pred is NULL ) then
if ( sys_context( g_app_ctx, 'RoleName' ) = 'EMP' ) then … elsif ( sys_context( g_app_ctx, 'RoleName' ) = 'MGR' ) then … elsif ( sys_context( g_app_ctx, 'RoleName' ) = 'HR_REP' ) then … else raise_application_error( -20005, 'Рольнеустановлена' ); end if; end if;
Полученный результат - это результат выполнения raise_application_error в предикатной функции. Конечный пользователь получает сообщение об ошибке ORA-28112. Далее, в следующей секции, мы рассмотрим, как обнаружить эти ошибки и отладить их.
Далее установим такую роль, чтобы можно было что-нибудь сделать, и попробуем выполнить эти же операции:
SQL> -- Теперь установим корректную роль и выполним что-нибудь
SQL> exec rls.set_role( 'emp' ); PL/SQL procedure successfully completed.
SQL> -- посмотрим контекст и данные, SQL> -- которые можно видеть - это только одна запись
SQL> exec rls.hr_app.listEmps ------ КонтекстСессии ---------- HR_APP_CTX.ROLENAME = EMP HR_APP_CTX.EMPNO = 7876 ------ Данные таблицы Emp, которые можно увидеть ----- RLS_ADAMS,1100,RESEARCH
PL/SQL procedure successfully completed.
SQL> -- несмотря на то, что данные "видно" SQL> -- их нельзя "изменить".
SQL> exec rls.hr_app.updateSal 0 rows updated
PL/SQL procedure successfully completed.
SQL> -- нельзя удалить никакую информацию
SQL> exec rls.hr_app.deleteAll 0 rows deleted
PL/SQL procedure successfully completed.
SQL> -- нельзя ничего создать SQL> exec rls.hr_app.insertNew(20) BEGIN rls.hr_app.insertNew(20); END; * ERROR at line 1: ORA-28115: нарушение политики с опцией проверки ORA-06512: at "RLS.HR_APP", line 44 ORA-06512: at line 1
Итак, результат показывает, что можно видеть только ту запись, которая соответствует текущему пользователю, нельзя изменить какие бы то ни было данные, нельзя удалить записи, и вставка нового служащего также завершается неудачно. Происходит как раз то, что и предполагалось. В самом приложении, HR_APP не делается ничего специально для выполнения этих правил, теперь это делает база данных.
Далее присоединимся как MGR и посмотрим, что произойдет:
SQL> -- Присоединимся как менеджер SQL> connect rls_jones/rls_jones Connected.
SQL> -- Включим возможность вывода на экран из PL/SQL SQL> set serveroutput on
SQL> -- Для начала попробуем стать менеджером SQL> -- мы являемся менеджером, так как на этот раз нам разрешено SQL> -- статьим
SQL> exec rls.set_role( 'mgr' ) PL/SQL procedure successfully completed.
SQL> -- посмотрим контекст и данные, SQL> -- которые можно видеть. На этот раз - более одной строки.
SQL> exec rls.hr_app.listEmps ------ КонтекстСессии ---------- HR_APP_CTX.ROLENAME = MGR HR_APP_CTX.EMPNO = 7566 ------ Данные таблицы Emp, которые можно увидеть ----- RLS_SMITH,800,RESEARCH RLS_JONES,2975,RESEARCH RLS_SCOTT,3000,RESEARCH RLS_ADAMS,1100,RESEARCH RLS_FORD,3000,RESEARCH
PL/SQL procedure successfully completed.
SQL> -- Следующая операция показывает, что некоторые записи можно SQL> -- изменить. Затем снова выполним listEmps для того, чтобы увидеть, SQL> -- какие строки изменились (только те, которые подчинены напрямую)
SQL> exec rls.hr_app.updateSal 2 rows updated
PL/SQL procedure successfully completed.
SQL> exec rls.hr_app.listEmps ------ КонтекстСессии ---------- HR_APP_CTX.ROLENAME = MGR HR_APP_CTX.EMPNO = 7566 ------ Данные таблицы Emp, которые можно увидеть ----- RLS_SMITH,800,RESEARCH RLS_JONES,2975,RESEARCH RLS_SCOTT,9999,RESEARCH RLS_ADAMS,1100,RESEARCH RLS_FORD,9999,RESEARCH
PL/SQL procedure successfully completed.
SQL> -- так как мы не являемся контролером, то, SQL> -- согласно заданным правилам, нельзя никого удалить
SQL> exec rls.hr_app.deleteAll 0 rows deleted
PL/SQL procedure successfully completed.
SQL> -- так как мы не являемся контролером, то, SQL> -- согласно заданным правилам, нельзя никого вставить SQL> exec rls.hr_app.insertNew(20) BEGIN rls.hr_app.insertNew(20); END; * ERROR at line 1: ORA-28115: нарушение политики с опцией проверки ORA-06512: at "RLS.HR_APP", line 44 ORA-06512: at line 1
Таким образом, теперь нам, как MGR, можно:
И, наконец, присоединимся как контролер и посмотрим на поведение приложения при работе с этой ролью:
SQL> -- Присоединимся как контролер SQL> connect rls_king/rls_king Connected.
SQL> -- Подключим возможность вывода на экран из PL/SQL SQL> set serveroutput on
SQL> -- Для начала, попробуем стать контролером SQL> -- Теперь мы являемся контролером, так как SQL> -- стать им разрешено
SQL> exec rls.set_role( 'hr_rep' ) PL/SQL procedure successfully completed.
SQL> -- посмотрим контекст и данные, SQL> -- которые можно видеть. На этот раз видно все строки, так как SQL> -- пользователь - контолер.
SQL> exec rls.hr_app.listEmps ------ КонтекстСессии ---------- HR_APP_CTX.ROLENAME = HR_REP HR_APP_CTX.EMPNO = 7839 ------ Данные таблицы Emp, которые можно увидеть ----- RLS_CLARK,2450,ACCOUNTING RLS_KING,5000,ACCOUNTING RLS_MILLER,1300,ACCOUNTING RLS_SMITH,800,RESEARCH RLS_JONES,2975,RESEARCH RLS_SCOTT,9999,RESEARCH RLS_ADAMS,1100,RESEARCH RLS_FORD,9999,RESEARCH RLS_ALLEN,1600,SALES RLS_WARD,1250,SALES RLS_MARTIN,1250,SALES RLS_BLAKE,2850,SALES RLS_TURNER,1500,SALES
RLS_JAMES,950,SALES
PL/SQL procedure successfully completed.
SQL> -- следующая операция показывает, что можно изменить любую запись SQL> -- в любом отделе, так как пользователь для всех SQL> -- является контролером SQL> -- далее снова запустим listEmps, чтобы увидеть, какие SQL> -- строки изменились (все)
SQL> exec rls.hr_app.updateSal 14 rows updated
PL/SQL procedure successfully completed.
SQL> -- так как пользователь - контролер, то он может SQL> -- удалить кого-нибудь согласно заданным правилам SQL> -- При удалении ВСЕХ не удаляется 'я', SQL> -- т.е. текущий пользователь
SQL> exec rls.hr_app.deleteAll 13 rows deleted
PL/SQL procedure successfully completed.
SQL> -- так как пользователь - контролер, то он может SQL> -- вставить кого-нибудь согласно заданным правилам
SQL> exec rls.hr_app.insertNew(20) PL/SQL procedure successfully completed.
SQL> -- посмотрим на результат изменения, удаления SQL> -- и последующей вставки
SQL> exec rls.hr_app.listEmps ------ КонтекстСессии ---------- HR_APP_CTX.ROLENAME = HR_REP HR_APP_CTX.EMPNO = 7839 ------ Данные таблицы Emp, которые можно увидеть ----- RLS_KING,9999,ACCOUNTING ,1111,RESEARCH PL/SQL procedure successfully completed.
На этом завершается тестирование трех ролей рассматриваемого примера. Все требования удовлетворены - безопасность данных обеспечена, и они стали прозрачными для приложения.
Во время создания вышеописанного приложения я натолкнулся на некоторые ошибки и должен был его отлаживать. Так как детальный контроль доступа работает на сервере, то при обнаружении ошибок и отладке приложения могут возникнуть сложности. Следующий раздел поможет успешной отладке и обнаружению ошибок.
Во время разработки процедур детального контроля доступа могут появиться четыре основных кода ошибок Oracle:
-
ORA-28110: функция политики или пакет <имя_функции> содержит ошибки. Это означает, что связанный с политикой пакет или функция содержат ошибки и не могут быть скомпилированы. Ошибки можно увидеть, если выполнить "show errors function <имя_функции>" или "show errors package body <имя_пакета>".
- ORA-28112: ошибка при выполнении функции политики. Возникает, если ошибка появляется во время выполнения предикатной функции. Это может произойти, например, когда при выполнении предложения SELECT INTO, находящегося внутри PL/SQL-функции, строки не найдены, и для этой ситуации нет обработчика исключений. Функция распространяет исключение NO_DATA_FOUND обратно в точку вызова (в ядро базы данных), и база данных инициирует ошибку ORA-28112.
- ORA-28113: предикат политики содержит ошибки. Эта ошибка возникает, когда предикатная функция успешно возвращает условие where, но при его добавлении к SQL-запросу внутри него обнаруживаются ошибки. Например, в том случае, когда возвращается условие where типа "x = 5", а таблица, с которой оно ассоциируется, не имеет столбца "x", буден получен код ошибки ORA-28113.
- ORA-28106: входное значение аргумента #2 неверно. Эта ошибка возникает при обращении к dbms_session.set_context, если имя атрибута не является правильным идентификатором Oracle. Имена атрибутов контекста приложения должны быть правильными идентификаторами (т.е. их можно использовать для назначения имен столбцов таблиц или PL/SQL-переменных). Необходимо только изменить имя атрибута. Например, в приложении могут использоваться атрибуты ‘SEL’, ‘INS’, ‘UPD’ и ‘DEL’ вместо ‘SELECT’, ‘INSERT’ и так далее, потому что ‘SELECT’ не является правильным именем идентификатора Oracle.
При написании предикатных функций я часто пользуюсь одной утилитой - это пакет ‘debug’. Этот пакет, автором которого является Кристофер Бек (Christopher Beck) из Oracle, позволяет вставить в код предложения команду ‘print’. Кроме того, этот пакет позволяет широко использовать предложения типа:
create function foo … as … begin debug.f( ‘Входвпроцедуру foo’ ); if ( some_condition ) then l_predicate := ‘x=1’; end if;
debug.f( ‘Переходквозвратупредиката "%s"’, l_predicate ); return l_predicate; end;
Таким образом, работа процедуры debug.f похожа на с-функцию printf, а сама она использует пакет UTL_FILE. На сервере базы данных она создает управляемые программистом файлы трассировки. Файлы трассировки содержат отладочные предложения, которые можно использовать для просмотра выполненных действий при выполнении кода. Так как программный код находится в ядре базы данных, отладка может оказаться сложной. Наличие файлов трассировки может сэкономить много времени. Скрипты, которые можно загрузить (см. далее в этом же разделе) содержат отладочный пакет и комментарии по его установке и использованию.
Существует много за эту возможность и совсем немного против . Фактически, сложно вообще найти хотя одно против этой возможности. Как бы то ни было, они перечислены ниже:
За |
Против |
Упрощает разработку приложения - переносит управление доступом из приложения на уровень данных.
|
Отладка может оказаться сложной, так как детальный контроль доступа осуществляется в фоновом режиме. Для этой цели более подходят пакеты типа ‘debug’, о которых идет речь в секции диагностики и отладки. |
Гарантирует полную защиту информации базы данных. Независимо от средства доступа к данным, гарантируется, что политика безопасности подключена и не может быть проигнорирована. |
|
Допускает значительные изменения политики безопасности без влияния на клиентские приложения. |
|
Упрощает управление объектами базы данных. Уменьшается общее число объектов базы данных, необходимых для поддержки приложения. |
|
Хорошо работает. Использование контекстов приложения позволяет воспользоваться преимуществами разделяемого SQL. |
|
Скрипты
Для того, чтобы получить все скрипты, используемые в этой статье, загрузите tar-файл. Пожалуйста, непременно прочитайте файл README.TXT, входящий в состав архива. Tar-файл можно открыть под Windows с помощью WinZip версии 6.0 и выше.
|