web-dev-qa-db-ja.com

ユーザーがメンバーになっているすべてのロール(継承されたロールを含む)を取得するにはどうすればよいですか?

2つのPostgresqlデータベースグループ、「作成者」と「編集者」、および2人のユーザー「maxwell」と「ernest」があるとします。

create role authors;

create role editors;

create user maxwell;

create user ernest;

grant authors to editors; --editors can do what authors can do

grant editors to maxwell; --maxwell is an editor

grant authors to ernest; --ernest is an author

Maxwellが属しているロール(できればそれらのOID)のリストを返す、次のようなパフォーマンス関数を記述したいと思います。

create or replace function get_all_roles() returns oid[] ...

Maxwell、作者、編集者(アーネストではない)のOIDを返す必要があります。

しかし、相続があるときにどうすればいいのかわかりません。

26
Neil McGuigan

再帰クエリ 、特に pg_auth_members

WITH RECURSIVE cte AS (
   SELECT oid FROM pg_roles WHERE rolname = 'maxwell'

   UNION ALL
   SELECT m.roleid
   FROM   cte
   JOIN   pg_auth_members m ON m.member = cte.oid
   )
SELECT oid, oid::regrole::text AS rolename FROM cte;  -- oid & name

オブジェクト識別子タイプregroleへのキャストに関するマニュアル。

ところで、INHERITCREATE ROLE と入力する必要はありません。

ところで:循環依存はできません。 Postgresはそれを許可しません。そのため、これを確認する必要はありません。

26

短縮版:

_SELECT a.oid 
FROM pg_authid a 
WHERE pg_has_role('maxwell', a.oid, 'member');
_

ここでは ロール名をサブジェクトとして使用する_pg_has_role_のバージョンと、メンバーシップをテストするロールoid を使用し、memberモードを渡して継承されたメンバーシップをテストします。

_pg_has_role_を使用する利点は、PostgreSQLのロール情報の内部キャッシュを使用して、メンバーシップクエリをすばやく満たすことです。

_SECURITY DEFINER_はアクセスを制限されているため、これを_pg_authid_関数でラップすることができます。何かのようなもの:

_CREATE OR REPLACE FUNCTION user_role_memberships(text)
RETURNS SETOF oid
LANGUAGE sql
SECURITY DEFINER
SET search_path = pg_catalog, pg_temp
AS $$
SELECT a.oid 
FROM pg_authid a 
WHERE pg_has_role($1, a.oid, 'member');
$$;

REVOKE EXECUTE ON FUNCTION user_role_memberships(text) FROM public;

GRANT EXECUTE ON FUNCTION user_role_memberships(text) TO ...whoever...;
_

pg_get_userbyid(oid)を使用すると、_pg_authid_をクエリする必要なく、oidからロール名を取得できます。

_SELECT a.oid AS member_oid, pg_get_userbyid(oid) AS member_name
FROM pg_authid a 
WHERE pg_has_role('maxwell', a.oid, 'member');
_
19
Craig Ringer

これは、スーパーユーザー以外が直接使用できる Craig Ringerの回答 の簡易バージョンです。

 SELECT oid, rolname FROM pg_roles WHERE
   pg_has_role( 'maxwell', oid, 'member');

pg_rolesは、pg_authidとは異なり、パスワードを明らかにしないため、基本的にはpg_authidの一般公開されたビューです。ベースoidもビューにエクスポートされます。パスワードが不要な場合は、専用のスーパーユーザーが所有する関数を作成しても意味がありません。

16
Daniel Vérité

これが私の見解です。特定のユーザーまたはすべてのユーザーに対して機能します。

select a.oid as user_role_id
, a.rolname as user_role_name
, b.roleid as other_role_id
, c.rolname as other_role_name
from pg_roles a
inner join pg_auth_members b on a.oid=b.member
inner join pg_roles c on b.roleid=c.oid 
where a.rolname = 'user_1'
4
Alexis.Rolland

これでうまくいくと思います

SELECT 
    oid 
FROM 
    pg_roles 
WHERE 
    oid IN (SELECT 
                roleid 
            FROM 
                pg_auth_members 
            WHERE 
                member=(SELECT oid FROM pg_roles WHERE rolname='maxwell'));

ロール名を取得する場合は、最初のoidrolnameに置き換えます。

1
SureShotUK

現在アクティブな役割のすべての役割を知りたい場合:

CREATE OR REPLACE VIEW public.my_roles
AS WITH RECURSIVE cte AS (
         SELECT pg_roles.oid,
            pg_roles.rolname
           FROM pg_roles
          WHERE pg_roles.rolname = CURRENT_USER
        UNION ALL
         SELECT m.roleid,
            pgr.rolname
           FROM cte cte_1
             JOIN pg_auth_members m ON m.member = cte_1.oid
             JOIN pg_roles pgr ON pgr.oid = m.roleid
        )
 SELECT array_agg(cte.rolname) AS my_roles
   FROM cte;
0