问题 检索特定角色的所有对象权限


是否有一种简单的方法可以枚举特定角色具有某些访问权限的所有对象?我知道这一套 has_*_privilege pg_catalog中的函数但它们不能完成这项工作,我想以相反的方式工作。实际上,我希望有一个视图为pg_class中存储的特定角色提供oid和access权限。

这样的视图非常便于检查数据库的安全性是否正确设置。通常,角色的关系远远少于关系,因此检查角色的麻烦要少得多。这种实用程序是否应该不适用于标准的PostgreSQL发行版?

根据源代码(acl.h),aclitem是一个结构:

typedef struct AclItem
{ Oid         ai_grantee;     /* ID that this item grants privs to */
  Oid         ai_grantor;     /* grantor of privs */
  AclMode     ai_privs;       /* privilege bits */
} AclItem;

易于使用。但是,pg_type将其列为用户定义的非复合类型。这是为什么?我现在看到的唯一方法是使用字符串函数解析aclitem []数组。有没有更好的方法来分析aclitem数组?

添加信息 浏览各种PG列表,显然这个问题至少从1997年开始以各种形式出现(我们当时有电脑吗?是电视吗?),最相关的讨论主题是“二进制输入/输出用于aclitem”在2011年初的pgsql-hackers上。作为PG技术熟练的用户 - 而不是黑客 - 我很欣赏开发人员对维护稳定界面的关注,但是线程中表达的一些担忧有点远我的口味。在系统目录中没有pg_acl表的真正原因是什么,其定义等于源代码中的AclItem结构?该结构何时发生变化?我也知道SE的发展很可能会改变安全性的处理方式 - 当用户选择的时候 - 大概是这样 - 所以我会满足于提供acl信息的东西,以便很容易枚举授予的权限特定用户,例如:

SELECT * FROM pg_privileges WHERE grantee = 16384;

像这样,它仍然可以是底层结构的抽象,因此引擎盖下的任何变化都可能(可能)仍然被转换为暴露的界面。我会说,与information_schema方法没什么不同。

干杯, 帕特里克


2297
2018-03-11 02:02


起源



答案:


没有开箱即用的这种视图,但创建它所需的数据在系统目录中:

http://www.postgresql.org/docs/current/static/catalogs.html

例如,有一个 relacl 在 pg_class

select oid::regclass, relacl from pg_class;

其他目录中也有类似的字段,即 typacl 在 pg_type 和 proacl 在 pg_proc

你可能想要再使用两个目录,即 pg_authid 了解哪些角色具有超级用户权限,以及 pg_auth_members 知道谁有什么角色。

(该 pg_default_acl 仅在对象创建期间使用,因此没有用。)

有一些与aclitem相关的内部函数可以在创建视图时派上用场。你可以列出它们 psql 像这样:

\df+ *acl*

尤其是 aclexplode()。以下示例有望让您入门:

select oid::regclass,
       (aclexplode(relacl)).grantor,
       (aclexplode(relacl)).grantee,
       (aclexplode(relacl)).privilege_type,
       (aclexplode(relacl)).is_grantable
from pg_class
where relacl is not null;

它可以通过首先扩展acl行来优化,例如:

select oid::regclass,
       aclitem.grantee
from (select oid, aclexplode(relacl) as aclitem from pg_class) sub

它会引导您直接达到预期的效果。

就我所知,这与使用内置工具一样好。 (当然,如果你想进一步优化它,你可以在C中编写自己的一组运算符。)

关于你的额外问题,我担心它们只能由世界上的少数人来回答,也就是核心开发者本身。他们比在这里更频繁地登上pg黑客列表。


14
2018-05-04 21:19



这正是我原始问题的起源。系统目录提供所有信息,但出于我的目的,格式错误。如果没有解析各种基于acl文本的列,我正在寻找一种更直接的方法来检查每个用户的权限。所以我担心这不是奖励奖励的答案,但感谢您的努力。 - Patrick
@Patrick:看我的编辑。 - Denis de Bernardy
很多有用的成分+1,特别是 aclexplode但是,仍然有人可以“把它们放在一起”。 - IMSoP
@IMSoP:我确信帕特里克很聪明,能够胜任。如果他的问题确实是如何在探测目录后解析权限,那么 aclexplode() 例子应该引导他直接找到解决方案。如果没有,他总是可以聘请顾问(提示:我!我!)。 - Denis de Bernardy
@Denis我想这个答案感觉有点未完成的原因是有很多“这个 威力 有用“,而不是”你可以使用这些确切的表,加上这个功能;这也可能很方便“(即使你没有完成确切的JOIN和UNIONs)。但最后,如果你想停在那里,由你决定;它仍然是很多非常有用的信息。 - IMSoP


答案:


没有开箱即用的这种视图,但创建它所需的数据在系统目录中:

http://www.postgresql.org/docs/current/static/catalogs.html

例如,有一个 relacl 在 pg_class

select oid::regclass, relacl from pg_class;

其他目录中也有类似的字段,即 typacl 在 pg_type 和 proacl 在 pg_proc

你可能想要再使用两个目录,即 pg_authid 了解哪些角色具有超级用户权限,以及 pg_auth_members 知道谁有什么角色。

(该 pg_default_acl 仅在对象创建期间使用,因此没有用。)

有一些与aclitem相关的内部函数可以在创建视图时派上用场。你可以列出它们 psql 像这样:

\df+ *acl*

尤其是 aclexplode()。以下示例有望让您入门:

select oid::regclass,
       (aclexplode(relacl)).grantor,
       (aclexplode(relacl)).grantee,
       (aclexplode(relacl)).privilege_type,
       (aclexplode(relacl)).is_grantable
from pg_class
where relacl is not null;

它可以通过首先扩展acl行来优化,例如:

select oid::regclass,
       aclitem.grantee
from (select oid, aclexplode(relacl) as aclitem from pg_class) sub

它会引导您直接达到预期的效果。

就我所知,这与使用内置工具一样好。 (当然,如果你想进一步优化它,你可以在C中编写自己的一组运算符。)

关于你的额外问题,我担心它们只能由世界上的少数人来回答,也就是核心开发者本身。他们比在这里更频繁地登上pg黑客列表。


14
2018-05-04 21:19



这正是我原始问题的起源。系统目录提供所有信息,但出于我的目的,格式错误。如果没有解析各种基于acl文本的列,我正在寻找一种更直接的方法来检查每个用户的权限。所以我担心这不是奖励奖励的答案,但感谢您的努力。 - Patrick
@Patrick:看我的编辑。 - Denis de Bernardy
很多有用的成分+1,特别是 aclexplode但是,仍然有人可以“把它们放在一起”。 - IMSoP
@IMSoP:我确信帕特里克很聪明,能够胜任。如果他的问题确实是如何在探测目录后解析权限,那么 aclexplode() 例子应该引导他直接找到解决方案。如果没有,他总是可以聘请顾问(提示:我!我!)。 - Denis de Bernardy
@Denis我想这个答案感觉有点未完成的原因是有很多“这个 威力 有用“,而不是”你可以使用这些确切的表,加上这个功能;这也可能很方便“(即使你没有完成确切的JOIN和UNIONs)。但最后,如果你想停在那里,由你决定;它仍然是很多非常有用的信息。 - IMSoP


可能不是最好/最有效的方式,但它对我帮助很大!我在需要删除角色和出错时遇到了问题。

ERROR:  role ROLE_NAME cannot be dropped because some objects depend on it

你可以用它

SELECT * FROM upg_roles_privs WHERE grantee = 'testuser'

代码如下。我不包括“系统”对象(来自pg_catalog和information_schema),如果要枚举它们,可以从查询中取出条件。

CREATE VIEW upg_roles_privs AS

    /* Databases */
    select type, objname, r1.rolname grantor, r2.rolname grantee, privilege_type
    from
    (select 
      'database'::text as type, datname as objname, datistemplate, datallowconn, 
      (aclexplode(datacl)).grantor as grantorI, 
      (aclexplode(datacl)).grantee as granteeI,
      (aclexplode(datacl)).privilege_type,
      (aclexplode(datacl)).is_grantable
    from pg_database) as db
    join pg_roles r1 on db.grantorI = r1.oid
    join pg_roles r2 on db.granteeI = r2.oid
    where r2.rolname not in ('postgres')

    union all

    /* Schemas / Namespaces */
    select type, objname, r1.rolname grantor, r2.rolname grantee, privilege_type from 
    (select
      'schema'::text as type, nspname as objname, 
      (aclexplode(nspacl)).grantor as grantorI, 
      (aclexplode(nspacl)).grantee as granteeI,
      (aclexplode(nspacl)).privilege_type,
      (aclexplode(nspacl)).is_grantable
    from pg_catalog.pg_namespace) as ns
    join pg_roles r1 on ns.grantorI = r1.oid
    join pg_roles r2 on ns.granteeI = r2.oid
    where r2.rolname not in ('postgres')

    union all

    /* Tabelas */
    select 'tables'::text as type, table_name||' ('||table_schema||')' as objname, grantor, grantee, privilege_type  
    from information_schema.role_table_grants 
    where grantee not in ('postgres')
    and table_schema not in ('information_schema', 'pg_catalog')
    and grantor <> grantee

    union all

    /* Colunas (TODO: se o revoke on table from x retirar acesso das colunas, nao precisa desse bloco) */
    select 
      'columns'::text as type, column_name||' ('||table_name||')' as objname,
      grantor, grantee, privilege_type
    from information_schema.role_column_grants
    where 
    table_schema not in ('information_schema', 'pg_catalog')
    and grantor <> grantee

    union all

    /* Funcoes / Procedures */
    select 'routine'::text as type, routine_name as objname, grantor, grantee, privilege_type
    from information_schema.role_routine_grants
    where grantor <> grantee
    and routine_schema not in ('information_schema', 'pg_catalog')

    --union all information_schema.role_udt_grants

    union all

    /* Outros objetos */
    select 'object'::text as type, object_name||'( '||object_type||')' as objname, grantor, grantee, privilege_type
    from information_schema.role_usage_grants
    where object_type <> 'COLLATION' and object_type <> 'DOMAIN'

1
2018-01-25 20:34