From ed42dde4639e2bb5ddcc4efae8e79ab4c7d0c9cc Mon Sep 17 00:00:00 2001 From: Stefan Benz <46600784+stebenz@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:09:00 +0100 Subject: [PATCH] fix: process org remove event in domain verified writemodel (#8790) # Which Problems Are Solved Domains are processed as still verified in the domain verified writemodel even if the org is removed. # How the Problems Are Solved Handle the org removed event in the writemodel. # Additional Changes None # Additional Context Closes #8514 --------- Co-authored-by: Livio Spring --- internal/command/org_domain_model.go | 10 +- internal/command/user_v2_human_test.go | 317 +++++++++++++++++++++++++ 2 files changed, 326 insertions(+), 1 deletion(-) diff --git a/internal/command/org_domain_model.go b/internal/command/org_domain_model.go index 43ab9e52d..b387e6f4b 100644 --- a/internal/command/org_domain_model.go +++ b/internal/command/org_domain_model.go @@ -202,6 +202,8 @@ func (wm *OrgDomainVerifiedWriteModel) AppendEvents(events ...eventstore.Event) continue } wm.WriteModel.AppendEvents(e) + case *org.OrgRemovedEvent: + wm.WriteModel.AppendEvents(e) } } } @@ -214,6 +216,11 @@ func (wm *OrgDomainVerifiedWriteModel) Reduce() error { wm.ResourceOwner = e.Aggregate().ResourceOwner case *org.DomainRemovedEvent: wm.Verified = false + case *org.OrgRemovedEvent: + if wm.ResourceOwner != e.Aggregate().ID { + continue + } + wm.Verified = false } } return wm.WriteModel.Reduce() @@ -225,6 +232,7 @@ func (wm *OrgDomainVerifiedWriteModel) Query() *eventstore.SearchQueryBuilder { AggregateTypes(org.AggregateType). EventTypes( org.OrgDomainVerifiedEventType, - org.OrgDomainRemovedEventType). + org.OrgDomainRemovedEventType, + org.OrgRemovedEventType). Builder() } diff --git a/internal/command/user_v2_human_test.go b/internal/command/user_v2_human_test.go index a50061c01..2b4399fb2 100644 --- a/internal/command/user_v2_human_test.go +++ b/internal/command/user_v2_human_test.go @@ -1725,6 +1725,323 @@ func TestCommandSide_AddUserHuman(t *testing.T) { wantID: "user1", }, }, + { + name: "register human (validate domain), already verified", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &userAgg.Aggregate, + false, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewDomainVerifiedEvent(context.Background(), + &org.NewAggregate("existing").Aggregate, + "example.com", + ), + ), + ), + ), + checkPermission: newMockPermissionCheckAllowed(), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + newCode: mockEncryptedCode("userinit", time.Hour), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + human: &AddHuman{ + Username: "username@example.com", + FirstName: "firstname", + LastName: "lastname", + Email: Email{ + Address: "email@example.com", + }, + PreferredLanguage: language.English, + Register: true, + UserAgentID: "userAgentID", + AuthRequestID: "authRequestID", + }, + secretGenerator: GetMockSecretGenerator(t), + allowInitMail: true, + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + res: res{ + err: func(err error) bool { + return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "COMMAND-SFd21", "Errors.User.DomainNotAllowedAsUsername")) + }, + }, + }, + { + name: "register human (validate domain), ok", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &userAgg.Aggregate, + false, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewDomainVerifiedEvent(context.Background(), + &org.NewAggregate(userAgg.ResourceOwner).Aggregate, + "example.com", + ), + ), + ), + expectPush( + user.NewHumanRegisteredEvent(context.Background(), + &userAgg.Aggregate, + "username@example.com", + "firstname", + "lastname", + "", + "firstname lastname", + language.English, + domain.GenderUnspecified, + "email@example.com", + false, + "userAgentID", + ), + user.NewHumanInitialCodeAddedEvent(context.Background(), + &userAgg.Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("userinit"), + }, + time.Hour*1, + "authRequestID", + ), + ), + ), + checkPermission: newMockPermissionCheckAllowed(), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + newCode: mockEncryptedCode("userinit", time.Hour), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + human: &AddHuman{ + Username: "username@example.com", + FirstName: "firstname", + LastName: "lastname", + Email: Email{ + Address: "email@example.com", + }, + PreferredLanguage: language.English, + Register: true, + UserAgentID: "userAgentID", + AuthRequestID: "authRequestID", + }, + secretGenerator: GetMockSecretGenerator(t), + allowInitMail: true, + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + res: res{ + want: &domain.ObjectDetails{ + Sequence: 0, + EventDate: time.Time{}, + ResourceOwner: "org1", + }, + wantID: "user1", + }, + }, + { + name: "register human (validate domain, domain removed), ok", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &userAgg.Aggregate, + false, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewDomainVerifiedEvent(context.Background(), + &org.NewAggregate("existing").Aggregate, + "example.com", + ), + ), + eventFromEventPusher( + org.NewDomainRemovedEvent(context.Background(), + &org.NewAggregate("existing").Aggregate, + "example.com", + true, + ), + ), + ), + expectPush( + user.NewHumanRegisteredEvent(context.Background(), + &userAgg.Aggregate, + "username@example.com", + "firstname", + "lastname", + "", + "firstname lastname", + language.English, + domain.GenderUnspecified, + "email@example.com", + false, + "userAgentID", + ), + user.NewHumanInitialCodeAddedEvent(context.Background(), + &userAgg.Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("userinit"), + }, + time.Hour*1, + "authRequestID", + ), + ), + ), + checkPermission: newMockPermissionCheckAllowed(), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + newCode: mockEncryptedCode("userinit", time.Hour), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + human: &AddHuman{ + Username: "username@example.com", + FirstName: "firstname", + LastName: "lastname", + Email: Email{ + Address: "email@example.com", + }, + PreferredLanguage: language.English, + Register: true, + UserAgentID: "userAgentID", + AuthRequestID: "authRequestID", + }, + secretGenerator: GetMockSecretGenerator(t), + allowInitMail: true, + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + res: res{ + want: &domain.ObjectDetails{ + Sequence: 0, + EventDate: time.Time{}, + ResourceOwner: "org1", + }, + wantID: "user1", + }, + }, + { + name: "register human (validate domain, org removed), ok", + fields: fields{ + eventstore: expectEventstore( + expectFilter(), + expectFilter( + eventFromEventPusher( + org.NewDomainPolicyAddedEvent(context.Background(), + &userAgg.Aggregate, + false, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + org.NewDomainVerifiedEvent(context.Background(), + &org.NewAggregate("existing").Aggregate, + "example.com", + ), + ), + eventFromEventPusher( + org.NewOrgRemovedEvent(context.Background(), + &org.NewAggregate("existing").Aggregate, + "org", + []string{}, + false, + []string{}, + []*domain.UserIDPLink{}, + []string{}, + ), + ), + ), + expectPush( + user.NewHumanRegisteredEvent(context.Background(), + &userAgg.Aggregate, + "username@example.com", + "firstname", + "lastname", + "", + "firstname lastname", + language.English, + domain.GenderUnspecified, + "email@example.com", + false, + "userAgentID", + ), + user.NewHumanInitialCodeAddedEvent(context.Background(), + &userAgg.Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("userinit"), + }, + time.Hour*1, + "authRequestID", + ), + ), + ), + checkPermission: newMockPermissionCheckAllowed(), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"), + newCode: mockEncryptedCode("userinit", time.Hour), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + human: &AddHuman{ + Username: "username@example.com", + FirstName: "firstname", + LastName: "lastname", + Email: Email{ + Address: "email@example.com", + }, + PreferredLanguage: language.English, + Register: true, + UserAgentID: "userAgentID", + AuthRequestID: "authRequestID", + }, + secretGenerator: GetMockSecretGenerator(t), + allowInitMail: true, + codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + res: res{ + want: &domain.ObjectDetails{ + Sequence: 0, + EventDate: time.Time{}, + ResourceOwner: "org1", + }, + wantID: "user1", + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {