如何在postgresql中找到授予用户的权限

时间:2014-02-05 21:37:34

标签: postgresql amazon-redshift

我正在使用redshift cluster db。

版本:

PostgreSQL 8.0.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3), Redshift 1.0.735

我只需要删除一个用户。它给出了以下错误消息:

redshiftpocdb=# drop user test_55;
ERROR:  user "test_55" cannot be dropped because the user has a privilege on some object

我正在调整\ dp输出:

redshiftpocdb=# \dp
              Access privileges
 schema |  name   | type  | access privileges
--------+---------+-------+-------------------
 public | company | table |
 public | test2   | table |
 public | test22  | table |
 public | test222 | table |
 public | v_date  | table |
(5 rows)

在物理postgresql环境中,我们有一个命令DROP OWNED BY。但是这个命令在redshift中不起作用。

那么,进一步如何找出授予TEST_55的私人资格?是否有查询它的任何视图(对于Oracle中的e..g,我们有DBA_ROLE_PRIVS,DBA_TAB_PRIVS ... DBA_SYS_PRIVS .etc)

谢谢

3 个答案:

答案 0 :(得分:14)

为了能够删除用户,您必须(至少)

  • 如果他们拥有任何对象,请将所有者更改为其他用户
  • 从任何对象中删除授权
  • 从群组中删除
  • 从架构中删除授权

您可以使用它来查找他们拥有的任何表(然后运行“alter table owner to”):

select * from pg_tables where tableowner = 'test_55'

您可以使用它来构建脚本以撤消任何授权:

select relacl , 
'revoke ' || substring(
            case when charindex('r',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',select ' else '' end 
          ||case when charindex('w',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',update ' else '' end 
          ||case when charindex('a',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',insert ' else '' end 
          ||case when charindex('d',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',delete ' else '' end 
          ||case when charindex('R',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',rule ' else '' end 
          ||case when charindex('x',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',references ' else '' end 
          ||case when charindex('t',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',trigger ' else '' end 
          ||case when charindex('X',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',execute ' else '' end 
          ||case when charindex('U',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',usage ' else '' end 
          ||case when charindex('C',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',create ' else '' end 
          ||case when charindex('T',split_part(split_part(array_to_string(relacl, '|'),pu.usename,2 ) ,'/',1)) > 0 then ',temporary ' else '' end 
       , 2,10000)
|| ' on '||namespace||'.'||item ||' from "'||pu.usename||'";' as grantsql
from 
(SELECT 
 use.usename as subject, 
 nsp.nspname as namespace, 
 c.relname as item, 
 c.relkind as type, 
 use2.usename as owner, 
 c.relacl 
 FROM 
 pg_user use 
 cross join pg_class c 
 left join pg_namespace nsp on (c.relnamespace = nsp.oid) 
 left join pg_user use2 on (c.relowner = use2.usesysid)
 WHERE 
 c.relowner = use.usesysid  
 and  nsp.nspname NOT IN ('pg_catalog', 'pg_toast', 'information_schema')
 ORDER BY   subject,   namespace,   item 
) join pg_user pu on array_to_string(relacl, '|') like '%'||pu.usename||'%' 
where relacl is not null
 and pu.usename='test_55'

您可以使用此查询的变体来查看用户是否属于任何组(然后使用“alter group drop user”):

select usesysid, usename, nvl(groname,'default') from pg_user u 
left join pg_group g on ','||array_to_string(grolist,',')||','
  like '%,'||cast(usesysid as varchar(10))||',%' 
where usename='test_55' order by 2,1;

您可以使用此查询来查看它们是否具有任何架构授权:

select * from pg_namespace where nspowner > 1 and array_to_string(nspacl,',') like '%test_55%';

答案 1 :(得分:2)

另一种变体,即将所有用户的特权组织在一起:

WITH 
usrs as (SELECT * FROM pg_user),
objs as (
  SELECT 
    schemaname, 't' AS obj_type,
    tablename AS objectname,
    schemaname + '.' + tablename AS fullobj
  FROM pg_tables
  WHERE schemaname not in ('pg_internal')
  UNION
  SELECT 
    schemaname, 'v' AS obj_type, 
    viewname AS objectname, 
    schemaname + '.' + viewname AS fullobj 
  FROM pg_views
  WHERE schemaname NOT IN ('pg_internal')
),
query as (
  SELECT 
    schemaname,
    objectname,
    usename,
    HAS_TABLE_PRIVILEGE(usrs.usename, fullobj, 'select') AS sel,
    HAS_TABLE_PRIVILEGE(usrs.usename, fullobj, 'insert') AS ins,
    HAS_TABLE_PRIVILEGE(usrs.usename, fullobj, 'update') AS upd,
    HAS_TABLE_PRIVILEGE(usrs.usename, fullobj, 'delete') AS del,
    HAS_TABLE_PRIVILEGE(usrs.usename, fullobj, 'references') AS ref
  FROM objs, usrs
  ORDER BY fullobj
)
SELECT * FROM query
WHERE (
  sel = TRUE 
  OR ins = TRUE 
  OR upd = TRUE 
  OR del = TRUE 
  OR ref = TRUE
) AND schemaname='[optional schemaname]'
  AND usename = '[optional username]';

答案 2 :(得分:0)

我不得不使用||连接字符串,因为我有区分大小写的对象名称 '"' || schemaname || '""' || tablename || '"' AS fullobj '"' || schemaname || '""' || viewname || '"' AS fullobj

而不是 schemaname +'。' + tablename AS fullobj schemaname +'。' + viewname AS fullobj