调用者权限过程的权限问题 |
中国自学编程网收集整理 发布日期:2008-04-25 进入论坛 |
首先描述一下当时我碰到的问题:我写了一个存储过程,要在其中使用DBMS_METADATA过程获取另一个用户的某对象的定义。 SQL> CREATE OR REPLACE PROCEDURE P_TEST AS 2 BEGIN 3 FOR I IN (SELECT DBMS_METADATA.GET_DDL(’TABLE’, ’DUAL’, ’SYS’) DEFINE FROM DUAL) LOOP 4 DBMS_OUTPUT.PUT_LINE(SUBSTR(I.DEFINE, 1, 255)); 5 END LOOP; 6 END; 7 / 过程已创建。 SQL> SET SERVEROUT ON SIZE 1000000 SQL> EXEC P_TEST BEGIN P_TEST; END; * ERROR 位于第 1 行: ORA-31603: 对象 \"DUAL\" 属于类型 TABLE, 在方案 \"SYS\" 中未找到 ORA-06512: 在\"SYS.DBMS_SYS_ERROR\", line 105 ORA-06512: 在\"SYS.DBMS_METADATA\", line 628 ORA-06512: 在\"SYS.DBMS_METADATA\", line 1221 ORA-06512: 在line 1 ORA-06512: 在\"YANGTK.P_TEST\", line 3 ORA-06512: 在line 1 过程在编译是没有报错,而在执行时报错。但是,如果单独执行上面的SQL是没有问题的: SQL> SELECT DBMS_METADATA.GET_DDL(’TABLE’, ’DUAL’, ’SYS’) FROM DUAL; DBMS_METADATA.GET_DDL(’TABLE’,’DUAL’,’SYS’) ------------------------------------------------------------------------- CREATE TABLE \"SYS\".\"DUAL\" ( \"DUMMY\" VARCHAR2(1) ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 32768 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE \"SYSTEM\" 当时认为,直接在SQL中可以运行,而在存储过程中不能运行,说明是角色的问题。存储过程中角色无效,导致了在执行DBMS_METADATA.GET_DDL过程时缺少权限。于是考虑使用调用者权限存储过程。因为调用者权限过程不会屏蔽角色: SQL> CREATE OR REPLACE PROCEDURE P_TEST AUTHID CURRENT_USER AS 2 BEGIN 3 FOR I IN (SELECT DBMS_METADATA.GET_DDL(’TABLE’, ’DUAL’, ’SYS’) DEFINE FROM DUAL) LOOP 4 DBMS_OUTPUT.PUT_LINE(SUBSTR(I.DEFINE, 1, 255)); 5 END LOOP; 6 END; 7 / 过程已创建。 SQL> EXEC P_TEST CREATE TABLE \"SYS\".\"DUAL\" ( \"DUMMY\" VARCHAR2(1) ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 32768 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL PL/SQL 过程已成功完成。 再次运行过程,这次执行成功。 一直就认为是角色导致的问题,而没有继续深究。而这次仔细看了Tom对定义者权限和调用者权限存储过程的描述才真正彻底清楚了导致上述现象的原因。 一个调用者权限的存储过程,如果在定义者权限存储过程中被调用,则它的行为表现将像一个定义者权限的过程。这时由于定义者权限过程中,CURRENT_SCHEMA和所拥有的权限都是固定的,调用者权限过程中所有可能发生变化的东西都被固定了下来。 而如果直接调用或者通过调用者权限过程来调用,那么这个调用者权限过程的全部特性得以保留。而这就是上面碰到的那个问题的真正答案。 DBMS_METADATA.GET_DDL本身是一个调用者权限过程: SQL> SELECT OBJECT_NAME, PROCEDURE_NAME, AUTHID FROM DBA_PROCEDURES 2 WHERE OBJECT_NAME = ’DBMS_METADATA’ AND PROCEDURE_NAME = ’GET_DDL’; OBJECT_NAME PROCEDURE_NAME AUTHID ------------------------------ ------------------------------ ------------ [Page] DBMS_METADATA GET_DDL CURRENT_USER 所以,当通过SQL直接调用或通过调用者权限存储过程调用时,Oracle运行没有问题,而通过定义者权限存储过程调用时,因为缺少了角色的权限而失败。 |
==============================================================
角色(数据库权限集)与存储过程、函数和数据包之间的交互方式是Oracle安全模型中最难以处理的一个部分。Oracle中的对象权限可以直接或通过角色间接授予用户。 假设一个HR用户向用户ABEL授予EMPLOYEES表的一些许可: GRANT select, insert, update, delete 这个语句直接把上述四个权限授予给用户ABEL。另一方面,假设一名HR用户这样做: GRANT select, insert, update, delete ON employees TO hr_role; 假如ABEL已被授予HR_ROLE角色,那么他现在通过这个角色就直接拥有了以上权限。 不管使用哪种方法,现在ABEL都拥有了HR.EMPLOYEES表的SELECT权限。假如ABEL通过SELECT语句直接从表中选择数据,那么他如何获得许可并不重要。 但是,假如ABEL试图建立从这个表中选择的存储过程、函数或数据包,那么他是直接获得许可,还是通过角色取得许可就存在很大差异。 Oracle要求直接向用户授予一个存储过程中的非拥有对象许可。在编辑过程中角色被临时关闭,用户不能访问授予给他们的任何内容。这样做是出于性能和安全考虑。 角色可以通过SET ROLE命令动态激活和禁用,假如Oracle需要不断检查哪个角色和许可当前处于激活状态,则会带来巨大的治理负担。 下面的代码是一个更新HR雇员文件的简短存储过程(这段代码用一个同义字EMPLOYEES来代表HR.EMPLOYEES)。当ABEL在第一种情况下试图用直接权限编辑这个文件时,编辑取得成功;当他在第二种情况下仅用间接权限编辑时,编辑失败。 CREATE OR REPLACE PROCEDURE update_emp ( p_employee_id IN NUMBER ,p_salary IN NUMBER ) AS v_department_idemployees.department_id%TYPE; BEGIN SELECT department_id INTO v_department_id FROM employees WHERE employee_id = p_employee_id; UPDATE employees SET salary = p_salary WHERE employee_id = p_employee_id; IF v_department_id = 100 THEN UPDATE local_employees SET salary = p_salary WHERE employee_id = p_employee_id; END IF; END; / 有趣的是,向PUBLIC授予许可和直接授予所有用户许可相同。PUBLIC常被认为是一个角色,但它并不是一个角色。它是一个用户集而不是一个许可集。假如向PUBLIC授权HR.EMPLOYEES的许可,ABEL将能够建立他自己的存储过程。虽然在EMPLOYEES表中我们不推荐这样做,但任何授予给PUBLIC的表都可以自由地在存储过程中应用。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/523774/viewspace-374314/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/523774/viewspace-374314/