fixup! fixup! fixup! fixup! fixup! fixup! fixup! Merge branch 'main' into syste-users-permissions

Tims requested changes
This commit is contained in:
Iraq Jaber
2025-03-21 09:11:26 +04:00
parent 9eaefcf989
commit 8fdc46c7af
15 changed files with 187 additions and 339 deletions

View File

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

View File

@@ -12,7 +12,7 @@ import (
)
type InitPermittedOrgsFunction52 struct {
eventstoreClient *database.DB
dbClient *database.DB
}
//go:embed 52/*.sql
@@ -25,7 +25,7 @@ func (mig *InitPermittedOrgsFunction52) Execute(ctx context.Context, _ eventstor
}
for _, stmt := range statements {
logging.WithFields("file", stmt.file, "migration", mig.String()).Info("execute statement")
if _, err := mig.eventstoreClient.ExecContext(ctx, stmt.query); err != nil {
if _, err := mig.dbClient.ExecContext(ctx, stmt.query); err != nil {
return fmt.Errorf("%s %s: %w", mig.String(), stmt.file, err)
}
}

View File

@@ -2,6 +2,22 @@ DROP FUNCTION IF EXISTS eventstore.get_system_permissions;
CREATE OR REPLACE FUNCTION eventstore.get_system_permissions(
permissions_json JSONB
/*
[
{
"member_type": "System",
"aggregate_id": "",
"object_id": "",
"permissions": ["iam.read", "iam.write", "iam.polic.read"]
},
{
"member_type": "IAM",
"aggregate_id": "310716990375453665",
"object_id": "",
"permissions": ["iam.read", "iam.write", "iam.polic.read"]
}
]
*/
, permm TEXT
)
RETURNS TABLE (

View File

@@ -1,3 +1,111 @@
DROP FUNCTION IF EXISTS eventstore.check_system_user_perms;
CREATE OR REPLACE FUNCTION eventstore.check_system_user_perms(
system_user_perms JSONB
, perm TEXT
, filter_orgs TEXT
, org_ids OUT TEXT[]
)
LANGUAGE 'plpgsql'
AS $$
DECLARE
has_instance_or_iam_permission bool;
member_type_found bool;
aggregate_ids TEXT;
check_aggregates bool;
BEGIN
DROP TABLE IF EXISTS matching_system_user_perms;
CREATE TEMPORARY TABLE matching_system_user_perms (
member_type TEXT,
aggregate_id TEXT,
object_id TEXT
) ON COMMIT DROP;
INSERT INTO matching_system_user_perms
(SELECT * FROM eventstore.get_system_permissions(system_user_perms, perm));
-- System member type
SELECT TRUE INTO member_type_found
FROM matching_system_user_perms msup
WHERE msup.member_type = 'System'
LIMIT 1;
IF member_type_found 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
CASE WHEN filter_orgs != ''
THEN o.org_id IN (filter_orgs)
ELSE TRUE END;
RETURN;
END IF;
-- IAM member type
SELECT TRUE, array_agg(msup.aggregate_id) INTO member_type_found, aggregate_ids
FROM matching_system_user_perms msup
WHERE msup.member_type = 'IAM'
GROUP BY msup.member_type
LIMIT 1;
IF member_type_found THEN
IF (SELECT FALSE WHERE '' = ANY (aggregate_ids::TEXT[])) = FALSE THEN
check_aggregates := FALSE;
ELSE
check_aggregates := TRUE;
END IF;
-- Return all organizations or only those in filter_orgs
SELECT array_agg(o.org_id) INTO org_ids
FROM eventstore.instance_orgs o
WHERE CASE
WHEN check_aggregates THEN
o.instance_id = ANY (aggregate_ids::TEXT[])
ELSE
TRUE
END
AND CASE WHEN filter_orgs != ''
THEN o.org_id IN (filter_orgs)
ELSE TRUE END;
RETURN;
END IF;
-- Organization member type
SELECT TRUE, array_agg(msup.aggregate_id) INTO member_type_found, aggregate_ids
FROM matching_system_user_perms msup
WHERE msup.member_type = 'Organization'
GROUP BY msup.member_type
LIMIT 1;
IF member_type_found THEN
member_type_found := FALSE;
-- if any of the aggregate_ids = '', then we search on all organization
IF (SELECT FALSE WHERE '' = ANY (aggregate_ids::TEXT[])) = FALSE THEN
check_aggregates := FALSE;
ELSE
check_aggregates := TRUE;
END IF;
-- Return all organizations or only those in filter_orgs
SELECT array_agg(o.org_id) INTO org_ids
FROM eventstore.instance_orgs o
WHERE
CASE
WHEN check_aggregates THEN
o.org_id = ANY (aggregate_ids::TEXT[])
ELSE
TRUE
END
AND CASE WHEN filter_orgs != ''
THEN o.org_id IN (filter_orgs)
ELSE TRUE END;
RETURN;
END IF;
END;
$$;
DROP FUNCTION IF EXISTS eventstore.permitted_orgs;
CREATE OR REPLACE FUNCTION eventstore.permitted_orgs(
@@ -14,104 +122,9 @@ AS $$
BEGIN
-- if system user
IF jsonb_array_length(system_user_perms) != 0 THEN
DECLARE
has_instance_or_iam_permission bool;
member_type_found bool;
aggregate_ids TEXT;
check_aggregates bool;
BEGIN
DROP TABLE IF EXISTS matching_system_user_perms;
CREATE TEMPORARY TABLE matching_system_user_perms (
member_type TEXT,
aggregate_id TEXT,
object_id TEXT
) ON COMMIT DROP;
INSERT INTO matching_system_user_perms
(SELECT * FROM eventstore.get_system_permissions(system_user_perms, perm));
-- System member type
SELECT TRUE INTO member_type_found
FROM matching_system_user_perms msup
WHERE msup.member_type = 'System'
LIMIT 1;
IF member_type_found 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
CASE WHEN filter_orgs != ''
THEN o.org_id IN (filter_orgs)
ELSE TRUE END;
RETURN;
END IF;
-- IAM member type
SELECT TRUE, array_agg(msup.aggregate_id) INTO member_type_found, aggregate_ids
FROM matching_system_user_perms msup
WHERE msup.member_type = 'IAM'
GROUP BY msup.member_type
LIMIT 1;
IF member_type_found THEN
IF (SELECT FALSE WHERE '' = ANY (aggregate_ids::TEXT[])) = FALSE THEN
check_aggregates := FALSE;
ELSE
check_aggregates := TRUE;
END IF;
-- Return all organizations or only those in filter_orgs
SELECT array_agg(o.org_id) INTO org_ids
FROM eventstore.instance_orgs o
WHERE CASE
WHEN check_aggregates THEN
o.instance_id = ANY (aggregate_ids::TEXT[])
ELSE
TRUE
END
AND CASE WHEN filter_orgs != ''
THEN o.org_id IN (filter_orgs)
ELSE TRUE END;
RETURN;
END IF;
-- Organization member type
SELECT TRUE, array_agg(msup.aggregate_id) INTO member_type_found, aggregate_ids
FROM matching_system_user_perms msup
WHERE msup.member_type = 'Organization'
GROUP BY msup.member_type
LIMIT 1;
IF member_type_found THEN
member_type_found := FALSE;
-- if any of the aggregate_ids = '', then we search on all organization
IF (SELECT FALSE WHERE '' = ANY (aggregate_ids::TEXT[])) = FALSE THEN
check_aggregates := FALSE;
ELSE
check_aggregates := TRUE;
END IF;
-- Return all organizations or only those in filter_orgs
SELECT array_agg(o.org_id) INTO org_ids
FROM eventstore.instance_orgs o
WHERE
CASE
WHEN check_aggregates THEN
o.org_id = ANY (aggregate_ids::TEXT[])
ELSE
TRUE
END
AND CASE WHEN filter_orgs != ''
THEN o.org_id IN (filter_orgs)
ELSE TRUE END;
RETURN;
END IF;
END;
IF system_user_perms IS NOT NULL THEN
org_ids := eventstore.check_system_user_perms(system_user_perms, perm, filter_orgs)
RETURN;
ELSE
DECLARE
matched_roles TEXT[]; -- roles containing permission
@@ -154,7 +167,6 @@ BEGIN
AND om.instance_id = instanceID
AND om.user_id = userId
) AS sub;
RETURN;
END;
END IF;
END;

View File

@@ -12,7 +12,7 @@ import (
"github.com/zitadel/zitadel/cmd/encryption"
"github.com/zitadel/zitadel/cmd/hooks"
"github.com/zitadel/zitadel/internal/actions"
internal_authz "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/oidc"
"github.com/zitadel/zitadel/internal/api/ui/login"
"github.com/zitadel/zitadel/internal/cache/connector"
@@ -33,7 +33,8 @@ type Config struct {
Database database.Config
Caches *connector.CachesConfig
SystemDefaults systemdefaults.SystemDefaults
InternalAuthZ internal_authz.Config
InternalAuthZ authz.Config
SystemAuthZ authz.Config
ExternalDomain string
ExternalPort uint16
ExternalSecure bool
@@ -51,7 +52,7 @@ type Config struct {
Login login.Config
WebAuthNName string
Telemetry *handlers.TelemetryPusherConfig
SystemAPIUsers map[string]*internal_authz.SystemAPIUser
SystemAPIUsers map[string]*authz.SystemAPIUser
}
type InitProjections struct {
@@ -66,12 +67,12 @@ func MustNewConfig(v *viper.Viper) *Config {
err := v.Unmarshal(config,
viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
hooks.SliceTypeStringDecode[*domain.CustomMessageText],
hooks.SliceTypeStringDecode[internal_authz.RoleMapping],
hooks.MapTypeStringDecode[string, *internal_authz.SystemAPIUser],
hooks.SliceTypeStringDecode[authz.RoleMapping],
hooks.MapTypeStringDecode[string, *authz.SystemAPIUser],
hooks.MapHTTPHeaderStringDecode,
database.DecodeHook,
actions.HTTPConfigDecodeHook,
hook.EnumHookFunc(internal_authz.MemberTypeString),
hook.EnumHookFunc(authz.MemberTypeString),
hook.Base64ToBytesHookFunc(),
hook.TagToLanguageHookFunc(),
mapstructure.StringToTimeDurationHookFunc(),

View File

@@ -178,7 +178,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
steps.s49InitPermittedOrgsFunction = &InitPermittedOrgsFunction{eventstoreClient: dbClient}
steps.s50IDPTemplate6UsePKCE = &IDPTemplate6UsePKCE{dbClient: dbClient}
steps.s51IDPTemplate6RootCA = &IDPTemplate6RootCA{dbClient: dbClient}
steps.s52InitPermittedOrgsFunction = &InitPermittedOrgsFunction52{eventstoreClient: dbClient}
steps.s52InitPermittedOrgsFunction = &InitPermittedOrgsFunction52{dbClient: dbClient}
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil, nil)
logging.OnError(err).Fatal("unable to start projections")
@@ -412,7 +412,7 @@ func startCommandsQueries(
sessionTokenVerifier,
func(q *query.Queries) domain.PermissionCheck {
return func(ctx context.Context, permission, orgID, resourceID string) (err error) {
return internal_authz.CheckPermission(ctx, &authz_es.UserMembershipRepo{Queries: q}, nil, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
return internal_authz.CheckPermission(ctx, &authz_es.UserMembershipRepo{Queries: q}, config.SystemAuthZ.RolePermissionMappings, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
}
},
0, // not needed for projections
@@ -437,7 +437,7 @@ func startCommandsQueries(
authZRepo, err := authz.Start(queries, eventstoreClient, dbClient, keys.OIDC, config.ExternalSecure)
logging.OnError(err).Fatal("unable to start authz repo")
permissionCheck := func(ctx context.Context, permission, orgID, resourceID string) (err error) {
return internal_authz.CheckPermission(ctx, authZRepo, nil, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
return internal_authz.CheckPermission(ctx, authZRepo, config.SystemAuthZ.RolePermissionMappings, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
}
commands, err := command.StartCommands(ctx,

View File

@@ -495,7 +495,7 @@ func startAPIs(
}
instanceInterceptor := middleware.InstanceInterceptor(queries, config.ExternalDomain, login.IgnoreInstanceEndpoints...)
assetsCache := middleware.AssetsCacheInterceptor(config.AssetStorage.Cache.MaxAge, config.AssetStorage.Cache.SharedMaxAge)
apis.RegisterHandlerOnPrefix(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, middleware.CallDurationHandler, instanceInterceptor.Handler, assetsCache.Handler, limitingAccessInterceptor.Handle))
apis.RegisterHandlerOnPrefix(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.SystemAuthZ, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, middleware.CallDurationHandler, instanceInterceptor.Handler, assetsCache.Handler, limitingAccessInterceptor.Handle))
apis.RegisterHandlerOnPrefix(idp.HandlerPrefix, idp.NewHandler(commands, queries, keys.IDPConfig, instanceInterceptor.Handler))
@@ -539,7 +539,7 @@ func startAPIs(
keys.User,
&config.SCIM,
instanceInterceptor.HandlerFuncWithError,
middleware.AuthorizationInterceptor(verifier, config.InternalAuthZ).HandlerFuncWithError))
middleware.AuthorizationInterceptor(verifier, config.SystemAuthZ, config.InternalAuthZ).HandlerFuncWithError))
c, err := console.Start(config.Console, config.ExternalSecure, oidcServer.IssuerFromRequest, middleware.CallDurationHandler, instanceInterceptor.Handler, limitingAccessInterceptor, config.CustomerPortal)
if err != nil {

View File

@@ -94,13 +94,13 @@ func DefaultErrorHandler(translator *i18n.Translator) func(w http.ResponseWriter
}
}
func NewHandler(commands *command.Commands, verifier authz.APITokenVerifier, authConfig authz.Config, idGenerator id.Generator, storage static.Storage, queries *query.Queries, callDurationInterceptor, instanceInterceptor, assetCacheInterceptor, accessInterceptor func(handler http.Handler) http.Handler) http.Handler {
func NewHandler(commands *command.Commands, verifier authz.APITokenVerifier, systemAuthCOnfig authz.Config, authConfig authz.Config, idGenerator id.Generator, storage static.Storage, queries *query.Queries, callDurationInterceptor, instanceInterceptor, assetCacheInterceptor, accessInterceptor func(handler http.Handler) http.Handler) http.Handler {
translator, err := i18n.NewZitadelTranslator(language.English)
logging.OnError(err).Panic("unable to get translator")
h := &Handler{
commands: commands,
errorHandler: DefaultErrorHandler(translator),
authInterceptor: http_mw.AuthorizationInterceptor(verifier, authConfig),
authInterceptor: http_mw.AuthorizationInterceptor(verifier, systemAuthCOnfig, authConfig),
idGenerator: idGenerator,
storage: storage,
query: queries,
@@ -129,8 +129,10 @@ func (l *publicFileDownloader) ResourceOwner(_ context.Context, ownerPath string
return ownerPath
}
const maxMemory = 2 << 20
const paramFile = "file"
const (
maxMemory = 2 << 20
paramFile = "file"
)
func UploadHandleFunc(s AssetsService, uploader Uploader) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {

View File

@@ -2,12 +2,12 @@ package authz
import (
"context"
"errors"
"fmt"
"reflect"
"slices"
"strings"
"github.com/zitadel/logging"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
)
@@ -167,7 +167,7 @@ func addGetSystemUserRolesFuncToCtx(ctx context.Context, systemUserRoleMap []Rol
slices.Sort(permissions)
permissions = slices.Compact(permissions)
systemUserPermissionsDbJsonQueryStruct[i].MemberType = MemberTypeServerToMemberTypeDBMap[systemPerm.MemberType]
systemUserPermissionsDbJsonQueryStruct[i].MemberType = systemPerm.MemberType.String()
systemUserPermissionsDbJsonQueryStruct[i].AggregateID = systemPerm.AggregateID
systemUserPermissionsDbJsonQueryStruct[i].Permissions = permissions
}
@@ -178,14 +178,15 @@ func addGetSystemUserRolesFuncToCtx(ctx context.Context, systemUserRoleMap []Rol
return ctx
}
func GetSystemUserPermissions(ctx context.Context) ([]SystemUserPermissionsDBQuery, error) {
func GetSystemUserPermissions(ctx context.Context) []SystemUserPermissionsDBQuery {
getSystemUserRolesFuncValue := ctx.Value(systemUserRolesFuncKey)
if getSystemUserRolesFuncValue == nil {
return nil, nil
return nil
}
getSystemUserRolesFunc, ok := getSystemUserRolesFuncValue.(func(context.Context) []SystemUserPermissionsDBQuery)
if !ok {
return nil, errors.New("unable to obtain systems role func")
logging.WithFields("Authz").Error("unable to cast []SystemUserPermissionsDBQuery")
return nil
}
return getSystemUserRolesFunc(ctx), nil
return getSystemUserRolesFunc(ctx)
}

View File

@@ -56,9 +56,6 @@ type Membership struct {
ObjectID string
Roles []string
// aggregate all the permissions for each role
Permissions []string
}
type MemberType int32
@@ -72,12 +69,6 @@ const (
MemberTypeSystem
)
var MemberTypeServerToMemberTypeDBMap map[MemberType]string = map[MemberType]string{
MemberTypeSystem: "System",
MemberTypeIAM: "IAM",
MemberTypeOrganization: "Organization",
}
type TokenVerifier interface {
ExistsOrg(ctx context.Context, id, domain string) (string, error)
ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error)

View File

@@ -14,14 +14,16 @@ import (
)
type AuthInterceptor struct {
verifier authz.APITokenVerifier
authConfig authz.Config
verifier authz.APITokenVerifier
authConfig authz.Config
systemAuthConfig authz.Config
}
func AuthorizationInterceptor(verifier authz.APITokenVerifier, authConfig authz.Config) *AuthInterceptor {
func AuthorizationInterceptor(verifier authz.APITokenVerifier, systemAuthConfig authz.Config, authConfig authz.Config) *AuthInterceptor {
return &AuthInterceptor{
verifier: verifier,
authConfig: authConfig,
verifier: verifier,
authConfig: authConfig,
systemAuthConfig: systemAuthConfig,
}
}
@@ -31,7 +33,7 @@ func (a *AuthInterceptor) Handler(next http.Handler) http.Handler {
func (a *AuthInterceptor) HandlerFunc(next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx, err := authorize(r, a.verifier, a.authConfig)
ctx, err := authorize(r, a.verifier, a.systemAuthConfig, a.authConfig)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
@@ -44,7 +46,7 @@ func (a *AuthInterceptor) HandlerFunc(next http.Handler) http.HandlerFunc {
func (a *AuthInterceptor) HandlerFuncWithError(next HandlerFuncWithError) HandlerFuncWithError {
return func(w http.ResponseWriter, r *http.Request) error {
ctx, err := authorize(r, a.verifier, a.authConfig)
ctx, err := authorize(r, a.verifier, a.systemAuthConfig, a.authConfig)
if err != nil {
return err
}
@@ -56,7 +58,7 @@ func (a *AuthInterceptor) HandlerFuncWithError(next HandlerFuncWithError) Handle
type httpReq struct{}
func authorize(r *http.Request, verifier authz.APITokenVerifier, authConfig authz.Config) (_ context.Context, err error) {
func authorize(r *http.Request, verifier authz.APITokenVerifier, systemAuthConfig authz.Config, authConfig authz.Config) (_ context.Context, err error) {
ctx := r.Context()
authOpt, needsToken := checkAuthMethod(r, verifier)
@@ -71,8 +73,7 @@ func authorize(r *http.Request, verifier authz.APITokenVerifier, authConfig auth
return nil, zerrors.ThrowUnauthenticated(nil, "AUT-1179", "auth header missing")
}
// TODO look into this
ctxSetter, err := authz.CheckUserAuthorization(authCtx, &httpReq{}, authToken, http_util.GetOrgID(r), "", verifier, nil, authConfig.RolePermissionMappings, authOpt, r.RequestURI)
ctxSetter, err := authz.CheckUserAuthorization(authCtx, &httpReq{}, authToken, http_util.GetOrgID(r), "", verifier, systemAuthConfig.RolePermissionMappings, authConfig.RolePermissionMappings, authOpt, r.RequestURI)
if err != nil {
return nil, err
}

View File

@@ -10,6 +10,7 @@ import (
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/drone/envsubst"
@@ -138,7 +139,7 @@ func machineID() (uint16, error) {
errors = append(errors, "No machine identification method enabled.")
}
// logging.WithFields("errors", strings.Join(errors, ", ")).Panic("none of the enabled methods for identifying the machine succeeded")
logging.WithFields("errors", strings.Join(errors, ", ")).Panic("none of the enabled methods for identifying the machine succeeded")
// this return will never happen because of panic one line before
return 0, nil
}

View File

@@ -108,179 +108,3 @@ SystemDefaults:
KeyConfig:
PrivateKeyLifetime: 7200h
PublicKeyLifetime: 14400h
SystemAuthZ:
RolePermissionMappings:
- Role: "SYSTEM_OWNER"
Permissions:
- "system.instance.read"
- "system.instance.write"
- "system.instance.delete"
- "system.domain.read"
- "system.domain.write"
- "system.domain.delete"
- "system.debug.read"
- "system.debug.write"
- "system.debug.delete"
- "system.feature.read"
- "system.feature.write"
- "system.feature.delete"
- "system.limits.write"
- "system.limits.delete"
- "system.quota.write"
- "system.quota.delete"
- "system.iam.member.read"
- Role: "IAM_OWNER"
Permissions:
- "iam.read"
- "iam.write"
- "iam.policy.read"
- "iam.policy.write"
- "iam.policy.delete"
- "iam.member.read"
- "iam.member.write"
- "iam.member.delete"
- "iam.idp.read"
- "iam.idp.write"
- "iam.idp.delete"
- "iam.action.read"
- "iam.action.write"
- "iam.action.delete"
- "iam.flow.read"
- "iam.flow.write"
- "iam.flow.delete"
- "iam.feature.read"
- "iam.feature.write"
- "iam.feature.delete"
- "iam.restrictions.read"
- "iam.restrictions.write"
- "iam.web_key.write"
- "iam.web_key.delete"
- "iam.web_key.read"
- "iam.debug.write"
- "iam.debug.read"
- "org.read"
- "org.global.read"
- "org.create"
- "org.write"
- "org.delete"
- "org.member.read"
- "org.member.write"
- "org.member.delete"
- "org.idp.read"
- "org.idp.write"
- "org.idp.delete"
- "org.action.read"
- "org.action.write"
- "org.action.delete"
- "org.flow.read"
- "org.flow.write"
- "org.flow.delete"
- "org.feature.read"
- "org.feature.write"
- "org.feature.delete"
- "user.read"
- "user.global.read"
- "user.write"
- "user.delete"
- "user.grant.read"
- "user.grant.write"
- "user.grant.delete"
- "user.membership.read"
- "user.credential.write"
- "user.passkey.write"
- "user.feature.read"
- "user.feature.write"
- "user.feature.delete"
- "policy.read"
- "policy.write"
- "policy.delete"
- "project.read"
- "project.create"
- "project.write"
- "project.delete"
- "project.member.read"
- "project.member.write"
- "project.member.delete"
- "project.role.read"
- "project.role.write"
- "project.role.delete"
- "project.app.read"
- "project.app.write"
- "project.app.delete"
- "project.grant.read"
- "project.grant.write"
- "project.grant.delete"
- "project.grant.member.read"
- "project.grant.member.write"
- "project.grant.member.delete"
- "events.read"
- "milestones.read"
- "session.read"
- "session.delete"
- "action.target.read"
- "action.target.write"
- "action.target.delete"
- "action.execution.read"
- "action.execution.write"
- "userschema.read"
- "userschema.write"
- "userschema.delete"
- "session.read"
- "session.delete"
- Role: "ORG_OWNER"
Permissions:
- "org.read"
- "org.global.read"
- "org.write"
- "org.delete"
- "org.member.read"
- "org.member.write"
- "org.member.delete"
- "org.idp.read"
- "org.idp.write"
- "org.idp.delete"
- "org.action.read"
- "org.action.write"
- "org.action.delete"
- "org.flow.read"
- "org.flow.write"
- "org.flow.delete"
- "org.feature.read"
- "org.feature.write"
- "org.feature.delete"
- "user.read"
- "user.global.read"
- "user.write"
- "user.delete"
- "user.grant.read"
- "user.grant.write"
- "user.grant.delete"
- "user.membership.read"
- "user.credential.write"
- "user.passkey.write"
- "user.feature.read"
- "user.feature.write"
- "user.feature.delete"
- "policy.read"
- "policy.write"
- "policy.delete"
- "project.read"
- "project.create"
- "project.write"
- "project.delete"
- "project.member.read"
- "project.member.write"
- "project.member.delete"
- "project.role.read"
- "project.role.write"
- "project.role.delete"
- "project.app.read"
- "project.app.write"
- "project.grant.read"
- "project.grant.write"
- "project.grant.delete"
- "project.grant.member.read"
- "project.grant.member.write"
- "project.grant.member.delete"
- "session.delete"

View File

@@ -9,6 +9,7 @@ import (
"github.com/zitadel/logging"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/zerrors"
)
const (
@@ -24,17 +25,18 @@ const (
// 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, systemUserPermission []authz.SystemUserPermissionsDBQuery, filterOrgIds, orgIDColumn, permission string) (sq.SelectBuilder, error) {
func wherePermittedOrgs(ctx context.Context, query sq.SelectBuilder, 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)
systemUserPermissions := authz.GetSystemUserPermissions(ctx)
var systemUserPermissionsJson []byte
if systemUserPermissions != nil {
var err error
systemUserPermissionsJson, err = json.Marshal(systemUserPermissions)
if err != nil {
return query, err
return query, zerrors.ThrowInternal(err, "AUTHZ-HS4us", "Errors.Internal")
}
systemUserPermissionsJson = string(systemUserPermissionsBytes)
}
return query.Where(
@@ -42,23 +44,23 @@ func wherePermittedOrgs(ctx context.Context, query sq.SelectBuilder, systemUserP
authz.GetInstance(ctx).InstanceID(),
userID,
systemUserPermissionsJson,
systemUserPermission,
permission,
filterOrgIds,
), nil
}
func wherePermittedOrgsOrCurrentUser(ctx context.Context, query sq.SelectBuilder, systemUserPermission []authz.SystemUserPermissionsDBQuery, filterOrgIds, orgIDColumn, userIdColum, permission string) (sq.SelectBuilder, error) {
func wherePermittedOrgsOrCurrentUser(ctx context.Context, query sq.SelectBuilder, 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)
systemUserPermissions := authz.GetSystemUserPermissions(ctx)
var systemUserPermissionsJson []byte
if systemUserPermissions != nil {
var err error
systemUserPermissionsJson, err = json.Marshal(systemUserPermissions)
if err != nil {
return query, err
return query, zerrors.ThrowInternal(err, "AUTHZ-HS4us", "Errors.Internal")
}
systemUserPermissionsJson = string(systemUserPermissionsBytes)
}
return query.Where(

View File

@@ -655,12 +655,7 @@ func (q *Queries) searchUsers(ctx context.Context, queries *UserSearchQueries, f
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
})
if permissionCheckV2 {
// extract system user roles
systemUserPermissions, err := authz.GetSystemUserPermissions(ctx)
if err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-GS9gs", "Errors.Internal")
}
query, err = wherePermittedOrgsOrCurrentUser(ctx, query, systemUserPermissions, filterOrgIds, UserResourceOwnerCol.identifier(), UserIDCol.identifier(), domain.PermissionUserRead)
query, err = wherePermittedOrgsOrCurrentUser(ctx, query, filterOrgIds, UserResourceOwnerCol.identifier(), UserIDCol.identifier(), domain.PermissionUserRead)
if err != nil {
return nil, err
}