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 {