2010-12-12 10 views
6

Tengo dos tablas. Uno tiene una clave externa que hace referencia a un campo serie en la otra tabla. He otorgado el privilegio INSERTAR a una función que no sea el propietario, pero todavía no puedo insertarla en la tabla que contiene la clave externa a menos que conceda al propietario de la tabla el privilegio ACTUALIZAR en la tabla que contiene el campo al que se hace referencia. No entiendo por qué el propietario necesita tener permiso de ACTUALIZACIÓN para otro rol distinto (con privilegio INSERT) para poder insertar una fila en este caso.permisos: ¿por qué el propietario de la tabla necesita ACTUALIZAR en este caso?

Esto es un poco confuso, así que he proporcionado un ejemplo reducido de mi problema.

createuser -U postgres testowner -DIRS --pwprompt 
createdb -U postgres -O testowner testdb 
createuser -U postgres testupdater -DIRS --pwprompt 

psql -d testdb -U testowner 
CREATE TABLE a (id serial PRIMARY KEY); 
CREATE TABLE b (a_id integer REFERENCES a(id)); 
GRANT SELECT,INSERT ON ALL TABLES IN SCHEMA public TO testupdater; 
GRANT USAGE,UPDATE ON SEQUENCE a_id_seq TO testupdater; 
REVOKE INSERT, UPDATE ON ALL TABLES IN SCHEMA public FROM testowner; 
INSERT INTO a VALUES (DEFAULT); -- as expected: ERROR: permission denied for relation a 
\q 

psql -d testdb -U testupdater 
INSERT INTO a VALUES (DEFAULT); 
SELECT id FROM a LIMIT 1; -- selects the first id (1) 
INSERT INTO b VALUES (1); -- unexpected error: see below 
\q 

ERROR: permission denied for relation a

CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."a" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR SHARE OF x"

Sin embargo, la inserción anterior funciona si doy vuelta testowner el privilegio UPDATE (GRANT UPDATE ON a TO testowner;). ¿Por qué necesita testowner ACTUALIZAR en este caso?

NOTA: GRANT UPDATE ON a TO testupdater; no ayuda; parece que tengo que OTORGAR ACTUALIZACIÓN al rol de tesorero.

+0

¿Funciona si le das permiso de lectura al usuario en testowner? Una inserción en testupdater deberá leer los valores de la clave externa en testowner para asegurarse de que la inserción sea válida. –

+0

@Macy Nunca revoqué el permiso SELECT de la función 'testowner'. 'testupdater' también recibió permiso SELECT, por lo que parece que debería poder leer la tabla' a' para verificar la referencia. –

+0

Funciona bien aquí, sin errores inesperados. –

Respuesta

6

Supongo que el problema es "PARA COMPARTIR DE" en esa declaración de selección: para poder crear ese bloqueo de fila, necesita al menos algún tipo de acceso de escritura a la tabla.

p. Ej. si creo una mesa y sólo concedo a mí mismo el acceso a la misma SELECT:

[email protected]=# create table t(t1_id serial primary key, value text); 
NOTICE: CREATE TABLE will create implicit sequence "t_t1_id_seq" for serial column "t.t1_id" 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "t_pkey" for table "t" 
CREATE TABLE 
[email protected]=# insert into t(value) values('foo'); 
INSERT 0 1 
[email protected]=# grant select on t to steve; 
GRANT 

ahora aunque puedo leer filas de la tabla, no puedo bloquearlos:

[email protected]@[local] => select * from t; 
t1_id | value 
-------+------- 
    1 | foo 
(1 row) 

[email protected]@[local] => select * from t for share; 
ERROR: permission denied for relation t 

hacer una conjetura ahora. .. presumiblemente la implementación de claves foráneas funciona al verificar las filas de destino existentes en las tablas foráneas y establecer un contexto de autorización para eso en función del propietario de la tabla de origen o la tabla de destino ... TBH Nunca revoqué la tabla privilegios del propietario, así que no he encontrado esto antes.

Supongo que esto se produce porque no desea una cuenta que tenga acceso a todas las tablas simplemente porque las crearon? Yo sugeriría:

  • Realizar cambios de esquema como 'postgres' o algún otro superusuario que tiene un acceso limitado en pg_hba.conf
  • Alternativamente, lleve a cabo los cambios de esquema ya que algunos usuarios (por ejemplo, el propietario de la base) que no tiene acceso de inicio de sesión, usando set session authorization desde 'postgres' u otro superusuario
Cuestiones relacionadas