diff --git a/internal/admin/repository/eventsourcing/eventstore/iam.go b/internal/admin/repository/eventsourcing/eventstore/iam.go index bb4c23f9c2..7740634f77 100644 --- a/internal/admin/repository/eventsourcing/eventstore/iam.go +++ b/internal/admin/repository/eventsourcing/eventstore/iam.go @@ -33,8 +33,8 @@ type IAMRepository struct { IAMV2 *iam_business.Repository } -func (repo *IAMRepository) IAMMemberByID(ctx context.Context, orgID, userID string) (*iam_model.IAMMemberView, error) { - member, err := repo.View.IAMMemberByIDs(orgID, userID) +func (repo *IAMRepository) IAMMemberByID(ctx context.Context, iamID, userID string) (*iam_model.IAMMemberView, error) { + member, err := repo.View.IAMMemberByIDs(iamID, userID) if err != nil { return nil, err } @@ -44,7 +44,7 @@ func (repo *IAMRepository) IAMMemberByID(ctx context.Context, orgID, userID stri func (repo *IAMRepository) AddIAMMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) { member.AggregateID = repo.SystemDefaults.IamID if repo.IAMV2 != nil { - return repo.IAMV2.AddIAMMember(ctx, member) + return repo.IAMV2.AddMember(ctx, member) } return repo.IAMEventstore.AddIAMMember(ctx, member) } @@ -52,7 +52,7 @@ func (repo *IAMRepository) AddIAMMember(ctx context.Context, member *iam_model.I func (repo *IAMRepository) ChangeIAMMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) { member.AggregateID = repo.SystemDefaults.IamID if repo.IAMV2 != nil { - return repo.IAMV2.ChangeIAMMember(ctx, member) + return repo.IAMV2.ChangeMember(ctx, member) } return repo.IAMEventstore.ChangeIAMMember(ctx, member) } @@ -60,7 +60,7 @@ func (repo *IAMRepository) ChangeIAMMember(ctx context.Context, member *iam_mode func (repo *IAMRepository) RemoveIAMMember(ctx context.Context, userID string) error { member := iam_model.NewIAMMember(repo.SystemDefaults.IamID, userID) if repo.IAMV2 != nil { - return repo.IAMV2.RemoveIAMMember(ctx, member) + return repo.IAMV2.RemoveMember(ctx, member) } return repo.IAMEventstore.RemoveIAMMember(ctx, member) } @@ -97,12 +97,17 @@ func (repo *IAMRepository) GetIAMMemberRoles() []string { } func (repo *IAMRepository) IDPConfigByID(ctx context.Context, idpConfigID string) (*iam_model.IDPConfigView, error) { + if repo.IAMV2 != nil { + return repo.IAMV2.IDPConfigByID(ctx, idpConfigID) + } + idp, err := repo.View.IDPConfigByID(idpConfigID) if err != nil { return nil, err } return iam_es_model.IDPConfigViewToModel(idp), nil } + func (repo *IAMRepository) AddOIDCIDPConfig(ctx context.Context, idp *iam_model.IDPConfig) (*iam_model.IDPConfig, error) { idp.AggregateID = repo.SystemDefaults.IamID return repo.IAMEventstore.AddIDPConfig(ctx, idp) diff --git a/internal/admin/repository/eventsourcing/repository.go b/internal/admin/repository/eventsourcing/repository.go index 69c134602f..202efab33b 100644 --- a/internal/admin/repository/eventsourcing/repository.go +++ b/internal/admin/repository/eventsourcing/repository.go @@ -16,6 +16,8 @@ import ( es_usr "github.com/caos/zitadel/internal/user/repository/eventsourcing" iam_business "github.com/caos/zitadel/internal/v2/business/iam" "github.com/caos/zitadel/internal/v2/repository/iam" + "github.com/caos/zitadel/internal/v2/repository/idp" + "github.com/caos/zitadel/internal/v2/repository/idp/oidc" "github.com/caos/zitadel/internal/v2/repository/member" ) @@ -43,7 +45,14 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, r esV2 := es.V2() esV2.RegisterFilterEventMapper(iam.MemberAddedEventType, member.AddedEventMapper). RegisterFilterEventMapper(iam.MemberChangedEventType, member.ChangedEventMapper). - RegisterFilterEventMapper(iam.MemberRemovedEventType, member.RemovedEventMapper) + RegisterFilterEventMapper(iam.MemberRemovedEventType, member.RemovedEventMapper). + RegisterFilterEventMapper(iam.IDPConfigAddedEventType, idp.ConfigAddedEventMapper). + RegisterFilterEventMapper(iam.IDPConfigChangedEventType, idp.ConfigChangedEventMapper). + RegisterFilterEventMapper(iam.IDPConfigDeactivatedEventType, idp.ConfigDeactivatedEventMapper). + RegisterFilterEventMapper(iam.IDPConfigReactivatedEventType, idp.ConfigReactivatedEventMapper). + RegisterFilterEventMapper(iam.IDPConfigRemovedEventType, idp.ConfigRemovedEventMapper). + RegisterFilterEventMapper(iam.IDPOIDCConfigAddedEventType, oidc.ConfigAddedEventMapper). + RegisterFilterEventMapper(iam.IDPOIDCConfigChangedEventType, oidc.ConfigChangedEventMapper) iam, err := es_iam.StartIAM(es_iam.IAMConfig{ Eventstore: es, diff --git a/internal/v2/business/iam/converter.go b/internal/v2/business/iam/converter.go index a406981d08..6ad42fd8db 100644 --- a/internal/v2/business/iam/converter.go +++ b/internal/v2/business/iam/converter.go @@ -6,6 +6,7 @@ import ( "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/repository/iam" iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" + "github.com/caos/zitadel/internal/v2/repository/idp" "github.com/caos/zitadel/internal/v2/repository/member" ) @@ -133,3 +134,24 @@ func writeModelToMember(writeModel *iam.MemberWriteModel) *model.IAMMember { UserID: writeModel.UserID, } } + +func readModelToIDPConfigView(rm *iam.IDPConfigReadModel) *model.IDPConfigView { + return &model.IDPConfigView{ + AggregateID: rm.AggregateID, + ChangeDate: rm.ChangeDate, + CreationDate: rm.CreationDate, + IDPConfigID: rm.ConfigID, + IDPProviderType: model.IDPProviderType(rm.ProviderType), + IsOIDC: rm.Type == idp.ConfigTypeOIDC, + Name: rm.Name, + OIDCClientID: rm.OIDCConfig.ClientID, + OIDCClientSecret: rm.OIDCConfig.ClientSecret, + OIDCIDPDisplayNameMapping: model.OIDCMappingField(rm.OIDCConfig.IDPDisplayNameMapping), + OIDCIssuer: rm.OIDCConfig.Issuer, + OIDCScopes: rm.OIDCConfig.Scopes, + OIDCUsernameMapping: model.OIDCMappingField(rm.OIDCConfig.UserNameMapping), + Sequence: rm.ProcessedSequence, + State: model.IDPConfigState(rm.State), + StylingType: model.IDPStylingType(rm.StylingType), + } +} diff --git a/internal/v2/business/iam/idp_oidc_config.go b/internal/v2/business/iam/idp_oidc_config.go new file mode 100644 index 0000000000..c67372e35d --- /dev/null +++ b/internal/v2/business/iam/idp_oidc_config.go @@ -0,0 +1,30 @@ +package iam + +import ( + "context" + + "github.com/caos/zitadel/internal/eventstore/v2" + iam_model "github.com/caos/zitadel/internal/iam/model" + "github.com/caos/zitadel/internal/v2/repository/iam" +) + +func (r *Repository) IDPConfigByID(ctx context.Context, idpConfigID string) (*iam_model.IDPConfigView, error) { + query := eventstore.NewSearchQueryFactory(eventstore.ColumnsEvent, iam.AggregateType). + EventData(map[string]interface{}{ + "idpConfigId": idpConfigID, + }) + + idpConfig := new(iam.IDPConfigReadModel) + + events, err := r.eventstore.FilterEvents(ctx, query) + if err != nil { + return nil, err + } + + idpConfig.AppendEvents(events...) + if err = idpConfig.Reduce(); err != nil { + return nil, err + } + + return readModelToIDPConfigView(idpConfig), nil +} diff --git a/internal/v2/business/iam/member.go b/internal/v2/business/iam/member.go index 2fd93373d1..951e512ad5 100644 --- a/internal/v2/business/iam/member.go +++ b/internal/v2/business/iam/member.go @@ -11,7 +11,9 @@ import ( iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" ) -func (r *Repository) AddIAMMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) { +func (r *Repository) AddMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) { + //TODO: check if roles valid + if !member.IsValid() { return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-W8m4l", "Errors.IAM.MemberInvalid") } @@ -40,14 +42,15 @@ func (r *Repository) AddIAMMember(ctx context.Context, member *iam_model.IAMMemb _, addedMember := iam.Members.MemberByUserID(member.UserID) if member == nil { - return nil, errors.ThrowInternal(nil, "IAM-nuoDN", "member not saved") + return nil, errors.ThrowInternal(nil, "IAM-nuoDN", "Errors.Internal") } return readModelToMember(addedMember), nil } -//ChangeIAMMember updates an existing member -//TODO: refactor to ChangeMember -func (r *Repository) ChangeIAMMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) { +//ChangeMember updates an existing member +func (r *Repository) ChangeMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) { + //TODO: check if roles valid + if !member.IsValid() { return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-LiaZi", "Errors.IAM.MemberInvalid") } @@ -66,16 +69,14 @@ func (r *Repository) ChangeIAMMember(ctx context.Context, member *iam_model.IAMM } existingMember.AppendEvents(events...) - - updatedMember, err := r.MemberByID(ctx, member.AggregateID, member.UserID) - if err != nil { + if err = existingMember.Reduce(); err != nil { return nil, err } - return readModelToMember(&updatedMember.ReadModel), nil + return writeModelToMember(existingMember), nil } -func (r *Repository) RemoveIAMMember(ctx context.Context, member *iam_model.IAMMember) error { +func (r *Repository) RemoveMember(ctx context.Context, member *iam_model.IAMMember) error { iam, err := r.iamByID(ctx, member.AggregateID) if err != nil { return err @@ -115,3 +116,20 @@ func (r *Repository) MemberByID(ctx context.Context, iamID, userID string) (memb return member, nil } + +func (r *Repository) memberWriteModelByID(ctx context.Context, iamID, userID string) (member *iam_repo.MemberWriteModel, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + writeModel := iam_repo.NewMemberReadModel(iamID, userID) + err = r.eventstore.FilterToQueryReducer(ctx, writeModel) + if err != nil { + return nil, err + } + + if writeModel.IsRemoved { + return nil, errors.ThrowNotFound(nil, "IAM-D8JxR", "Errors.NotFound") + } + + return writeModel, nil +} diff --git a/internal/v2/business/iam/repository.go b/internal/v2/business/iam/repository.go index 1bf5e9afee..1849201249 100644 --- a/internal/v2/business/iam/repository.go +++ b/internal/v2/business/iam/repository.go @@ -3,7 +3,6 @@ package iam import ( "context" - "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/v2" iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/tracing" @@ -45,20 +44,3 @@ func (r *Repository) iamByID(ctx context.Context, id string) (_ *iam_repo.ReadMo return readModel, nil } - -func (r *Repository) memberWriteModelByID(ctx context.Context, iamID, userID string) (member *iam_repo.MemberWriteModel, err error) { - ctx, span := tracing.NewSpan(ctx) - defer func() { span.EndWithError(err) }() - - writeModel := iam_repo.NewMemberReadModel(iamID, userID) - err = r.eventstore.FilterToQueryReducer(ctx, writeModel) - if err != nil { - return nil, err - } - - if writeModel.IsRemoved { - return nil, errors.ThrowNotFound(nil, "IAM-D8JxR", "Errors.NotFound") - } - - return writeModel, nil -} diff --git a/internal/v2/business/iam/setup.go b/internal/v2/business/iam/setup.go index 2bec7fb9e5..38d82f61c3 100644 --- a/internal/v2/business/iam/setup.go +++ b/internal/v2/business/iam/setup.go @@ -1,49 +1,50 @@ package iam -// import ( -// "context" +import ( + "context" -// caos_errs "github.com/caos/zitadel/internal/errors" -// "github.com/caos/zitadel/internal/eventstore/v2" -// iam_model "github.com/caos/zitadel/internal/iam/model" -// ) + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + iam_model "github.com/caos/zitadel/internal/iam/model" + iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" +) -// func (r *Repository) StartSetup(ctx context.Context, iamID string, step iam_model.Step) (*iam_model.IAM, error) { -// iam, err := r.setup(ctx, iamID, iam_repo.Step(step), iam_repo.NewSetupStepStartedEvent(ctx, iam_repo.Step(step))) -// if err != nil { -// return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-zx03n", "Setup start failed") -// } -// return iam, nil -// } +func (r *Repository) StartSetup(ctx context.Context, iamID string, step iam_model.Step) (*iam_model.IAM, error) { + iam, err := r.setup(ctx, iamID, iam_repo.Step(step), iam_repo.NewSetupStepStartedEvent(ctx, iam_repo.Step(step))) + if err != nil { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-zx03n", "Setup start failed") + } + return iam, nil +} -// func (r *Repository) SetupDone(ctx context.Context, iamID string, step iam_model.Step) (*iam_model.IAM, error) { -// iam, err := r.setup(ctx, iamID, iam_repo.Step(step), iam_repo.NewSetupStepDoneEvent(ctx, iam_repo.Step(step))) -// if err != nil { -// return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-zx03n", "Setup start failed") -// } -// return iam, nil -// } +func (r *Repository) SetupDone(ctx context.Context, iamID string, step iam_model.Step) (*iam_model.IAM, error) { + iam, err := r.setup(ctx, iamID, iam_repo.Step(step), iam_repo.NewSetupStepDoneEvent(ctx, iam_repo.Step(step))) + if err != nil { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-zx03n", "Setup start failed") + } + return iam, nil +} -// func (r *Repository) setup(ctx context.Context, iamID string, step iam_repo.Step, event eventstore.EventPusher) (*iam_model.IAM, error) { -// iam, err := r.iamByID(ctx, iamID) -// if err != nil && !caos_errs.IsNotFound(err) { -// return nil, err -// } +func (r *Repository) setup(ctx context.Context, iamID string, step iam_repo.Step, event eventstore.EventPusher) (*iam_model.IAM, error) { + iam, err := r.iamByID(ctx, iamID) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } -// if iam != nil && (iam.SetUpStarted >= iam_repo.Step(step) || iam.SetUpStarted != iam.SetUpDone) { -// return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9so34", "setup error") -// } + if iam != nil && (iam.SetUpStarted >= iam_repo.Step(step) || iam.SetUpStarted != iam.SetUpDone) { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9so34", "setup error") + } -// aggregate := iam_repo.AggregateFromReadModel(iam). -// PushEvents(event) + aggregate := iam_repo.AggregateFromReadModel(iam). + PushEvents(event) -// events, err := r.eventstore.PushAggregates(ctx, aggregate) -// if err != nil { -// return nil, err -// } + events, err := r.eventstore.PushAggregates(ctx, aggregate) + if err != nil { + return nil, err + } -// if err = iam.AppendAndReduce(events...); err != nil { -// return nil, err -// } -// return readModelToIAM(iam), nil -// } + if err = iam.AppendAndReduce(events...); err != nil { + return nil, err + } + return readModelToIAM(iam), nil +} diff --git a/internal/v2/repository/iam/aggregate.go b/internal/v2/repository/iam/aggregate.go index c07395b504..7840e6764d 100644 --- a/internal/v2/repository/iam/aggregate.go +++ b/internal/v2/repository/iam/aggregate.go @@ -17,9 +17,6 @@ const ( type Aggregate struct { eventstore.Aggregate - - // SetUpStarted Step - // SetUpDone Step } func NewAggregate( @@ -54,8 +51,6 @@ func AggregateFromReadModel(rm *ReadModel) *Aggregate { AggregateVersion, rm.ProcessedSequence, ), - // SetUpDone: rm.SetUpDone, - // SetUpStarted: rm.SetUpStarted, } } @@ -82,3 +77,13 @@ func (a *Aggregate) PushMemberRemoved(ctx context.Context, userID string) *Aggre a.Aggregate = *a.PushEvents(NewMemberRemovedEvent(ctx, userID)) return a } + +func (a *Aggregate) PushStepStarted(ctx context.Context, step Step) *Aggregate { + a.Aggregate = *a.PushEvents(NewSetupStepStartedEvent(ctx, step)) + return a +} + +func (a *Aggregate) PushStepDone(ctx context.Context, step Step) *Aggregate { + a.Aggregate = *a.PushEvents(NewSetupStepDoneEvent(ctx, step)) + return a +} diff --git a/internal/v2/repository/iam/idp_config.go b/internal/v2/repository/iam/idp_config.go new file mode 100644 index 0000000000..4fb64ea7cf --- /dev/null +++ b/internal/v2/repository/iam/idp_config.go @@ -0,0 +1,192 @@ +package iam + +import ( + "context" + + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/idp" + "github.com/caos/zitadel/internal/v2/repository/idp/oidc" +) + +const ( + IDPConfigAddedEventType eventstore.EventType = "iam.idp.config.added" + IDPConfigChangedEventType eventstore.EventType = "iam.idp.config.changed" + IDPConfigRemovedEventType eventstore.EventType = "iam.idp.config.removed" + IDPConfigDeactivatedEventType eventstore.EventType = "iam.idp.config.deactivated" + IDPConfigReactivatedEventType eventstore.EventType = "iam.idp.config.reactivated" +) + +type IDPConfigReadModel struct { + idp.ConfigReadModel +} + +func (rm *IDPConfigReadModel) AppendEvents(events ...eventstore.EventReader) { + for _, event := range events { + switch e := event.(type) { + case *IDPConfigAddedEvent: + rm.ConfigReadModel.AppendEvents(&e.ConfigAddedEvent) + case *IDPConfigChangedEvent: + rm.ConfigReadModel.AppendEvents(&e.ConfigChangedEvent) + case *IDPConfigDeactivatedEvent: + rm.ConfigReadModel.AppendEvents(&e.ConfigDeactivatedEvent) + case *IDPConfigReactivatedEvent: + rm.ConfigReadModel.AppendEvents(&e.ConfigReactivatedEvent) + case *IDPConfigRemovedEvent: + rm.ConfigReadModel.AppendEvents(&e.ConfigRemovedEvent) + case *idp.ConfigAddedEvent, + *idp.ConfigChangedEvent, + *idp.ConfigDeactivatedEvent, + *idp.ConfigReactivatedEvent, + *idp.ConfigRemovedEvent, + *oidc.ConfigAddedEvent, + *oidc.ConfigChangedEvent: + + rm.ConfigReadModel.AppendEvents(e) + } + } +} + +type IDPConfigWriteModel struct { + idp.ConfigWriteModel +} + +func (rm *IDPConfigWriteModel) AppendEvents(events ...eventstore.EventReader) { + for _, event := range events { + switch e := event.(type) { + case *IDPConfigAddedEvent: + rm.ConfigWriteModel.AppendEvents(&e.ConfigAddedEvent) + case *IDPConfigChangedEvent: + rm.ConfigWriteModel.AppendEvents(&e.ConfigChangedEvent) + case *IDPConfigDeactivatedEvent: + rm.ConfigWriteModel.AppendEvents(&e.ConfigDeactivatedEvent) + case *IDPConfigReactivatedEvent: + rm.ConfigWriteModel.AppendEvents(&e.ConfigReactivatedEvent) + case *IDPConfigRemovedEvent: + rm.ConfigWriteModel.AppendEvents(&e.ConfigRemovedEvent) + case *idp.ConfigAddedEvent, + *idp.ConfigChangedEvent, + *idp.ConfigDeactivatedEvent, + *idp.ConfigReactivatedEvent, + *idp.ConfigRemovedEvent: + + rm.ConfigWriteModel.AppendEvents(e) + } + } +} + +type IDPConfigAddedEvent struct { + idp.ConfigAddedEvent +} + +func NewIDPConfigAddedEvent( + ctx context.Context, + configID string, + name string, + configType idp.ConfigType, + stylingType idp.StylingType, +) *IDPConfigAddedEvent { + + return &IDPConfigAddedEvent{ + ConfigAddedEvent: *idp.NewConfigAddedEvent( + eventstore.NewBaseEventForPush( + ctx, + IDPConfigAddedEventType, + ), + configID, + name, + configType, + stylingType, + ), + } +} + +type IDPConfigChangedEvent struct { + idp.ConfigChangedEvent +} + +func NewIDPConfigChangedEvent( + ctx context.Context, + current *IDPConfigWriteModel, + configID string, + name string, + configType idp.ConfigType, + stylingType idp.StylingType, +) (*IDPConfigChangedEvent, error) { + event, err := idp.NewConfigChangedEvent( + eventstore.NewBaseEventForPush( + ctx, + IDPConfigChangedEventType, + ), + ¤t.ConfigWriteModel, + name, + stylingType, + ) + + if err != nil { + return nil, err + } + + return &IDPConfigChangedEvent{ + ConfigChangedEvent: *event, + }, nil +} + +type IDPConfigRemovedEvent struct { + idp.ConfigRemovedEvent +} + +func NewIDPConfigRemovedEvent( + ctx context.Context, + configID string, +) *IDPConfigRemovedEvent { + + return &IDPConfigRemovedEvent{ + ConfigRemovedEvent: *idp.NewConfigRemovedEvent( + eventstore.NewBaseEventForPush( + ctx, + IDPConfigRemovedEventType, + ), + configID, + ), + } +} + +type IDPConfigDeactivatedEvent struct { + idp.ConfigDeactivatedEvent +} + +func NewIDPConfigDeactivatedEvent( + ctx context.Context, + configID string, +) *IDPConfigDeactivatedEvent { + + return &IDPConfigDeactivatedEvent{ + ConfigDeactivatedEvent: *idp.NewConfigDeactivatedEvent( + eventstore.NewBaseEventForPush( + ctx, + IDPConfigDeactivatedEventType, + ), + configID, + ), + } +} + +type IDPConfigReactivatedEvent struct { + idp.ConfigReactivatedEvent +} + +func NewIDPConfigReactivatedEvent( + ctx context.Context, + configID string, +) *IDPConfigReactivatedEvent { + + return &IDPConfigReactivatedEvent{ + ConfigReactivatedEvent: *idp.NewConfigReactivatedEvent( + eventstore.NewBaseEventForPush( + ctx, + IDPConfigReactivatedEventType, + ), + configID, + ), + } +} diff --git a/internal/v2/repository/iam/idp_oidc_config.go b/internal/v2/repository/iam/idp_oidc_config.go new file mode 100644 index 0000000000..9d34e9eb61 --- /dev/null +++ b/internal/v2/repository/iam/idp_oidc_config.go @@ -0,0 +1,104 @@ +package iam + +import ( + "context" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/idp/oidc" +) + +const ( + IDPOIDCConfigAddedEventType eventstore.EventType = "iam.idp.oidc.config.added" + IDPOIDCConfigChangedEventType eventstore.EventType = "iam.idp.oidc.config.changed" +) + +type IDPOIDCConfigWriteModel struct { + oidc.ConfigWriteModel +} + +func (rm *IDPOIDCConfigWriteModel) AppendEvents(events ...eventstore.EventReader) { + for _, event := range events { + switch e := event.(type) { + case *IDPOIDCConfigAddedEvent: + rm.ConfigWriteModel.AppendEvents(&e.ConfigAddedEvent) + case *IDPOIDCConfigChangedEvent: + rm.ConfigWriteModel.AppendEvents(&e.ConfigChangedEvent) + case *oidc.ConfigAddedEvent, + *oidc.ConfigChangedEvent: + + rm.ConfigWriteModel.AppendEvents(e) + } + } +} + +type IDPOIDCConfigAddedEvent struct { + oidc.ConfigAddedEvent +} + +func NewIDPOIDCConfigAddedEvent( + ctx context.Context, + clientID, + idpConfigID, + issuer string, + clientSecret *crypto.CryptoValue, + idpDisplayNameMapping, + userNameMapping oidc.MappingField, + scopes ...string, +) *IDPOIDCConfigAddedEvent { + + return &IDPOIDCConfigAddedEvent{ + ConfigAddedEvent: *oidc.NewConfigAddedEvent( + eventstore.NewBaseEventForPush( + ctx, + IDPOIDCConfigAddedEventType, + ), + clientID, + idpConfigID, + issuer, + clientSecret, + idpDisplayNameMapping, + userNameMapping, + scopes..., + ), + } +} + +type IDPOIDCConfigChangedEvent struct { + oidc.ConfigChangedEvent +} + +func NewIDPOIDCConfigChangedEvent( + ctx context.Context, + current *IDPOIDCConfigWriteModel, + clientID, + idpConfigID, + issuer string, + clientSecret *crypto.CryptoValue, + idpDisplayNameMapping, + userNameMapping oidc.MappingField, + scopes ...string, +) (*IDPOIDCConfigChangedEvent, error) { + + event, err := oidc.NewConfigChangedEvent( + eventstore.NewBaseEventForPush( + ctx, + IDPOIDCConfigAddedEventType, + ), + ¤t.ConfigWriteModel, + clientID, + issuer, + clientSecret, + idpDisplayNameMapping, + userNameMapping, + scopes..., + ) + + if err != nil { + return nil, err + } + + return &IDPOIDCConfigChangedEvent{ + ConfigChangedEvent: *event, + }, nil +} diff --git a/internal/v2/repository/iam/member.go b/internal/v2/repository/iam/member.go index ee2fc9f8c7..cb5814038e 100644 --- a/internal/v2/repository/iam/member.go +++ b/internal/v2/repository/iam/member.go @@ -87,7 +87,7 @@ func MemberChangedEventFromExisting( roles ...string, ) (*MemberChangedEvent, error) { - m, err := member.ChangeEventFromExisting( + event, err := member.ChangeEventFromExisting( eventstore.NewBaseEventForPush( ctx, MemberChangedEventType, @@ -100,7 +100,7 @@ func MemberChangedEventFromExisting( } return &MemberChangedEvent{ - ChangedEvent: *m, + ChangedEvent: *event, }, nil } diff --git a/internal/v2/repository/iam/read_model.go b/internal/v2/repository/iam/read_model.go index 823ef9aac7..207f349dc8 100644 --- a/internal/v2/repository/iam/read_model.go +++ b/internal/v2/repository/iam/read_model.go @@ -89,9 +89,7 @@ func (rm *ReadModel) Reduce() (err error) { } func (rm *ReadModel) AppendAndReduce(events ...eventstore.EventReader) error { - if err := rm.AppendEvents(events...); err != nil { - return err - } + rm.AppendEvents(events...) return rm.Reduce() } diff --git a/internal/v2/repository/idp/config.go b/internal/v2/repository/idp/config.go index 8683ff17f8..79020ded85 100644 --- a/internal/v2/repository/idp/config.go +++ b/internal/v2/repository/idp/config.go @@ -2,37 +2,10 @@ package idp import ( "github.com/caos/zitadel/internal/eventstore/v2" - "github.com/caos/zitadel/internal/v2/repository/idp/oidc" ) type ConfigAggregate struct { eventstore.Aggregate - - ConfigID string - Type ConfigType - Name string - StylingType StylingType - State ConfigState - // OIDCConfig *oidc.ConfigReadModel -} - -type ConfigReadModel struct { - eventstore.ReadModel - - ConfigID string - Type ConfigType - Name string - StylingType StylingType - State ConfigState - OIDCConfig *oidc.ConfigReadModel -} - -func (rm *ConfigReadModel) AppendEvents(events ...eventstore.EventReader) { - rm.ReadModel.AppendEvents(events...) -} - -func (rm *ConfigReadModel) Reduce() error { - return nil } type ConfigType int32 @@ -40,19 +13,50 @@ type ConfigType int32 const ( ConfigTypeOIDC ConfigType = iota ConfigTypeSAML + + //count is for validation + configTypeCount ) +func (f ConfigType) Valid() bool { + return f >= 0 && f < configTypeCount +} + type ConfigState int32 const ( ConfigStateActive ConfigState = iota ConfigStateInactive ConfigStateRemoved + + configStateCount ) +func (f ConfigState) Valid() bool { + return f >= 0 && f < configStateCount +} + type StylingType int32 const ( - StylingTypeUnspecified StylingType = iota - StylingTypeGoogle + StylingTypeGoogle StylingType = iota + 1 + + stylingTypeCount ) + +func (f StylingType) Valid() bool { + return f >= 0 && f < stylingTypeCount +} + +type ProviderType int8 + +const ( + ProviderTypeSystem ProviderType = iota + ProviderTypeOrg + + providerTypeCount +) + +func (f ProviderType) Valid() bool { + return f >= 0 && f < providerTypeCount +} diff --git a/internal/v2/repository/idp/config_read_model.go b/internal/v2/repository/idp/config_read_model.go new file mode 100644 index 0000000000..45fb85b4a1 --- /dev/null +++ b/internal/v2/repository/idp/config_read_model.go @@ -0,0 +1,64 @@ +package idp + +import ( + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/idp/oidc" +) + +type ConfigReadModel struct { + eventstore.ReadModel + + Type ConfigType + + State ConfigState + ConfigID string + Name string + StylingType StylingType + ProviderType ProviderType + + OIDCConfig *oidc.ConfigReadModel +} + +func (rm *ConfigReadModel) AppendEvents(events ...eventstore.EventReader) { + rm.ReadModel.AppendEvents(events...) + for _, event := range events { + switch event.(type) { + case *oidc.ConfigAddedEvent: + rm.OIDCConfig = &oidc.ConfigReadModel{} + rm.OIDCConfig.AppendEvents(event) + case *oidc.ConfigChangedEvent: + rm.OIDCConfig.AppendEvents(event) + } + } +} + +func (rm *ConfigReadModel) Reduce() error { + for _, event := range rm.Events { + switch e := event.(type) { + case *ConfigAddedEvent: + rm.ConfigID = e.ConfigID + rm.Name = e.Name + rm.StylingType = e.StylingType + rm.State = ConfigStateActive + case *ConfigChangedEvent: + if e.Name != "" { + rm.Name = e.Name + } + if e.StylingType.Valid() { + rm.StylingType = e.StylingType + } + case *ConfigDeactivatedEvent: + rm.State = ConfigStateInactive + case *ConfigReactivatedEvent: + rm.State = ConfigStateActive + case *ConfigRemovedEvent: + rm.State = ConfigStateRemoved + case *oidc.ConfigAddedEvent: + rm.Type = ConfigTypeOIDC + } + } + if err := rm.OIDCConfig.Reduce(); err != nil { + return err + } + return rm.ReadModel.Reduce() +} diff --git a/internal/v2/repository/idp/config_write_model.go b/internal/v2/repository/idp/config_write_model.go new file mode 100644 index 0000000000..1f297a02a8 --- /dev/null +++ b/internal/v2/repository/idp/config_write_model.go @@ -0,0 +1,50 @@ +package idp + +import ( + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/idp/oidc" +) + +type ConfigWriteModel struct { + eventstore.WriteModel + + ConfigID string + Name string + StylingType StylingType + OIDCConfig *oidc.ConfigWriteModel +} + +func (rm *ConfigWriteModel) AppendEvents(events ...eventstore.EventReader) { + rm.WriteModel.AppendEvents(events...) + for _, event := range events { + switch event.(type) { + case *oidc.ConfigAddedEvent: + rm.OIDCConfig = &oidc.ConfigWriteModel{} + rm.OIDCConfig.AppendEvents(event) + case *oidc.ConfigChangedEvent: + rm.OIDCConfig.AppendEvents(event) + } + } +} + +func (rm *ConfigWriteModel) Reduce() error { + for _, event := range rm.Events { + switch e := event.(type) { + case *ConfigAddedEvent: + rm.ConfigID = e.ConfigID + rm.Name = e.Name + rm.StylingType = e.StylingType + case *ConfigChangedEvent: + if e.Name != "" { + rm.Name = e.Name + } + if e.StylingType.Valid() { + rm.StylingType = e.StylingType + } + } + } + if err := rm.OIDCConfig.Reduce(); err != nil { + return err + } + return rm.WriteModel.Reduce() +} diff --git a/internal/v2/repository/idp/event_config_added.go b/internal/v2/repository/idp/event_config_added.go index 12b03af90e..97f543b922 100644 --- a/internal/v2/repository/idp/event_config_added.go +++ b/internal/v2/repository/idp/event_config_added.go @@ -1,17 +1,23 @@ package idp -import "github.com/caos/zitadel/internal/eventstore/v2" +import ( + "encoding/json" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" +) type ConfigAddedEvent struct { - eventstore.BaseEvent + eventstore.BaseEvent `json:"-"` - ID string `json:"idpConfigId"` + ConfigID string `json:"idpConfigId"` Name string `json:"name"` - Type ConfigType `json:"idpType,omitempty"` + Typ ConfigType `json:"idpType,omitempty"` StylingType StylingType `json:"stylingType,omitempty"` } -func NewAddedEvent( +func NewConfigAddedEvent( base *eventstore.BaseEvent, configID string, name string, @@ -21,10 +27,10 @@ func NewAddedEvent( return &ConfigAddedEvent{ BaseEvent: *base, - ID: configID, + ConfigID: configID, Name: name, StylingType: stylingType, - Type: configType, + Typ: configType, } } @@ -36,6 +42,15 @@ func (e *ConfigAddedEvent) Data() interface{} { return e } -type ConfigType uint32 +func ConfigAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ConfigAddedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } -type StylingType uint32 + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "OIDC-plaBZ", "unable to unmarshal event") + } + + return e, nil +} diff --git a/internal/v2/repository/idp/event_config_changed.go b/internal/v2/repository/idp/event_config_changed.go index 32d63cd150..7af445388c 100644 --- a/internal/v2/repository/idp/event_config_changed.go +++ b/internal/v2/repository/idp/event_config_changed.go @@ -1,40 +1,44 @@ package idp import ( + "encoding/json" + "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" ) type ConfigChangedEvent struct { eventstore.BaseEvent `json:"-"` - ID string `json:"idpConfigId"` + ConfigID string `json:"idpConfigId"` + Name string `json:"name,omitempty"` StylingType StylingType `json:"stylingType,omitempty"` - - hasChanged bool } func NewConfigChangedEvent( base *eventstore.BaseEvent, - current, - changed *ConfigAggregate, + current *ConfigWriteModel, + name string, + stylingType StylingType, ) (*ConfigChangedEvent, error) { change := &ConfigChangedEvent{ BaseEvent: *base, + ConfigID: current.ConfigID, + } + hasChanged := false + + if current.Name != name { + change.Name = name + hasChanged = true + } + if stylingType != current.StylingType { + change.StylingType = stylingType + hasChanged = true } - if current.ConfigID != changed.ConfigID { - change.ID = changed.ConfigID - change.hasChanged = true - } - - if current.StylingType != changed.StylingType { - change.StylingType = changed.StylingType - change.hasChanged = true - } - - if !change.hasChanged { + if !hasChanged { return nil, errors.ThrowPreconditionFailed(nil, "IDP-UBJbB", "Errors.NoChanges") } @@ -46,8 +50,18 @@ func (e *ConfigChangedEvent) CheckPrevious() bool { } func (e *ConfigChangedEvent) Data() interface{} { - if e.current.Name != e.changed.Name { - e.Name = e.changed.Name - } return e } + +func ConfigChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ConfigChangedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "OIDC-plaBZ", "unable to unmarshal event") + } + + return e, nil +} diff --git a/internal/v2/repository/idp/event_config_deactivated.go b/internal/v2/repository/idp/event_config_deactivated.go index 476e9a7eea..39aaebd4c0 100644 --- a/internal/v2/repository/idp/event_config_deactivated.go +++ b/internal/v2/repository/idp/event_config_deactivated.go @@ -1,28 +1,47 @@ package idp -import "github.com/caos/zitadel/internal/eventstore/v2" +import ( + "encoding/json" -type DeactivatedEvent struct { - eventstore.BaseEvent + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" +) - ID string `idpConfigId` +type ConfigDeactivatedEvent struct { + eventstore.BaseEvent `json:"-"` + + ConfigID string `idpConfigId` } -func NewDeactivatedEvent( +func NewConfigDeactivatedEvent( base *eventstore.BaseEvent, configID string, -) *DeactivatedEvent { +) *ConfigDeactivatedEvent { - return &DeactivatedEvent{ + return &ConfigDeactivatedEvent{ BaseEvent: *base, - ID: configID, + ConfigID: configID, } } -func (e *DeactivatedEvent) CheckPrevious() bool { +func (e *ConfigDeactivatedEvent) CheckPrevious() bool { return true } -func (e *DeactivatedEvent) Data() interface{} { +func (e *ConfigDeactivatedEvent) Data() interface{} { return e } + +func ConfigDeactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ConfigDeactivatedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "OIDC-plaBZ", "unable to unmarshal event") + } + + return e, nil +} diff --git a/internal/v2/repository/idp/event_config_reactivated.go b/internal/v2/repository/idp/event_config_reactivated.go new file mode 100644 index 0000000000..9a7c53115d --- /dev/null +++ b/internal/v2/repository/idp/event_config_reactivated.go @@ -0,0 +1,47 @@ +package idp + +import ( + "encoding/json" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" +) + +type ConfigReactivatedEvent struct { + eventstore.BaseEvent `json:"-"` + + ConfigID string `idpConfigId` +} + +func NewConfigReactivatedEvent( + base *eventstore.BaseEvent, + configID string, +) *ConfigReactivatedEvent { + + return &ConfigReactivatedEvent{ + BaseEvent: *base, + ConfigID: configID, + } +} + +func (e *ConfigReactivatedEvent) CheckPrevious() bool { + return true +} + +func (e *ConfigReactivatedEvent) Data() interface{} { + return e +} + +func ConfigReactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ConfigReactivatedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "OIDC-plaBZ", "unable to unmarshal event") + } + + return e, nil +} diff --git a/internal/v2/repository/idp/event_config_removed.go b/internal/v2/repository/idp/event_config_removed.go new file mode 100644 index 0000000000..90e04f2ba8 --- /dev/null +++ b/internal/v2/repository/idp/event_config_removed.go @@ -0,0 +1,47 @@ +package idp + +import ( + "encoding/json" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" +) + +type ConfigRemovedEvent struct { + eventstore.BaseEvent `json:"-"` + + ConfigID string `idpConfigId` +} + +func NewConfigRemovedEvent( + base *eventstore.BaseEvent, + configID string, +) *ConfigRemovedEvent { + + return &ConfigRemovedEvent{ + BaseEvent: *base, + ConfigID: configID, + } +} + +func (e *ConfigRemovedEvent) CheckPrevious() bool { + return true +} + +func (e *ConfigRemovedEvent) Data() interface{} { + return e +} + +func ConfigRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ConfigRemovedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "OIDC-plaBZ", "unable to unmarshal event") + } + + return e, nil +} diff --git a/internal/v2/repository/idp/oidc/added_event.go b/internal/v2/repository/idp/oidc/added_event.go deleted file mode 100644 index 492ed1d938..0000000000 --- a/internal/v2/repository/idp/oidc/added_event.go +++ /dev/null @@ -1,15 +0,0 @@ -package oidc - -import "github.com/caos/zitadel/internal/crypto" - -type AddedEvent struct { - eventstore.BaseEvent - - IDPConfigID string `json:"idpConfigId"` - ClientID string `json:"clientId"` - Secret *crypto.CryptoValue `json:"clientSecret"` - Issuer string `json:"issuer"` - Scopes []string `json:"scpoes"` - IDPDisplayNameMapping int32 `json:"idpDisplayNameMapping,omitempty"` - UsernameMapping int32 `json:"usernameMapping,omitempty"` -} diff --git a/internal/v2/repository/idp/oidc/changed_event.go b/internal/v2/repository/idp/oidc/changed_event.go deleted file mode 100644 index 3c6cc2559e..0000000000 --- a/internal/v2/repository/idp/oidc/changed_event.go +++ /dev/null @@ -1,3 +0,0 @@ -package oidc - -type ChangedEvent struct{} diff --git a/internal/v2/repository/idp/oidc/config.go b/internal/v2/repository/idp/oidc/config.go deleted file mode 100644 index 1bcd2e944e..0000000000 --- a/internal/v2/repository/idp/oidc/config.go +++ /dev/null @@ -1,35 +0,0 @@ -package oidc - -import ( - "github.com/caos/zitadel/internal/crypto" - "github.com/caos/zitadel/internal/eventstore/v2" -) - -type ConfigReadModel struct { - eventstore.ReadModel - - IDPConfigID string - ClientID string - ClientSecret *crypto.CryptoValue - ClientSecretString string - Issuer string - Scopes []string - IDPDisplayNameMapping MappingField - UsernameMapping MappingField -} - -func (rm *ConfigReadModel) AppendEvents(events ...eventstore.EventReader) { - rm.ReadModel.AppendEvents(events...) -} - -func (rm *ConfigReadModel) Reduce() error { - return nil -} - -type MappingField int32 - -const ( - OIDCMappingFieldUnspecified MappingField = iota - OIDCMappingFieldPreferredLoginName - OIDCMappingFieldEmail -) diff --git a/internal/v2/repository/idp/oidc/config_read_model.go b/internal/v2/repository/idp/oidc/config_read_model.go new file mode 100644 index 0000000000..338a6a35c7 --- /dev/null +++ b/internal/v2/repository/idp/oidc/config_read_model.go @@ -0,0 +1,51 @@ +package oidc + +import ( + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/eventstore/v2" +) + +type ConfigReadModel struct { + eventstore.ReadModel + + IDPConfigID string + ClientID string + ClientSecret *crypto.CryptoValue + Issuer string + Scopes []string + IDPDisplayNameMapping MappingField + UserNameMapping MappingField +} + +func (rm *ConfigReadModel) Reduce() error { + for _, event := range rm.Events { + switch e := event.(type) { + case *ConfigAddedEvent: + rm.IDPConfigID = e.IDPConfigID + rm.ClientID = e.ClientID + rm.ClientSecret = e.ClientSecret + rm.Issuer = e.Issuer + rm.Scopes = e.Scopes + rm.IDPDisplayNameMapping = e.IDPDisplayNameMapping + rm.UserNameMapping = e.UserNameMapping + case *ConfigChangedEvent: + if e.ClientID != "" { + rm.ClientID = e.ClientID + } + if e.Issuer != "" { + rm.Issuer = e.Issuer + } + if len(e.Scopes) > 0 { + rm.Scopes = e.Scopes + } + if e.IDPDisplayNameMapping.Valid() { + rm.IDPDisplayNameMapping = e.IDPDisplayNameMapping + } + if e.UserNameMapping.Valid() { + rm.UserNameMapping = e.UserNameMapping + } + } + } + + return rm.ReadModel.Reduce() +} diff --git a/internal/v2/repository/idp/oidc/config_write_model.go b/internal/v2/repository/idp/oidc/config_write_model.go new file mode 100644 index 0000000000..8b12e2998a --- /dev/null +++ b/internal/v2/repository/idp/oidc/config_write_model.go @@ -0,0 +1,52 @@ +package oidc + +import ( + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/eventstore/v2" +) + +type ConfigWriteModel struct { + eventstore.WriteModel + + IDPConfigID string + ClientID string + ClientSecret *crypto.CryptoValue + Issuer string + Scopes []string + + IDPDisplayNameMapping MappingField + UserNameMapping MappingField +} + +func (wm *ConfigWriteModel) Reduce() error { + for _, event := range wm.Events { + switch e := event.(type) { + case *ConfigAddedEvent: + wm.IDPConfigID = e.IDPConfigID + wm.ClientID = e.ClientID + wm.ClientSecret = e.ClientSecret + wm.Issuer = e.Issuer + wm.Scopes = e.Scopes + wm.IDPDisplayNameMapping = e.IDPDisplayNameMapping + wm.UserNameMapping = e.UserNameMapping + case *ConfigChangedEvent: + if e.ClientID != "" { + wm.ClientID = e.ClientID + } + if e.Issuer != "" { + wm.Issuer = e.Issuer + } + if len(e.Scopes) > 0 { + wm.Scopes = e.Scopes + } + if e.IDPDisplayNameMapping.Valid() { + wm.IDPDisplayNameMapping = e.IDPDisplayNameMapping + } + if e.UserNameMapping.Valid() { + wm.UserNameMapping = e.UserNameMapping + } + } + } + + return wm.WriteModel.Reduce() +} diff --git a/internal/v2/repository/idp/oidc/deactivated_event.go b/internal/v2/repository/idp/oidc/deactivated_event.go deleted file mode 100644 index 5871a60ce5..0000000000 --- a/internal/v2/repository/idp/oidc/deactivated_event.go +++ /dev/null @@ -1,3 +0,0 @@ -package oidc - -type DeactivatedEvent struct{} diff --git a/internal/v2/repository/idp/oidc/event_added.go b/internal/v2/repository/idp/oidc/event_added.go new file mode 100644 index 0000000000..a732587f02 --- /dev/null +++ b/internal/v2/repository/idp/oidc/event_added.go @@ -0,0 +1,67 @@ +package oidc + +import ( + "encoding/json" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" +) + +type ConfigAddedEvent struct { + eventstore.BaseEvent + + IDPConfigID string `json:"idpConfigId"` + ClientID string `json:"clientId"` + ClientSecret *crypto.CryptoValue `json:"clientSecret"` + Issuer string `json:"issuer"` + Scopes []string `json:"scpoes"` + + IDPDisplayNameMapping MappingField `json:"idpDisplayNameMapping"` + UserNameMapping MappingField `json:"usernameMapping"` +} + +func (e *ConfigAddedEvent) CheckPrevious() bool { + return true +} + +func (e *ConfigAddedEvent) Data() interface{} { + return e +} + +func NewConfigAddedEvent( + base *eventstore.BaseEvent, + clientID, + idpConfigID, + issuer string, + clientSecret *crypto.CryptoValue, + idpDisplayNameMapping, + userNameMapping MappingField, + scopes ...string, +) *ConfigAddedEvent { + + return &ConfigAddedEvent{ + BaseEvent: *base, + IDPConfigID: idpConfigID, + ClientID: clientID, + ClientSecret: clientSecret, + Issuer: issuer, + Scopes: scopes, + IDPDisplayNameMapping: idpDisplayNameMapping, + UserNameMapping: userNameMapping, + } +} + +func ConfigAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ConfigAddedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "OIDC-plaBZ", "unable to unmarshal event") + } + + return e, nil +} diff --git a/internal/v2/repository/idp/oidc/event_changed.go b/internal/v2/repository/idp/oidc/event_changed.go new file mode 100644 index 0000000000..eb2e723d32 --- /dev/null +++ b/internal/v2/repository/idp/oidc/event_changed.go @@ -0,0 +1,105 @@ +package oidc + +import ( + "encoding/json" + "reflect" + "sort" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" +) + +type ConfigChangedEvent struct { + eventstore.BaseEvent `json:"-"` + + IDPConfigID string `json:"idpConfigId"` + + ClientID string `json:"clientId"` + ClientSecret *crypto.CryptoValue `json:"clientSecret"` + Issuer string `json:"issuer"` + Scopes []string `json:"scpoes"` + + IDPDisplayNameMapping MappingField `json:"idpDisplayNameMapping"` + UserNameMapping MappingField `json:"usernameMapping"` +} + +func (e *ConfigChangedEvent) CheckPrevious() bool { + return true +} + +func (e *ConfigChangedEvent) Data() interface{} { + return e +} + +func NewConfigChangedEvent( + base *eventstore.BaseEvent, + current *ConfigWriteModel, + clientID, + issuer string, + clientSecret *crypto.CryptoValue, + idpDisplayNameMapping, + userNameMapping MappingField, + scopes ...string, +) (*ConfigChangedEvent, error) { + + event := &ConfigChangedEvent{ + BaseEvent: *base, + IDPConfigID: current.IDPConfigID, + } + hasChanged := false + + if clientID != "" && clientID != current.ClientID { + event.ClientID = clientID + hasChanged = true + } + + if issuer != "" && issuer != current.Issuer { + event.Issuer = issuer + hasChanged = true + } + + if clientSecret != nil && clientSecret != current.ClientSecret { + event.ClientSecret = clientSecret + hasChanged = true + } + + if idpDisplayNameMapping.Valid() && idpDisplayNameMapping != current.IDPDisplayNameMapping { + event.IDPDisplayNameMapping = idpDisplayNameMapping + hasChanged = true + } + + if userNameMapping.Valid() && userNameMapping != current.UserNameMapping { + event.UserNameMapping = userNameMapping + hasChanged = true + } + + if len(scopes) > 0 { + sort.Strings(scopes) + sort.Strings(current.Scopes) + if !reflect.DeepEqual(scopes, current.Scopes) { + event.Scopes = scopes + hasChanged = true + } + } + + if !hasChanged { + return nil, errors.ThrowPreconditionFailed(nil, "OIDC-zPDOL", "Errors.NoChanges") + } + + return event, nil +} + +func ConfigChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ConfigChangedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "OIDC-plaBZ", "unable to unmarshal event") + } + + return e, nil +} diff --git a/internal/v2/repository/idp/oidc/mapping_field.go b/internal/v2/repository/idp/oidc/mapping_field.go new file mode 100644 index 0000000000..d3c932f8ed --- /dev/null +++ b/internal/v2/repository/idp/oidc/mapping_field.go @@ -0,0 +1,14 @@ +package oidc + +type MappingField int32 + +const ( + MappingFieldPreferredLoginName MappingField = iota + 1 + MappingFieldEmail + // count is for validation purposes + mappingFieldCount +) + +func (f MappingField) Valid() bool { + return f > 0 && f < mappingFieldCount +} diff --git a/internal/v2/repository/idp/oidc/removed_event.go b/internal/v2/repository/idp/oidc/removed_event.go deleted file mode 100644 index 516eef5b07..0000000000 --- a/internal/v2/repository/idp/oidc/removed_event.go +++ /dev/null @@ -1,3 +0,0 @@ -package oidc - -type RemovedEvent struct{} diff --git a/internal/v2/repository/member/event_added.go b/internal/v2/repository/member/event_added.go index df65b7ed87..96e215e460 100644 --- a/internal/v2/repository/member/event_added.go +++ b/internal/v2/repository/member/event_added.go @@ -5,7 +5,7 @@ import ( "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/v2" - "github.com/caos/zitadel/internal/eventstore/v2/repository" + es_repo "github.com/caos/zitadel/internal/eventstore/v2/repository" ) const ( @@ -40,7 +40,7 @@ func NewAddedEvent( } } -func AddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { +func AddedEventMapper(event *es_repo.Event) (eventstore.EventReader, error) { e := &AddedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), } diff --git a/internal/v2/repository/member/event_changed.go b/internal/v2/repository/member/event_changed.go index 443ffb9044..4b004ab2ef 100644 --- a/internal/v2/repository/member/event_changed.go +++ b/internal/v2/repository/member/event_changed.go @@ -19,8 +19,6 @@ type ChangedEvent struct { Roles []string `json:"roles,omitempty"` UserID string `json:"userId,omitempty"` - - hasChanged bool } func (e *ChangedEvent) CheckPrevious() bool { @@ -38,15 +36,16 @@ func ChangeEventFromExisting( ) (*ChangedEvent, error) { change := NewChangedEvent(base, current.userID) + hasChanged := false sort.Strings(current.Roles) sort.Strings(roles) if !reflect.DeepEqual(current.Roles, roles) { change.Roles = roles - change.hasChanged = true + hasChanged = true } - if !change.hasChanged { + if !hasChanged { return nil, errors.ThrowPreconditionFailed(nil, "MEMBE-SeKlD", "Errors.NoChanges") }