检索特定角色的所有对象权限
Posted
技术标签:
【中文标题】检索特定角色的所有对象权限【英文标题】:Retrieving all object privileges for specific role 【发布时间】:2014-03-11 02:02:40 【问题描述】:是否有一种简单的方法来枚举特定角色具有某些访问权限的所有对象?我知道 pg_catalog 中的一组 has_*_privilege
函数,但它们不能完成这项工作,我想反过来工作。实际上,我希望有一个视图,它可以为存储在 pg_class 中的特定角色的任何内容提供 oid 和访问权限。
这样的视图对于检查数据库的安全性是否设置正确非常方便。通常,角色比关系少得多,因此检查角色的难度要小得多恕我直言。标准 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 的(技术熟练的)用户 - 而不是黑客 - 我很欣赏开发人员对维护稳定界面的关注,但线程中表达的一些关注对于我的口味。系统目录中没有定义等于源代码中的 AclItem 结构的 pg_acl 表的真正原因是什么?该结构最后一次更改是什么时候?我也知道 SE 的发展可能会改变处理安全性的方式——大概当用户选择时——所以我会满足于以一种易于枚举授予权限的方式呈现 acl 信息的东西特定用户,例如:
SELECT * FROM pg_privileges WHERE grantee = 16384;
就像这样,它仍然可以是底层结构的抽象,因此引擎盖下的任何更改都可以(大概)仍然转换为公开的接口。我想说,与 information_schema 方法没有太大区别。
干杯, 帕特里克
【问题讨论】:
【参考方案1】:没有这种开箱即用的视图,但创建它所需的数据在系统目录中:
http://www.postgresql.org/docs/current/static/catalogs.html
例如,pg_class
中有一个 relacl
字段:
select oid::regclass, relacl from pg_class;
其他目录中也有类似的字段,即pg_type
中的typacl
和pg_proc
中的proacl
。
您可能还想使用另外两个目录,即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 黑客名单上的次数比他们在这里的次数要多。
【讨论】:
这正是我最初的问题起源的情况。系统目录提供了所有信息,但格式不符合我的目的。除了解析各种基于 acl 文本的列之外,我正在寻找一种更直接的方法来检查每个用户的权限。所以恐怕这不是将奖励奖金的答案,而是感谢您的尝试。 +1 表示许多有用的成分,尤其是aclexplode
,但可以说,仍有人可以“把它们放在一起”。
@IMSoP:我确信帕特里克足够聪明和有能力完成它。如果他的问题真的是在探测目录后如何解析权限,aclexplode()
示例应该会直接引导他找到解决方案。如果没有,他可以随时聘请顾问(提示:我!我!)。
@Denis 我猜这个答案感觉有点未完成的原因是有很多“这个可能有用”,而不是“你可以使用这些确切的表格,加上这个函数;这也可能很方便”(即使您没有计算出确切的 JOIN 和 UNION)。但最后,你是否想停在那里;它仍然有很多非常有用的信息。
@Denis: aclexplode()
不是解决方案,因为(a)它仍然需要字符串解析(不是我自己,但仍然); (b) 它适用于从对象到用户(因此,为了检查特定用户的权限,我必须让 PG 将 acl 数据转换为 all 对象的字符串,然后将这些字符串 acexplode一堆数组,然后解析所有数组以查看我的用户是否隐藏在其中)。不完全是一项有效的工作。因此,虽然它是 a 解决方案,但它不是 解决方案。另请参阅我对上述问题的补充。【参考方案2】:
可能不是最好/最有效的方法,但它对我有很大帮助!我在删除角色和出错时遇到问题时需要它。
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'
【讨论】:
以上是关于检索特定角色的所有对象权限的主要内容,如果未能解决你的问题,请参考以下文章