package eventsourcing import ( "context" "github.com/caos/zitadel/internal/api/authz" caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/models" iam_model "github.com/caos/zitadel/internal/iam/model" iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "testing" ) func TestLoginPolicyAddedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.Org new *iam_es_model.LoginPolicy aggCreator *models.AggregateCreator } type res struct { eventLen int eventTypes []models.EventType wantErr bool errFunc func(err error) bool } tests := []struct { name string args args res res }{ { name: "add login polciy", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, }, new: &iam_es_model.LoginPolicy{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, AllowUsernamePassword: true, }, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicyAdded}, }, }, { name: "existing org nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, { name: "login policy config nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}}, new: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { agg, err := LoginPolicyAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx) if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) { t.Errorf("got wrong err: %v ", err) return } if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) } for i := 0; i < tt.res.eventLen; i++ { if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] { t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) } if !tt.res.wantErr && agg.Events[i].Data == nil { t.Errorf("should have data in event") } } }) } } func TestLoginPolicyChangedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.Org new *iam_es_model.LoginPolicy aggCreator *models.AggregateCreator } type res struct { eventLen int eventTypes []models.EventType wantErr bool errFunc func(err error) bool } tests := []struct { name string args args res res }{ { name: "change login policy", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, LoginPolicy: &iam_es_model.LoginPolicy{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, }, }, new: &iam_es_model.LoginPolicy{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, AllowUsernamePassword: true, AllowRegister: true, }, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicyChanged}, }, }, { name: "existing org nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, { name: "login policy config nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}}, new: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { agg, err := LoginPolicyChangedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx) if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) { t.Errorf("got wrong err: %v ", err) return } if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) } for i := 0; i < tt.res.eventLen; i++ { if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] { t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) } if !tt.res.wantErr && agg.Events[i].Data == nil { t.Errorf("should have data in event") } } }) } } func TestLoginPolicyRemovedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.Org aggCreator *models.AggregateCreator } type res struct { eventLen int eventTypes []models.EventType wantErr bool errFunc func(err error) bool } tests := []struct { name string args args res res }{ { name: "remove login policy", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, LoginPolicy: &iam_es_model.LoginPolicy{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, }, }, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicyRemoved}, }, }, { name: "existing org nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { agg, err := LoginPolicyRemovedAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx) if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) { t.Errorf("got wrong err: %v ", err) return } if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) } for i := 0; i < tt.res.eventLen; i++ { if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] { t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) } } }) } } func TestLoginPolicyIdpProviderAddedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.Org new *iam_es_model.IDPProvider aggCreator *models.AggregateCreator } type res struct { eventLen int eventTypes []models.EventType wantErr bool errFunc func(err error) bool } tests := []struct { name string args args res res }{ { name: "add idp provider to login policy", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, }, new: &iam_es_model.IDPProvider{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Type: int32(iam_model.IDPProviderTypeSystem), IDPConfigID: "IDPConfigID", }, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicyIDPProviderAdded}, }, }, { name: "existing org nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, { name: "idp config config nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}}, new: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { agg, err := LoginPolicyIDPProviderAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new, "iamID")(tt.args.ctx) if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) { t.Errorf("got wrong err: %v ", err) return } if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) } for i := 0; i < tt.res.eventLen; i++ { if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] { t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) } if !tt.res.wantErr && agg.Events[i].Data == nil { t.Errorf("should have data in event") } } }) } } func TestLoginPolicyIdpProviderRemovedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.Org new *iam_es_model.IDPProviderID cascade bool aggCreator *models.AggregateCreator } type res struct { eventLen int eventTypes []models.EventType wantErr bool errFunc func(err error) bool } tests := []struct { name string args args res res }{ { name: "remove idp provider to login policy", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, LoginPolicy: &iam_es_model.LoginPolicy{ AllowUsernamePassword: true, IDPProviders: []*iam_es_model.IDPProvider{ {IDPConfigID: "IDPConfigID", Type: int32(iam_model.IDPProviderTypeSystem)}, }, }}, new: &iam_es_model.IDPProviderID{ IDPConfigID: "IDPConfigID", }, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicyIDPProviderRemoved}, }, }, { name: "remove idp provider to login policy cascade", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, LoginPolicy: &iam_es_model.LoginPolicy{ AllowUsernamePassword: true, IDPProviders: []*iam_es_model.IDPProvider{ {IDPConfigID: "IDPConfigID", Type: int32(iam_model.IDPProviderTypeSystem)}, }, }}, new: &iam_es_model.IDPProviderID{ IDPConfigID: "IDPConfigID", }, cascade: true, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicyIDPProviderCascadeRemoved}, }, }, { name: "existing org nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, { name: "idp config config nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}}, new: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { agg, err := LoginPolicyIDPProviderRemovedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing, tt.args.new, tt.args.cascade) if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) { t.Errorf("got wrong err: %v ", err) return } if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) } for i := 0; i < tt.res.eventLen; i++ { if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] { t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) } if !tt.res.wantErr && agg.Events[i].Data == nil { t.Errorf("should have data in event") } } }) } } func TestLoginPolicySecondFactorAddedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.Org new *iam_es_model.MFA aggCreator *models.AggregateCreator } type res struct { eventLen int eventTypes []models.EventType wantErr bool errFunc func(err error) bool } tests := []struct { name string args args res res }{ { name: "add second factor to login policy", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, }, new: &iam_es_model.MFA{ MFAType: int32(iam_model.SecondFactorTypeOTP), }, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicySecondFactorAdded}, }, }, { name: "existing org nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, { name: "mfa nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}}, new: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { agg, err := LoginPolicySecondFactorAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new, "iamID")(tt.args.ctx) if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) { t.Errorf("got wrong err: %v ", err) return } if !tt.res.wantErr && (agg == nil || len(agg.Events) != tt.res.eventLen) { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) return } for i := 0; i < tt.res.eventLen; i++ { if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] { t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) } if !tt.res.wantErr && agg.Events[i].Data == nil { t.Errorf("should have data in event") } } }) } } func TestLoginPolicySecondFactorRemovedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.Org new *iam_es_model.MFA aggCreator *models.AggregateCreator } type res struct { eventLen int eventTypes []models.EventType wantErr bool errFunc func(err error) bool } tests := []struct { name string args args res res }{ { name: "remove second factor from login policy", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, LoginPolicy: &iam_es_model.LoginPolicy{ AllowUsernamePassword: true, SecondFactors: []int32{ int32(iam_model.SecondFactorTypeOTP), }, }}, new: &iam_es_model.MFA{ MFAType: int32(iam_model.SecondFactorTypeOTP), }, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicySecondFactorRemoved}, }, }, { name: "existing org nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, { name: "mfa nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}}, new: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { agg, err := LoginPolicySecondFactorRemovedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx) if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) { t.Errorf("got wrong err: %v ", err) return } if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) } for i := 0; i < tt.res.eventLen; i++ { if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] { t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) } if !tt.res.wantErr && agg.Events[i].Data == nil { t.Errorf("should have data in event") } } }) } } func TestLoginPolicyMultiFactorAddedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.Org new *iam_es_model.MFA aggCreator *models.AggregateCreator } type res struct { eventLen int eventTypes []models.EventType wantErr bool errFunc func(err error) bool } tests := []struct { name string args args res res }{ { name: "add mfa to login policy", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, }, new: &iam_es_model.MFA{ MFAType: int32(iam_model.MultiFactorTypeU2FWithPIN), }, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicyMultiFactorAdded}, }, }, { name: "existing org nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, { name: "mfa nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}}, new: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { agg, err := LoginPolicyMultiFactorAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new, "iamID")(tt.args.ctx) if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) { t.Errorf("got wrong err: %v ", err) return } if !tt.res.wantErr && (agg == nil || len(agg.Events) != tt.res.eventLen) { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) return } for i := 0; i < tt.res.eventLen; i++ { if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] { t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) } if !tt.res.wantErr && agg.Events[i].Data == nil { t.Errorf("should have data in event") } } }) } } func TestLoginPolicyMultiFactorRemovedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.Org new *iam_es_model.MFA aggCreator *models.AggregateCreator } type res struct { eventLen int eventTypes []models.EventType wantErr bool errFunc func(err error) bool } tests := []struct { name string args args res res }{ { name: "remove mfa from login policy", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, LoginPolicy: &iam_es_model.LoginPolicy{ AllowUsernamePassword: true, MultiFactors: []int32{ int32(iam_model.MultiFactorTypeU2FWithPIN), }, }}, new: &iam_es_model.MFA{ MFAType: int32(iam_model.MultiFactorTypeU2FWithPIN), }, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ eventLen: 1, eventTypes: []models.EventType{model.LoginPolicyMultiFactorRemoved}, }, }, { name: "existing org nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, { name: "mfa nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), existing: &model.Org{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}}, new: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ wantErr: true, errFunc: caos_errs.IsPreconditionFailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { agg, err := LoginPolicyMultiFactorRemovedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx) if tt.res.wantErr && !tt.res.errFunc(err) || (err != nil && !tt.res.wantErr) { t.Errorf("got wrong err: %v ", err) return } if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) } for i := 0; i < tt.res.eventLen; i++ { if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] { t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) } if !tt.res.wantErr && agg.Events[i].Data == nil { t.Errorf("should have data in event") } } }) } }