Existe-t-il une requête que je peux exécuter pour afficher les privilèges actuellement attribués sur un schéma particulier?
c'est-à-dire des privilèges qui ont été attribués comme suit:
GRANT USAGE ON SCHEMA dbo TO MyUser
J'ai essayé
SELECT *
FROM information_schema.usage_privileges;
mais cela ne renvoie que des subventions au rôle PUBLIC intégré. Au lieu de cela, je veux voir quels utilisateurs ont obtenu des privilèges sur les différents schémas.
Remarque: j'utilise en fait Amazon Redshift plutôt que PostgreSQL pur, bien que j'accepterai une réponse PostgreSQL pure si ce n'est pas possible dans Amazon Redshift. (Bien que je pense que oui)
Les privilèges sont stockés dans le champ nspacl de pg_namespace. Comme il s'agit d'un champ de tableau, vous devez effectuer un petit codage sophistiqué pour l'analyser. Cette requête vous donnera les instructions de subvention utilisées pour les utilisateurs et les groupes:
select
'grant ' || substring(
case when charindex('U',split_part(split_part(array_to_string(nspacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',usage ' else '' end
||case when charindex('C',split_part(split_part(array_to_string(nspacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',create ' else '' end
, 2,10000)
|| ' on schema '||nspname||' to "'||pu.usename||'";'
from pg_namespace pn,pg_user pu
where array_to_string(nspacl,',') like '%'||pu.usename||'%' --and pu.usename='<username>'
and nspowner > 1
union
select
'grant ' || substring(
case when charindex('U',split_part(split_part(array_to_string(nspacl, '|'),pg.groname,2 ) ,'/',1)) > 0 then ',usage ' else '' end
||case when charindex('C',split_part(split_part(array_to_string(nspacl, '|'),pg.groname,2 ) ,'/',1)) > 0 then ',create ' else '' end
, 2,10000)
|| ' on schema '||nspname||' to group "'||pg.groname||'";'
from pg_namespace pn,pg_group pg
where array_to_string(nspacl,',') like '%'||pg.groname||'%' --and pg.groname='<username>'
and nspowner > 1
dans la console, utilisez psql:
\dn+
vous montrera
Name | Owner | Access privileges | Description
Liste tous les schémas avec leurs privilèges pour l'utilisateur actuel:
WITH "names"("name") AS (
SELECT n.nspname AS "name"
FROM pg_catalog.pg_namespace n
WHERE n.nspname !~ '^pg_'
AND n.nspname <> 'information_schema'
) SELECT "name",
pg_catalog.has_schema_privilege(current_user, "name", 'CREATE') AS "create",
pg_catalog.has_schema_privilege(current_user, "name", 'USAGE') AS "usage"
FROM "names";
La réponse sera par exemple:
name | create | usage
---------+--------+-------
public | t | t
test | t | t
awesome | f | f
(3 rows)
Dans cet exemple, l'utilisateur actuel n'est pas propriétaire du schéma awesome
.
Comme vous pouvez le deviner, demande similaire pour un schéma particulier:
SELECT
pg_catalog.has_schema_privilege(
current_user, 'awesome', 'CREATE') AS "create",
pg_catalog.has_schema_privilege(
current_user, 'awesome', 'USAGE') AS "usage";
et réponse:
create | usage
--------+-------
f | f
Comme vous le savez, il est possible d'utiliser pg_catalog.current_schema()
pour le schéma actuel.
De tous les privilèges possibles
-- SELECT
-- INSERT
-- UPDATE
-- DELETE
-- TRUNCATE
-- REFERENCES
-- TRIGGER
-- CREATE
-- CONNECT
-- TEMP
-- EXECUTE
-- USAGE
les seuls CREATE
et USAGE
autorisés pour les schémas.
Comme la current_schema()
le current_user
Peut être remplacé par un rôle particulier.
Bonus [~ # ~] [~ # ~] avec colonne current
WITH "names"("name") AS (
SELECT n.nspname AS "name"
FROM pg_catalog.pg_namespace n
WHERE n.nspname !~ '^pg_'
AND n.nspname <> 'information_schema'
) SELECT "name",
pg_catalog.has_schema_privilege(current_user, "name", 'CREATE') AS "create",
pg_catalog.has_schema_privilege(current_user, "name", 'USAGE') AS "usage",
"name" = pg_catalog.current_schema() AS "current"
FROM "names";
-- name | create | usage | current
-- ---------+--------+-------+---------
-- public | t | t | t
-- test | t | t | f
-- awesome | f | f | f
-- (3 rows)
AVEC | Fonctions d'informations système | GRANT (privilèges)
Essayez celui-ci (fonctionne pour le rôle PUBLIC):
SELECT nspname,
coalesce(nullif(role.name,''), 'PUBLIC') AS name,
substring(
CASE WHEN position('U' in split_part(split_part((','||array_to_string(nspacl,',')), ','||role.name||'=',2 ) ,'/',1)) > 0 THEN ', USAGE' ELSE '' END
|| CASE WHEN position('C' in split_part(split_part((','||array_to_string(nspacl,',')), ','||role.name||'=',2 ) ,'/',1)) > 0 THEN ', CREATE' ELSE '' END
, 3,10000) AS privileges
FROM pg_namespace pn, (SELECT pg_roles.rolname AS name
FROM pg_roles UNION ALL SELECT '' AS name) AS role
WHERE (','||array_to_string(nspacl,',')) LIKE '%,'||role.name||'=%'
AND nspowner > 1;
Version combinée (groupes, utilisateurs, PUBLIC) qui fonctionne pour AWS Redshift:
SELECT *
FROM (SELECT CASE
WHEN charindex ('U',SPLIT_PART(SPLIT_PART(ARRAY_TO_STRING(nspacl,'|'),pu.usename,2),'/',1)) > 0 THEN ' USAGE'
ELSE ''
END ||case WHEN charindex('C',SPLIT_PART(SPLIT_PART(ARRAY_TO_STRING(nspacl,'|'),pu.usename,2),'/',1)) > 0 THEN ' CREATE' ELSE '' END AS rights,
nspname AS schema,
'' AS role,
pu.usename AS user
FROM pg_namespace pn,
pg_user pu
WHERE ARRAY_TO_STRING(nspacl,',') LIKE '%' ||pu.usename|| '%'
--and pu.usename='<username>'
AND nspowner > 1
UNION
SELECT CASE
WHEN charindex ('U',SPLIT_PART(SPLIT_PART(ARRAY_TO_STRING(nspacl,'|'),pg.groname,2),'/',1)) > 0 THEN ' USAGE '
ELSE ''
END ||case WHEN charindex('C',SPLIT_PART(SPLIT_PART(ARRAY_TO_STRING(nspacl,'|'),pg.groname,2),'/',1)) > 0 THEN ' CREATE' ELSE '' END as rights,
nspname AS schema,
pg.groname AS role,
'' AS user
FROM pg_namespace pn,
pg_group pg
WHERE ARRAY_TO_STRING(nspacl,',') LIKE '%' ||pg.groname|| '%'
--and pg.groname='<username>'
AND nspowner > 1
UNION
SELECT CASE
WHEN POSITION('U' IN SPLIT_PART(SPLIT_PART((',' ||array_to_string (nspacl,',')),',' ||roles.name|| '=',2),'/',1)) > 0 THEN ' USAGE'
ELSE ''
END
|| CASE
WHEN POSITION('C' IN SPLIT_PART(SPLIT_PART((',' ||array_to_string (nspacl,',')),',' ||roles.name|| '=',2),'/',1)) > 0 THEN ' CREATE'
ELSE ''
END AS rights,
nspname AS schema,
COALESCE(NULLIF(roles.name,''),'PUBLIC') AS role,
'' AS user
FROM pg_namespace pn,
(SELECT pg_group.groname AS name
FROM pg_group
UNION ALL
SELECT '' AS name) AS roles
WHERE (',' ||array_to_string (nspacl,',')) LIKE '%,' ||roles.name|| '=%'
AND nspowner > 1) privs
ORDER BY schema,rights
C'est ce que psql utilise en interne :)
SELECT n.nspname AS "Name",
pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner",
pg_catalog.array_to_string(n.nspacl, E'\n') AS "Access privileges",
pg_catalog.obj_description(n.oid, 'pg_namespace') AS "Description"
FROM pg_catalog.pg_namespace n
WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'
ORDER BY 1;
Je sais que ce message est ancien mais j'ai fait une autre requête basée sur les différentes réponses pour en avoir une qui soit courte et facile à utiliser par la suite:
select
nspname as schema_name
, r.rolname as role_name
, pg_catalog.has_schema_privilege(r.rolname, nspname, 'CREATE') as create_grant
, pg_catalog.has_schema_privilege(r.rolname, nspname, 'USAGE') as usage_grant
from pg_namespace pn,pg_catalog.pg_roles r
where array_to_string(nspacl,',') like '%'||r.rolname||'%'
and nspowner > 1
Je continue de penser qu'un jour je ferai une requête pour avoir tous les droits dans une seule vue ... Un jour. ;)
Pour la question actuelle, essayez celle-ci:
SELECT r.rolname AS role_name,
n.nspname AS schema_name,
p.perm AS privilege
FROM pg_catalog.pg_namespace AS n
CROSS JOIN pg_catalog.pg_roles AS r
CROSS JOIN (VALUES ('USAGE'), ('CREATE')) AS p(perm)
WHERE has_schema_privilege(r.oid, n.oid, p.perm)
-- AND n.nspname <> 'information_schema'
-- AND n.nspname !~~ 'pg\_%'
-- AND NOT r.rolsuper
Pourrait être assez faible dans les performances de la base de données avec beaucoup d'objets et d'utilisateurs avec lesquels je suis tombé. J'ai donc une solution de contournement possible en utilisant aclexplode()
fonction par défaut comme ceci:
SELECT oid_to_rolname(a.grantee) AS role_name,
n.nspname AS schema_name,
a.privilege_type AS privilege_type
FROM pg_catalog.pg_namespace AS n,
aclexplode(nspacl) a
WHERE n.nspacl IS NOT NULL
AND oid_to_rolname(a.grantee) IS NOT NULL
-- AND n.nspname <> 'information_schema'
-- AND n.nspname !~~ 'pg\_%'
Mais, soyez prudent , le dernier n'inclut pas les privilèges que les utilisateurs ont obtenus du rôle PUBLIC
. Où oid_to_rolname()
est une simple fonction personnalisée SELECT rolname FROM pg_roles WHERE oid = $1
.
Et, comme @ Jaisus , ma tâche exigeait d'avoir tous les privilèges dont disposent tous les utilisateurs. J'ai donc des requêtes de privilèges similaires à schema
pour table
, views
, columns
, sequences
, functions
, database
et même default
privilèges.
En outre, il existe une extension utile pg_permission
où je reçois la logique pour les requêtes fournies et que je viens de mettre à niveau pour mes besoins.