Implementacija modela uloge pristupa korišćenjem Row Level Security u PostgreSQL

Razvoj teme Etid o implementaciji Row Level Security u PostgreSQL in za obsežno odgovornost na komentar.

Uporabljena strategija pomeni uporabo koncepta 'Poslovna logika v BDP', kar je bilo nekoliko podrobneje opisano tukaj — Etid o implementaciji poslovne logike na nivou sačuvanih funkcija PostgreSQL

Teorijski deo je odlično opisan u dokumentaciji Postgres Pro — Politike zaštite redova. Spodaj je obravnavana praktična izvedba konkretne poslovne naloge — rolni model dostopa do podatkov.

Implementacija modela uloge pristupa korišćenjem Row Level Security u PostgreSQL

U članku nema ničeg novog, nema skrivenog smisla ili tajnih znanja. Samo skica o praktičnoj realizaciji teorijske ideje. Ako nekoga zanima — čitajte. Onima kojima nije zanimljivo — nemojte trošiti vreme uzalud.

Definisanje zadatka

Zaradi vloge uporabnika aplikacije je potrebno omejiti dostop do ogledovanja/uložitev/spremembe/brisanja dokumenta. Pod vlogo se razume zapis v tabeli roles v zvezi z mnogimi na mnoge s tabelo users. Podrobnosti izvedbe tabel so bile zaradi trivialnosti izpuščene. Prav tako so izpuščene konkretne podrobnosti izvedbe, povezane s predmetno področje.

Implementacija

Ustvarjanje vlog, shem, tabelo

Ustvarjanje objektov BDP

CREATE ROLE store;
CREATE SCHEMA store AUTHORIZATION store;
CREATE TABLE store.docs
(
  id integer ,         --id dokumenta
  man_id integer , --id upravitelja dokumenta
  stat_id integer ,  --id statusa dokumenta
  ...
  is_del BOOLEAN DEFAULT FALSE 
);
ALTER TABLE store.docs ADD CONSTRAINT doc_pk PRIMARY KEY (id);
ALTER TABLE store.docs OWNER TO store ;

Ustvarjanje funkcij za izvajanje RLS

Preverjanje možnosti izvedbe SELECT vrstice

check_select

ZCREATE OR REPLACE FUNCTION store.check_select (current_id store.docs.id%TYPE) RETURNS boolean AS $$
DECLARE
  result boolean;
  curr_pid integer;
  curr_stat_id integer;
  doc_man_id integer;
BEGIN
  -- DBA ima pristup svim dokumentima
  IF SESSION_USER = 'curr_dba'
  THEN
    RETURN TRUE;
  END IF;
  --------------------------------

  --Ako dokument ima oznaku 'izbrisan' - ne prikazivati u selekciji
  SELECT
    is_del
  INTO
    result
  FROM
    store.docs
  WHERE
    id = current_id;
 IF result = TRUE
 THEN
   RETURN FALSE;
 END IF;
 --------------------------------

 --Dobiti id trenutnog korisnika
 SELECT
   service_function.get_curr_pid()
 INTO
   curr_pid;
 --------------------------------

 --Dobiti id menadžera dokumenta
 SELECT
   man_id
 INTO
   doc_man_id
 FROM
   store.docs
 WHERE
   id = current_id;
 --------------------------------

 --Ako menadžer dokumenta nije trenutni korisnik ili menadžer nije dodeljen
 --dodati dokument u selekciju
 IF doc_man_id != curr_pid OR doc_man_id IS NULL
 THEN
   RETURN TRUE;
 ELSE
   --Dobiti trenutni status dokumenta
   SELECT
     stat_id
   INTO
     curr_statid
   FROM
     store.docs
   WHERE
     id = current_id;
    
   --Ako status dozvoljava pregled dokumenta - dodati dokument u selekciju
   IF curr_statid = 4 OR curr_statid = 9
   THEN
     RETURN TRUE;
   ELSE
   --Inače - isključiti dokument iz selekcije
     RETURN FALSE;
    END IF;
  END IF;
  --------------------------------

 RETURN FALSE;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.check_select(store.docs.id%TYPE) OWNER TO store;
REVOKE EXECUTE ON FUNCTION store.check_select(store.docs.id%TYPE) FROM public;
GRANT EXECUTE ON FUNCTION store.check_select(store.docs.id%TYPE) TO service_functions; 

Provera mogućnosti izvršenja INSERT reda

check_insert

CREATE OR REPLACE FUNCTION store.check_insert (current_id store.docs.id%TYPE) RETURNS boolean AS $$
DECLARE
  curr_role_id integer;
BEGIN
  --DBA može dodavati red u svakom slučaju
  IF SESSION_USER = 'curr_dba'
  THEN
    RETURN TRUE;
  END IF;
  --------------------------------

 --Dobiti id uloge trenutnog korisnika
 SELECT
   service_functions.current_rid()
  INTO
    curr_role_id;
 --------------------------------

--Ako uloga dozvoljava mogućnost kreiranja novog dokumenta
--dozvoliti
IF curr_role_id = 3 OR curr_role_id = 5
THEN
  RETURN TRUE;
END IF;
--------------------------------
RETURN FALSE;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.check_insert(store.docs.id%TYPE) OWNER TO store;
REVOKE EXECUTE ON FUNCTION store.check_insert(store.docs.id%TYPE) FROM public;
GRANT EXECUTE ON FUNCTION store.check_insert(store.docs.id%TYPE) TO service_functions; 

Provera mogućnosti izvršenja DELETE reda

check_delete

CREATE OR REPLACE FUNCTION store.check_delete (current_id store.docs.id%TYPE)
RETURNS boolean AS $$
BEGIN
  --Samo DBA može brisati red
  IF SESSION_USER = 'curr_dba'
  THEN
    RETURN TRUE;
  END IF;
  --------------------------------

  RETURN FALSE;
END
$$ LANGUAGE plpgsql
SECURITY DEFINER;
ALTER FUNCTION store.check_delete(store.docs.id%TYPE) OWNER TO store;
REVOKE EXECUTE ON FUNCTION store.check_delete(store.docs.id%TYPE) FROM public;

Provera mogućnosti izvršenja UPDATE reda.

update_using

CREATE OR REPLACE FUNCTION store.update_using ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$
BEGIN  
   --Dokumenti s statusom 'izbrisan' - ne uređuju se
   IF is_del 
   THEN
     RETURN FALSE ;
 ELSE
    RETURN TRUE ;
  END IF ;

END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.update_using( store.docs.id%TYPE , boolean ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE , boolean ) FROM public;
GRANT EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE ) TO service_functions;

update_check

CREATE OR REPLACE FUNCTION store.update_with_check ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$
DECLARE
  current_rid integer ;
  current_statid integer ;
BEGIN                

  --DBA može pregledati red
  IF SESSION_USER = 'curr_dba'
  THEN
    RETURN TRUE ;
  END IF ;
  --------------------------------

 --Dobijanje id uloge trenutnog korisnika 
 SELECT
   service_functions.current_rid()
  INTO
    curr_role_id ;
 --------------------------------                            

 --Brisanje dokumenta - promjena stanja 
 IF is_deleted
 THEN
   --Ako je uloga korisnika ***
   IF current_role_id = 3        
   THEN
      SELECT
        stat_id                                          
      INTO
        curr_statid
      FROM
        store.docs
      WHERE
        id = current_id ;

      --Dokument u statusu *** ne može se obrisati 
      IF current_status_id = 11
      THEN
         RETURN FALSE ;
      ELSE
      --Može se obrisati dokument u drugim statusima
        RETURN TRUE ;
      END IF ;

    --Inače, ako je uloga korisnika ***
    ELSIF current_role_id = 5            
    THEN
      --Svi statusi dokumenta 
      RETURN TRUE ;
    ELSE
      --Drugi korisnici ne mogu brisati dokumente
      RETURN FALSE ;
    END IF ;
 ELSE      
   --Ažuriranje dokumenta je dozvoljeno
    RETURN TRUE ;
END IF ;

RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.update_with_check( store.docs.id%TYPE ,  boolean   ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.update_with_check( store.docs.id%TYPE ,  boolean   )  FROM public;
GRANT EXECUTE ON FUNCTION store.update_with_check( store.docs.id%TYPE ) TO service_functions;

Uključivanje politike Row Level Security za tabelu.

ENABLE ROW LEVEL SECURITY

ALTER TABLE store.docs ENABLE ROW LEVEL SECURITY ;

CREATE POLICY doc_select ON store.docs FOR SELECT TO service_functions USING ( (SELECT store.check_select(id)) );
CREATE POLICY doc_insert ON store.docs FOR INSERT TO service_functions WITH CHECK ( (SELECT store.check_insert(id)) );
CREATE POLICY docs_delete ON store.docs FOR DELETE TO service_functions USING ( (SELECT store.check_delete(id)) );

CREATE POLICY doc_update_using ON store.docs FOR UPDATE TO service_functions USING ( (SELECT store.update_using(id , is_del )) );
CREATE POLICY doc_update_check ON store.docs FOR UPDATE TO service_functions WITH CHECK ( (SELECT store.update_with_check(id , is_del )) );

Zaključek

To funkcioniše.

Predložena strategija omogućila je prenos implementacije modelske uloge sa nivoa poslovnih funkcija na nivo skladištenja podataka.

Funkcije se mogu koristiti kao šablon za implementaciju sofisticiranijih modela sakrivanja podataka, ako to poslovne potrebe zahtevaju.

Izvor: habr.com

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster