2010-12-12 62 views
6

J'ai deux tables. On a une clé étrangère référençant un champ série dans l'autre table. J'ai accordé le privilège INSERT à un rôle autre que le propriétaire, mais je ne peux toujours pas insérer dans la table contenant la clé étrangère à moins que j'accorde le propriétaire du privilège UPDATE de table sur la table contenant le champ référencé. Je ne comprends pas très bien pourquoi le propriétaire a besoin de l'autorisation UPDATE pour qu'un autre rôle distinct (avec le privilège INSERT) puisse insérer une ligne dans ce cas.autorisations: pourquoi UPDATE est-il nécessaire au propriétaire de la table dans ce cas?

Ceci est un peu déroutant, donc j'ai fourni un exemple réduit de mon problème.

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"

Cependant, l'insert ci-dessus fonctionne si je donne le privilège testowner retour UPDATE (GRANT UPDATE ON a TO testowner;). Pourquoi le testowner a-t-il besoin de UPDATE dans ce cas?

REMARQUE: GRANT UPDATE ON a TO testupdater; n'aide pas; il semble que je doive accorder la mise à jour au rôle de testowner.

+0

Est-ce que cela fonctionne si vous autorisez l'utilisateur à lire le testowner? Un insert sur testupdater devra lire les valeurs de la clé étrangère dans testowner pour s'assurer que l'insert est valide. –

+0

@Macy Je n'ai jamais révoqué l'autorisation SELECT du rôle 'testowner'. 'testupdater' a également reçu l'autorisation SELECT, il semble donc qu'il devrait être capable de lire la table' a' pour vérifier la référence. –

+0

Cela fonctionne très bien ici, pas d'erreurs inattendues. –

Répondre

6

Je suppose que le problème est le «POUR PARTAGER DE» dans cette déclaration select - afin de pouvoir créer ce verrou de ligne, vous avez besoin d'au moins une sorte d'accès en écriture à la table.

par exemple. si je crée une table et que moi-même accorde l'accès SELECT à elle:

[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 

maintenant, bien que je peux lire les lignes de la table, je ne peux pas les enfermer:

[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 

Faire une supposition maintenant. .. l'implémentation des clés étrangères fonctionne probablement en vérifiant que les lignes cibles existent dans les tables étrangères et en définissant un contexte d'autorisation pour celles basées sur le propriétaire de la table source ou de la table cible ... TBH Je n'ai jamais révoqué la table privilèges du propriétaire, donc je n'ai pas rencontré cela avant.

Je suppose que cela vient parce que vous ne voulez pas un compte qui a accès à toutes les tables simplement parce qu'ils les ont créés? Je suggère:

  • Apporter les modifications du schéma comme « postgres » ou d'une autre super-utilisateur qui a un accès limité à pg_hba.conf
  • Vous pouvez également effectuer des changements de schéma avec un utilisateur (par exemple, le propriétaire de la base de données) qui n'a pas accès à la connexion, en utilisant set session authorization à partir de 'postgres' ou d'un autre super-utilisateur