通过定义者角色权限在 PL/SQL 过程中执行动态 DDL
Execute dynamic DDL in PL/SQL procedure through definer role permissions
我想在管理员用户拥有的过程中执行一些动态 DDL。我想与具有定义者权限的技术操作用户一起执行此过程(操作用户没有创建 table 角色)。
问题是 'create table' 权限是通过使用角色授予管理员用户的,这不允许我执行 DDL,因为角色似乎不计入命名 pl/sql块。
create or replace
PROCEDURE test_permissions AUTHID DEFINER AS
v_query_string VARCHAR2(400 CHAR) := 'CREATE TABLE TEST(abcd VARCHAR2(200 CHAR))';
BEGIN
EXECUTE IMMEDIATE v_query_string;
END;
我尝试了什么:
- 运行 从函数设置为 AUTHID DEFINER 的过程在过程中使用 AUTHID CURRENT_USER(希望函数会以某种方式级联定义器)
- 将匿名块放入函数中以执行 DDL(因为角色似乎计入匿名块)
如果我将 AUTHID 设置为 CURRENT_USER,我可以使用 admin 用户正确执行该过程。
有什么办法可以解决这个问题而不直接将 CREATE TABLE 授予管理员用户?
您只能在 PL/SQL 存储的 procedure/function 中设置角色,前提是它具有 调用者权限 (AUTHID CURRENT_USER
)(see doc).这意味着您不能使用 ops_user 调用 admin_user 的过程然后访问 admin_user 的角色。如果您的 DBA 坚持使用角色来控制 CREATE TABLE
权限,这是我以前见过的方法:
create or replace package admin_user.role_test authid current_user is
procedure test_permissions;
end role_test;
/
create or replace package body admin_user.role_test is
procedure test_permissions is
v_query_string VARCHAR2(400 CHAR) := 'begin
dbms_output.put_line(''after'');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
end;';
begin
dbms_output.put_line('before');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
DBMS_SESSION.SET_ROLE('CREATE_TABLE_ROLE IDENTIFIED BY "SECRET_PASSWORD"');
execute immediate v_query_string;
DBMS_SESSION.SET_ROLE('ALL EXCEPT CREATE_TABLE_ROLE'); -- restore defaults
end;
end role_test;
/
grant execute on admin_user.role_test to ops_user;
这将临时授予 ops_user 角色以执行您的代码。默认情况下,ops_user 应该无法查看 admin_user 的包主体源。您可能可以包装包体以进一步保护密码。但是撇开密码安全不谈,我对这种方法最大的担忧是 Oracle 没有提供禁用单个角色的好方法,因此如果 ops_user 有其他受密码保护的角色,这段代码可能会在以下情况下引发 ORA-01979它试图恢复它们。
所以,有一个答案,但我仍然建议按照其他评论者的建议进行操作,并向您的管理员用户授予 CREATE TABLE。
我想在管理员用户拥有的过程中执行一些动态 DDL。我想与具有定义者权限的技术操作用户一起执行此过程(操作用户没有创建 table 角色)。
问题是 'create table' 权限是通过使用角色授予管理员用户的,这不允许我执行 DDL,因为角色似乎不计入命名 pl/sql块。
create or replace
PROCEDURE test_permissions AUTHID DEFINER AS
v_query_string VARCHAR2(400 CHAR) := 'CREATE TABLE TEST(abcd VARCHAR2(200 CHAR))';
BEGIN
EXECUTE IMMEDIATE v_query_string;
END;
我尝试了什么:
- 运行 从函数设置为 AUTHID DEFINER 的过程在过程中使用 AUTHID CURRENT_USER(希望函数会以某种方式级联定义器)
- 将匿名块放入函数中以执行 DDL(因为角色似乎计入匿名块)
如果我将 AUTHID 设置为 CURRENT_USER,我可以使用 admin 用户正确执行该过程。
有什么办法可以解决这个问题而不直接将 CREATE TABLE 授予管理员用户?
您只能在 PL/SQL 存储的 procedure/function 中设置角色,前提是它具有 调用者权限 (AUTHID CURRENT_USER
)(see doc).这意味着您不能使用 ops_user 调用 admin_user 的过程然后访问 admin_user 的角色。如果您的 DBA 坚持使用角色来控制 CREATE TABLE
权限,这是我以前见过的方法:
create or replace package admin_user.role_test authid current_user is
procedure test_permissions;
end role_test;
/
create or replace package body admin_user.role_test is
procedure test_permissions is
v_query_string VARCHAR2(400 CHAR) := 'begin
dbms_output.put_line(''after'');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
end;';
begin
dbms_output.put_line('before');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
DBMS_SESSION.SET_ROLE('CREATE_TABLE_ROLE IDENTIFIED BY "SECRET_PASSWORD"');
execute immediate v_query_string;
DBMS_SESSION.SET_ROLE('ALL EXCEPT CREATE_TABLE_ROLE'); -- restore defaults
end;
end role_test;
/
grant execute on admin_user.role_test to ops_user;
这将临时授予 ops_user 角色以执行您的代码。默认情况下,ops_user 应该无法查看 admin_user 的包主体源。您可能可以包装包体以进一步保护密码。但是撇开密码安全不谈,我对这种方法最大的担忧是 Oracle 没有提供禁用单个角色的好方法,因此如果 ops_user 有其他受密码保护的角色,这段代码可能会在以下情况下引发 ORA-01979它试图恢复它们。
所以,有一个答案,但我仍然建议按照其他评论者的建议进行操作,并向您的管理员用户授予 CREATE TABLE。