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

This commit is contained in:
Iraq Jaber
2025-03-17 18:06:15 +04:00
parent a8f8757b1a
commit 889c175bbd
12 changed files with 145 additions and 293 deletions

View File

@@ -113,8 +113,7 @@ core_unit_test:
.PHONY: core_integration_db_up .PHONY: core_integration_db_up
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 --pull always --wait $${INTEGRATION_DB_FLAVOR} cache
docker compose -f internal/integration/config/docker-compose.yaml up --wait $${INTEGRATION_DB_FLAVOR} cache
.PHONY: core_integration_db_down .PHONY: core_integration_db_down
core_integration_db_down: core_integration_db_down:

View File

@@ -28,10 +28,8 @@ type Migration struct {
Machine *id.Config Machine *id.Config
} }
var ( //go:embed defaults.yaml
//go:embed defaults.yaml var defaultConfig []byte
defaultConfig []byte
)
func mustNewMigrationConfig(v *viper.Viper) *Migration { func mustNewMigrationConfig(v *viper.Viper) *Migration {
config := new(Migration) config := new(Migration)

View File

@@ -43,14 +43,14 @@ BEGIN
END; END;
-- Return the organizations where permission were granted thru org-level roles -- 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 ( FROM (
SELECT DISTINCT om.org_id SELECT DISTINCT om.org_id
FROM eventstore.org_members om FROM eventstore.org_members om
WHERE om.role = ANY(matched_roles) WHERE om.role = ANY(matched_roles)
AND om.instance_id = instanceID AND om.instance_id = instanceID
AND om.user_id = userId AND om.user_id = userId
); ) AS sub;
RETURN; RETURN;
END; END;
$$; $$;

View File

@@ -3,42 +3,67 @@ DROP FUNCTION IF EXISTS eventstore.permitted_orgs;
CREATE OR REPLACE FUNCTION eventstore.permitted_orgs( CREATE OR REPLACE FUNCTION eventstore.permitted_orgs(
instanceId TEXT instanceId TEXT
, userId TEXT , userId TEXT
, system_user_perms JSONB
, perm TEXT , 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 , filter_orgs TEXT
, org_ids OUT TEXT[] , org_ids OUT TEXT[]
) )
LANGUAGE 'plpgsql' LANGUAGE 'plpgsql'
STABLE -- STABLE
AS $$ AS $$
DECLARE DECLARE
matched_roles TEXT[]; -- roles containing permission matched_roles TEXT[]; -- roles containing permission
BEGIN BEGIN
IF system_user_memeber_type IS NOT NULL THEN -- if system user
IF jsonb_array_length(system_user_perms) = 0 THEN
DECLARE DECLARE
system_user_permission_found bool; has_instance_or_iam_permission bool;
BEGIN 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 SELECT array_agg(o.org_id) INTO org_ids
FROM eventstore.instance_orgs o FROM eventstore.instance_orgs o
WHERE o.instance_id = instanceId WHERE o.instance_id = instanceId
AND CASE WHEN filter_orgs != '' AND CASE WHEN filter_orgs != ''
THEN o.org_id IN (filter_orgs) THEN o.org_id IN (filter_orgs)
ELSE TRUE END; ELSE TRUE END;
RETURN;
END IF; 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; END;
RETURN;
END IF; END IF;
SELECT array_agg(rp.role) INTO matched_roles 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 -- First try if the permission was granted thru an instance-level role
DECLARE DECLARE
has_instance_permission bool; has_instance_permission bool;
BEGIN BEGIN
SELECT true INTO has_instance_permission SELECT true INTO has_instance_permission
FROM eventstore.instance_members im FROM eventstore.instance_members im
WHERE im.role = ANY(matched_roles) WHERE im.role = ANY(matched_roles)
AND im.instance_id = instanceId AND im.instance_id = instanceId
AND im.user_id = userId AND im.user_id = userId
LIMIT 1; LIMIT 1;
IF has_instance_permission THEN IF has_instance_permission THEN
-- Return all organizations or only those in filter_orgs -- Return all organizations or only those in filter_orgs
@@ -82,84 +107,32 @@ BEGIN
END; END;
$$; $$;
DROP FUNCTION IF EXISTS eventstore.get_org_permission;
CREATE OR REPLACE FUNCTION eventstore.get_org_permission(
perm TEXT
, instance_idd TEXT DROP FUNCTION IF EXISTS eventstore.get_system_permissions;
, org_id TEXT CREATE OR REPLACE FUNCTION eventstore.get_system_permissions(
, system_user_memeber_type INTEGER[] permissions_json JSONB
, sustem_user_instance_id TEXT[] , permm TEXT
, system_user_aggregate_id TEXT[] -- , res OUT eventstore.system_perms
, system_user_permissions TEXT[][]
, system_user_permissions_length INTEGER[]
-- , outt OUT TEXT[]
, outt OUT BOOL
) )
LANGUAGE 'plpgsql' RETURNS TABLE (
AS $$ member_type TEXT,
DECLARE -- instance_id TEXT,
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,
aggregate_id TEXT, aggregate_id TEXT,
object_id TEXT,
permission TEXT permission TEXT
); ) AS $$
BEGIN
-- <<outer_loop>> RETURN QUERY
FOR i IN 1..length LOOP SELECT * FROM (
-- only interested in organization level and higher SELECT
IF system_user_memeber_type[i] > 3 THEN (perm)->>'member_type' AS member_type,
CONTINUE; (perm)->>'aggregate_id' AS agregate_id,
END IF; (perm)->>'object_id' AS objectId,
permission_length := system_user_permissions_length[i]; permis AS permission
FROM jsonb_array_elements(permissions_json) AS perm
FOR j IN 1..permission_length LOOP CROSS JOIN jsonb_array_elements_text(perm->'permissions') AS permis) as p
IF system_user_permissions[i][j] != perm THEN WHERE p.permission = permm;
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;
END; END;
$$; $$ LANGUAGE plpgsql;

View File

@@ -1,7 +1,6 @@
package start package start
import ( import (
"fmt"
"time" "time"
"github.com/mitchellh/mapstructure" "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. // Copy the global role permissions mappings to the instance until we allow instance-level configuration over the API.
config.DefaultInstance.RolePermissionMappings = config.InternalAuthZ.RolePermissionMappings config.DefaultInstance.RolePermissionMappings = config.InternalAuthZ.RolePermissionMappings
fmt.Printf("@@ >>>>>>>>>>>>>>>>>>>>>>>>>>>> config.SystemAuthZ = %+v\n", config.SystemAuthZ)
return config return config
} }

View File

@@ -32,7 +32,7 @@ func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID,
if requiredAuthOption.Permission == authenticated { if requiredAuthOption.Permission == authenticated {
return func(parent context.Context) context.Context { 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) return context.WithValue(parent, dataKey, ctxData)
}, nil }, nil
} }
@@ -53,7 +53,7 @@ func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID,
parent = context.WithValue(parent, dataKey, ctxData) parent = context.WithValue(parent, dataKey, ctxData)
parent = context.WithValue(parent, allPermissionsKey, allPermissions) parent = context.WithValue(parent, allPermissionsKey, allPermissions)
parent = context.WithValue(parent, requestPermissionsKey, requestedPermissions) parent = context.WithValue(parent, requestPermissionsKey, requestedPermissions)
parent = addGetSystemUserRolesFuncToCtx(parent, SystemAuthConfig.RolePermissionMappings, requestedPermissions, ctxData) parent = addGetSystemUserRolesFuncToCtx(parent, SystemAuthConfig.RolePermissionMappings, ctxData)
return parent return parent
}, nil }, nil
} }
@@ -130,42 +130,34 @@ func GetAllPermissionCtxIDs(perms []string) []string {
return ctxIDs return ctxIDs
} }
type SystemUserAuthParams struct { type SystemUserPermissionsDBQuery struct {
MemberType []int32 MemberType string `json:"member_type"`
InstanceID []string AggregateID string `json:"aggregate_id"`
AggregateID []string ObjectID string `json:"object_id"`
Permissions [][]string Permissions []string `json:"permissions"`
PermissionsLength []int32
} }
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 { if len(ctxData.SystemMemberships) == 0 {
return ctx return ctx
// } else if ctxData.SystemMemberships[0].MemberType == MemberTypeSystem {
} else { } else {
ctx = context.WithValue(ctx, systemUserRolesFuncKey, func() func(ctx context.Context) *SystemUserAuthParams { ctx = context.WithValue(ctx, systemUserRolesFuncKey, func() func(ctx context.Context) []SystemUserPermissionsDBQuery {
var systemUserAuthParams *SystemUserAuthParams var systemUserPermissionsDbJsonQueryStruct []SystemUserPermissionsDBQuery
chann := make(chan struct{}, 1) chann := make(chan struct{}, 1)
return func(ctx context.Context) *SystemUserAuthParams { return func(ctx context.Context) []SystemUserPermissionsDBQuery {
if systemUserAuthParams != nil { if systemUserPermissionsDbJsonQueryStruct != nil {
return systemUserAuthParams return systemUserPermissionsDbJsonQueryStruct
} }
chann <- struct{}{} chann <- struct{}{}
defer func() { defer func() {
<-chann <-chann
}() }()
if systemUserAuthParams != nil { if systemUserPermissionsDbJsonQueryStruct != nil {
return systemUserAuthParams return systemUserPermissionsDbJsonQueryStruct
} }
systemUserAuthParams = &SystemUserAuthParams{ systemUserPermissionsDbJsonQueryStruct = make([]SystemUserPermissionsDBQuery, len(ctxData.SystemMemberships))
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)),
}
for i, systemPerm := range ctxData.SystemMemberships { for i, systemPerm := range ctxData.SystemMemberships {
permissions := []string{} permissions := []string{}
@@ -175,25 +167,23 @@ func addGetSystemUserRolesFuncToCtx(ctx context.Context, systemUserRoleMap []Rol
slices.Sort(permissions) slices.Sort(permissions)
permissions = slices.Compact(permissions) permissions = slices.Compact(permissions)
systemUserAuthParams.MemberType[i] = MemberTypeServerToMemberTypeDBMap[systemPerm.MemberType] systemUserPermissionsDbJsonQueryStruct[i].MemberType = MemberTypeServerToMemberTypeDBMap[systemPerm.MemberType]
systemUserAuthParams.InstanceID[i] = systemPerm.InstanceID systemUserPermissionsDbJsonQueryStruct[i].AggregateID = systemPerm.AggregateID
systemUserAuthParams.AggregateID[i] = systemPerm.AggregateID systemUserPermissionsDbJsonQueryStruct[i].Permissions = permissions
systemUserAuthParams.Permissions[i] = permissions
systemUserAuthParams.PermissionsLength[i] = int32(len(permissions))
} }
return systemUserAuthParams return systemUserPermissionsDbJsonQueryStruct
} }
}()) }())
} }
return ctx return ctx
} }
func GetSystemUserAuthParams(ctx context.Context) (*SystemUserAuthParams, error) { func GetSystemUserPermissions(ctx context.Context) ([]SystemUserPermissionsDBQuery, error) {
getSystemUserRolesFuncValue := ctx.Value(systemUserRolesFuncKey) getSystemUserRolesFuncValue := ctx.Value(systemUserRolesFuncKey)
if getSystemUserRolesFuncValue == nil { 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 { if !ok {
return nil, errors.New("unable to obtain systems role func") return nil, errors.New("unable to obtain systems role func")
} }

View File

@@ -72,10 +72,10 @@ const (
MemberTypeSystem MemberTypeSystem
) )
var MemberTypeServerToMemberTypeDBMap map[MemberType]int32 = map[MemberType]int32{ var MemberTypeServerToMemberTypeDBMap map[MemberType]string = map[MemberType]string{
MemberTypeSystem: 1, MemberTypeSystem: "System",
MemberTypeIAM: 2, MemberTypeIAM: "IAM",
MemberTypeOrganization: 3, MemberTypeOrganization: "Organization",
} }
type TokenVerifier interface { type TokenVerifier interface {

View File

@@ -32,8 +32,8 @@ func getUserPermissions(ctx context.Context, resolver MembershipsResolver, requi
if ctxData.SystemMemberships != nil { if ctxData.SystemMemberships != nil {
// for when we get rid of internalAuthz // for when we get rid of internalAuthz
// requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, SystemUserRoleMappings) requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, SystemUserRoleMappings)
requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, roleMappings) // requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, roleMappings)
return requestedPermissions, allPermissions, nil return requestedPermissions, allPermissions, nil
} }

View File

@@ -4,13 +4,11 @@ import (
"context" "context"
"crypto/rsa" "crypto/rsa"
"errors" "errors"
"fmt"
"os" "os"
"sync" "sync"
"time" "time"
"github.com/go-jose/go-jose/v4" "github.com/go-jose/go-jose/v4"
"github.com/zitadel/logging"
"github.com/zitadel/oidc/v3/pkg/op" "github.com/zitadel/oidc/v3/pkg/op"
"github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/crypto"
@@ -33,14 +31,7 @@ func StartSystemTokenVerifierFromConfig(issuer string, keys map[string]*SystemAP
} }
for _, membership := range key.Memberships { for _, membership := range key.Memberships {
switch membership.MemberType { switch membership.MemberType {
case MemberTypeSystem, MemberTypeIAM: case MemberTypeSystem, MemberTypeIAM, MemberTypeOrganization:
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)
}
systemUsers[userID] = key.Memberships systemUsers[userID] = key.Memberships
case MemberTypeUnspecified, MemberTypeProject, MemberTypeProjectGrant: case MemberTypeUnspecified, MemberTypeProject, MemberTypeProjectGrant:
return nil, errors.New("for system users, only the membership types System, IAM and Organization are supported") 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 { for _, membership := range systemUserMemberships {
if membership.MemberType == MemberTypeSystem || if membership.MemberType == MemberTypeSystem ||
membership.MemberType == MemberTypeIAM && GetInstance(ctx).InstanceID() == membership.AggregateID || 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) matchingMemberships = append(matchingMemberships, membership)
} }
} }

View File

@@ -130,13 +130,6 @@ SystemAuthZ:
- "system.quota.write" - "system.quota.write"
- "system.quota.delete" - "system.quota.delete"
- "system.iam.member.read" - "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" - Role: "IAM_OWNER"
Permissions: Permissions:
- "iam.read" - "iam.read"
@@ -235,47 +228,10 @@ SystemAuthZ:
- "userschema.delete" - "userschema.delete"
- "session.read" - "session.read"
- "session.delete" - "session.delete"
- Role: "IAM_OWNER_VIEWER" - Role: "ORG_OWNER"
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"
Permissions: Permissions:
- "org.read" - "org.read"
- "org.global.read" - "org.global.read"
- "org.create"
- "org.write" - "org.write"
- "org.delete" - "org.delete"
- "org.member.read" - "org.member.read"
@@ -321,7 +277,6 @@ SystemAuthZ:
- "project.role.delete" - "project.role.delete"
- "project.app.read" - "project.app.read"
- "project.app.write" - "project.app.write"
- "project.app.delete"
- "project.grant.read" - "project.grant.read"
- "project.grant.write" - "project.grant.write"
- "project.grant.delete" - "project.grant.delete"
@@ -329,74 +284,3 @@ SystemAuthZ:
- "project.grant.member.write" - "project.grant.member.write"
- "project.grant.member.delete" - "project.grant.member.delete"
- "session.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"

View File

@@ -2,6 +2,7 @@ package query
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
sq "github.com/Masterminds/squirrel" sq "github.com/Masterminds/squirrel"
@@ -11,48 +12,63 @@ import (
) )
const ( const (
// eventstore.permitted_orgs(instanceid text, userid text, perm text, system_user_perms text[], filter_orgs text) // eventstore.permitted_orgs(instanceid text, userid text, system_user_perms JSONB, perm text filter_orgs text)
wherePermittedOrgsClause = "%s = ANY(eventstore.permitted_orgs(?, ?, ?, ?, ?, ?, ?, ?, ?))" wherePermittedOrgsClause = "%s = ANY(eventstore.permitted_orgs(?, ?, ?, ?, ?))"
wherePermittedOrgsOrCurrentUserClause = "(" + wherePermittedOrgsClause + " OR %s = ?" + ")" wherePermittedOrgsOrCurrentUserClause = "(" + wherePermittedOrgsClause + " OR %s = ?" + ")"
) )
// wherePermittedOrgs sets a `WHERE` clause to the query that filters the orgs // wherePermittedOrgs sets a `WHERE` clause to the query that filters the orgs
// for which the authenticated user has the requested permission for. // for which the authenticated user has the requested permission for.
// The user ID is taken from the context. // The user ID is taken from the context.
//
// The `orgIDColumn` specifies the table column to which this filter must be applied, // The `orgIDColumn` specifies the table column to which this filter must be applied,
// and is typically the `resource_owner` column in ZITADEL. // and is typically the `resource_owner` column in ZITADEL.
// We use full identifiers in the query builder so this function should be // We use full identifiers in the query builder so this function should be
// called with something like `UserResourceOwnerCol.identifier()` for example. // 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 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") 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( return query.Where(
fmt.Sprintf(wherePermittedOrgsClause, orgIDColumn), fmt.Sprintf(wherePermittedOrgsClause, orgIDColumn),
authz.GetInstance(ctx).InstanceID(), authz.GetInstance(ctx).InstanceID(),
userID, userID,
systemUserPermissionsJson,
systemUserPermission,
permission, permission,
systemUserAuthParams,
filterOrgIds, 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 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") 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( return query.Where(
fmt.Sprintf(wherePermittedOrgsOrCurrentUserClause, orgIDColumn, userIdColum), fmt.Sprintf(wherePermittedOrgsOrCurrentUserClause, orgIDColumn, userIdColum),
authz.GetInstance(ctx).InstanceID(), authz.GetInstance(ctx).InstanceID(),
userID, userID,
systemUserPermissionsJson,
permission, permission,
systemUserAuthParams.MemberType,
systemUserAuthParams.InstanceID,
systemUserAuthParams.AggregateID,
systemUserAuthParams.Permissions,
systemUserAuthParams.PermissionsLength,
filterOrgIds, filterOrgIds,
userID, userID,
) ), nil
} }

View File

@@ -658,11 +658,14 @@ func (q *Queries) searchUsers(ctx context.Context, queries *UserSearchQueries, f
}) })
if permissionCheckV2 { if permissionCheckV2 {
// extract system user roles // extract system user roles
systemUserPermissions, err := authz.GetSystemUserAuthParams(ctx) systemUserPermissions, err := authz.GetSystemUserPermissions(ctx)
if err != nil { if err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-GS9gs", "Errors.Internal") 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() stmt, args, err := query.ToSql()