Новое в 8i: полномочия предъявителя в PL/SQL
Новое в 8i: полномочия предъявителя в PL/SQL
Владимир Пржиялковский
16 февраля 2000 г.
Версия Oracle 8i (8.1), выпущенная в 1999 году после долгих задержек, содержит большой объем нововведений (как утверждает сама фирма, “более 150”). Многие из них коснулись такой базовой компоненты, как PL/SQL. Несмотря на появление у разработчика альтернативы в виде Java (говорят, в фирме Oracle долго спорили по поводу перспектив выбора языка программирования для системы, но, в конце концов, пришли к Соломонову решению), PL/SQL остается наиболее эффективным встроенным языком в Oracle, превосходя по своим возможностям аналоги конкурентов – Informix 4GL и Sybase/Microsoft Transact-SQL. Тем обиднее, что некоторые качества PL/SQL появляются только сейчас, в версии 8.1, а не были встроены 10 лет назад, в результате чего разработчики оказались лишены, казалось бы, естественных возможностей и тратили свои усилия на придумывание ухищрений, ныне лишенных смысла. Особенно обидно, когда речь идет о синтаксических конструкциях, исчерпывающихся всего парой слов, но меняющих, несмотря на это, значительную часть архитектуры создаваемого кода.
Одно из таких “микро-нововведений”, приближающих логику функционирования кода на PL/SQL логике исполнения программ в Unix, рассмотрим сегодня. Речь идет о так называемых “полномочиях предъявителя” (invoker rights) для процедур на PL/SQL.
Полномочия создавшего, прежде единственные
В версиях 7 и 8.0 единственной логикой контроля доступа к объектам БД из процедуры на PL/SQL была логика “полномочия создавшего” (definer rights). Процедура всегда создается от какого-нибудь имени пользователя Oracle. Вызываться она может и другим пользователем (владеющим на это правом, данным с помощью предложения GRANT EXECUTE), но при попытке работать с объектами БД – таблицами, последовательностями – права на доступ к этим объектам в предыдущих версиях соответствовали полномочиям создателя процедуры. (Сейчас это верно только по умолчанию, если специально не оговорить другую схему работы). Вот некоторые свойства такой модели полномочий:
все внешние ссылки в программе должны быть разрешены на этапе трансляции с помощью прямой передачи полномочий пользователю, от имени которого транслируется программа
имеющиеся роли на этапе трансляции не действуют
права на доступ к объектам БД на этапе выполнения процедуры полностью совпадают с правами пользователя-создателя процедуры
хотя “транслирующий” пользователь и должен иметь полномочия на работу с используемыми в процедуре объектами, пользователь, вызывающий программу, иметь такие полномочия не обязан
Такая логика работы имеет определенные преимущества. Вот, примерно, как их формулировали в фирме Oracle:
Такая модель позволяет улучшить контроль работы с данными. Работу с таблицей можно организовать так, что изменение ее содержимого станет пользователям Oracle возможно только посредством обращения к определенным процедурам.
Процедуры работают быстро, потому что не тратят время на проверку прав доступа во время исполнения.
Разработчик не должен беспокоиться о том, что может быть ненамеренно модифицирована не та таблица – все объекты жестко предопределены.
Звучит разумно.
Проблемы с полномочиями создавшего
Тем не менее, 90% разработчиков сознаются, что использование модели “полномочий создавшего” доставляет им непрерывную головную боль из-за необходимости придумывать специальные ухищрения, в конечном счете негативно сказывающиеся на архитектуре создаваемой системы.
Вот типичный случай. Пусть создается система по схеме “центр – территориальные отделения”. Все территориальные отделения (ТО) однородны по сути и работают с одними и теми же программами, но каждое со своими собственными данными. Пусть все обслуживается одним сервером БД (например, работа идет через Internet). Тогда логично (и правильно с точки зрения безопасности и разграничения доступа) дать каждому ТО по самостоятельному имени в БД и по отдельной схеме данных. Другое дело, что схемы эти будут у всех одинаковы. И одинаковым должен быть код программ, работающих с данными.
Для кода напрашивается (логически правильное) решение: создать отдельную схему БД, скажем, с именем COMMON, и в ней создавать сами PL/SQL-пакеты и процедуры. Но как ими будут пользоваться ТО ? Обратиться к процедуре просто new_employee ТО не может, так как процедура ему не принадлежит. Обратиться COMMON.new_employee тоже нельзя, потому что схема COMMON не владеет данными вызывающего ТО, а кроме того помещать в код приложения имя схемы тоже не всегда правильно.
Прежде в таких ситуациях приходилось копировать пакеты из COMMON в схемы ТО (см. рисунок) – во многих отношениях не лучшее решение, но часто единственно приемлемое.
Полномочия предъявителя
Синтаксис указания полномочий предъявителя чрезвычайно прост: в заголовке процедуры или функции перед словом IS или AS надо написать AUTHID CURRENT_USER. (Соответственно появившееся вариантное указание AUTHID DEFINER вступает в силу при отсутствии указаний). Модель прав предъявителя работает по следующим правилам:
Для разрешения внешних ссылок при выполнении программы анализируются роли пользователя, запустившего программу.
Предложение AUTHID можно использовать лишь в заголовках отдельных программ, пакетов и спецификаций объектного типа. Предложение AUTHID нельзя использовать в отдельных программах или методах из состава пакета или описания типа объекта.
Вот перечень предложений, для которых права доступа проверяются динамически во время исполнения программы:
SELECT, INSERT, UPDATE, DELETE
LOCK TABLE
OPEN и OPEN-FOR для курсоров
EXECUTE IMMEDIATE и OPEN-FOR-USING предложения динамического SQL
SQL-предложения, транслируемые программой
Внешние ссылки на PL/SQL-программы и методы объектов разрешаются во время компиляции по правилам создавшего. Вот как примером разъясняет такое положение дел Стивен Фойерштайн (применение предложения AUTHID CURRENT_USER выделено серым фоном):
/* Basic demonstration of AUTHID CURRENT_USER feature */
CONNECT demo/demo
CREATE PROCEDURE dummy1 IS
BEGIN
DBMS_OUTPUT.put_line ('Dummy1 owned by demo');
END;
/
GRANT execute on dummy1 to public;
CONNECT scott/tiger
CREATE PROCEDURE dummy1 IS
BEGIN
DBMS_OUTPUT.put_line ('Dummy1 owned by scott');
END;
/
GRANT execute on dummy1 to public;
CREATE PROCEDURE dummy2 AUTHID CURRENT_USER
IS
BEGIN
dummy1;
END;
/
GRANT execute on dummy2 to public;
EXEC scott.dummy2
CONNECT demo/demo
SET serveroutput on
EXEC scott.dummy2
Результаты вызова dummy2 от имени SCOTT и от имени DEMO разные.
Совсем по-другому будет выглядеть теперь схема использования программ территориальными отделениями (см. рисунок).
Какую модель когда использовать ?
Применение модели “полномочий предъявителя” возможно и в других ситуациях, помимо приведенной. Оно полезно, когда администратор (или кто-нибудь из разработчиков) создает программы общего назначения для всех пользователей. Вот еще одна простая иллюстрация из Стивена Фойерштайна:
CREATE OF REPLACE PROCEDURE runddl (ddl_in in VARCHAR2)
AUTHID CURRENT_USER
IS
BEGIN
EXECUTE IMMEDIATE ddl_in;
END;
/
EXECUTE IMMEDIATE – еще одно нововведение версии 8i, требующее особого разговора; здесь же важно, что мы имеем возможность дать всем пользователям общую и полезную процедуру, не утруждая себя кухней проверки прав. Вся ответственность за корректное обращение с данными ложится на пользователя, вызвавшего процедуру.
Но вернемся к перечню “преимуществ модели полномочий создавшего” выше. Он не теряет своей актуальности, и отказываться от этой модели полностью было бы неразумно. Очевидно, что несколько запоздалое нововведение Oracle добавляет разработчику не одну, а две дополнительные возможности для построения архитектуры программной системы: кроме возможности использования чистой модели полномочий создавшего (как раньше) появляется и возможность использования чистой модели полномочий предъявителя, и возможность комбинированного использования обеих моделей. Последний вариант – самый неоднозначный в плане конкретной реализации, так как теоретически охватывает все возможные комбинации разделения/обобществления (в “центральной” схеме) данных и разделения/обобществления кода. Выбор из этого множества конкретной комбинации для своей задачи должен быть сделан разработчиком взвешенно и ответственно.
|