mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:37:32 +00:00
chore!: Introduce ZITADEL v3 (#9645)
This PR summarizes multiple changes specifically only available with ZITADEL v3: - feat: Web Keys management (https://github.com/zitadel/zitadel/pull/9526) - fix(cmd): ensure proper working of mirror (https://github.com/zitadel/zitadel/pull/9509) - feat(Authz): system user support for permission check v2 (https://github.com/zitadel/zitadel/pull/9640) - chore(license): change from Apache to AGPL (https://github.com/zitadel/zitadel/pull/9597) - feat(console): list v2 sessions (https://github.com/zitadel/zitadel/pull/9539) - fix(console): add loginV2 feature flag (https://github.com/zitadel/zitadel/pull/9682) - fix(feature flags): allow reading "own" flags (https://github.com/zitadel/zitadel/pull/9649) - feat(console): add Actions V2 UI (https://github.com/zitadel/zitadel/pull/9591) BREAKING CHANGE - feat(webkey): migrate to v2beta API (https://github.com/zitadel/zitadel/pull/9445) - chore!: remove CockroachDB Support (https://github.com/zitadel/zitadel/pull/9444) - feat(actions): migrate to v2beta API (https://github.com/zitadel/zitadel/pull/9489) --------- Co-authored-by: Livio Spring <livio.a@gmail.com> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com> Co-authored-by: Ramon <mail@conblem.me> Co-authored-by: Elio Bischof <elio@zitadel.com> Co-authored-by: Kenta Yamaguchi <56732734+KEY60228@users.noreply.github.com> Co-authored-by: Harsha Reddy <harsha.reddy@klaviyo.com> Co-authored-by: Livio Spring <livio@zitadel.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Iraq <66622793+kkrime@users.noreply.github.com> Co-authored-by: Florian Forster <florian@zitadel.com> Co-authored-by: Tim Möhlmann <tim+github@zitadel.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Max Peintner <peintnerm@gmail.com>
This commit is contained in:
@@ -4,8 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
@@ -16,10 +19,10 @@ const (
|
||||
|
||||
// CheckUserAuthorization verifies that:
|
||||
// - the token is active,
|
||||
// - the organisation (**either** provided by ID or verified domain) exists
|
||||
// - the organization (**either** provided by ID or verified domain) exists
|
||||
// - 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]
|
||||
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, systemRolePermissionMapping []RoleMapping, rolePermissionMapping []RoleMapping, requiredAuthOption Option, method string) (ctxSetter func(context.Context) context.Context, err error) {
|
||||
ctx, span := tracing.NewServerInterceptorSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
@@ -30,11 +33,12 @@ func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID,
|
||||
|
||||
if requiredAuthOption.Permission == authenticated {
|
||||
return func(parent context.Context) context.Context {
|
||||
parent = addGetSystemUserRolesToCtx(parent, systemRolePermissionMapping, ctxData)
|
||||
return context.WithValue(parent, dataKey, ctxData)
|
||||
}, nil
|
||||
}
|
||||
|
||||
requestedPermissions, allPermissions, err := getUserPermissions(ctx, verifier, requiredAuthOption.Permission, authConfig.RolePermissionMappings, ctxData, ctxData.OrgID)
|
||||
requestedPermissions, allPermissions, err := getUserPermissions(ctx, verifier, requiredAuthOption.Permission, systemRolePermissionMapping, rolePermissionMapping, ctxData, ctxData.OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -50,6 +54,7 @@ func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID,
|
||||
parent = context.WithValue(parent, dataKey, ctxData)
|
||||
parent = context.WithValue(parent, allPermissionsKey, allPermissions)
|
||||
parent = context.WithValue(parent, requestPermissionsKey, requestedPermissions)
|
||||
parent = addGetSystemUserRolesToCtx(parent, systemRolePermissionMapping, ctxData)
|
||||
return parent
|
||||
}, nil
|
||||
}
|
||||
@@ -125,3 +130,43 @@ func GetAllPermissionCtxIDs(perms []string) []string {
|
||||
}
|
||||
return ctxIDs
|
||||
}
|
||||
|
||||
type SystemUserPermissionsDBQuery struct {
|
||||
MemberType string `json:"member_type"`
|
||||
AggregateID string `json:"aggregate_id"`
|
||||
ObjectID string `json:"object_id"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
|
||||
func addGetSystemUserRolesToCtx(ctx context.Context, systemUserRoleMap []RoleMapping, ctxData CtxData) context.Context {
|
||||
if len(ctxData.SystemMemberships) == 0 {
|
||||
return ctx
|
||||
}
|
||||
systemUserPermissions := make([]SystemUserPermissionsDBQuery, len(ctxData.SystemMemberships))
|
||||
for i, systemPerm := range ctxData.SystemMemberships {
|
||||
permissions := make([]string, 0, len(systemPerm.Roles))
|
||||
for _, role := range systemPerm.Roles {
|
||||
permissions = append(permissions, getPermissionsFromRole(systemUserRoleMap, role)...)
|
||||
}
|
||||
slices.Sort(permissions)
|
||||
permissions = slices.Compact(permissions)
|
||||
|
||||
systemUserPermissions[i].MemberType = systemPerm.MemberType.String()
|
||||
systemUserPermissions[i].AggregateID = systemPerm.AggregateID
|
||||
systemUserPermissions[i].Permissions = permissions
|
||||
}
|
||||
return context.WithValue(ctx, systemUserRolesKey, systemUserPermissions)
|
||||
}
|
||||
|
||||
func GetSystemUserPermissions(ctx context.Context) []SystemUserPermissionsDBQuery {
|
||||
getSystemUserRolesFuncValue := ctx.Value(systemUserRolesKey)
|
||||
if getSystemUserRolesFuncValue == nil {
|
||||
return nil
|
||||
}
|
||||
systemUserRoles, ok := getSystemUserRolesFuncValue.([]SystemUserPermissionsDBQuery)
|
||||
if !ok {
|
||||
logging.WithFields("Authz").Error("unable to cast []SystemUserPermissionsDBQuery")
|
||||
return nil
|
||||
}
|
||||
return systemUserRoles
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ const (
|
||||
dataKey key = 2
|
||||
allPermissionsKey key = 3
|
||||
instanceKey key = 4
|
||||
systemUserRolesKey key = 5
|
||||
)
|
||||
|
||||
type CtxData struct {
|
||||
@@ -50,7 +51,8 @@ type Memberships []*Membership
|
||||
type Membership struct {
|
||||
MemberType MemberType
|
||||
AggregateID string
|
||||
//ObjectID differs from aggregate id if object is sub of an aggregate
|
||||
InstanceID string
|
||||
// ObjectID differs from aggregate id if object is sub of an aggregate
|
||||
ObjectID string
|
||||
|
||||
Roles []string
|
||||
|
@@ -7,8 +7,8 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func CheckPermission(ctx context.Context, resolver MembershipsResolver, roleMappings []RoleMapping, permission, orgID, resourceID string) (err error) {
|
||||
requestedPermissions, _, err := getUserPermissions(ctx, resolver, permission, roleMappings, GetCtxData(ctx), orgID)
|
||||
func CheckPermission(ctx context.Context, resolver MembershipsResolver, systemUserRoleMapping []RoleMapping, roleMappings []RoleMapping, permission, orgID, resourceID string) (err error) {
|
||||
requestedPermissions, _, err := getUserPermissions(ctx, resolver, permission, systemUserRoleMapping, roleMappings, GetCtxData(ctx), orgID)
|
||||
if err != nil {
|
||||
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),
|
||||
// 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)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
@@ -31,7 +31,7 @@ func getUserPermissions(ctx context.Context, resolver MembershipsResolver, requi
|
||||
}
|
||||
|
||||
if ctxData.SystemMemberships != nil {
|
||||
requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, roleMappings)
|
||||
requestedPermissions, allPermissions = mapMembershipsToPermissions(requiredPerm, ctxData.SystemMemberships, systemUserRoleMappings)
|
||||
return requestedPermissions, allPermissions, nil
|
||||
}
|
||||
|
||||
|
@@ -120,7 +120,7 @@ func Test_GetUserPermissions(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, perms, err := getUserPermissions(context.Background(), tt.args.membershipsResolver, tt.args.requiredPerm, tt.args.authConfig.RolePermissionMappings, tt.args.ctxData, tt.args.ctxData.OrgID)
|
||||
_, perms, err := getUserPermissions(context.Background(), tt.args.membershipsResolver, tt.args.requiredPerm, nil, tt.args.authConfig.RolePermissionMappings, tt.args.ctxData, tt.args.ctxData.OrgID)
|
||||
|
||||
if tt.wantErr && err == nil {
|
||||
t.Errorf("got wrong result, should get err: actual: %v ", err)
|
||||
|
Reference in New Issue
Block a user