Execute dynamic DDL in PL/SQL procedure through definer role permissions

与世无争的帅哥 提交于 2019-12-06 06:20:33

问题


I want to perform some dynamic DDL in a procedure owned by an admin user. I'd like to execute this procedure with a technical operational user with definer rights (operational user doesn't have the create table role).

The problem is the 'create table' permission is granted to the admin user through use of a role, which doesn't allow me to execute the DDL as it seems that roles don't count in named pl/sql blocks.

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;

What I tried:

  • Running the procedure from a function set to AUTHID DEFINER with AUTHID CURRENT_USER on the proc (hoping the function would cascade the definer somehow)
  • Putting an anonymous block inside the function to execute the DDL (as roles seem to count in anonymous block)

If I set the AUTHID to CURRENT_USER, I can execute the procedure correctly with the admin user.

Is there any way I can work around this without granting CREATE TABLE directly to the admin user?


回答1:


You can only set a role within a PL/SQL stored procedure/function if it has Invoker's Rights (AUTHID CURRENT_USER)(see doc). Which means that you can't use ops_user to call admin_user's procedure and then access admin_user's roles. If your DBAs insist on using a role to control the CREATE TABLE privilege, here's the approach I've seen before:

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;

This will temporarily grant the role to ops_user just to execute your code. By default the ops_user should not be able to view the admin_user's package body source. You could probably wrap the package body to further protect the password. But password security aside, my biggest concern with this approach is that Oracle doesn't provide a nice way to disable a single role, so if ops_user has other password-protected roles, this code might raise an ORA-01979 when it tries to restore them.

So, there's an answer, but I'd still recommend doing what the other commenters suggested and granting CREATE TABLE to your admin user.



来源:https://stackoverflow.com/questions/45411898/execute-dynamic-ddl-in-pl-sql-procedure-through-definer-role-permissions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!