fix: allow other users to set up MFAs (#7914)

* fix: allow other users to set up MFAs

* update tests

* update integration tests
This commit is contained in:
Livio Spring
2024-05-07 07:38:26 +02:00
committed by GitHub
parent 016e5e5da1
commit 5bf195d374
20 changed files with 701 additions and 193 deletions

View File

@@ -25,7 +25,8 @@ import (
func TestCommandSide_AddHumanTOTP(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(t *testing.T) *eventstore.Eventstore
permissionCheck domain.PermissionCheck
}
type (
args struct {
@@ -47,12 +48,10 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
{
name: "userid missing, invalid argument error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
orgID: "org1",
userID: "",
},
@@ -63,13 +62,12 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
{
name: "user not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(),
),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
orgID: "org1",
userID: "user1",
},
@@ -77,11 +75,40 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
err: zerrors.IsPreconditionFailed,
},
},
{
name: "other user, no permission error",
fields: fields{
eventstore: expectEventstore(
expectFilter(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user2", "org1").Aggregate,
"username",
"firstname",
"lastname",
"nickname",
"displayname",
language.German,
domain.GenderUnspecified,
"email@test.ch",
true,
),
),
),
permissionCheck: newMockPermissionCheckNotAllowed(),
},
args: args{
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
orgID: "org1",
userID: "user2",
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
{
name: "org not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
@@ -100,7 +127,7 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
orgID: "org1",
userID: "user1",
},
@@ -111,8 +138,7 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
{
name: "org iam policy not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
@@ -138,7 +164,7 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
orgID: "org1",
userID: "user1",
},
@@ -149,8 +175,7 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
{
name: "otp already exists, already exists error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
@@ -197,7 +222,7 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
orgID: "org1",
userID: "user1",
},
@@ -209,7 +234,8 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
checkPermission: tt.fields.permissionCheck,
}
got, err := r.AddHumanTOTP(tt.args.ctx, tt.args.userID, tt.args.orgID)
if tt.res.err == nil {
@@ -227,7 +253,8 @@ func TestCommandSide_AddHumanTOTP(t *testing.T) {
func TestCommands_createHumanTOTP(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(t *testing.T) *eventstore.Eventstore
checkPermission domain.PermissionCheck
}
type args struct {
ctx context.Context
@@ -244,23 +271,51 @@ func TestCommands_createHumanTOTP(t *testing.T) {
{
name: "user not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(),
),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
resourceOwner: "org1",
userID: "user1",
},
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-SqyJz", "Errors.User.NotFound"),
},
{
name: "other user, no permission error",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user2", "org1").Aggregate,
"username",
"firstname",
"lastname",
"nickname",
"displayname",
language.German,
domain.GenderUnspecified,
"email@test.ch",
true,
),
),
),
),
checkPermission: newMockPermissionCheckNotAllowed(),
},
args: args{
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
resourceOwner: "org1",
userID: "user2",
},
wantErr: zerrors.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
},
{
name: "org not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
@@ -281,7 +336,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
resourceOwner: "org1",
userID: "user1",
},
@@ -290,8 +345,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
{
name: "org iam policy not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
@@ -321,7 +375,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
resourceOwner: "org1",
userID: "user1",
},
@@ -330,8 +384,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
{
name: "otp already exists, already exists error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
@@ -385,7 +438,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
resourceOwner: "org1",
userID: "user1",
},
@@ -394,8 +447,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
{
name: "issuer not in context",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
@@ -434,7 +486,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
),
},
args: args{
ctx: context.Background(),
ctx: authz.NewMockContext("instanceID", "org1", "user1"),
resourceOwner: "org1",
userID: "user1",
},
@@ -443,8 +495,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
{
name: "success",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
@@ -483,17 +534,67 @@ func TestCommands_createHumanTOTP(t *testing.T) {
),
},
args: args{
ctx: authz.WithRequestedDomain(context.Background(), "zitadel.com"),
ctx: authz.WithRequestedDomain(authz.NewMockContext("instanceID", "org1", "user1"), "zitadel.com"),
resourceOwner: "org1",
userID: "user1",
},
want: true,
},
{
name: "success, other user",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user2", "org1").Aggregate,
"username",
"firstname",
"lastname",
"nickname",
"displayname",
language.German,
domain.GenderUnspecified,
"email@test.ch",
true,
),
),
),
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&user.NewAggregate("org1", "org1").Aggregate,
"org",
),
),
),
expectFilter(
eventFromEventPusher(
org.NewDomainPolicyAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
true,
true,
true,
),
),
),
expectFilter(),
),
checkPermission: newMockPermissionCheckAllowed(),
},
args: args{
ctx: authz.WithRequestedDomain(authz.NewMockContext("instanceID", "org1", "user1"), "zitadel.com"),
resourceOwner: "org1",
userID: "user2",
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
checkPermission: tt.fields.checkPermission,
multifactors: domain.MultifactorConfigs{
OTP: domain.OTPConfig{
CryptoMFA: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
@@ -522,12 +623,14 @@ func TestCommands_HumanCheckMFATOTPSetup(t *testing.T) {
key, secret, err := domain.NewTOTPKey("example.com", "user1", cryptoAlg)
require.NoError(t, err)
userAgg := &user.NewAggregate("user1", "org1").Aggregate
userAgg2 := &user.NewAggregate("user2", "org1").Aggregate
code, err := totp.GenerateCode(key.Secret(), time.Now())
require.NoError(t, err)
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(t *testing.T) *eventstore.Eventstore
checkPermission domain.PermissionCheck
}
type args struct {
userID string
@@ -542,14 +645,17 @@ func TestCommands_HumanCheckMFATOTPSetup(t *testing.T) {
wantErr error
}{
{
name: "missing user id",
name: "missing user id",
fields: fields{
eventstore: expectEventstore(),
},
args: args{},
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-8N9ds", "Errors.User.UserIDMissing"),
},
{
name: "filter error",
fields: fields{
eventstore: eventstoreExpect(t,
eventstore: expectEventstore(
expectFilterError(io.ErrClosedPipe),
),
},
@@ -559,11 +665,28 @@ func TestCommands_HumanCheckMFATOTPSetup(t *testing.T) {
},
wantErr: io.ErrClosedPipe,
},
{
name: "other user, no permission error",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPAddedEvent(ctx, userAgg2, secret),
),
),
),
checkPermission: newMockPermissionCheckNotAllowed(),
},
args: args{
resourceOwner: "org1",
userID: "user2",
},
wantErr: zerrors.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
},
{
name: "otp not existing error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPAddedEvent(ctx, userAgg, secret),
@@ -583,8 +706,7 @@ func TestCommands_HumanCheckMFATOTPSetup(t *testing.T) {
{
name: "otp already ready error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPAddedEvent(ctx, userAgg, secret),
@@ -607,8 +729,7 @@ func TestCommands_HumanCheckMFATOTPSetup(t *testing.T) {
{
name: "wrong code",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPAddedEvent(ctx, userAgg, secret),
@@ -626,8 +747,7 @@ func TestCommands_HumanCheckMFATOTPSetup(t *testing.T) {
{
name: "push error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPAddedEvent(ctx, userAgg, secret),
@@ -651,8 +771,7 @@ func TestCommands_HumanCheckMFATOTPSetup(t *testing.T) {
{
name: "success",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPAddedEvent(ctx, userAgg, secret),
@@ -672,11 +791,36 @@ func TestCommands_HumanCheckMFATOTPSetup(t *testing.T) {
userID: "user1",
},
},
{
name: "success, other user",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPAddedEvent(ctx, userAgg2, secret),
),
),
expectPush(
user.NewHumanOTPVerifiedEvent(ctx,
userAgg2,
"agent1",
),
),
),
checkPermission: newMockPermissionCheckAllowed(),
},
args: args{
resourceOwner: "org1",
code: code,
userID: "user2",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
checkPermission: tt.fields.checkPermission,
multifactors: domain.MultifactorConfigs{
OTP: domain.OTPConfig{
CryptoMFA: cryptoAlg,
@@ -695,7 +839,7 @@ func TestCommands_HumanCheckMFATOTPSetup(t *testing.T) {
func TestCommandSide_RemoveHumanTOTP(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(t *testing.T) *eventstore.Eventstore
}
type (
args struct {
@@ -717,9 +861,7 @@ func TestCommandSide_RemoveHumanTOTP(t *testing.T) {
{
name: "userid missing, invalid argument error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -733,8 +875,7 @@ func TestCommandSide_RemoveHumanTOTP(t *testing.T) {
{
name: "otp not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(),
),
},
@@ -750,8 +891,7 @@ func TestCommandSide_RemoveHumanTOTP(t *testing.T) {
{
name: "otp not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPAddedEvent(context.Background(),
@@ -782,7 +922,7 @@ func TestCommandSide_RemoveHumanTOTP(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
}
got, err := r.HumanRemoveTOTP(tt.args.ctx, tt.args.userID, tt.args.orgID)
if tt.res.err == nil {
@@ -801,7 +941,8 @@ func TestCommandSide_RemoveHumanTOTP(t *testing.T) {
func TestCommandSide_AddHumanOTPSMS(t *testing.T) {
ctx := authz.NewMockContext("inst1", "org1", "user1")
type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore
eventstore func(*testing.T) *eventstore.Eventstore
checkPermission domain.PermissionCheck
}
type (
args struct {
@@ -837,15 +978,24 @@ func TestCommandSide_AddHumanOTPSMS(t *testing.T) {
{
name: "wrong user, permission denied error",
fields: fields{
eventstore: expectEventstore(),
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPSMSAddedEvent(ctx,
&user.NewAggregate("user2", "org1").Aggregate,
),
),
),
),
checkPermission: newMockPermissionCheckNotAllowed(),
},
args: args{
ctx: ctx,
userID: "other",
userID: "user2",
resourceOwner: "org1",
},
res: res{
err: zerrors.ThrowPermissionDenied(nil, "AUTH-Bohd2", "Errors.User.UserIDWrong"),
err: zerrors.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
},
},
{
@@ -954,11 +1104,48 @@ func TestCommandSide_AddHumanOTPSMS(t *testing.T) {
},
},
},
{
name: "successful add, other user",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanPhoneChangedEvent(ctx,
&user.NewAggregate("user2", "org1").Aggregate,
"+4179654321",
),
),
eventFromEventPusher(
user.NewHumanPhoneVerifiedEvent(ctx,
&user.NewAggregate("user2", "org1").Aggregate,
),
),
),
expectPush(
user.NewHumanOTPSMSAddedEvent(ctx,
&user.NewAggregate("user2", "org1").Aggregate,
),
),
),
checkPermission: newMockPermissionCheckAllowed(),
},
args: args{
ctx: ctx,
userID: "user2",
resourceOwner: "org1",
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore(t),
eventstore: tt.fields.eventstore(t),
checkPermission: tt.fields.checkPermission,
}
got, err := r.AddHumanOTPSMS(tt.args.ctx, tt.args.userID, tt.args.resourceOwner)
assert.ErrorIs(t, err, tt.res.err)
@@ -1942,7 +2129,8 @@ func TestCommandSide_HumanCheckOTPSMS(t *testing.T) {
func TestCommandSide_AddHumanOTPEmail(t *testing.T) {
ctx := authz.NewMockContext("inst1", "org1", "user1")
type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore
eventstore func(*testing.T) *eventstore.Eventstore
checkPermission domain.PermissionCheck
}
type (
args struct {
@@ -1975,6 +2163,29 @@ func TestCommandSide_AddHumanOTPEmail(t *testing.T) {
err: zerrors.ThrowInvalidArgument(nil, "COMMAND-Sg1hz", "Errors.User.UserIDMissing"),
},
},
{
name: "wrong user, permission denied error",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPEmailAddedEvent(ctx,
&user.NewAggregate("user2", "org1").Aggregate,
),
),
),
),
checkPermission: newMockPermissionCheckNotAllowed(),
},
args: args{
ctx: ctx,
userID: "user2",
resourceOwner: "org1",
},
res: res{
err: zerrors.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
},
},
{
name: "otp email already exists, already exists error",
fields: fields{
@@ -2048,11 +2259,48 @@ func TestCommandSide_AddHumanOTPEmail(t *testing.T) {
},
},
},
{
name: "successful add, other user",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanEmailChangedEvent(ctx,
&user.NewAggregate("user2", "org1").Aggregate,
"email@test.ch",
),
),
eventFromEventPusher(
user.NewHumanEmailVerifiedEvent(ctx,
&user.NewAggregate("user2", "org1").Aggregate,
),
),
),
expectPush(
user.NewHumanOTPEmailAddedEvent(ctx,
&user.NewAggregate("user2", "org1").Aggregate,
),
),
),
checkPermission: newMockPermissionCheckAllowed(),
},
args: args{
ctx: ctx,
userID: "user2",
resourceOwner: "org1",
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore(t),
eventstore: tt.fields.eventstore(t),
checkPermission: tt.fields.checkPermission,
}
got, err := r.AddHumanOTPEmail(tt.args.ctx, tt.args.userID, tt.args.resourceOwner)
assert.ErrorIs(t, err, tt.res.err)