mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-25 18:27:54 +00:00
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:
@@ -1172,6 +1172,34 @@ DefaultInstance:
|
|||||||
# If an audit log retention is set using an instance limit, it will overwrite the system default.
|
# If an audit log retention is set using an instance limit, it will overwrite the system default.
|
||||||
AuditLogRetention: 0s # ZITADEL_AUDITLOGRETENTION
|
AuditLogRetention: 0s # ZITADEL_AUDITLOGRETENTION
|
||||||
|
|
||||||
|
SystemAuthZ:
|
||||||
|
# Configure the RolePermissionMappings by environment variable using JSON notation:
|
||||||
|
# ZITADEL_INTERNALAUTHZ_ROLEPERMISSIONMAPPINGS='[{"role": "IAM_OWNER", "permissions": ["iam.write"]}, {"role": "ORG_OWNER", "permissions": ["org.write"]}]'
|
||||||
|
# Beware that if you configure the RolePermissionMappings by environment variable, all the default RolePermissionMappings are lost.
|
||||||
|
#
|
||||||
|
# Warning: RolePermissionMappings are synhronized to the database.
|
||||||
|
# Changes here will only be applied after running `zitadel setup` or `zitadel start-from-setup`.
|
||||||
|
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"
|
||||||
|
|
||||||
InternalAuthZ:
|
InternalAuthZ:
|
||||||
# Configure the RolePermissionMappings by environment variable using JSON notation:
|
# Configure the RolePermissionMappings by environment variable using JSON notation:
|
||||||
# ZITADEL_INTERNALAUTHZ_ROLEPERMISSIONMAPPINGS='[{"role": "IAM_OWNER", "permissions": ["iam.write"]}, {"role": "ORG_OWNER", "permissions": ["org.write"]}]'
|
# ZITADEL_INTERNALAUTHZ_ROLEPERMISSIONMAPPINGS='[{"role": "IAM_OWNER", "permissions": ["iam.write"]}, {"role": "ORG_OWNER", "permissions": ["org.write"]}]'
|
||||||
|
@@ -147,7 +147,7 @@ func projections(
|
|||||||
sessionTokenVerifier,
|
sessionTokenVerifier,
|
||||||
func(q *query.Queries) domain.PermissionCheck {
|
func(q *query.Queries) domain.PermissionCheck {
|
||||||
return func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
return func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
||||||
return internal_authz.CheckPermission(ctx, &authz_es.UserMembershipRepo{Queries: q}, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
return internal_authz.CheckPermission(ctx, &authz_es.UserMembershipRepo{Queries: q}, nil, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
@@ -184,7 +184,7 @@ func projections(
|
|||||||
keys.Target,
|
keys.Target,
|
||||||
&http.Client{},
|
&http.Client{},
|
||||||
func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
||||||
return internal_authz.CheckPermission(ctx, authZRepo, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
return internal_authz.CheckPermission(ctx, authZRepo, nil, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
||||||
},
|
},
|
||||||
sessionTokenVerifier,
|
sessionTokenVerifier,
|
||||||
config.OIDC.DefaultAccessTokenLifetime,
|
config.OIDC.DefaultAccessTokenLifetime,
|
||||||
|
@@ -410,7 +410,7 @@ func startCommandsQueries(
|
|||||||
sessionTokenVerifier,
|
sessionTokenVerifier,
|
||||||
func(q *query.Queries) domain.PermissionCheck {
|
func(q *query.Queries) domain.PermissionCheck {
|
||||||
return func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
return func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
||||||
return internal_authz.CheckPermission(ctx, &authz_es.UserMembershipRepo{Queries: q}, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
return internal_authz.CheckPermission(ctx, &authz_es.UserMembershipRepo{Queries: q}, nil, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
0, // not needed for projections
|
0, // not needed for projections
|
||||||
@@ -435,7 +435,7 @@ func startCommandsQueries(
|
|||||||
authZRepo, err := authz.Start(queries, eventstoreClient, dbClient, keys.OIDC, config.ExternalSecure)
|
authZRepo, err := authz.Start(queries, eventstoreClient, dbClient, keys.OIDC, config.ExternalSecure)
|
||||||
logging.OnError(err).Fatal("unable to start authz repo")
|
logging.OnError(err).Fatal("unable to start authz repo")
|
||||||
permissionCheck := func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
permissionCheck := func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
||||||
return internal_authz.CheckPermission(ctx, authZRepo, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
return internal_authz.CheckPermission(ctx, authZRepo, nil, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
commands, err := command.StartCommands(ctx,
|
commands, err := command.StartCommands(ctx,
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package start
|
package start
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
@@ -11,7 +12,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/cmd/hooks"
|
"github.com/zitadel/zitadel/cmd/hooks"
|
||||||
"github.com/zitadel/zitadel/internal/actions"
|
"github.com/zitadel/zitadel/internal/actions"
|
||||||
admin_es "github.com/zitadel/zitadel/internal/admin/repository/eventsourcing"
|
admin_es "github.com/zitadel/zitadel/internal/admin/repository/eventsourcing"
|
||||||
internal_authz "github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/api/http/middleware"
|
"github.com/zitadel/zitadel/internal/api/http/middleware"
|
||||||
"github.com/zitadel/zitadel/internal/api/oidc"
|
"github.com/zitadel/zitadel/internal/api/oidc"
|
||||||
"github.com/zitadel/zitadel/internal/api/saml"
|
"github.com/zitadel/zitadel/internal/api/saml"
|
||||||
@@ -65,12 +66,13 @@ type Config struct {
|
|||||||
Login login.Config
|
Login login.Config
|
||||||
Console console.Config
|
Console console.Config
|
||||||
AssetStorage static_config.AssetStorageConfig
|
AssetStorage static_config.AssetStorageConfig
|
||||||
InternalAuthZ internal_authz.Config
|
InternalAuthZ authz.Config
|
||||||
|
SystemAuthZ authz.Config
|
||||||
SystemDefaults systemdefaults.SystemDefaults
|
SystemDefaults systemdefaults.SystemDefaults
|
||||||
EncryptionKeys *encryption.EncryptionKeyConfig
|
EncryptionKeys *encryption.EncryptionKeyConfig
|
||||||
DefaultInstance command.InstanceSetup
|
DefaultInstance command.InstanceSetup
|
||||||
AuditLogRetention time.Duration
|
AuditLogRetention time.Duration
|
||||||
SystemAPIUsers map[string]*internal_authz.SystemAPIUser
|
SystemAPIUsers map[string]*authz.SystemAPIUser
|
||||||
CustomerPortal string
|
CustomerPortal string
|
||||||
Machine *id.Config
|
Machine *id.Config
|
||||||
Actions *actions.Config
|
Actions *actions.Config
|
||||||
@@ -94,12 +96,12 @@ func MustNewConfig(v *viper.Viper) *Config {
|
|||||||
err := v.Unmarshal(config,
|
err := v.Unmarshal(config,
|
||||||
viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
|
viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
|
||||||
hooks.SliceTypeStringDecode[*domain.CustomMessageText],
|
hooks.SliceTypeStringDecode[*domain.CustomMessageText],
|
||||||
hooks.SliceTypeStringDecode[internal_authz.RoleMapping],
|
hooks.SliceTypeStringDecode[authz.RoleMapping],
|
||||||
hooks.MapTypeStringDecode[string, *internal_authz.SystemAPIUser],
|
hooks.MapTypeStringDecode[string, *authz.SystemAPIUser],
|
||||||
hooks.MapHTTPHeaderStringDecode,
|
hooks.MapHTTPHeaderStringDecode,
|
||||||
database.DecodeHook,
|
database.DecodeHook,
|
||||||
actions.HTTPConfigDecodeHook,
|
actions.HTTPConfigDecodeHook,
|
||||||
hook.EnumHookFunc(internal_authz.MemberTypeString),
|
hook.EnumHookFunc(authz.MemberTypeString),
|
||||||
hooks.MapTypeStringDecode[domain.Feature, any],
|
hooks.MapTypeStringDecode[domain.Feature, any],
|
||||||
hooks.SliceTypeStringDecode[*command.SetQuota],
|
hooks.SliceTypeStringDecode[*command.SetQuota],
|
||||||
hook.Base64ToBytesHookFunc(),
|
hook.Base64ToBytesHookFunc(),
|
||||||
@@ -129,6 +131,7 @@ 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
|
||||||
}
|
}
|
||||||
|
@@ -174,6 +174,12 @@ func startZitadel(ctx context.Context, config *Config, masterKey string, server
|
|||||||
return fmt.Errorf("unable to start caches: %w", err)
|
return fmt.Errorf("unable to start caches: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
systemPermissions := make([]string, 0)
|
||||||
|
// for _, roleMapping := range config.SystemAuthZ.RolePermissionMappings {
|
||||||
|
// systemPermissions = append(systemPermissions, roleMapping.Permissions...)
|
||||||
|
// }
|
||||||
|
// config.InternalAuthZ.SystemUserPermissions = systemPermissions
|
||||||
|
|
||||||
queries, err := query.StartQueries(
|
queries, err := query.StartQueries(
|
||||||
ctx,
|
ctx,
|
||||||
eventstoreClient,
|
eventstoreClient,
|
||||||
@@ -192,7 +198,7 @@ func startZitadel(ctx context.Context, config *Config, masterKey string, server
|
|||||||
sessionTokenVerifier,
|
sessionTokenVerifier,
|
||||||
func(q *query.Queries) domain.PermissionCheck {
|
func(q *query.Queries) domain.PermissionCheck {
|
||||||
return func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
return func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
||||||
return internal_authz.CheckPermission(ctx, &authz_es.UserMembershipRepo{Queries: q}, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
return internal_authz.CheckPermission(ctx, &authz_es.UserMembershipRepo{Queries: q}, systemPermissions, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
config.AuditLogRetention,
|
config.AuditLogRetention,
|
||||||
@@ -208,7 +214,7 @@ func startZitadel(ctx context.Context, config *Config, masterKey string, server
|
|||||||
return fmt.Errorf("error starting authz repo: %w", err)
|
return fmt.Errorf("error starting authz repo: %w", err)
|
||||||
}
|
}
|
||||||
permissionCheck := func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
permissionCheck := func(ctx context.Context, permission, orgID, resourceID string) (err error) {
|
||||||
return internal_authz.CheckPermission(ctx, authZRepo, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
return internal_authz.CheckPermission(ctx, authZRepo, systemPermissions, config.InternalAuthZ.RolePermissionMappings, permission, orgID, resourceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
storage, err := config.AssetStorage.NewStorage(dbClient.DB)
|
storage, err := config.AssetStorage.NewStorage(dbClient.DB)
|
||||||
@@ -407,7 +413,8 @@ func startAPIs(
|
|||||||
http_util.WithMaxAge(int(math.Floor(config.Quotas.Access.ExhaustedCookieMaxAge.Seconds()))),
|
http_util.WithMaxAge(int(math.Floor(config.Quotas.Access.ExhaustedCookieMaxAge.Seconds()))),
|
||||||
)
|
)
|
||||||
limitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, exhaustedCookieHandler, &config.Quotas.Access.AccessConfig)
|
limitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, exhaustedCookieHandler, &config.Quotas.Access.AccessConfig)
|
||||||
apis, err := api.New(ctx, config.Port, router, queries, verifier, config.InternalAuthZ, tlsConfig, config.ExternalDomain, append(config.InstanceHostHeaders, config.PublicHostHeaders...), limitingAccessInterceptor)
|
|
||||||
|
apis, err := api.New(ctx, config.Port, router, queries, verifier, config.SystemAuthZ, config.InternalAuthZ, tlsConfig, config.ExternalDomain, append(config.InstanceHostHeaders, config.PublicHostHeaders...), limitingAccessInterceptor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error creating api %w", err)
|
return nil, fmt.Errorf("error creating api %w", err)
|
||||||
}
|
}
|
||||||
@@ -600,7 +607,7 @@ func listen(ctx context.Context, router *mux.Router, port uint16, tlsConfig *tls
|
|||||||
go func() {
|
go func() {
|
||||||
logging.Infof("server is listening on %s", lis.Addr().String())
|
logging.Infof("server is listening on %s", lis.Addr().String())
|
||||||
if tlsConfig != nil {
|
if tlsConfig != nil {
|
||||||
//we don't need to pass the files here, because we already initialized the TLS config on the server
|
// we don't need to pass the files here, because we already initialized the TLS config on the server
|
||||||
errCh <- http1Server.ServeTLS(lis, "", "")
|
errCh <- http1Server.ServeTLS(lis, "", "")
|
||||||
} else {
|
} else {
|
||||||
errCh <- http1Server.Serve(lis)
|
errCh <- http1Server.Serve(lis)
|
||||||
|
@@ -15,7 +15,7 @@ import (
|
|||||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
||||||
"google.golang.org/grpc/reflection"
|
"google.golang.org/grpc/reflection"
|
||||||
|
|
||||||
internal_authz "github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||||
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
|
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
|
||||||
@@ -29,7 +29,7 @@ import (
|
|||||||
type API struct {
|
type API struct {
|
||||||
port uint16
|
port uint16
|
||||||
grpcServer *grpc.Server
|
grpcServer *grpc.Server
|
||||||
verifier internal_authz.APITokenVerifier
|
verifier authz.APITokenVerifier
|
||||||
health healthCheck
|
health healthCheck
|
||||||
router *mux.Router
|
router *mux.Router
|
||||||
hostHeaders []string
|
hostHeaders []string
|
||||||
@@ -72,8 +72,9 @@ func New(
|
|||||||
port uint16,
|
port uint16,
|
||||||
router *mux.Router,
|
router *mux.Router,
|
||||||
queries *query.Queries,
|
queries *query.Queries,
|
||||||
verifier internal_authz.APITokenVerifier,
|
verifier authz.APITokenVerifier,
|
||||||
authZ internal_authz.Config,
|
systemAuthz authz.Config,
|
||||||
|
authZ authz.Config,
|
||||||
tlsConfig *tls.Config,
|
tlsConfig *tls.Config,
|
||||||
externalDomain string,
|
externalDomain string,
|
||||||
hostHeaders []string,
|
hostHeaders []string,
|
||||||
@@ -89,7 +90,7 @@ func New(
|
|||||||
hostHeaders: hostHeaders,
|
hostHeaders: hostHeaders,
|
||||||
}
|
}
|
||||||
|
|
||||||
api.grpcServer = server.CreateServer(api.verifier, authZ, queries, externalDomain, tlsConfig, accessInterceptor.AccessService())
|
api.grpcServer = server.CreateServer(api.verifier, systemAuthz, authZ, queries, externalDomain, tlsConfig, accessInterceptor.AccessService())
|
||||||
api.grpcGateway, err = server.CreateGateway(ctx, port, hostHeaders, accessInterceptor, tlsConfig)
|
api.grpcGateway, err = server.CreateGateway(ctx, port, hostHeaders, accessInterceptor, tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@@ -20,7 +20,7 @@ const (
|
|||||||
// - the organisation (**either** provided by ID or verified domain) exists
|
// - the organisation (**either** provided by ID or verified domain) exists
|
||||||
// - the user is permitted to call the requested endpoint (permission option in proto)
|
// - the user is permitted to call the requested endpoint (permission option in proto)
|
||||||
// it will pass the [CtxData] and permission of the user into the ctx [context.Context]
|
// it will pass the [CtxData] and permission of the user into the ctx [context.Context]
|
||||||
func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID, orgDomain string, verifier APITokenVerifier, authConfig Config, requiredAuthOption Option, method string) (ctxSetter func(context.Context) context.Context, err error) {
|
func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID, orgDomain string, verifier APITokenVerifier, SystemAuthConfig Config, authConfig Config, requiredAuthOption Option, method string) (ctxSetter func(context.Context) context.Context, err error) {
|
||||||
ctx, span := tracing.NewServerInterceptorSpan(ctx)
|
ctx, span := tracing.NewServerInterceptorSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
@@ -31,12 +31,12 @@ 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, ctxData)
|
parent = addGetSystemUserRolesFuncToCtx(parent, SystemAuthConfig.RolePermissionMappings, ctxData)
|
||||||
return context.WithValue(parent, dataKey, ctxData)
|
return context.WithValue(parent, dataKey, ctxData)
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
requestedPermissions, allPermissions, err := getUserPermissions(ctx, verifier, requiredAuthOption.Permission, authConfig.RolePermissionMappings, ctxData, ctxData.OrgID)
|
requestedPermissions, allPermissions, err := getUserPermissions(ctx, verifier, requiredAuthOption.Permission, SystemAuthConfig.RolePermissionMappings, authConfig.RolePermissionMappings, ctxData, ctxData.OrgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,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, ctxData)
|
parent = addGetSystemUserRolesFuncToCtx(parent, SystemAuthConfig.RolePermissionMappings, ctxData)
|
||||||
return parent
|
return parent
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -129,17 +129,17 @@ func GetAllPermissionCtxIDs(perms []string) []string {
|
|||||||
return ctxIDs
|
return ctxIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
func addGetSystemUserRolesFuncToCtx(ctx context.Context, 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 && ctxData.SystemMemberships[0].MemberType == MemberTypeSystem {
|
||||||
ctx = context.WithValue(ctx, systemUserRolesFuncKey, func() func(ctx context.Context) ([]string, error) {
|
ctx = context.WithValue(ctx, systemUserRolesFuncKey, func() func(ctx context.Context) ([]string, error) {
|
||||||
var roles []string
|
var permissions []string
|
||||||
return func(ctx context.Context) ([]string, error) {
|
return func(ctx context.Context) ([]string, error) {
|
||||||
if roles != nil {
|
if permissions != nil {
|
||||||
return roles, nil
|
return permissions, nil
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
roles, err = getSystemUserRoles(ctx)
|
permissions, err = getSystemUserPermissions(ctx, systemUserRoleMap)
|
||||||
return roles, err
|
return permissions, err
|
||||||
}
|
}
|
||||||
}())
|
}())
|
||||||
}
|
}
|
||||||
@@ -158,17 +158,15 @@ func GetSystemUserRoles(ctx context.Context) ([]string, error) {
|
|||||||
return getSystemUserRolesFunc(ctx)
|
return getSystemUserRolesFunc(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSystemUserRoles(ctx context.Context) ([]string, error) {
|
func getSystemUserPermissions(ctx context.Context, systemUserRoleMap []RoleMapping) ([]string, error) {
|
||||||
ctxData, ok := ctx.Value(dataKey).(CtxData)
|
ctxData, ok := ctx.Value(dataKey).(CtxData)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("unable to obtain ctxData")
|
return nil, errors.New("unable to obtain ctxData")
|
||||||
}
|
}
|
||||||
var roles []string
|
var permissions []string
|
||||||
if ctxData.SystemMemberships != nil {
|
for _, member := range ctxData.SystemMemberships {
|
||||||
for _, member := range ctxData.SystemMemberships {
|
permissions = append(permissions, member.Roles...)
|
||||||
roles = append(roles, member.Roles...)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return roles, nil
|
return permissions, nil
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,9 @@ type Membership struct {
|
|||||||
ObjectID string
|
ObjectID string
|
||||||
|
|
||||||
Roles []string
|
Roles []string
|
||||||
|
|
||||||
|
// aggregate all the permissions for each role
|
||||||
|
Permissions []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MemberType int32
|
type MemberType int32
|
||||||
|
@@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CheckPermission(ctx context.Context, resolver MembershipsResolver, roleMappings []RoleMapping, permission, orgID, resourceID string) (err error) {
|
func CheckPermission(ctx context.Context, resolver MembershipsResolver, systemPermissions []string, roleMappings []RoleMapping, permission, orgID, resourceID string) (err error) {
|
||||||
requestedPermissions, _, err := getUserPermissions(ctx, resolver, permission, roleMappings, GetCtxData(ctx), orgID)
|
requestedPermissions, _, err := getUserPermissions(ctx, resolver, permission, roleMappings, GetCtxData(ctx), orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -22,7 +22,7 @@ func CheckPermission(ctx context.Context, resolver MembershipsResolver, roleMapp
|
|||||||
|
|
||||||
// getUserPermissions retrieves the memberships of the authenticated user (on instance and provided organisation level),
|
// getUserPermissions retrieves the memberships of the authenticated user (on instance and provided organisation level),
|
||||||
// and maps them to permissions. It will return the requested permission(s) and all other granted permissions separately.
|
// and maps them to permissions. It will return the requested permission(s) and all other granted permissions separately.
|
||||||
func getUserPermissions(ctx context.Context, resolver MembershipsResolver, requiredPerm string, roleMappings []RoleMapping, ctxData CtxData, orgID string) (requestedPermissions, allPermissions []string, err error) {
|
func getUserPermissions(ctx context.Context, resolver MembershipsResolver, requiredPerm string, SystemUserRoleMappings []RoleMapping, roleMappings []RoleMapping, ctxData CtxData, orgID string) (requestedPermissions, allPermissions []string, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ func getUserPermissions(ctx context.Context, resolver MembershipsResolver, requi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ctxData.SystemMemberships != nil {
|
if ctxData.SystemMemberships != nil {
|
||||||
requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, roleMappings)
|
requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, SystemUserRoleMappings)
|
||||||
return requestedPermissions, allPermissions, nil
|
return requestedPermissions, allPermissions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,13 +13,13 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AuthorizationInterceptor(verifier authz.APITokenVerifier, authConfig authz.Config) grpc.UnaryServerInterceptor {
|
func AuthorizationInterceptor(verifier authz.APITokenVerifier, systemUserPermissions authz.Config, authConfig authz.Config) grpc.UnaryServerInterceptor {
|
||||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||||
return authorize(ctx, req, info, handler, verifier, authConfig)
|
return authorize(ctx, req, info, handler, verifier, systemUserPermissions, authConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, verifier authz.APITokenVerifier, authConfig authz.Config) (_ interface{}, err error) {
|
func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, verifier authz.APITokenVerifier, systemUserPermissions authz.Config, authConfig authz.Config) (_ interface{}, err error) {
|
||||||
authOpt, needsToken := verifier.CheckAuthMethod(info.FullMethod)
|
authOpt, needsToken := verifier.CheckAuthMethod(info.FullMethod)
|
||||||
if !needsToken {
|
if !needsToken {
|
||||||
return handler(ctx, req)
|
return handler(ctx, req)
|
||||||
@@ -34,7 +34,7 @@ func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
orgID, orgDomain := orgIDAndDomainFromRequest(authCtx, req)
|
orgID, orgDomain := orgIDAndDomainFromRequest(authCtx, req)
|
||||||
ctxSetter, err := authz.CheckUserAuthorization(authCtx, req, authToken, orgID, orgDomain, verifier, authConfig, authOpt, info.FullMethod)
|
ctxSetter, err := authz.CheckUserAuthorization(authCtx, req, authToken, orgID, orgDomain, verifier, systemUserPermissions, authConfig, authOpt, info.FullMethod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,7 @@ type WithGatewayPrefix interface {
|
|||||||
|
|
||||||
func CreateServer(
|
func CreateServer(
|
||||||
verifier authz.APITokenVerifier,
|
verifier authz.APITokenVerifier,
|
||||||
|
systemAuthz authz.Config,
|
||||||
authConfig authz.Config,
|
authConfig authz.Config,
|
||||||
queries *query.Queries,
|
queries *query.Queries,
|
||||||
externalDomain string,
|
externalDomain string,
|
||||||
@@ -53,7 +54,7 @@ func CreateServer(
|
|||||||
middleware.AccessStorageInterceptor(accessSvc),
|
middleware.AccessStorageInterceptor(accessSvc),
|
||||||
middleware.ErrorHandler(),
|
middleware.ErrorHandler(),
|
||||||
middleware.LimitsInterceptor(system_pb.SystemService_ServiceDesc.ServiceName),
|
middleware.LimitsInterceptor(system_pb.SystemService_ServiceDesc.ServiceName),
|
||||||
middleware.AuthorizationInterceptor(verifier, authConfig),
|
middleware.AuthorizationInterceptor(verifier, systemAuthz, authConfig),
|
||||||
middleware.TranslationHandler(),
|
middleware.TranslationHandler(),
|
||||||
middleware.QuotaExhaustedInterceptor(accessSvc, system_pb.SystemService_ServiceDesc.ServiceName),
|
middleware.QuotaExhaustedInterceptor(accessSvc, system_pb.SystemService_ServiceDesc.ServiceName),
|
||||||
middleware.ExecutionHandler(queries),
|
middleware.ExecutionHandler(queries),
|
||||||
|
@@ -71,7 +71,7 @@ func authorize(r *http.Request, verifier authz.APITokenVerifier, authConfig auth
|
|||||||
return nil, zerrors.ThrowUnauthenticated(nil, "AUT-1179", "auth header missing")
|
return nil, zerrors.ThrowUnauthenticated(nil, "AUT-1179", "auth header missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxSetter, err := authz.CheckUserAuthorization(authCtx, &httpReq{}, authToken, http_util.GetOrgID(r), "", verifier, authConfig, authOpt, r.RequestURI)
|
ctxSetter, err := authz.CheckUserAuthorization(authCtx, &httpReq{}, authToken, http_util.GetOrgID(r), "", verifier, authConfig, authConfig, authOpt, r.RequestURI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user