fix: correct user self management on metadata and delete (#10666)

# Which Problems Are Solved

This PR fixes the self-management of users for metadata and own removal
and improves the corresponding permission checks.
While looking into the problems, I also noticed that there's a bug in
the metadata mapping when using `api.metadata.push` in actions v1 and
that re-adding a previously existing key after its removal was not
possible.

# How the Problems Are Solved

- Added a parameter `allowSelfManagement` to checkPermissionOnUser to
not require a permission if a user is changing its own data.
- Updated use of `NewPermissionCheckUserWrite` including prevention of
self-management for metadata.
- Pass permission check to the command side (for metadata functions) to
allow it implicitly for login v1 and actions v1.
- Use of json.Marshal for the metadata mapping (as with
`AppendMetadata`)
- Check the metadata state when comparing the value.

# Additional Changes

- added a variadic `roles` parameter to the `CreateOrgMembership`
integration test helper function to allow defining specific roles.

# Additional Context

- noted internally while testing v4.1.x
- requires backport to v4.x
- closes https://github.com/zitadel/zitadel/issues/10470
- relates to https://github.com/zitadel/zitadel/pull/10426

(cherry picked from commit 5329d50509)
This commit is contained in:
Livio Spring
2025-09-16 14:26:21 +02:00
parent 389f908041
commit fa83c39510
31 changed files with 695 additions and 208 deletions

View File

@@ -18,6 +18,7 @@ import (
)
func TestCommandSide_LockUserV2(t *testing.T) {
userAgg := &user.NewAggregate("user1", "org1").Aggregate
type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore
checkPermission domain.PermissionCheck
@@ -79,7 +80,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -93,7 +94,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserLockedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -117,7 +118,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -127,7 +128,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserLockedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -151,7 +152,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -166,7 +167,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
),
expectPush(
user.NewUserLockedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -189,7 +190,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -222,7 +223,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -233,7 +234,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
),
expectPush(
user.NewUserLockedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -271,6 +272,7 @@ func TestCommandSide_LockUserV2(t *testing.T) {
}
func TestCommandSide_UnlockUserV2(t *testing.T) {
userAgg := &user.NewAggregate("user1", "org1").Aggregate
type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore
checkPermission domain.PermissionCheck
@@ -332,7 +334,7 @@ func TestCommandSide_UnlockUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -364,7 +366,7 @@ func TestCommandSide_UnlockUserV2(t *testing.T) {
eventstore: expectEventstore(
expectFilter(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -392,7 +394,7 @@ func TestCommandSide_UnlockUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -406,12 +408,12 @@ func TestCommandSide_UnlockUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserLockedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate),
userAgg),
),
),
expectPush(
user.NewUserUnlockedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -434,7 +436,7 @@ func TestCommandSide_UnlockUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -448,7 +450,7 @@ func TestCommandSide_UnlockUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserLockedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate),
userAgg),
),
),
),
@@ -471,7 +473,7 @@ func TestCommandSide_UnlockUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -481,12 +483,12 @@ func TestCommandSide_UnlockUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserLockedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate),
userAgg),
),
),
expectPush(
user.NewUserUnlockedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -524,6 +526,7 @@ func TestCommandSide_UnlockUserV2(t *testing.T) {
}
func TestCommandSide_DeactivateUserV2(t *testing.T) {
userAgg := &user.NewAggregate("user1", "org1").Aggregate
type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore
checkPermission domain.PermissionCheck
@@ -585,7 +588,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -599,7 +602,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewHumanInitialCodeAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
nil, time.Hour*1,
"",
),
@@ -625,7 +628,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -639,7 +642,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserDeactivatedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -663,7 +666,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -677,13 +680,13 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewHumanInitializedCheckSucceededEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
expectPush(
user.NewUserDeactivatedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -706,7 +709,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -720,7 +723,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewHumanInitializedCheckSucceededEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -744,7 +747,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -754,7 +757,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserDeactivatedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -778,7 +781,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -789,7 +792,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
),
expectPush(
user.NewUserDeactivatedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -827,6 +830,7 @@ func TestCommandSide_DeactivateUserV2(t *testing.T) {
}
func TestCommandSide_ReactivateUserV2(t *testing.T) {
userAgg := &user.NewAggregate("user1", "org1").Aggregate
type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore
checkPermission domain.PermissionCheck
@@ -888,7 +892,7 @@ func TestCommandSide_ReactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -921,7 +925,7 @@ func TestCommandSide_ReactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -950,7 +954,7 @@ func TestCommandSide_ReactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -964,12 +968,12 @@ func TestCommandSide_ReactivateUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserDeactivatedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate),
userAgg),
),
),
expectPush(
user.NewUserReactivatedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -992,7 +996,7 @@ func TestCommandSide_ReactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -1006,7 +1010,7 @@ func TestCommandSide_ReactivateUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserDeactivatedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate),
userAgg),
),
),
),
@@ -1029,7 +1033,7 @@ func TestCommandSide_ReactivateUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -1039,12 +1043,12 @@ func TestCommandSide_ReactivateUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserDeactivatedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate),
userAgg),
),
),
expectPush(
user.NewUserReactivatedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -1084,6 +1088,8 @@ func TestCommandSide_ReactivateUserV2(t *testing.T) {
func TestCommandSide_RemoveUserV2(t *testing.T) {
ctxUserID := "ctxUserID"
ctx := authz.SetCtxData(context.Background(), authz.CtxData{UserID: ctxUserID})
userAgg := &user.NewAggregate("user1", "org1").Aggregate
orgAgg := &org.NewAggregate("org1").Aggregate
type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore
checkPermission domain.PermissionCheck
@@ -1144,7 +1150,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -1158,7 +1164,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserRemovedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
nil,
true,
@@ -1184,7 +1190,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -1199,8 +1205,8 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
),
expectFilter(
eventFromEventPusher(
org.NewDomainPolicyAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
org.NewDomainPolicyAddedEvent(context.Background(),
orgAgg,
true,
true,
true,
@@ -1209,7 +1215,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
),
expectPush(
user.NewUserRemovedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
nil,
true,
@@ -1234,7 +1240,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"firstname",
"lastname",
@@ -1248,7 +1254,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewHumanInitializedCheckSucceededEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
),
),
),
@@ -1269,7 +1275,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -1279,7 +1285,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
),
eventFromEventPusher(
user.NewUserRemovedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
nil,
true,
@@ -1304,7 +1310,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
"name",
"description",
@@ -1315,8 +1321,8 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
),
expectFilter(
eventFromEventPusher(
org.NewDomainPolicyAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
org.NewDomainPolicyAddedEvent(context.Background(),
orgAgg,
true,
true,
true,
@@ -1325,7 +1331,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
),
expectPush(
user.NewUserRemovedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
userAgg,
"username",
nil,
true,
@@ -1344,7 +1350,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
},
},
{
name: "remove self, ok",
name: "remove self, permission denied",
fields: fields{
eventstore: expectEventstore(
expectFilter(
@@ -1363,24 +1369,6 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
),
),
),
expectFilter(
eventFromEventPusher(
org.NewDomainPolicyAddedEvent(ctx,
&user.NewAggregate(ctxUserID, "org1").Aggregate,
true,
true,
true,
),
),
),
expectPush(
user.NewUserRemovedEvent(ctx,
&user.NewAggregate(ctxUserID, "org1").Aggregate,
"username",
nil,
true,
),
),
),
checkPermission: newMockPermissionCheckNotAllowed(),
},
@@ -1388,9 +1376,7 @@ func TestCommandSide_RemoveUserV2(t *testing.T) {
userID: ctxUserID,
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
err: zerrors.IsPermissionDenied,
},
},
}