Теперь присоединимся различными пользователями и протестируем функциональность приложения.
SQL> @rls_adams
SQL> -- Присоединимся как служащий, у которого нет способности управлять.
SQL> connect rls_adams/rls_adams
Connected.
SQL> set serveroutput on
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;
return g_sel_pred; end;
Полученный результат - это результат выполнения raise_application_error в предикатной функции. Конечный пользователь получает сообщение об ошибке ORA-28112. Далее, в следующей секции, мы рассмотрим, как обнаружить эти ошибки и отладить их.
Далее установим такую роль, чтобы можно было что-нибудь сделать, и попробуем выполнить эти же операции:
SQL> -- Теперь установим корректную роль и выполним что-нибудь
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> -- посмотрим контекст и данные, 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, можно:
Просматривать не только свои данные. Видно всех, кто нам подчинен и тех, кто подчинен нашим подчиненным и так далее (по иерархии).
Изменять некоторые данные. Точнее, можно изменять только те записи, которые относятся к нашим непосредственным подчиненным - что и требуется.
Ни над какими данными все еще нельзя выполнить DELETE или INSERT - что и требуется
И, наконец, присоединимся как контролер и посмотрим на поведение приложения при работе с этой ролью:
SQL> -- Присоединимся как контролер SQL> connect rls_king/rls_king Connected.
SQL> -- Подключим возможность вывода на экран из PL/SQL SQL> set serveroutput on
SQL> -- Для начала, попробуем стать контролером SQL> -- Теперь мы являемся контролером, так как SQL> -- стать им разрешено
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> -- посмотрим на результат изменения, удаления 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 похожа на с-функцию printf, а сама она использует пакет UTL_FILE. На сервере базы данных она создает управляемые программистом файлы трассировки. Файлы трассировки содержат отладочные предложения, которые можно использовать для просмотра выполненных действий при выполнении кода. Так как программный код находится в ядре базы данных, отладка может оказаться сложной. Наличие файлов трассировки может сэкономить много времени. Скрипты, которые можно загрузить (см. далее в этом же разделе) содержат отладочный пакет и комментарии по его установке и использованию.
Существует много за эту возможность и совсем немного против . Фактически, сложно вообще найти хотя одно против этой возможности. Как бы то ни было, они перечислены ниже:
За
Против
Упрощает разработку приложения - переносит управление доступом из приложения на уровень данных.
Отладка может оказаться сложной, так какдетальный контроль доступа осуществляется в фоновом режиме. Для этой цели более подходят пакеты типа ‘debug’, о которых идет речь в секции диагностики и отладки.
Гарантирует полную защиту информации базы данных. Независимо от средства доступа к данным, гарантируется, что политика безопасности подключена и не может быть проигнорирована.
Допускает значительные изменения политики безопасности без влияния на клиентские приложения.
Упрощает управление объектами базы данных. Уменьшается общее число объектов базы данных, необходимых для поддержки приложения.
Хорошо работает. Использование контекстов приложения позволяет воспользоваться преимуществами разделяемого SQL.
Для того, чтобы получить все скрипты, используемые в этой статье, загрузите tar-файл. Пожалуйста, непременно прочитайте файл README.TXT, входящий в состав архива. Tar-файл можно открыть под Windows с помощью WinZip версии 6.0 и выше.