postgresql-просмотр привилегий схемы

есть ли запрос, который я могу запустить, чтобы показать текущие назначенные привилегии на определенной схеме?

т. е. привилегии, которые были назначены так:

GRANT USAGE ON SCHEMA dbo TO MyUser

Я пробовал

SELECT *
FROM information_schema.usage_privileges;

но это возвращает только гранты встроенной публичной роли. Вместо этого я хочу увидеть, каким пользователям были предоставлены привилегии в различных схемах.

Примечание: На самом деле я использую Amazon Redshift, а не чистый PostgreSQL, хотя я приму чистый Ответ PostgreSQL, если это невозможно в Amazon Redshift. (Хотя я подозреваю, что это так)

6 ответов


привилегии хранятся в поле nspacl pg_namespace. Поскольку это поле массива, вам нужно сделать небольшое причудливое кодирование, чтобы разобрать его. Этот запрос даст вам инструкции grant, используемые для пользователей и групп:

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 

в консоли util psql:

\dn+

покажет

     Name      |  Owner   |   Access privileges   |      Description   

Список всех схем с их priveleges для текущего пользователя:

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";

ответ будет, например:

  name   | create | usage 
---------+--------+-------
 public  | t      | t
 test    | t      | t
 awesome | f      | f
(3 rows)

в этом примере текущий пользователь не является владельцем awesome схемы.

как вы могли догадаться, аналогичный запрос для конкретной схемы:

SELECT
  pg_catalog.has_schema_privilege(
    current_user, 'awesome', 'CREATE') AS "create",
  pg_catalog.has_schema_privilege(
    current_user, 'awesome', 'USAGE') AS "usage";

и ответ:

 create | usage 
--------+-------
 f      | f

как вы знаете, это можно использовать pg_catalog.current_schema() для текущей схемы.

из всех возможных привилегии

-- SELECT
-- INSERT
-- UPDATE
-- DELETE
-- TRUNCATE
-- REFERENCES
-- TRIGGER
-- CREATE
-- CONNECT
-- TEMP
-- EXECUTE
-- USAGE

только CREATE и USAGE допускается для схем.

как current_schema() на current_user можно заменить на определенную роль.


бонус С 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)

С | Функции Системной Информации | предоставлять (привилегии)


попробуйте это (работает для публичной роли):

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;

комбинированная версия (группы, пользователи, PUBLIC), которая работает для 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

это то, что psql использует внутренне:)

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;