From 889c175bbda605a518fc96325e2d5b1ff60a2e1c Mon Sep 17 00:00:00 2001 From: Iraq Jaber Date: Mon, 17 Mar 2025 18:06:15 +0400 Subject: [PATCH] fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! feat(permissions): Addeding system user support for permission check v2 --- Makefile | 3 +- cmd/mirror/config.go | 6 +- cmd/setup/49/01-permitted_orgs_function.sql | 4 +- cmd/setup/51/01-permitted_orgs_function.sql | 175 +++++++++----------- cmd/start/config.go | 2 - internal/api/authz/authorization.go | 56 +++---- internal/api/authz/context.go | 8 +- internal/api/authz/permissions.go | 4 +- internal/api/authz/system_token.go | 13 +- internal/integration/config/zitadel.yaml | 118 +------------ internal/query/permission.go | 42 +++-- internal/query/user.go | 7 +- 12 files changed, 145 insertions(+), 293 deletions(-) diff --git a/Makefile b/Makefile index e5cc24f1f8..27e76c0614 100644 --- a/Makefile +++ b/Makefile @@ -113,8 +113,7 @@ core_unit_test: .PHONY: core_integration_db_up core_integration_db_up: - # docker compose -f internal/integration/config/docker-compose.yaml up --pull always --wait $${INTEGRATION_DB_FLAVOR} cache - docker compose -f internal/integration/config/docker-compose.yaml up --wait $${INTEGRATION_DB_FLAVOR} cache + docker compose -f internal/integration/config/docker-compose.yaml up --pull always --wait $${INTEGRATION_DB_FLAVOR} cache .PHONY: core_integration_db_down core_integration_db_down: diff --git a/cmd/mirror/config.go b/cmd/mirror/config.go index cc98000869..dfba6753ce 100644 --- a/cmd/mirror/config.go +++ b/cmd/mirror/config.go @@ -28,10 +28,8 @@ type Migration struct { Machine *id.Config } -var ( - //go:embed defaults.yaml - defaultConfig []byte -) +//go:embed defaults.yaml +var defaultConfig []byte func mustNewMigrationConfig(v *viper.Viper) *Migration { config := new(Migration) diff --git a/cmd/setup/49/01-permitted_orgs_function.sql b/cmd/setup/49/01-permitted_orgs_function.sql index 9f291c016b..84ee2e5f2d 100644 --- a/cmd/setup/49/01-permitted_orgs_function.sql +++ b/cmd/setup/49/01-permitted_orgs_function.sql @@ -43,14 +43,14 @@ BEGIN END; -- Return the organizations where permission were granted thru org-level roles - SELECT array_agg(org_id) INTO org_ids + SELECT array_agg(sub.org_id) INTO org_ids FROM ( SELECT DISTINCT om.org_id FROM eventstore.org_members om WHERE om.role = ANY(matched_roles) AND om.instance_id = instanceID AND om.user_id = userId - ); + ) AS sub; RETURN; END; $$; diff --git a/cmd/setup/51/01-permitted_orgs_function.sql b/cmd/setup/51/01-permitted_orgs_function.sql index 9ac526bba8..57d452dff3 100644 --- a/cmd/setup/51/01-permitted_orgs_function.sql +++ b/cmd/setup/51/01-permitted_orgs_function.sql @@ -3,42 +3,67 @@ DROP FUNCTION IF EXISTS eventstore.permitted_orgs; CREATE OR REPLACE FUNCTION eventstore.permitted_orgs( instanceId TEXT , userId TEXT + , system_user_perms JSONB , perm TEXT - , system_user_memeber_type INTEGER[] - , system_user_instance_id TEXT[] - , system_user_aggregate_id TEXT[] - , system_user_permissions TEXT[][] - , system_user_permissions_length INTEGER[] , filter_orgs TEXT , org_ids OUT TEXT[] ) LANGUAGE 'plpgsql' - STABLE + -- STABLE AS $$ DECLARE matched_roles TEXT[]; -- roles containing permission BEGIN - IF system_user_memeber_type IS NOT NULL THEN + -- if system user + IF jsonb_array_length(system_user_perms) = 0 THEN DECLARE - system_user_permission_found bool; + has_instance_or_iam_permission bool; BEGIN - SELECT result.perm_found INTO system_user_permission_found - FROM (SELECT eventstore.get_org_permission(perm, instanceId,filter_orgs, - system_user_memeber_type, system_user_instance_id, system_user_aggregate_id, - system_user_permissions, system_user_permissions_length) AS perm_found) AS result; - IF system_user_permission_found THEN + DROP TABLE IF EXISTS matching_system_user_perms; + CREATE TEMPORARY TABLE matching_system_user_perms ( + member_type TEXT, + -- instance_id TEXT, + aggregate_id TEXT, + object_id TEXT, + permission TEXT + ) ON COMMIT DROP; + + + INSERT INTO matching_system_user_perms + (SELECT * FROM eventstore.get_system_permissions(system_user_perms, perm)); + + -- check instance or iam level + SELECT true INTO has_instance_or_iam_permission + FROM matching_system_user_perms msup + WHERE (msup.member_type = 'System' AND msup.aggregate_id = '') + OR (msup.member_type = 'System' AND msup.aggregate_id = instanceId) + OR (msup.member_type = 'IAM' AND msup.aggregate_id = instanceId) + LIMIT 1; + + IF has_instance_or_iam_permission THEN + -- Return all organizations or only those in filter_orgs SELECT array_agg(o.org_id) INTO org_ids - FROM eventstore.instance_orgs o - WHERE o.instance_id = instanceId - AND CASE WHEN filter_orgs != '' - THEN o.org_id IN (filter_orgs) - ELSE TRUE END; + FROM eventstore.instance_orgs o + WHERE o.instance_id = instanceId + AND CASE WHEN filter_orgs != '' + THEN o.org_id IN (filter_orgs) + ELSE TRUE END; + RETURN; END IF; + + -- SELECT array_agg(msup.aggregate_id) INTO org_ids + -- FROM matching_system_user_perms msup + -- WHERE msup.instance_id = instanceId + -- AND msup.member_type = 'Organization' + -- AND CASE WHEN filter_orgs != '' + -- THEN msup.aggregate_id IN (filter_orgs) + -- ELSE TRUE END; + -- RETURN; + END; - RETURN; END IF; SELECT array_agg(rp.role) INTO matched_roles @@ -48,14 +73,14 @@ BEGIN -- First try if the permission was granted thru an instance-level role DECLARE - has_instance_permission bool; + has_instance_permission bool; BEGIN SELECT true INTO has_instance_permission FROM eventstore.instance_members im - WHERE im.role = ANY(matched_roles) - AND im.instance_id = instanceId - AND im.user_id = userId - LIMIT 1; + WHERE im.role = ANY(matched_roles) + AND im.instance_id = instanceId + AND im.user_id = userId + LIMIT 1; IF has_instance_permission THEN -- Return all organizations or only those in filter_orgs @@ -82,84 +107,32 @@ BEGIN END; $$; -DROP FUNCTION IF EXISTS eventstore.get_org_permission; -CREATE OR REPLACE FUNCTION eventstore.get_org_permission( - perm TEXT - , instance_idd TEXT - , org_id TEXT - , system_user_memeber_type INTEGER[] - , sustem_user_instance_id TEXT[] - , system_user_aggregate_id TEXT[] - , system_user_permissions TEXT[][] - , system_user_permissions_length INTEGER[] --- , outt OUT TEXT[] - , outt OUT BOOL + + + +DROP FUNCTION IF EXISTS eventstore.get_system_permissions; +CREATE OR REPLACE FUNCTION eventstore.get_system_permissions( + permissions_json JSONB + , permm TEXT + -- , res OUT eventstore.system_perms ) - LANGUAGE 'plpgsql' -AS $$ -DECLARE - i INTEGER; - length INTEGER; - permission_length INTEGER; -BEGIN - -- outt := FALSE; - length := array_length(system_user_memeber_type, 1); - -- length := 3; - - DROP TABLE IF EXISTS permissions; - CREATE TEMPORARY TABLE permissions ( - member_type INTEGER, - instance_id TEXT, +RETURNS TABLE ( + member_type TEXT, + -- instance_id TEXT, aggregate_id TEXT, + object_id TEXT, permission TEXT - ); - - -- <> - FOR i IN 1..length LOOP - -- only interested in organization level and higher - IF system_user_memeber_type[i] > 3 THEN - CONTINUE; - END IF; - permission_length := system_user_permissions_length[i]; - - FOR j IN 1..permission_length LOOP - IF system_user_permissions[i][j] != perm THEN - CONTINUE; - END IF; - INSERT INTO permissions (member_type, instance_id, aggregate_id, permission) VALUES - (system_user_memeber_type[i], sustem_user_instance_id[i], system_user_aggregate_id[i], system_user_permissions[i][j] ); --- outt := 555; --- RETURN; - END LOOP; - END LOOP; - - -- outt := (SELECT permission FROM permissions LIMIT 1); - SELECT result.res INTO outt - FROM (SELECT TRUE AS res FROM permissions p - WHERE - -- check instance id - CASE WHEN p.member_type = 1 OR p.member_type = 2 THEN -- System or IAM - p.aggregate_id = instance_idd - -- OR p.instance_id IS NULL - OR p.instance_id = '' - ELSE - p.instance_id = instance_idd - -- OR p.instance_id IS NULL - OR p.instance_id = '' - END - AND - -- check organization - CASE WHEN p.member_type = 3 THEN -- organization - p.aggregate_id = org_id - ELSE - TRUE - END - Limit 1 - ) AS result; - - DROP TABLE permissions; - +) AS $$ +BEGIN + RETURN QUERY + SELECT * FROM ( + SELECT + (perm)->>'member_type' AS member_type, + (perm)->>'aggregate_id' AS agregate_id, + (perm)->>'object_id' AS objectId, + permis AS permission + FROM jsonb_array_elements(permissions_json) AS perm + CROSS JOIN jsonb_array_elements_text(perm->'permissions') AS permis) as p + WHERE p.permission = permm; END; -$$; - - +$$ LANGUAGE plpgsql; diff --git a/cmd/start/config.go b/cmd/start/config.go index 380cc91029..25d3e3c505 100644 --- a/cmd/start/config.go +++ b/cmd/start/config.go @@ -1,7 +1,6 @@ package start import ( - "fmt" "time" "github.com/mitchellh/mapstructure" @@ -131,7 +130,6 @@ func MustNewConfig(v *viper.Viper) *Config { // Copy the global role permissions mappings to the instance until we allow instance-level configuration over the API. config.DefaultInstance.RolePermissionMappings = config.InternalAuthZ.RolePermissionMappings - fmt.Printf("@@ >>>>>>>>>>>>>>>>>>>>>>>>>>>> config.SystemAuthZ = %+v\n", config.SystemAuthZ) return config } diff --git a/internal/api/authz/authorization.go b/internal/api/authz/authorization.go index 13323324a4..27267ce33b 100644 --- a/internal/api/authz/authorization.go +++ b/internal/api/authz/authorization.go @@ -32,7 +32,7 @@ func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID, if requiredAuthOption.Permission == authenticated { return func(parent context.Context) context.Context { - parent = addGetSystemUserRolesFuncToCtx(parent, SystemAuthConfig.RolePermissionMappings, nil, ctxData) + parent = addGetSystemUserRolesFuncToCtx(parent, SystemAuthConfig.RolePermissionMappings, ctxData) return context.WithValue(parent, dataKey, ctxData) }, nil } @@ -53,7 +53,7 @@ func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID, parent = context.WithValue(parent, dataKey, ctxData) parent = context.WithValue(parent, allPermissionsKey, allPermissions) parent = context.WithValue(parent, requestPermissionsKey, requestedPermissions) - parent = addGetSystemUserRolesFuncToCtx(parent, SystemAuthConfig.RolePermissionMappings, requestedPermissions, ctxData) + parent = addGetSystemUserRolesFuncToCtx(parent, SystemAuthConfig.RolePermissionMappings, ctxData) return parent }, nil } @@ -130,42 +130,34 @@ func GetAllPermissionCtxIDs(perms []string) []string { return ctxIDs } -type SystemUserAuthParams struct { - MemberType []int32 - InstanceID []string - AggregateID []string - Permissions [][]string - PermissionsLength []int32 +type SystemUserPermissionsDBQuery struct { + MemberType string `json:"member_type"` + AggregateID string `json:"aggregate_id"` + ObjectID string `json:"object_id"` + Permissions []string `json:"permissions"` } -func addGetSystemUserRolesFuncToCtx(ctx context.Context, systemUserRoleMap []RoleMapping, requestedPermissions []string, ctxData CtxData) context.Context { +func addGetSystemUserRolesFuncToCtx(ctx context.Context, systemUserRoleMap []RoleMapping, ctxData CtxData) context.Context { if len(ctxData.SystemMemberships) == 0 { return ctx - // } else if ctxData.SystemMemberships[0].MemberType == MemberTypeSystem { } else { - ctx = context.WithValue(ctx, systemUserRolesFuncKey, func() func(ctx context.Context) *SystemUserAuthParams { - var systemUserAuthParams *SystemUserAuthParams + ctx = context.WithValue(ctx, systemUserRolesFuncKey, func() func(ctx context.Context) []SystemUserPermissionsDBQuery { + var systemUserPermissionsDbJsonQueryStruct []SystemUserPermissionsDBQuery chann := make(chan struct{}, 1) - return func(ctx context.Context) *SystemUserAuthParams { - if systemUserAuthParams != nil { - return systemUserAuthParams + return func(ctx context.Context) []SystemUserPermissionsDBQuery { + if systemUserPermissionsDbJsonQueryStruct != nil { + return systemUserPermissionsDbJsonQueryStruct } chann <- struct{}{} defer func() { <-chann }() - if systemUserAuthParams != nil { - return systemUserAuthParams + if systemUserPermissionsDbJsonQueryStruct != nil { + return systemUserPermissionsDbJsonQueryStruct } - systemUserAuthParams = &SystemUserAuthParams{ - MemberType: make([]int32, len(ctxData.SystemMemberships)), - InstanceID: make([]string, len(ctxData.SystemMemberships)), - AggregateID: make([]string, len(ctxData.SystemMemberships)), - Permissions: make([][]string, len(ctxData.SystemMemberships)), - PermissionsLength: make([]int32, len(ctxData.SystemMemberships)), - } + systemUserPermissionsDbJsonQueryStruct = make([]SystemUserPermissionsDBQuery, len(ctxData.SystemMemberships)) for i, systemPerm := range ctxData.SystemMemberships { permissions := []string{} @@ -175,25 +167,23 @@ func addGetSystemUserRolesFuncToCtx(ctx context.Context, systemUserRoleMap []Rol slices.Sort(permissions) permissions = slices.Compact(permissions) - systemUserAuthParams.MemberType[i] = MemberTypeServerToMemberTypeDBMap[systemPerm.MemberType] - systemUserAuthParams.InstanceID[i] = systemPerm.InstanceID - systemUserAuthParams.AggregateID[i] = systemPerm.AggregateID - systemUserAuthParams.Permissions[i] = permissions - systemUserAuthParams.PermissionsLength[i] = int32(len(permissions)) + systemUserPermissionsDbJsonQueryStruct[i].MemberType = MemberTypeServerToMemberTypeDBMap[systemPerm.MemberType] + systemUserPermissionsDbJsonQueryStruct[i].AggregateID = systemPerm.AggregateID + systemUserPermissionsDbJsonQueryStruct[i].Permissions = permissions } - return systemUserAuthParams + return systemUserPermissionsDbJsonQueryStruct } }()) } return ctx } -func GetSystemUserAuthParams(ctx context.Context) (*SystemUserAuthParams, error) { +func GetSystemUserPermissions(ctx context.Context) ([]SystemUserPermissionsDBQuery, error) { getSystemUserRolesFuncValue := ctx.Value(systemUserRolesFuncKey) if getSystemUserRolesFuncValue == nil { - return &SystemUserAuthParams{}, nil + return nil, nil } - getSystemUserRolesFunc, ok := getSystemUserRolesFuncValue.(func(context.Context) *SystemUserAuthParams) + getSystemUserRolesFunc, ok := getSystemUserRolesFuncValue.(func(context.Context) []SystemUserPermissionsDBQuery) if !ok { return nil, errors.New("unable to obtain systems role func") } diff --git a/internal/api/authz/context.go b/internal/api/authz/context.go index d3759efbc7..9e48e79625 100644 --- a/internal/api/authz/context.go +++ b/internal/api/authz/context.go @@ -72,10 +72,10 @@ const ( MemberTypeSystem ) -var MemberTypeServerToMemberTypeDBMap map[MemberType]int32 = map[MemberType]int32{ - MemberTypeSystem: 1, - MemberTypeIAM: 2, - MemberTypeOrganization: 3, +var MemberTypeServerToMemberTypeDBMap map[MemberType]string = map[MemberType]string{ + MemberTypeSystem: "System", + MemberTypeIAM: "IAM", + MemberTypeOrganization: "Organization", } type TokenVerifier interface { diff --git a/internal/api/authz/permissions.go b/internal/api/authz/permissions.go index 891347abb7..3d3c65e5d9 100644 --- a/internal/api/authz/permissions.go +++ b/internal/api/authz/permissions.go @@ -32,8 +32,8 @@ func getUserPermissions(ctx context.Context, resolver MembershipsResolver, requi if ctxData.SystemMemberships != nil { // for when we get rid of internalAuthz - // requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, SystemUserRoleMappings) - requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, roleMappings) + requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, SystemUserRoleMappings) + // requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, roleMappings) return requestedPermissions, allPermissions, nil } diff --git a/internal/api/authz/system_token.go b/internal/api/authz/system_token.go index f6c92b7fea..b8e360f8fa 100644 --- a/internal/api/authz/system_token.go +++ b/internal/api/authz/system_token.go @@ -4,13 +4,11 @@ import ( "context" "crypto/rsa" "errors" - "fmt" "os" "sync" "time" "github.com/go-jose/go-jose/v4" - "github.com/zitadel/logging" "github.com/zitadel/oidc/v3/pkg/op" "github.com/zitadel/zitadel/internal/crypto" @@ -33,14 +31,7 @@ func StartSystemTokenVerifierFromConfig(issuer string, keys map[string]*SystemAP } for _, membership := range key.Memberships { switch membership.MemberType { - case MemberTypeSystem, MemberTypeIAM: - systemUsers[userID] = key.Memberships - case MemberTypeOrganization: - if membership.AggregateID != "" && membership.InstanceID == "" { - errorMsg := fmt.Sprintf("system user %s must include InstancID if AggregateID is set for member type Organization", userID) - logging.Error(errorMsg) - return nil, errors.New(errorMsg) - } + case MemberTypeSystem, MemberTypeIAM, MemberTypeOrganization: systemUsers[userID] = key.Memberships case MemberTypeUnspecified, MemberTypeProject, MemberTypeProjectGrant: return nil, errors.New("for system users, only the membership types System, IAM and Organization are supported") @@ -76,7 +67,7 @@ func (s *SystemTokenVerifierFromConfig) VerifySystemToken(ctx context.Context, t for _, membership := range systemUserMemberships { if membership.MemberType == MemberTypeSystem || membership.MemberType == MemberTypeIAM && GetInstance(ctx).InstanceID() == membership.AggregateID || - membership.MemberType == MemberTypeOrganization && orgID == membership.AggregateID && GetInstance(ctx).InstanceID() == membership.InstanceID { + membership.MemberType == MemberTypeOrganization && orgID == membership.AggregateID { matchingMemberships = append(matchingMemberships, membership) } } diff --git a/internal/integration/config/zitadel.yaml b/internal/integration/config/zitadel.yaml index 48c1527549..c978af1822 100644 --- a/internal/integration/config/zitadel.yaml +++ b/internal/integration/config/zitadel.yaml @@ -130,13 +130,6 @@ SystemAuthZ: - "system.quota.write" - "system.quota.delete" - "system.iam.member.read" - - Role: "SYSTEM_OWNER_VIEWER" - Permissions: - - "system.instance.read" - - "system.domain.read" - - "system.debug.read" - - "system.feature.read" - - "system.iam.member.read" - Role: "IAM_OWNER" Permissions: - "iam.read" @@ -235,47 +228,10 @@ SystemAuthZ: - "userschema.delete" - "session.read" - "session.delete" - - Role: "IAM_OWNER_VIEWER" - Permissions: - - "iam.read" - - "iam.policy.read" - - "iam.member.read" - - "iam.idp.read" - - "iam.action.read" - - "iam.flow.read" - - "iam.restrictions.read" - - "iam.feature.read" - - "iam.web_key.read" - - "iam.debug.read" - - "org.read" - - "org.member.read" - - "org.idp.read" - - "org.action.read" - - "org.flow.read" - - "org.feature.read" - - "user.read" - - "user.global.read" - - "user.grant.read" - - "user.membership.read" - - "user.feature.read" - - "policy.read" - - "project.read" - - "project.member.read" - - "project.role.read" - - "project.app.read" - - "project.grant.read" - - "project.grant.member.read" - - "events.read" - - "milestones.read" - - "action.target.read" - - "action.execution.read" - - "userschema.read" - - "session.read" - - Role: "IAM_ORG_MANAGER" + - Role: "ORG_OWNER" Permissions: - "org.read" - "org.global.read" - - "org.create" - "org.write" - "org.delete" - "org.member.read" @@ -321,7 +277,6 @@ SystemAuthZ: - "project.role.delete" - "project.app.read" - "project.app.write" - - "project.app.delete" - "project.grant.read" - "project.grant.write" - "project.grant.delete" @@ -329,74 +284,3 @@ SystemAuthZ: - "project.grant.member.write" - "project.grant.member.delete" - "session.delete" - - Role: "IAM_USER_MANAGER" - Permissions: - - "org.read" - - "org.global.read" - - "org.member.read" - - "org.member.delete" - - "user.read" - - "user.global.read" - - "user.write" - - "user.delete" - - "user.grant.read" - - "user.grant.write" - - "user.grant.delete" - - "user.membership.read" - - "user.passkey.write" - - "user.feature.read" - - "user.feature.write" - - "user.feature.delete" - - "project.read" - - "project.member.read" - - "project.role.read" - - "project.app.read" - - "project.grant.read" - - "project.grant.write" - - "project.grant.delete" - - "project.grant.member.read" - - "session.delete" - - Role: "IAM_ADMIN_IMPERSONATOR" - Permissions: - - "admin.impersonation" - - "impersonation" - - Role: "IAM_END_USER_IMPERSONATOR" - Permissions: - - "impersonation" - - Role: "IAM_LOGIN_CLIENT" - Permissions: - - "iam.read" - - "iam.policy.read" - - "iam.member.read" - - "iam.member.write" - - "iam.idp.read" - - "iam.feature.read" - - "iam.restrictions.read" - - "org.read" - - "org.member.read" - - "org.member.write" - - "org.idp.read" - - "org.feature.read" - - "user.read" - - "user.write" - - "user.grant.read" - - "user.grant.write" - - "user.membership.read" - - "user.credential.write" - - "user.passkey.write" - - "user.feature.read" - - "policy.read" - - "project.read" - - "project.member.read" - - "project.member.write" - - "project.role.read" - - "project.app.read" - - "project.member.read" - - "project.member.write" - - "project.grant.read" - - "project.grant.member.read" - - "project.grant.member.write" - - "session.read" - - "session.link" - - "session.delete" - - "userschema.read" diff --git a/internal/query/permission.go b/internal/query/permission.go index 1a4e94a10b..e139ded6c1 100644 --- a/internal/query/permission.go +++ b/internal/query/permission.go @@ -2,6 +2,7 @@ package query import ( "context" + "encoding/json" "fmt" sq "github.com/Masterminds/squirrel" @@ -11,48 +12,63 @@ import ( ) const ( - // eventstore.permitted_orgs(instanceid text, userid text, perm text, system_user_perms text[], filter_orgs text) - wherePermittedOrgsClause = "%s = ANY(eventstore.permitted_orgs(?, ?, ?, ?, ?, ?, ?, ?, ?))" + // eventstore.permitted_orgs(instanceid text, userid text, system_user_perms JSONB, perm text filter_orgs text) + wherePermittedOrgsClause = "%s = ANY(eventstore.permitted_orgs(?, ?, ?, ?, ?))" wherePermittedOrgsOrCurrentUserClause = "(" + wherePermittedOrgsClause + " OR %s = ?" + ")" ) // wherePermittedOrgs sets a `WHERE` clause to the query that filters the orgs // for which the authenticated user has the requested permission for. // The user ID is taken from the context. -// // The `orgIDColumn` specifies the table column to which this filter must be applied, // and is typically the `resource_owner` column in ZITADEL. // We use full identifiers in the query builder so this function should be // called with something like `UserResourceOwnerCol.identifier()` for example. -func wherePermittedOrgs(ctx context.Context, query sq.SelectBuilder, systemUserAuthParams *authz.SystemUserAuthParams, filterOrgIds, orgIDColumn, permission string) sq.SelectBuilder { +func wherePermittedOrgs(ctx context.Context, query sq.SelectBuilder, systemUserPermission []authz.SystemUserPermissionsDBQuery, filterOrgIds, orgIDColumn, permission string) (sq.SelectBuilder, error) { userID := authz.GetCtxData(ctx).UserID logging.WithFields("permission_check_v2_flag", authz.GetFeatures(ctx).PermissionCheckV2, "org_id_column", orgIDColumn, "permission", permission, "user_id", userID).Debug("permitted orgs check used") + systemUserPermissionsJson := "[]" + if systemUserPermission != nil { + systemUserPermissionsBytes, err := json.Marshal(systemUserPermission) + if err != nil { + return query, err + } + systemUserPermissionsJson = string(systemUserPermissionsBytes) + } + return query.Where( fmt.Sprintf(wherePermittedOrgsClause, orgIDColumn), authz.GetInstance(ctx).InstanceID(), userID, + systemUserPermissionsJson, + systemUserPermission, permission, - systemUserAuthParams, filterOrgIds, - ) + ), nil } -func wherePermittedOrgsOrCurrentUser(ctx context.Context, query sq.SelectBuilder, systemUserAuthParams *authz.SystemUserAuthParams, filterOrgIds, orgIDColumn, userIdColum, permission string) sq.SelectBuilder { +func wherePermittedOrgsOrCurrentUser(ctx context.Context, query sq.SelectBuilder, systemUserPermission []authz.SystemUserPermissionsDBQuery, filterOrgIds, orgIDColumn, userIdColum, permission string) (sq.SelectBuilder, error) { userID := authz.GetCtxData(ctx).UserID logging.WithFields("permission_check_v2_flag", authz.GetFeatures(ctx).PermissionCheckV2, "org_id_column", orgIDColumn, "user_id_colum", userIdColum, "permission", permission, "user_id", userID).Debug("permitted orgs check used") + systemUserPermissionsJson := "[]" + if systemUserPermission != nil { + systemUserPermissionsBytes, err := json.Marshal(systemUserPermission) + if err != nil { + return query, err + } + systemUserPermissionsJson = string(systemUserPermissionsBytes) + } + fmt.Printf("@@ >>>>>>>>>>>>>>>>>>>>>>>>>>>> systemUserPermissionsJson = %+v\n", systemUserPermissionsJson) + return query.Where( fmt.Sprintf(wherePermittedOrgsOrCurrentUserClause, orgIDColumn, userIdColum), authz.GetInstance(ctx).InstanceID(), userID, + systemUserPermissionsJson, permission, - systemUserAuthParams.MemberType, - systemUserAuthParams.InstanceID, - systemUserAuthParams.AggregateID, - systemUserAuthParams.Permissions, - systemUserAuthParams.PermissionsLength, filterOrgIds, userID, - ) + ), nil } diff --git a/internal/query/user.go b/internal/query/user.go index 7e1aab2075..c3cb90066b 100644 --- a/internal/query/user.go +++ b/internal/query/user.go @@ -658,11 +658,14 @@ func (q *Queries) searchUsers(ctx context.Context, queries *UserSearchQueries, f }) if permissionCheckV2 { // extract system user roles - systemUserPermissions, err := authz.GetSystemUserAuthParams(ctx) + systemUserPermissions, err := authz.GetSystemUserPermissions(ctx) if err != nil { return nil, zerrors.ThrowInternal(err, "QUERY-GS9gs", "Errors.Internal") } - query = wherePermittedOrgsOrCurrentUser(ctx, query, systemUserPermissions, filterOrgIds, UserResourceOwnerCol.identifier(), UserIDCol.identifier(), domain.PermissionUserRead) + query, err = wherePermittedOrgsOrCurrentUser(ctx, query, systemUserPermissions, filterOrgIds, UserResourceOwnerCol.identifier(), UserIDCol.identifier(), domain.PermissionUserRead) + if err != nil { + return nil, err + } } stmt, args, err := query.ToSql()