Jak na leniucha nadać/zabrać uprawnienia do wszystkich tabel?



Uprawnienia w bazach danych to soczysty kawałek chleba. Odpowiednie nadanie uprawnień to klucz do bezpieczeństwa danych. Nie należy uprawnień nadawać hojną ręką, bez należytego uzasadnienia.

Są jednak tacy użytkownicy w systemach lub sytuacje, gdzie te uprawnienia możemy i chcemy nadawać szczodrze, praktycznie bez większej weryfikacji. Może to być w przypadku użytkownika/roli technicznej, gdzie użytkownik ten powinien mieć dostęp do wszystkich tabel/obiektów w kilku schematach ale nie powinien mieć uprawnień dba. Możemy też chcieć nadać uprawnienia do wszystkich tabel w systemach testowych czy developerskich. W takich przypadkach przydałoby nam się jakieś sprytne narzędzie, które zrobiłoby to za nas.

Jak nadać uprawnienia do tabel użytkownikowi?
Nadajemy uprawnienia do tabeli takie jak SELECT, INSERT, DELETE, UPDATE lub w skrócie ALL używając polecenia GRANT .

GRANT SELECT, UPDATE, DELETE, INSERT ON <table_name> to <user_name>
GRANT ALL ON <table_name> to <user_name>

Usuwamy za pomocą polecenia REVOKE.

REVOKE SELECT, UPDATE, DELETE, INSERT ON <table_name> FROM <user_name>
REVOKE ALL ON <table_name> FROM <user_name>

Tylko że te uprawnienia nadajemy tylko dla pojedynczej tabeli. Nie ma niestety czegoś w stylu GRANT ALL ON ALL TABLES :D . Ale. Od czego mamy tabele słownikowe i EXECUTE IMMEDIATE! EXECUTE IMMEDIATE jest bardzo niewydajne i z reguły nie zalecam używania ale do takich jednorazowych akcji się nada.

---------------------------------------------------------------------------------------------------------------------------------
-- grant to all tables
---------------------------------------------------------------------------------------------------------------------------------

set serveroutput on

DECLARE 
vUserName  ALL_TABLES.OWNER%TYPE  := 'PERF_IDX';
vOwnerName ALL_TABLES.OWNER%TYPE  := 'HR';
BEGIN

    FOR z IN (
        SELECT owner, table_name 
        FROM all_tables 
        WHERE owner = vOwnerName
    )
    LOOP 
      
        EXECUTE IMMEDIATE 
           'GRANT SELECT, UPDATE, DELETE, INSERT ON ' || z.owner||'.' || z.table_name|| '  to '|| vUserName ;     
    END LOOP;

END; 

/
---------------------------------------------------------------------------------------------------------------------------------
-- revoke from all tables
---------------------------------------------------------------------------------------------------------------------------------

set serveroutput on

DECLARE 
vUserName  ALL_TABLES.OWNER%TYPE  := 'PERF_IDX';
vOwnerName ALL_TABLES.OWNER%TYPE  := 'HR';
vSql varchar2(500);
BEGIN

    FOR z IN (
        SELECT owner, table_name 
        FROM all_tables 
        WHERE owner = vOwnerName
    )
    LOOP
        vSql := 'REVOKE SELECT, UPDATE, DELETE, INSERT ON ' || z.owner||'.' || z.table_name|| '  from '|| vUserName ; 
        
        dbms_output.put_line(vsql);
        EXECUTE IMMEDIATE 
           vsql;
    END LOOP;

END; 

/

A co jeśli byśmy chcieli by automatycznie po utworzeniu tabeli - były nadawane użytkownikowi uprawnienia do niej? 

Możemy to zrobić wykorzystując triger DDL. Jest tylko jeden haczyk - ponieważ nadawanie uprawnień należy również do poleceń DDL - nie możemy wykonać poleceń GRANT czy REVOKE bezpośrednio z trigera. Ale możemy utworzyć joba z poleceniem nadania uprawnień. I voila, recepta na automatyczne nadawanie uprawnień gotowa.

Procedura do nadawania uprawnień. Procedura będzie uruchomiona z joba.
create or replace procedure grant_all_on_table(pvTableName varchar2, pvUserName varchar2 , pvOwner varchar2) is

begin
   EXECUTE IMMEDIATE  'GRANT SELECT, UPDATE, DELETE, INSERT ON ' ||pvOwner||'.'|| pvTableName ||   ' TO ' || pvUserName ;    
end;

Triger DDL - AFTER CREATE ON SCHEMA. Żeby ograniczyć wykonywanie tylko do tabel wykorzystamy atrybuty:

sys.dictionary_obj_type = typ obiektu, nas interesują tylko TABELE
sys.dictionary_obj_name - nazwa obiektu
sys.dictionary_obj_owner  - właściciel obiektu

Do uruchomienia joba wykorzystam proccedurę  dbms_job.submit.

create or replace trigger tab_priv_grants after create  on schema
declare
 iJobId integer;
 vsql varchar2(500);
begin
     IF SYS.DICTIONARY_OBJ_TYPE = 'TABLE' then 
       vsql := 'BEGIN grant_all_on_table( pvTableName => '''|| sys.dictionary_obj_name || ''' , 
                                          pvUserName => ''PERF_IDX'' , 
                                          pvOwner => '''||sys.dictionary_obj_owner ||''') ; 
                '|| ' END;';
      
      dbms_output.put_line(vsql);
       dbms_job.submit( iJobId,
                     vsql,
                    sysdate +3/86400 );
      end if ;

end;


Test przeprowadziłam na schemacie HR oraz nowo utworzonym użytkowniku PERF_TEST.

-- hr user
create table test_grants (a number);

--perf_test user
select * from hr.test_grants;
ORA-00942: tabela lub perspektywa nie istnieje
00942. 00000 -  "table or view does not exist"
*Cause:    
*Action:
Error at Line: 1 Column: 18

--- after 3 seconds
no rows selected


Działa :D
--------------------------------------------------------------------------------------------------------------------------
A na koniec kod z wieloma zmiennymi, którymi można sobie sterować, jakie uprawnienia nadać. Czy nadać czy odebrać. Jeden z tych kodów, które bardzo fajnie się pisało, a które prawdopodobnie nigdy nie będą użyte. Łatwiej jest puścić zwykły skrypt z  ręki niż bawić się ustawianie tylu zmiennych :D Ale co tam, fajnie się pisało :D

set serveroutput on

DECLARE 
vUserName  ALL_TABLES.OWNER%TYPE  := 'PERF_IDX';
vOwnerName ALL_TABLES.OWNER%TYPE  := 'HR';
-------------------------------------------
bGrants_Revokes varchar2(1) := 'G';  --G - grants /R - revokes
-------------------------------------------
bSel boolean := true;
bUpd boolean := true;
bDel boolean := true;
bIns boolean := true;
-------------------------------------------
bExecute boolean := true;
-------------------------------------------
vSql varchar2(200);
vSqlGrants varchar2(200);
eNoGrants exception;
BEGIN


if (bSel or bUpd or bDel or bIns) = false 
then
   raise eNoGrants;
end if;

vSqlGrants :=  case bGrants_Revokes when 'G' then  'GRANT ' else 'REVOKE ' end||  
                    case when  bSel =  true then  'SELECT, ' end ||
                    case when  bUpd =  true then  'UPDATE, ' end ||
                    case when  bDel =  true then  'DELETE, ' end ||
                    case when  bIns =  true then  'INSERT, ' end ;

-- cut last ,
vSqlGrants := substr(vSqlGrants, 1, length(trim(vSqlGrants)) -1);       


    FOR z IN (
        SELECT owner, table_name 
        FROM all_tables 
        WHERE owner = vOwnerName
    )
    LOOP
    vSql := vSqlGrants || ' ON '||z.owner||'.'||z.table_name|| 
            case bGrants_Revokes when 'G' then  ' TO ' else ' FROM ' end|| vUserName;
   
    dbms_output.put_line (vSql);
  
    if bExecute then 
        EXECUTE IMMEDIATE 
            vSql;
    end if;
    
    END LOOP;

exception  when eNoGrants then 
    dbms_output.put_line ('No grants was specified');
END; 

/


Komentarze