mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 18:17:35 +00:00

# Which Problems Are Solved Add the possibility to filter project resources based on project member roles. # How the Problems Are Solved Extend and refactor existing Pl/PgSQL functions to implement the following: - Solve O(n) complexity in returned resources IDs by returning a boolean filter for instance level permissions. - Individually permitted orgs are returned only if there was no instance permission - Individually permitted projects are returned only if there was no instance permission - Because of the multiple filter terms, use `INNER JOIN`s instead of `WHERE` clauses. # Additional Changes - system permission function no longer query the organization view and therefore can be `immutable`, giving big performance benefits for frequently reused system users. (like our hosted login in Zitadel cloud) - The permitted org and project functions are now defined as `stable` because the don't modify on-disk data. This might give a small performance gain - The Pl/PgSQL functions are now tested using Go unit tests. # Additional Context - Depends on https://github.com/zitadel/zitadel/pull/9677 - Part of https://github.com/zitadel/zitadel/issues/9188 - Closes https://github.com/zitadel/zitadel/issues/9190
115 lines
3.5 KiB
PL/PgSQL
115 lines
3.5 KiB
PL/PgSQL
DROP FUNCTION IF EXISTS eventstore.check_system_user_perms;
|
|
DROP FUNCTION IF EXISTS eventstore.get_system_permissions;
|
|
DROP TYPE IF EXISTS eventstore.project_grant;
|
|
|
|
|
|
/*
|
|
Function get_system_permissions unpacks an JSON array of system member permissions,
|
|
into a table format. Each array entry maps to one row representing a membership which
|
|
contained the req_permission.
|
|
|
|
[
|
|
{
|
|
"member_type": "IAM",
|
|
"aggregate_id": "310716990375453665",
|
|
"object_id": "",
|
|
"permissions": ["iam.read", "iam.write", "iam.policy.read"]
|
|
},
|
|
...
|
|
]
|
|
|
|
| member_type | aggregate_id | object_id |
|
|
| "IAM" | "310716990375453665" | null |
|
|
*/
|
|
CREATE OR REPLACE FUNCTION eventstore.get_system_permissions(
|
|
permissions_json JSONB
|
|
, permm TEXT
|
|
)
|
|
RETURNS TABLE (
|
|
member_type TEXT,
|
|
aggregate_id TEXT,
|
|
object_id TEXT
|
|
)
|
|
LANGUAGE 'plpgsql' IMMUTABLE
|
|
AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT res.member_type, res.aggregate_id, res.object_id FROM (
|
|
SELECT
|
|
(perm)->>'member_type' AS member_type,
|
|
(perm)->>'aggregate_id' AS aggregate_id,
|
|
(perm)->>'object_id' AS object_id,
|
|
permission
|
|
FROM jsonb_array_elements(permissions_json) AS perm
|
|
CROSS JOIN jsonb_array_elements_text(perm->'permissions') AS permission) AS res
|
|
WHERE res.permission = permm;
|
|
END;
|
|
$$;
|
|
|
|
/*
|
|
Type project_grant is composite identifier using its project and grant IDs.
|
|
*/
|
|
CREATE TYPE eventstore.project_grant AS (
|
|
project_id TEXT -- mapped from a permission's aggregate_id
|
|
, grant_id TEXT -- mapped from a permission's object_id
|
|
);
|
|
|
|
/*
|
|
Function check_system_user_perms uses system member permissions to establish
|
|
on which organization, project or project grant the user has the requested permission.
|
|
The permission can also apply to the complete instance when a IAM membership matches
|
|
the requested instance ID, or through system membership.
|
|
|
|
See eventstore.get_system_permissions() on the supported JSON format.
|
|
*/
|
|
CREATE OR REPLACE FUNCTION eventstore.check_system_user_perms(
|
|
system_user_perms JSONB
|
|
, req_instance_id TEXT
|
|
, perm TEXT
|
|
|
|
, instance_permitted OUT BOOLEAN
|
|
, org_ids OUT TEXT[]
|
|
, project_ids OUT TEXT[]
|
|
, project_grants OUT eventstore.project_grant[]
|
|
)
|
|
LANGUAGE 'plpgsql' IMMUTABLE
|
|
AS $$
|
|
BEGIN
|
|
-- make sure no nulls are returned
|
|
instance_permitted := FALSE;
|
|
org_ids := ARRAY[]::TEXT[];
|
|
project_ids := ARRAY[]::TEXT[];
|
|
project_grants := ARRAY[]::eventstore.project_grant[];
|
|
DECLARE
|
|
p RECORD;
|
|
BEGIN
|
|
FOR p IN SELECT member_type, aggregate_id, object_id
|
|
FROM eventstore.get_system_permissions(system_user_perms, perm)
|
|
LOOP
|
|
CASE p.member_type
|
|
WHEN 'System' THEN
|
|
instance_permitted := TRUE;
|
|
RETURN;
|
|
WHEN 'IAM' THEN
|
|
IF p.aggregate_id = req_instance_id THEN
|
|
instance_permitted := TRUE;
|
|
RETURN;
|
|
END IF;
|
|
WHEN 'Organization' THEN
|
|
IF p.aggregate_id != '' THEN
|
|
org_ids := array_append(org_ids, p.aggregate_id);
|
|
END IF;
|
|
WHEN 'Project' THEN
|
|
IF p.aggregate_id != '' THEN
|
|
project_ids := array_append(project_ids, p.aggregate_id);
|
|
END IF;
|
|
WHEN 'ProjectGrant' THEN
|
|
IF p.aggregate_id != '' THEN
|
|
project_grants := array_append(project_grants, ROW(p.aggregate_id, p.object_id)::eventstore.project_grant);
|
|
END IF;
|
|
END CASE;
|
|
END LOOP;
|
|
END;
|
|
END;
|
|
$$;
|