From 57fc3ddd167be5eedc1d3a707f5284cb0e1971b1 Mon Sep 17 00:00:00 2001 From: adlerhurst Date: Fri, 6 Nov 2020 22:09:19 +0100 Subject: [PATCH] policies implemented --- internal/api/service/service.go | 20 +++++ internal/eventstore/v2/aggregate.go | 34 ++++++++ internal/eventstore/v2/event.go | 6 -- internal/eventstore/v2/event_base.go | 6 +- internal/eventstore/v2/eventstore_test.go | 5 +- internal/eventstore/v2/example_test.go | 5 +- internal/eventstore/v2/read_model.go | 47 ++-------- internal/v2/repository/iam/aggregate.go | 7 +- internal/v2/repository/iam/event_iam_added.go | 3 +- .../repository/iam/event_iam_project_set.go | 13 ++- internal/v2/repository/iam/events_step.go | 23 ++++- internal/v2/repository/iam/read_model.go | 52 +++++++++++ internal/v2/repository/member/event_added.go | 9 +- .../v2/repository/member/event_changed.go | 39 +++++++++ .../v2/repository/member/event_removed.go | 8 +- internal/v2/repository/member/read_models.go | 84 ++++++++++++++++++ internal/v2/repository/policy/events_label.go | 76 +++++++++++++++- internal/v2/repository/policy/events_login.go | 75 +++++++++++++++- .../v2/repository/policy/events_org_iam.go | 2 - .../repository/policy/events_password_age.go | 80 ++++++++++++++++- .../policy/events_password_complexity.go | 87 ++++++++++++++++++- .../policy/events_password_lockout.go | 73 +++++++++++++++- 22 files changed, 667 insertions(+), 87 deletions(-) create mode 100644 internal/api/service/service.go create mode 100644 internal/eventstore/v2/aggregate.go create mode 100644 internal/v2/repository/iam/read_model.go create mode 100644 internal/v2/repository/member/event_changed.go create mode 100644 internal/v2/repository/member/read_models.go diff --git a/internal/api/service/service.go b/internal/api/service/service.go new file mode 100644 index 000000000..dd9956f67 --- /dev/null +++ b/internal/api/service/service.go @@ -0,0 +1,20 @@ +package service + +import "context" + +type serviceKey struct{} + +var key *serviceKey = (*serviceKey)(nil) + +func WithService(partent context.Context, serviceName string) context.Context { + return context.WithValue(partent, key, serviceName) +} + +func FromContext(ctx context.Context) string { + value := ctx.Value(key) + if name, ok := value.(string); ok { + return name + } + + return "" +} diff --git a/internal/eventstore/v2/aggregate.go b/internal/eventstore/v2/aggregate.go new file mode 100644 index 000000000..69f2531de --- /dev/null +++ b/internal/eventstore/v2/aggregate.go @@ -0,0 +1,34 @@ +package eventstore + +func NewAggregate(id string) *Aggregate { + return &Aggregate{ + ID: id, + Events: []EventPusher{}, + } +} + +type Aggregate struct { + PreviousSequence uint64 `json:"-"` + ID string `json:"-"` + Events []EventPusher `json:"-"` +} + +//AppendEvents adds all the events to the aggregate. +// The function doesn't compute the new state of the aggregate +func (a *Aggregate) AppendEvents(events ...EventPusher) *Aggregate { + a.Events = append(a.Events, events...) + return a +} + +//Reduce must be the last step in the reduce function of the extension +func (a *Aggregate) Reduce() error { + if len(a.Events) == 0 { + return nil + } + + a.PreviousSequence = a.Events[len(a.Events)-1].Sequence() + // all events processed and not needed anymore + a.Events = nil + a.Events = []Event{} + return nil +} diff --git a/internal/eventstore/v2/event.go b/internal/eventstore/v2/event.go index 37a0824bd..98b38be0c 100644 --- a/internal/eventstore/v2/event.go +++ b/internal/eventstore/v2/event.go @@ -39,9 +39,3 @@ type EventReader interface { PreviousSequence() uint64 CreationDate() time.Time } - -//Event is the representation of a state change -type Event interface { - EventPusher - EventReader -} diff --git a/internal/eventstore/v2/event_base.go b/internal/eventstore/v2/event_base.go index 8c5a8e778..b7fcee022 100644 --- a/internal/eventstore/v2/event_base.go +++ b/internal/eventstore/v2/event_base.go @@ -5,6 +5,7 @@ import ( "time" "github.com/caos/zitadel/internal/api/authz" + "github.com/caos/zitadel/internal/api/service" "github.com/caos/zitadel/internal/eventstore/v2/repository" ) @@ -77,10 +78,11 @@ func BaseEventFromRepo(event *repository.Event) *BaseEvent { } } -func NewBaseEventForPush(ctx context.Context, service string, typ EventType) *BaseEvent { +func NewBaseEventForPush(ctx context.Context, typ EventType) *BaseEvent { + svcName := service.FromContext(ctx) return &BaseEvent{ User: authz.GetCtxData(ctx).UserID, - Service: service, + Service: svcName, EventType: typ, } } diff --git a/internal/eventstore/v2/eventstore_test.go b/internal/eventstore/v2/eventstore_test.go index f81653d63..9e752f043 100644 --- a/internal/eventstore/v2/eventstore_test.go +++ b/internal/eventstore/v2/eventstore_test.go @@ -7,6 +7,7 @@ import ( "sync" "testing" + "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/v2/repository" ) @@ -56,7 +57,7 @@ func newTestEvent(description string, data func() interface{}, checkPrevious boo data: data, shouldCheckPrevious: checkPrevious, BaseEvent: *NewBaseEventForPush( - "editorUser", + authz.NewMockContext("resourceOwner", "editorUser"), "editorService", "test.event", ), @@ -87,7 +88,7 @@ func Test_eventstore_RegisterFilterEventMapper(t *testing.T) { mapper func(*repository.Event) (EventReader, error) } type res struct { - event Event + event EventReader mapperCount int } diff --git a/internal/eventstore/v2/example_test.go b/internal/eventstore/v2/example_test.go index 51336c3d5..4d6be8982 100644 --- a/internal/eventstore/v2/example_test.go +++ b/internal/eventstore/v2/example_test.go @@ -18,9 +18,8 @@ import ( // ------------------------------------------------------------ type UserAggregate struct { - eventstore.BaseEvent - eventstore.Aggregate + FirstName string } @@ -54,7 +53,7 @@ func NewUserAggregate(id string) *UserAggregate { } } -func (rm *UserAggregate) AppendEvents(events ...eventstore.Event) *UserAggregate { +func (rm *UserAggregate) AppendEvents(events ...eventstore.EventReader) *UserAggregate { rm.Aggregate.AppendEvents(events...) return rm } diff --git a/internal/eventstore/v2/read_model.go b/internal/eventstore/v2/read_model.go index c53be4264..d7fffbb6b 100644 --- a/internal/eventstore/v2/read_model.go +++ b/internal/eventstore/v2/read_model.go @@ -2,9 +2,9 @@ package eventstore import "time" -func NewReadModel(id string) *ReadModel { +func NewReadModel( /*id string*/ ) *ReadModel { return &ReadModel{ - ID: id, + // ID: id, Events: []EventReader{}, } } @@ -12,11 +12,11 @@ func NewReadModel(id string) *ReadModel { //ReadModel is the minimum representation of a View model. // it might be saved in a database or in memory type ReadModel struct { - ProcessedSequence uint64 `json:"-"` - ID string `json:"-"` - CreationDate time.Time `json:"-"` - ChangeDate time.Time `json:"-"` - Events []EventReader `json:"-"` + ProcessedSequence uint64 `json:"-"` + // ID string `json:"-"` + CreationDate time.Time `json:"-"` + ChangeDate time.Time `json:"-"` + Events []EventReader `json:"-"` } //AppendEvents adds all the events to the read model. @@ -42,36 +42,3 @@ func (rm *ReadModel) Reduce() error { rm.Events = []EventReader{} return nil } - -func NewAggregate(id string) *Aggregate { - return &Aggregate{ - ID: id, - Events: []Event{}, - } -} - -type Aggregate struct { - PreviousSequence uint64 `json:"-"` - ID string `json:"-"` - Events []Event `json:"-"` -} - -//AppendEvents adds all the events to the aggregate. -// The function doesn't compute the new state of the aggregate -func (a *Aggregate) AppendEvents(events ...Event) *Aggregate { - a.Events = append(a.Events, events...) - return a -} - -//Reduce must be the last step in the reduce function of the extension -func (a *Aggregate) Reduce() error { - if len(a.Events) == 0 { - return nil - } - - a.PreviousSequence = a.Events[len(a.Events)-1].Sequence() - // all events processed and not needed anymore - a.Events = nil - a.Events = []Event{} - return nil -} diff --git a/internal/v2/repository/iam/aggregate.go b/internal/v2/repository/iam/aggregate.go index fd78082bd..bf30340c8 100644 --- a/internal/v2/repository/iam/aggregate.go +++ b/internal/v2/repository/iam/aggregate.go @@ -1,7 +1,12 @@ package iam -import "github.com/caos/zitadel/internal/eventstore/v2" +import ( + "github.com/caos/zitadel/internal/eventstore/v2" +) type Aggregate struct { eventstore.Aggregate + + SetUpStarted Step + SetUpDone Step } diff --git a/internal/v2/repository/iam/event_iam_added.go b/internal/v2/repository/iam/event_iam_added.go index 1f670a201..9047642d5 100644 --- a/internal/v2/repository/iam/event_iam_added.go +++ b/internal/v2/repository/iam/event_iam_added.go @@ -24,11 +24,10 @@ func (e *GlobalOrgSetEvent) Data() interface{} { return e } -func NewGlobalOrgSetEventEvent(ctx context.Context, service, orgID string) *GlobalOrgSetEvent { +func NewGlobalOrgSetEventEvent(ctx context.Context, orgID string) *GlobalOrgSetEvent { return &GlobalOrgSetEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, GlobalOrgSetEventType, ), OrgID: orgID, diff --git a/internal/v2/repository/iam/event_iam_project_set.go b/internal/v2/repository/iam/event_iam_project_set.go index 9b4c809b0..64478e90e 100644 --- a/internal/v2/repository/iam/event_iam_project_set.go +++ b/internal/v2/repository/iam/event_iam_project_set.go @@ -7,28 +7,27 @@ import ( ) const ( - IAMProjectSetEventType eventstore.EventType = "iam.project.iam.set" + ProjectSetEventType eventstore.EventType = "iam.project.iam.set" ) -type IAMProjectSetEvent struct { +type ProjectSetEvent struct { eventstore.BaseEvent `json:"-"` ProjectID string `json:"iamProjectId"` } -func (e *IAMProjectSetEvent) CheckPrevious() bool { +func (e *ProjectSetEvent) CheckPrevious() bool { return e.Type() == SetupStartedEventType } -func (e *IAMProjectSetEvent) Data() interface{} { +func (e *ProjectSetEvent) Data() interface{} { return e } -func NewIAMProjectSetEvent(ctx context.Context, service, projectID string) *IAMProjectSetEvent { - return &IAMProjectSetEvent{ +func NewProjectSetEvent(ctx context.Context, projectID string) *ProjectSetEvent { + return &ProjectSetEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, SetupDoneEventType, ), ProjectID: projectID, diff --git a/internal/v2/repository/iam/events_step.go b/internal/v2/repository/iam/events_step.go index 5ec5d25ce..02f4b8bec 100644 --- a/internal/v2/repository/iam/events_step.go +++ b/internal/v2/repository/iam/events_step.go @@ -2,8 +2,11 @@ package iam import ( "context" + "encoding/json" + "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" ) const ( @@ -17,6 +20,7 @@ type SetupStepEvent struct { eventstore.BaseEvent `json:"-"` Step Step `json:"Step"` + Done bool `json:"-"` } func (e *SetupStepEvent) CheckPrevious() bool { @@ -27,21 +31,32 @@ func (e *SetupStepEvent) Data() interface{} { return e } -func NewSetupStepDoneEvent(ctx context.Context, service string) *SetupStepEvent { +func SetupStepMapper(event *repository.Event) (eventstore.EventReader, error) { + step := &SetupStepEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + Done: eventstore.EventType(event.Type) == SetupDoneEventType, + } + err := json.Unmarshal(event.Data, step) + if err != nil { + return nil, errors.ThrowInternal(err, "IAM-O6rVg", "unable to unmarshal step") + } + + return step, nil +} + +func NewSetupStepDoneEvent(ctx context.Context) *SetupStepEvent { return &SetupStepEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, SetupDoneEventType, ), } } -func NewSetupStepStartedEvent(ctx context.Context, service string) *SetupStepEvent { +func NewSetupStepStartedEvent(ctx context.Context) *SetupStepEvent { return &SetupStepEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, SetupStartedEventType, ), } diff --git a/internal/v2/repository/iam/read_model.go b/internal/v2/repository/iam/read_model.go new file mode 100644 index 000000000..c95b42cac --- /dev/null +++ b/internal/v2/repository/iam/read_model.go @@ -0,0 +1,52 @@ +package iam + +import ( + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/member" +) + +type ReadModel struct { + eventstore.ReadModel + + SetUpStarted Step + SetUpDone Step + + Members member.MembersReadModel + + GlobalOrgID string + ProjectID string +} + +func (rm *ReadModel) AppendEvents(events ...eventstore.EventReader) (err error) { + rm.ReadModel.AppendEvents(events...) + for _, event := range events { + switch event.(type) { + case *member.MemberAddedEvent, *member.MemberChangedEvent, *member.MemberRemovedEvent: + err = rm.Members.AppendEvents(events...) + } + + } + return err +} + +func (rm *ReadModel) Reduce() (err error) { + for _, event := range rm.Events { + switch e := event.(type) { + case *ProjectSetEvent: + rm.ProjectID = e.ProjectID + case *GlobalOrgSetEvent: + rm.GlobalOrgID = e.OrgID + case *SetupStepEvent: + if e.Done { + rm.SetUpDone = e.Step + } else { + rm.SetUpStarted = e.Step + } + } + } + err = rm.Members.Reduce() + if err != nil { + return err + } + return rm.ReadModel.Reduce() +} diff --git a/internal/v2/repository/member/event_added.go b/internal/v2/repository/member/event_added.go index a94bbb867..8feeadbc8 100644 --- a/internal/v2/repository/member/event_added.go +++ b/internal/v2/repository/member/event_added.go @@ -21,11 +21,16 @@ func (e *MemberAddedEvent) Data() interface{} { return e } -func NewMemberAddedEvent(ctx context.Context, eventType eventstore.EventType, service, userID string, roles ...string) *MemberAddedEvent { +func NewMemberAddedEvent( + ctx context.Context, + eventType eventstore.EventType, + userID string, + roles ...string, +) *MemberAddedEvent { + return &MemberAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, eventType, ), Roles: roles, diff --git a/internal/v2/repository/member/event_changed.go b/internal/v2/repository/member/event_changed.go new file mode 100644 index 000000000..d081bdcd9 --- /dev/null +++ b/internal/v2/repository/member/event_changed.go @@ -0,0 +1,39 @@ +package member + +import ( + "context" + + "github.com/caos/zitadel/internal/eventstore/v2" +) + +type MemberChangedEvent struct { + eventstore.BaseEvent `json:"-"` + + Roles []string `json:"roles"` + UserID string `json:"userId"` +} + +func (e *MemberChangedEvent) CheckPrevious() bool { + return true +} + +func (e *MemberChangedEvent) Data() interface{} { + return e +} + +func NewMemberChangedEvent( + ctx context.Context, + eventType eventstore.EventType, + userID string, + roles ...string, +) *MemberChangedEvent { + + return &MemberChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + eventType, + ), + Roles: roles, + UserID: userID, + } +} diff --git a/internal/v2/repository/member/event_removed.go b/internal/v2/repository/member/event_removed.go index fd7cc9fa5..8627c466b 100644 --- a/internal/v2/repository/member/event_removed.go +++ b/internal/v2/repository/member/event_removed.go @@ -20,11 +20,15 @@ func (e *MemberRemovedEvent) Data() interface{} { return e } -func NewMemberRemovedEvent(ctx context.Context, eventType eventstore.EventType, service, userID string) *MemberRemovedEvent { +func NewMemberRemovedEvent( + ctx context.Context, + eventType eventstore.EventType, + userID string, +) *MemberRemovedEvent { + return &MemberRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, eventType, ), UserID: userID, diff --git a/internal/v2/repository/member/read_models.go b/internal/v2/repository/member/read_models.go new file mode 100644 index 000000000..289d4a528 --- /dev/null +++ b/internal/v2/repository/member/read_models.go @@ -0,0 +1,84 @@ +package member + +import "github.com/caos/zitadel/internal/eventstore/v2" + +type MemberReadModel struct { + eventstore.ReadModel + + UserID string + Roles []string +} + +func NewMemberReadModel(userID string) *MemberReadModel { + return &MemberReadModel{ + ReadModel: *eventstore.NewReadModel(), + } +} + +func (rm *MemberReadModel) Reduce() error { + for _, event := range rm.Events { + switch e := event.(type) { + case *MemberAddedEvent: + rm.UserID = e.UserID + rm.Roles = e.Roles + case *MemberChangedEvent: + rm.UserID = e.UserID + rm.Roles = e.Roles + } + } + return rm.ReadModel.Reduce() +} + +type MembersReadModel struct { + eventstore.ReadModel + Members []*MemberReadModel +} + +func NewMembersReadModel() *MembersReadModel { + return &MembersReadModel{ + ReadModel: *eventstore.NewReadModel(), + Members: []*MemberReadModel{}, + } +} + +func (rm *MembersReadModel) MemberByUserID(id string) (idx int, member *MemberReadModel) { + for idx, member = range rm.Members { + if member.UserID == id { + return idx, member + } + } + return -1, nil +} + +func (rm *MembersReadModel) AppendEvents(events ...eventstore.EventReader) (err error) { + for _, event := range events { + switch e := event.(type) { + case *MemberAddedEvent: + member := NewMemberReadModel(e.UserID) + rm.Members = append(rm.Members, member) + member.AppendEvents(e) + case *MemberChangedEvent: + _, member := rm.MemberByUserID(e.UserID) + member.AppendEvents(e) + case *MemberRemovedEvent: + idx, _ := rm.MemberByUserID(e.UserID) + if idx < 0 { + return nil + } + copy(rm.Members[idx:], rm.Members[idx+1:]) + rm.Members[len(rm.Members)-1] = nil + rm.Members = rm.Members[:len(rm.Members)-1] + } + } + return err +} + +func (rm *MembersReadModel) Reduce() (err error) { + for _, member := range rm.Members { + err = member.Reduce() + if err != nil { + return err + } + } + return rm.ReadModel.Reduce() +} diff --git a/internal/v2/repository/policy/events_label.go b/internal/v2/repository/policy/events_label.go index d8ff02258..3ab6ed5e6 100644 --- a/internal/v2/repository/policy/events_label.go +++ b/internal/v2/repository/policy/events_label.go @@ -7,9 +7,18 @@ import ( ) const ( - LabelPolicyAddedEventType = "policy.label.added" + LabelPolicyAddedEventType = "policy.label.added" + LabelPolicyChangedEventType = "policy.label.changed" + LabelPolicyRemovedEventType = "policy.label.removed" ) +type LabelPolicyAggregate struct { + eventstore.Aggregate + + PrimaryColor string + SecondaryColor string +} + type LabelPolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` @@ -27,7 +36,6 @@ func (e *LabelPolicyAddedEvent) Data() interface{} { func NewLabelPolicyAddedEvent( ctx context.Context, - service string, primaryColor, secondaryColor string, ) *LabelPolicyAddedEvent { @@ -35,10 +43,72 @@ func NewLabelPolicyAddedEvent( return &LabelPolicyAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, LabelPolicyAddedEventType, ), PrimaryColor: primaryColor, SecondaryColor: secondaryColor, } } + +type LabelPolicyChangedEvent struct { + eventstore.BaseEvent `json:"-"` + + current *LabelPolicyAggregate + changed *LabelPolicyAggregate +} + +func (e *LabelPolicyChangedEvent) CheckPrevious() bool { + return true +} + +func (e *LabelPolicyChangedEvent) Data() interface{} { + changes := map[string]interface{}{} + if e.current.PrimaryColor != e.changed.PrimaryColor { + changes["primaryColor"] = e.changed.PrimaryColor + } + if e.current.SecondaryColor != e.changed.SecondaryColor { + changes["secondaryColor"] = e.changed.SecondaryColor + } + + return changes +} + +func NewLabelPolicyChangedEvent( + ctx context.Context, + current, + changed *LabelPolicyAggregate, +) *LabelPolicyChangedEvent { + + return &LabelPolicyChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + LabelPolicyChangedEventType, + ), + current: current, + changed: changed, + } +} + +type LabelPolicyRemovedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *LabelPolicyRemovedEvent) CheckPrevious() bool { + return true +} + +func (e *LabelPolicyRemovedEvent) Data() interface{} { + return nil +} + +func NewLabelPolicyRemovedEvent( + ctx context.Context, +) *LabelPolicyRemovedEvent { + + return &LabelPolicyRemovedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + LabelPolicyChangedEventType, + ), + } +} diff --git a/internal/v2/repository/policy/events_login.go b/internal/v2/repository/policy/events_login.go index 7f939ddcc..69cfba49e 100644 --- a/internal/v2/repository/policy/events_login.go +++ b/internal/v2/repository/policy/events_login.go @@ -7,9 +7,19 @@ import ( ) const ( - LoginPolicyAddedEventType = "policy.login.added" + LoginPolicyAddedEventType = "policy.login.added" + LoginPolicyChangedEventType = "policy.login.changed" + LoginPolicyRemovedEventType = "policy.login.removed" ) +type LoginPolicyAggregate struct { + eventstore.Aggregate + + AllowUserNamePassword bool + AllowRegister bool + AllowExternalIDP bool +} + type LoginPolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` @@ -29,7 +39,6 @@ func (e *LoginPolicyAddedEvent) Data() interface{} { func NewLoginPolicyAddedEvent( ctx context.Context, - service string, allowUserNamePassword, allowRegister, allowExternalIDP bool, @@ -38,7 +47,6 @@ func NewLoginPolicyAddedEvent( return &LoginPolicyAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, LoginPolicyAddedEventType, ), AllowExternalIDP: allowExternalIDP, @@ -46,3 +54,64 @@ func NewLoginPolicyAddedEvent( AllowUserNamePassword: allowUserNamePassword, } } + +type LoginPolicyChangedEvent struct { + eventstore.BaseEvent `json:"-"` + + current *LoginPolicyAggregate + changed *LoginPolicyAggregate +} + +func (e *LoginPolicyChangedEvent) CheckPrevious() bool { + return true +} + +func (e *LoginPolicyChangedEvent) Data() interface{} { + changes := map[string]interface{}{} + if e.current.AllowExternalIDP != e.changed.AllowExternalIDP { + changes["allowUsernamePassword"] = e.changed.AllowExternalIDP + } + if e.current.AllowRegister != e.changed.AllowRegister { + changes["allowRegister"] = e.changed.AllowExternalIDP + } + if e.current.AllowExternalIDP != e.changed.AllowExternalIDP { + changes["allowExternalIdp"] = e.changed.AllowExternalIDP + } + + return changes +} + +func NewLoginPolicyChangedEvent( + ctx context.Context, + current, + changed *LoginPolicyAggregate, +) *LoginPolicyChangedEvent { + + return &LoginPolicyChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + LoginPolicyChangedEventType, + ), + } +} + +type LoginPolicyRemovedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *LoginPolicyRemovedEvent) CheckPrevious() bool { + return true +} + +func (e *LoginPolicyRemovedEvent) Data() interface{} { + return nil +} + +func NewLoginPolicyRemovedEvent(ctx context.Context) *LoginPolicyRemovedEvent { + return &LoginPolicyRemovedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + LoginPolicyRemovedEventType, + ), + } +} diff --git a/internal/v2/repository/policy/events_org_iam.go b/internal/v2/repository/policy/events_org_iam.go index 9f5ffb022..f22b49473 100644 --- a/internal/v2/repository/policy/events_org_iam.go +++ b/internal/v2/repository/policy/events_org_iam.go @@ -26,14 +26,12 @@ func (e *OrgIAMPolicyAddedEvent) Data() interface{} { func NewOrgIAMPolicyAddedEvent( ctx context.Context, - service string, userLoginMustBeDomain bool, ) *OrgIAMPolicyAddedEvent { return &OrgIAMPolicyAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, OrgIAMPolicyAddedEventType, ), UserLoginMustBeDomain: userLoginMustBeDomain, diff --git a/internal/v2/repository/policy/events_password_age.go b/internal/v2/repository/policy/events_password_age.go index a1e5c166c..765859e6c 100644 --- a/internal/v2/repository/policy/events_password_age.go +++ b/internal/v2/repository/policy/events_password_age.go @@ -7,9 +7,18 @@ import ( ) const ( - PasswordAgePolicyAddedEventType = "policy.password.age.added" + PasswordAgePolicyAddedEventType = "policy.password.age.added" + PasswordAgePolicyChangedEventType = "policy.password.age.changed" + PasswordAgePolicyRemovedEventType = "policy.password.age.removed" ) +type PasswordAgePolicyAggregate struct { + eventstore.Aggregate + + ExpireWarnDays int + MaxAgeDays int +} + type PasswordAgePolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` @@ -27,17 +36,82 @@ func (e *PasswordAgePolicyAddedEvent) Data() interface{} { func NewPasswordAgePolicyAddedEvent( ctx context.Context, - service string, expireWarnDays, maxAgeDays int, ) *PasswordAgePolicyAddedEvent { + return &PasswordAgePolicyAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, PasswordAgePolicyAddedEventType, ), ExpireWarnDays: expireWarnDays, MaxAgeDays: maxAgeDays, } } + +type PasswordAgePolicyChangedEvent struct { + eventstore.BaseEvent `json:"-"` + + current *PasswordAgePolicyAggregate + changed *PasswordAgePolicyAggregate +} + +func (e *PasswordAgePolicyChangedEvent) CheckPrevious() bool { + return true +} + +func (e *PasswordAgePolicyChangedEvent) Data() interface{} { + changes := map[string]interface{}{} + + if e.current.ExpireWarnDays != e.changed.ExpireWarnDays { + changes["expireWarnDays"] = e.changed.ExpireWarnDays + } + if e.current.MaxAgeDays != e.changed.MaxAgeDays { + changes["maxAgeDays"] = e.changed.ExpireWarnDays + } + + return changes +} + +func NewPasswordAgePolicyChangedEvent( + ctx context.Context, + current, + changed *PasswordAgePolicyAggregate, +) *PasswordAgePolicyChangedEvent { + + return &PasswordAgePolicyChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + PasswordAgePolicyChangedEventType, + ), + current: current, + changed: changed, + } +} + +type PasswordAgePolicyRemovedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *PasswordAgePolicyRemovedEvent) CheckPrevious() bool { + return true +} + +func (e *PasswordAgePolicyRemovedEvent) Data() interface{} { + return nil +} + +func NewPasswordAgePolicyRemovedEvent( + ctx context.Context, + current, + changed *PasswordAgePolicyRemovedEvent, +) *PasswordAgePolicyChangedEvent { + + return &PasswordAgePolicyChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + PasswordAgePolicyChangedEventType, + ), + } +} diff --git a/internal/v2/repository/policy/events_password_complexity.go b/internal/v2/repository/policy/events_password_complexity.go index c8896c849..7635d33d9 100644 --- a/internal/v2/repository/policy/events_password_complexity.go +++ b/internal/v2/repository/policy/events_password_complexity.go @@ -7,9 +7,19 @@ import ( ) const ( - PasswordComplexityPolicyAddedEventType = "policy.password.complexity.added" + PasswordComplexityPolicyAddedEventType = "policy.password.complexity.added" + PasswordComplexityPolicyChangedEventType = "policy.password.complexity.changed" + PasswordComplexityPolicyRemovedEventType = "policy.password.complexity.removed" ) +type PasswordComplexityPolicyAggregate struct { + MinLength int + HasLowercase bool + HasUpperCase bool + HasNumber bool + HasSymbol bool +} + type PasswordComplexityPolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` @@ -30,7 +40,6 @@ func (e *PasswordComplexityPolicyAddedEvent) Data() interface{} { func NewPasswordComplexityPolicyAddedEvent( ctx context.Context, - service string, hasLowerCase, hasUpperCase, hasNumber, @@ -41,7 +50,6 @@ func NewPasswordComplexityPolicyAddedEvent( return &PasswordComplexityPolicyAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, PasswordComplexityPolicyAddedEventType, ), HasLowercase: hasLowerCase, @@ -51,3 +59,76 @@ func NewPasswordComplexityPolicyAddedEvent( MinLength: minLength, } } + +type PasswordComplexityPolicyChangedEvent struct { + eventstore.BaseEvent `json:"-"` + + current *PasswordComplexityPolicyAggregate + changed *PasswordComplexityPolicyAggregate +} + +func (e *PasswordComplexityPolicyChangedEvent) CheckPrevious() bool { + return true +} + +func (e *PasswordComplexityPolicyChangedEvent) Data() interface{} { + changes := map[string]interface{}{} + + if e.current.MinLength != e.changed.MinLength { + changes["minLength"] = e.changed.MinLength + } + if e.current.HasLowercase != e.changed.HasLowercase { + changes["hasLowercase"] = e.changed.HasLowercase + } + if e.current.HasUpperCase != e.changed.HasUpperCase { + changes["hasUppercase"] = e.changed.HasUpperCase + } + if e.current.HasNumber != e.changed.HasNumber { + changes["hasNumber"] = e.changed.HasNumber + } + if e.current.HasSymbol != e.changed.HasSymbol { + changes["hasSymbol"] = e.changed.HasSymbol + } + + return changes +} + +func NewPasswordComplexityPolicyChangedEvent( + ctx context.Context, + current, + changed *PasswordComplexityPolicyAggregate, +) *PasswordComplexityPolicyChangedEvent { + + return &PasswordComplexityPolicyChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + PasswordComplexityPolicyAddedEventType, + ), + current: current, + changed: changed, + } +} + +type PasswordComplexityPolicyRemovedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *PasswordComplexityPolicyRemovedEvent) CheckPrevious() bool { + return true +} + +func (e *PasswordComplexityPolicyRemovedEvent) Data() interface{} { + return nil +} + +func NewPasswordComplexityPolicyRemovedEvent( + ctx context.Context, +) *PasswordComplexityPolicyRemovedEvent { + + return &PasswordComplexityPolicyRemovedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + PasswordComplexityPolicyChangedEventType, + ), + } +} diff --git a/internal/v2/repository/policy/events_password_lockout.go b/internal/v2/repository/policy/events_password_lockout.go index a5a123d6d..1f4c755fb 100644 --- a/internal/v2/repository/policy/events_password_lockout.go +++ b/internal/v2/repository/policy/events_password_lockout.go @@ -10,6 +10,13 @@ const ( PasswordLockoutPolicyAddedEventType = "policy.password.lockout.added" ) +type PasswordLockoutAggregate struct { + eventstore.Aggregate + + MaxAttempts int + ShowLockOutFailures bool +} + type PasswordLockoutPolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` @@ -27,7 +34,6 @@ func (e *PasswordLockoutPolicyAddedEvent) Data() interface{} { func NewPasswordLockoutPolicyAddedEvent( ctx context.Context, - service string, maxAttempts int, showLockOutFailures bool, ) *PasswordLockoutPolicyAddedEvent { @@ -35,10 +41,73 @@ func NewPasswordLockoutPolicyAddedEvent( return &PasswordLockoutPolicyAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - service, LabelPolicyAddedEventType, ), MaxAttempts: maxAttempts, ShowLockOutFailures: showLockOutFailures, } } + +type PasswordLockoutPolicyChangedEvent struct { + eventstore.BaseEvent `json:"-"` + + current *PasswordLockoutAggregate + changed *PasswordLockoutAggregate +} + +func (e *PasswordLockoutPolicyChangedEvent) CheckPrevious() bool { + return true +} + +func (e *PasswordLockoutPolicyChangedEvent) Data() interface{} { + changes := map[string]interface{}{} + + if e.current.MaxAttempts != e.changed.MaxAttempts { + changes["maxAttempts"] = e.changed.MaxAttempts + } + if e.current.ShowLockOutFailures != e.changed.ShowLockOutFailures { + changes["showLockOutFailures"] = e.changed.ShowLockOutFailures + } + + return changes +} + +func NewPasswordLockoutPolicyChangedEvent( + ctx context.Context, + current, + changed *PasswordLockoutAggregate, +) *PasswordLockoutPolicyChangedEvent { + + return &PasswordLockoutPolicyChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + LabelPolicyAddedEventType, + ), + current: current, + changed: changed, + } +} + +type PasswordLockoutPolicyRemovedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func (e *PasswordLockoutPolicyRemovedEvent) CheckPrevious() bool { + return true +} + +func (e *PasswordLockoutPolicyRemovedEvent) Data() interface{} { + return nil +} + +func NewPasswordLockoutPolicyRemovedEvent( + ctx context.Context, +) *PasswordLockoutPolicyRemovedEvent { + + return &PasswordLockoutPolicyRemovedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + LabelPolicyAddedEventType, + ), + } +}