Muy buenos dias a todos.
Me pude dar un tiempo y me dedique a investigar el tema de referencia (Row
Security) llevo en ello ya dos días y pido disculpas si lo que pregunto es
muy obvio.

No encuentro como propagar la seguridad en integridad referencial.

Esto es: Si defino una regla de seguridad a nivel registro, quiero que los
detalles en otras tablas que hacen referencia, tambien hereden la
visibilidad definida en la regla.

Asi como logré hacerlo andar debo en todas las tablas definir las reglas, y
si en un detalle que apunta a una cabecera no lo hiciera, el usuario
logeado veria el detalle que tiene un ID en el campo del FK que apunta a
una tupla que para él no existe.

Esta es la prueba y como pude lograr lo que queria, aun cuando no es lo
automático que pretendo:

create schema aux;

create table aux.empresas (
   id serial not null primary key,
   descripcion text
);

create table aux.cabeceras (
   id serial not null primary key,
   descripcion text
);

create table aux.detalles (
   id serial not null primary key,
   cabera integer references aux.cabeceras(id),
   descripcion text
)

create table aux.empresas_usos_datos (
   esquema text,
   tabla text,
   id integer,
   empresa integer references aux.empresas(id),
   primary key (esquema, tabla, id, empresa)
)

create table aux.empresas_usuarios (
   empresa integer references aux.empresas(id),
   usuario text,
   primary key (empresa,usuario)
)

grant all on aux.empresas_usos_datos to administracion;
grant all on aux.empresas_usuarios to administracion;


insert into aux.empresas (descripcion) values ('Empresa 1');
insert into aux.empresas (descripcion) values ('Empresa 2');

insert into aux.empresas_usuarios (empresa,usuario) values (1,'vhr');
insert into aux.empresas_usuarios (empresa,usuario) values (2,'sofy');

CREATE OR REPLACE FUNCTION aux.vinculo_tupla_con_empresa()
  RETURNS trigger AS
$BODY$
declare

    v_old_data TEXT;
    v_new_data TEXT;
    v_c integer;
    r_cursor record;
    id1 integer;

BEGIN
    BEGIN
          v_c := NEW.ID;
    EXCEPTION
      WHEN OTHERS THEN
      BEGIN
            v_c := NEW.GID;
      EXCEPTION
        WHEN OTHERS THEN
          v_c := -1;
      END;
    END;

    IF (TG_OP = 'DELETE') THEN
        for id1 in (select distinct u1.empresa from aux.empresas_usuarios
u1 where u1.usuario = session_user::TEXT ) loop
            RAISE NOTICE 'Ejecutado borrado % % % % % %',id1,
v_c,session_user, TG_TABLE_SCHEMA::TEXT,TG_TABLE_NAME::TEXT, now();
            delete from aux.empresas_usos_datos where
esquema=TG_TABLE_SCHEMA::TEXT and tabla=TG_TABLE_NAME::TEXT and id=v_c and
empresa= id1;
        end loop;
        RETURN NEW;
    ELSIF (TG_OP = 'INSERT') THEN
        for id1 in (select distinct u1.empresa from aux.empresas_usuarios
u1 where u1.usuario = session_user::TEXT ) loop
            RAISE NOTICE 'Ejecutado % % % % % %',id1,
v_c,user,session_user, current_user, now();
            insert into aux.empresas_usos_datos (empresa,esquema,tabla,id )
values (id1, TG_TABLE_SCHEMA::TEXT,TG_TABLE_NAME::TEXT,v_c);
        end loop;
        RETURN NEW;
    END IF;

EXCEPTION
    WHEN data_exception THEN
        RAISE WARNING '[aux.vinculo_tupla_con_empresa] - ERROR [DATA
EXCEPTION] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
        RETURN NULL;
    WHEN unique_violation THEN
        RAISE WARNING '[aux.vinculo_tupla_con_empresa] - ERROR [UNIQUE] -
SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
        RETURN NULL;
    WHEN OTHERS THEN
        RAISE WARNING '[aux.vinculo_tupla_con_empresa] - ERROR [OTHER] -
SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
        RETURN NULL;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE SECURITY DEFINER
  COST 100;

CREATE OR REPLACE FUNCTION aux.verifico_tupla_con_empresa(esquema_r
text,tabla_r text, id_r integer)
  RETURNS boolean AS
$BODY$
declare

    v_c integer;
    r_cursor record;
    id1 integer;

BEGIN
        --RAISE NOTICE 'Ejecutado % % % %
%',id_r,esquema_r,tabla_r,session_user, now();
   select 1 from aux.empresas_usos_datos u1 into id1
          where u1.id = id_r and u1.esquema = esquema_r and u1.tabla =
tabla_r and exists (select 1 from aux.empresas_usuarios eu where eu.usuario
= session_user and eu.empresa = u1.empresa);
        if (id1 = 1) then
            return true;
        else
            return false;
        end if;

EXCEPTION
    WHEN data_exception THEN
        RAISE WARNING '[aux.verifico_tupla_con_empresa] - ERROR [DATA
EXCEPTION] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
        RETURN NULL;
    WHEN unique_violation THEN
        RAISE WARNING '[aux.verifico_tupla_con_empresa] - ERROR [UNIQUE] -
SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
        RETURN NULL;
    WHEN OTHERS THEN
        RAISE WARNING '[aux.verifico_tupla_con_empresa] - ERROR [OTHER] -
SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
        RETURN NULL;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE SECURITY DEFINER
  COST 100;

grant all on aux.verifico_tupla_con_empresa(


CREATE TRIGGER cabeceras_trg
  after INSERT OR DELETE
  ON aux.cabeceras
  FOR EACH ROW
  EXECUTE PROCEDURE aux.vinculo_tupla_con_empresa();

CREATE TRIGGER detalles_trg
  after INSERT OR DELETE
  ON aux.detalles
  FOR EACH ROW
  EXECUTE PROCEDURE aux.vinculo_tupla_con_empresa();

GRANT ALL ON SCHEMA aux TO administracion;
grant all on aux.cabeceras to administracion;
GRANT ALL ON aux.cabeceras_id_seq TO administracion;
grant all on aux.detalles to administracion;
GRANT ALL ON aux.detalles_id_seq TO administracion;

ALTER TABLE aux.cabeceras ENABLE ROW LEVEL SECURITY;

DROP POLICY cabeceras_administracion ON aux.cabeceras;

CREATE POLICY cabeceras_administracion ON aux.cabeceras TO administracion
  USING ( aux.verifico_tupla_con_empresa( 'aux','cabeceras', id)
  );

drop POLICY cabeceras_select_administracion ON aux.cabeceras;

CREATE POLICY cabeceras_select_administracion ON aux.cabeceras for select
TO administracion
  USING ( aux.verifico_tupla_con_empresa( 'aux','cabeceras', id)
  );

drop POLICY cabeceras_insert_administracion ON aux.cabeceras;
CREATE POLICY cabeceras_insert_administracion ON aux.cabeceras for INSERT
TO administracion
  WITH CHECK  (true);

DROP POLICY cabeceras_update_administracion ON aux.cabeceras
CREATE POLICY cabeceras_update_administracion ON aux.cabeceras for update
TO administracion
  USING ( aux.verifico_tupla_con_empresa( 'aux','cabeceras', id)
  );


ALTER TABLE aux.detalles ENABLE ROW LEVEL SECURITY;

DROP POLICY detalles_administracion ON aux.detalles;


CREATE POLICY detalles_administracion ON aux.detalles TO administracion
  USING ( aux.verifico_tupla_con_empresa( 'aux','detalles', id)
  );


drop POLICY detalles_select_administracion ON aux.detalles;


CREATE POLICY detalles_select_administracion ON aux.detalles for select TO
administracion
  USING ( aux.verifico_tupla_con_empresa( 'aux','detalles', id)
  );

drop POLICY detalles_insert_administracion ON aux.detalles;
CREATE POLICY detalles_insert_administracion ON aux.detalles for INSERT TO
administracion
  WITH CHECK  (true);

DROP POLICY detalles_update_administracion ON aux.detalles
CREATE POLICY detalles_update_administracion ON aux.detalles for update TO
administracion
  USING ( aux.verifico_tupla_con_empresa( 'aux','detalles', id)
  );

select * from aux.detalles

delete from aux.empresas_usos_datos
where id < 19

table aux.empresas_usos_datos
table aux.empresas_usuarios

delete from aux.cabeceras
where id > 0

SET SESSION AUTHORIZATION vhr;

insert into aux.cabeceras(descripcion) values ('Intento con usuario:
'||session_user||' '||now()::text);
insert into aux.detalles (cabera,descripcion) select b.id,'renglon 1 de
'||b.descripcion from aux.cabeceras b

select * from aux.cabeceras
select * from aux.detalles

SET SESSION AUTHORIZATION sofy;

select * from aux.cabeceras
select * from aux.detalles

insert into aux.cabeceras(descripcion) values ('Intento con usuario:
'||session_user||' '||now()::text);
insert into aux.detalles (cabera,descripcion) select b.id,'renglon 1 de
'||b.descripcion from aux.cabeceras b




La pregunta hay algo automático que resuleva este problema?
O La integridad dependerá de mi prolijidad al definir las reglas de
seguridad?

Desde ya muchas gracias por la ayuda que pudieran darme y nuevamente
disculpas si lo que pregunto es trivial.
Fuerte Abrazo a todos

Responder a