diff --git a/internal/admin/model/setup_org.go b/internal/admin/model/setup_org.go deleted file mode 100644 index 2007f5e26a..0000000000 --- a/internal/admin/model/setup_org.go +++ /dev/null @@ -1,11 +0,0 @@ -package model - -import ( - org_model "github.com/caos/zitadel/internal/org/model" - usr_model "github.com/caos/zitadel/internal/user/model" -) - -type SetupOrg struct { - *org_model.Org - *usr_model.User -} diff --git a/internal/admin/repository/eventsourcing/eventstore/iam.go b/internal/admin/repository/eventsourcing/eventstore/iam.go index 2be59c575d..af5a038db9 100644 --- a/internal/admin/repository/eventsourcing/eventstore/iam.go +++ b/internal/admin/repository/eventsourcing/eventstore/iam.go @@ -2,7 +2,11 @@ package eventstore import ( "context" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/user/repository/view/model" + "github.com/caos/zitadel/internal/v2/domain" "strings" caos_errs "github.com/caos/zitadel/internal/errors" @@ -11,19 +15,14 @@ import ( admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view" "github.com/caos/zitadel/internal/config/systemdefaults" iam_model "github.com/caos/zitadel/internal/iam/model" - iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing" iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/telemetry/tracing" usr_model "github.com/caos/zitadel/internal/user/model" - usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type IAMRepository struct { - SearchLimit uint64 - *iam_es.IAMEventstore - OrgEvents *org_es.OrgEventstore - UserEvents *usr_es.UserEventstore + Eventstore eventstore.Eventstore + SearchLimit uint64 View *admin_view.View SystemDefaults systemdefaults.SystemDefaults Roles []string @@ -130,7 +129,7 @@ func (repo *IAMRepository) GetDefaultLoginPolicy(ctx context.Context) (*iam_mode if caos_errs.IsNotFound(viewErr) { policy = new(iam_es_model.LoginPolicyView) } - events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getIAMEvents(ctx, policy.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.LoginPolicy.NotFound") } @@ -199,7 +198,7 @@ func (repo *IAMRepository) GetDefaultPasswordComplexityPolicy(ctx context.Contex if caos_errs.IsNotFound(viewErr) { policy = new(iam_es_model.PasswordComplexityPolicyView) } - events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getIAMEvents(ctx, policy.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-1Mc0s", "Errors.IAM.PasswordComplexityPolicy.NotFound") } @@ -224,7 +223,7 @@ func (repo *IAMRepository) GetDefaultPasswordAgePolicy(ctx context.Context) (*ia if caos_errs.IsNotFound(viewErr) { policy = new(iam_es_model.PasswordAgePolicyView) } - events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getIAMEvents(ctx, policy.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-vMyS3", "Errors.IAM.PasswordAgePolicy.NotFound") } @@ -249,7 +248,7 @@ func (repo *IAMRepository) GetDefaultPasswordLockoutPolicy(ctx context.Context) if caos_errs.IsNotFound(viewErr) { policy = new(iam_es_model.PasswordLockoutPolicyView) } - events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getIAMEvents(ctx, policy.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-2M9oP", "Errors.IAM.PasswordLockoutPolicy.NotFound") } @@ -274,7 +273,7 @@ func (repo *IAMRepository) GetOrgIAMPolicy(ctx context.Context) (*iam_model.OrgI if caos_errs.IsNotFound(viewErr) { policy = new(iam_es_model.OrgIAMPolicyView) } - events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getIAMEvents(ctx, policy.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-MkoL0", "Errors.IAM.OrgIAMPolicy.NotFound") } @@ -344,3 +343,11 @@ func (repo *IAMRepository) GetDefaultMailText(ctx context.Context, textType stri text.Default = true return iam_es_model.MailTextViewToModel(text), err } + +func (repo *IAMRepository) getIAMEvents(ctx context.Context, sequence uint64) ([]*models.Event, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, sequence) + if err != nil { + return nil, err + } + return repo.Eventstore.FilterEvents(ctx, query) +} diff --git a/internal/admin/repository/eventsourcing/eventstore/org.go b/internal/admin/repository/eventsourcing/eventstore/org.go index 8cc6fffdbb..d8031e70e2 100644 --- a/internal/admin/repository/eventsourcing/eventstore/org.go +++ b/internal/admin/repository/eventsourcing/eventstore/org.go @@ -2,9 +2,12 @@ package eventstore import ( "context" - "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" iam_model "github.com/caos/zitadel/internal/iam/model" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/org/repository/view" "github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/logging" @@ -13,15 +16,11 @@ import ( "github.com/caos/zitadel/internal/eventstore" iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model" org_model "github.com/caos/zitadel/internal/org/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/view/model" - usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type OrgRepo struct { - Eventstore eventstore.Eventstore - OrgEventstore *org_es.OrgEventstore - UserEventstore *usr_es.UserEventstore + Eventstore eventstore.Eventstore View *admin_view.View @@ -29,8 +28,29 @@ type OrgRepo struct { SystemDefaults systemdefaults.SystemDefaults } -func (repo *OrgRepo) OrgByID(ctx context.Context, id string) (*org_model.Org, error) { - return repo.OrgEventstore.OrgByID(ctx, org_model.NewOrg(id)) +func (repo *OrgRepo) OrgByID(ctx context.Context, id string) (*org_model.OrgView, error) { + org, viewErr := repo.View.OrgByID(id) + if viewErr != nil && !errors.IsNotFound(viewErr) { + return nil, viewErr + } + if errors.IsNotFound(viewErr) { + org = new(model.OrgView) + } + events, esErr := repo.getOrgEvents(ctx, id, org.Sequence) + if errors.IsNotFound(viewErr) && len(events) == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-Lsoj7", "Errors.Org.NotFound") + } + if esErr != nil { + logging.Log("EVENT-PSoc3").WithError(esErr).Debug("error retrieving new events") + return model.OrgToModel(org), nil + } + orgCopy := *org + for _, event := range events { + if err := orgCopy.AppendEvent(event); err != nil { + return model.OrgToModel(&orgCopy), nil + } + } + return model.OrgToModel(&orgCopy), nil } func (repo *OrgRepo) SearchOrgs(ctx context.Context, query *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error) { @@ -55,7 +75,18 @@ func (repo *OrgRepo) SearchOrgs(ctx context.Context, query *org_model.OrgSearchR } func (repo *OrgRepo) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) { - return repo.OrgEventstore.IsOrgUnique(ctx, name, domain) + var found bool + err = es_sdk.Filter(ctx, repo.Eventstore.FilterEvents, isUniqueValidation(&found), view.OrgNameUniqueQuery(name)) + if (err != nil && !errors.IsNotFound(err)) || found { + return false, err + } + + err = es_sdk.Filter(ctx, repo.Eventstore.FilterEvents, isUniqueValidation(&found), view.OrgDomainUniqueQuery(domain)) + if err != nil && !errors.IsNotFound(err) { + return false, err + } + + return !found, nil } func (repo *OrgRepo) GetOrgIAMPolicyByID(ctx context.Context, id string) (*iam_model.OrgIAMPolicyView, error) { @@ -77,3 +108,22 @@ func (repo *OrgRepo) GetDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.Org policy.Default = true return iam_es_model.OrgIAMViewToModel(policy), err } + +func (repo *OrgRepo) getOrgEvents(ctx context.Context, orgID string, sequence uint64) ([]*models.Event, error) { + query, err := view.OrgByIDQuery(orgID, sequence) + if err != nil { + return nil, err + } + return repo.Eventstore.FilterEvents(ctx, query) +} + +func isUniqueValidation(unique *bool) func(events ...*models.Event) error { + return func(events ...*models.Event) error { + if len(events) == 0 { + return nil + } + *unique = *unique || events[0].Type == org_es_model.OrgDomainReserved || events[0].Type == org_es_model.OrgNameReserved + + return nil + } +} diff --git a/internal/admin/repository/eventsourcing/eventstore/setup_model.go b/internal/admin/repository/eventsourcing/eventstore/setup_model.go deleted file mode 100644 index 527b514781..0000000000 --- a/internal/admin/repository/eventsourcing/eventstore/setup_model.go +++ /dev/null @@ -1,36 +0,0 @@ -package eventstore - -import ( - admin_model "github.com/caos/zitadel/internal/admin/model" - es_models "github.com/caos/zitadel/internal/eventstore/models" - "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" - usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" -) - -type Setup struct { - *model.Org - *usr_es.User -} - -func (s *Setup) AppendEvents(events ...*es_models.Event) error { - for _, event := range events { - var err error - switch event.AggregateType { - case model.OrgAggregate: - err = s.Org.AppendEvent(event) - case usr_es.UserAggregate: - err = s.User.AppendEvent(event) - } - if err != nil { - return err - } - } - return nil -} - -func SetupToModel(setup *Setup) *admin_model.SetupOrg { - return &admin_model.SetupOrg{ - Org: model.OrgToModel(setup.Org), - User: usr_es.UserToModel(setup.User), - } -} diff --git a/internal/admin/repository/eventsourcing/handler/handler.go b/internal/admin/repository/eventsourcing/handler/handler.go index 041c1a7720..40c125c21e 100644 --- a/internal/admin/repository/eventsourcing/handler/handler.go +++ b/internal/admin/repository/eventsourcing/handler/handler.go @@ -8,9 +8,6 @@ import ( "github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/query" - iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type Configs map[string]*Config @@ -32,19 +29,12 @@ func (h *handler) Eventstore() eventstore.Eventstore { return h.es } -type EventstoreRepos struct { - UserEvents *usr_event.UserEventstore - IamEvents *iam_event.IAMEventstore - OrgEvents *org_event.OrgEventstore -} - -func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, defaults systemdefaults.SystemDefaults) []query.Handler { +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, defaults systemdefaults.SystemDefaults) []query.Handler { return []query.Handler{ newOrg( handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount, es}), newIAMMember( - handler{view, bulkLimit, configs.cycleDuration("IamMember"), errorCount, es}, - repos.UserEvents), + handler{view, bulkLimit, configs.cycleDuration("IamMember"), errorCount, es}), newIDPConfig( handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount, es}), newLabelPolicy( @@ -53,13 +43,9 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount, es}), newIDPProvider( handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount, es}, - defaults, - repos.IamEvents, - repos.OrgEvents), + defaults), newUser( handler{view, bulkLimit, configs.cycleDuration("User"), errorCount, es}, - repos.OrgEvents, - repos.IamEvents, defaults), newPasswordComplexityPolicy( handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount, es}), @@ -71,9 +57,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount, es}), newExternalIDP( handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount, es}, - defaults, - repos.IamEvents, - repos.OrgEvents), + defaults), newMailTemplate( handler{view, bulkLimit, configs.cycleDuration("MailTemplate"), errorCount, es}), newMailText( diff --git a/internal/admin/repository/eventsourcing/handler/iam_member.go b/internal/admin/repository/eventsourcing/handler/iam_member.go index 438fd0263b..58ca23e7e3 100644 --- a/internal/admin/repository/eventsourcing/handler/iam_member.go +++ b/internal/admin/repository/eventsourcing/handler/iam_member.go @@ -2,16 +2,19 @@ package handler import ( "context" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/user/repository/view" + view_model "github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/logging" "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" iam_model "github.com/caos/zitadel/internal/iam/repository/view/model" usr_model "github.com/caos/zitadel/internal/user/model" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) @@ -21,14 +24,12 @@ const ( type IAMMember struct { handler - userEvents *usr_event.UserEventstore subscription *eventstore.Subscription } -func newIAMMember(handler handler, userEvents *usr_event.UserEventstore) *IAMMember { +func newIAMMember(handler handler) *IAMMember { iamMember := &IAMMember{ - handler: handler, - userEvents: userEvents, + handler: handler, } iamMember.subscribe() @@ -129,7 +130,7 @@ func (m *IAMMember) processUser(event *es_models.Event) (err error) { if len(members) == 0 { return m.view.ProcessedIAMMemberSequence(event) } - user, err := m.userEvents.UserByID(context.Background(), event.AggregateID) + user, err := m.getUserByID(event.AggregateID) if err != nil { return err } @@ -145,7 +146,7 @@ func (m *IAMMember) processUser(event *es_models.Event) (err error) { } func (m *IAMMember) fillData(member *iam_model.IAMMemberView) (err error) { - user, err := m.userEvents.UserByID(context.Background(), member.UserID) + user, err := m.getUserByID(member.UserID) if err != nil { return err } @@ -153,16 +154,16 @@ func (m *IAMMember) fillData(member *iam_model.IAMMemberView) (err error) { return nil } -func (m *IAMMember) fillUserData(member *iam_model.IAMMemberView, user *usr_model.User) { +func (m *IAMMember) fillUserData(member *iam_model.IAMMemberView, user *view_model.UserView) { member.UserName = user.UserName - if user.Human != nil { + if user.HumanView != nil { member.FirstName = user.FirstName member.LastName = user.LastName member.DisplayName = user.FirstName + " " + user.LastName - member.Email = user.EmailAddress + member.Email = user.Email } - if user.Machine != nil { - member.DisplayName = user.Machine.Name + if user.MachineView != nil { + member.DisplayName = user.MachineView.Name } } func (m *IAMMember) OnError(event *es_models.Event, err error) error { @@ -173,3 +174,36 @@ func (m *IAMMember) OnError(event *es_models.Event, err error) error { func (m *IAMMember) OnSuccess() error { return spooler.HandleSuccess(m.view.UpdateIAMMemberSpoolerRunTimestamp) } + +func (m *IAMMember) getUserByID(userID string) (*view_model.UserView, error) { + user, usrErr := m.view.UserByID(userID) + if usrErr != nil && !caos_errs.IsNotFound(usrErr) { + return nil, usrErr + } + if user == nil { + user = &view_model.UserView{} + } + events, err := m.getUserEvents(userID, user.Sequence) + if err != nil { + return user, usrErr + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return user, nil + } + } + if userCopy.State == int32(usr_model.UserStateDeleted) { + return nil, caos_errs.ThrowNotFound(nil, "HANDLER-4n9fs", "Errors.User.NotFound") + } + return &userCopy, nil +} + +func (m *IAMMember) getUserEvents(userID string, sequence uint64) ([]*models.Event, error) { + query, err := view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + + return m.es.FilterEvents(context.Background(), query) +} diff --git a/internal/admin/repository/eventsourcing/handler/idp_providers.go b/internal/admin/repository/eventsourcing/handler/idp_providers.go index 59956f6f76..38cc64fe5d 100644 --- a/internal/admin/repository/eventsourcing/handler/idp_providers.go +++ b/internal/admin/repository/eventsourcing/handler/idp_providers.go @@ -2,6 +2,12 @@ package handler import ( "context" + "github.com/caos/zitadel/internal/errors" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + org_model "github.com/caos/zitadel/internal/org/model" + "github.com/caos/zitadel/internal/org/repository/view" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/logging" "github.com/caos/zitadel/internal/config/systemdefaults" @@ -10,10 +16,8 @@ import ( "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" iam_model "github.com/caos/zitadel/internal/iam/model" - "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model" - org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" ) @@ -24,22 +28,16 @@ const ( type IDPProvider struct { handler systemDefaults systemdefaults.SystemDefaults - iamEvents *eventsourcing.IAMEventstore - orgEvents *org_events.OrgEventstore subscription *eventstore.Subscription } func newIDPProvider( handler handler, systemDefaults systemdefaults.SystemDefaults, - iamEvents *eventsourcing.IAMEventstore, - orgEvents *org_events.OrgEventstore, ) *IDPProvider { h := &IDPProvider{ handler: handler, systemDefaults: systemDefaults, - iamEvents: iamEvents, - orgEvents: orgEvents, } h.subscribe() @@ -117,7 +115,7 @@ func (i *IDPProvider) processIdpProvider(event *es_models.Event) (err error) { if err != nil { return err } - config, err := i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID) + config, err := i.getDefaultIDPConfig(context.Background(), esConfig.IDPConfigID) if err != nil { return err } @@ -137,9 +135,9 @@ func (i *IDPProvider) processIdpProvider(event *es_models.Event) (err error) { func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) { var config *iam_model.IDPConfig if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) { - config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, provider.IDPConfigID) + config, err = i.getDefaultIDPConfig(context.Background(), provider.IDPConfigID) } else { - config, err = i.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID) + config, err = i.getOrgIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID) } if err != nil { return err @@ -163,3 +161,64 @@ func (i *IDPProvider) OnError(event *es_models.Event, err error) error { func (i *IDPProvider) OnSuccess() error { return spooler.HandleSuccess(i.view.UpdateIDPProviderSpoolerRunTimestamp) } + +func (i *IDPProvider) getOrgIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := i.getOrgByID(ctx, aggregateID) + if err != nil { + return nil, err + } + if _, i := existing.GetIDP(idpConfigID); i != nil { + return i, nil + } + return nil, errors.ThrowNotFound(nil, "EVENT-4m0fs", "Errors.Org.IdpNotExisting") +} + +func (i *IDPProvider) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, i.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-4m9gs", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *IDPProvider) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &model.IAM{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && errors.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return model.IAMToModel(iam), nil +} + +func (u *IDPProvider) getDefaultIDPConfig(ctx context.Context, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if _, existingIDP := existing.GetIDP(idpConfigID); existingIDP != nil { + return existingIDP, nil + } + return nil, errors.ThrowNotFound(nil, "EVENT-4M=Fs", "Errors.IAM.IdpNotExisting") +} diff --git a/internal/admin/repository/eventsourcing/handler/org.go b/internal/admin/repository/eventsourcing/handler/org.go index 128eab554a..8f2da5ca7a 100644 --- a/internal/admin/repository/eventsourcing/handler/org.go +++ b/internal/admin/repository/eventsourcing/handler/org.go @@ -2,12 +2,12 @@ package handler import ( "github.com/caos/logging" + "github.com/caos/zitadel/internal/org/repository/view" "github.com/caos/zitadel/internal/eventstore" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" org_model "github.com/caos/zitadel/internal/org/repository/view/model" ) @@ -53,7 +53,7 @@ func (o *Org) EventQuery() (*es_models.SearchQuery, error) { if err != nil { return nil, err } - return eventsourcing.OrgQuery(sequence.CurrentSequence), nil + return view.OrgQuery(sequence.CurrentSequence), nil } func (o *Org) CurrentSequence() (uint64, error) { diff --git a/internal/admin/repository/eventsourcing/handler/user.go b/internal/admin/repository/eventsourcing/handler/user.go index 0c568128b3..1dd8146410 100644 --- a/internal/admin/repository/eventsourcing/handler/user.go +++ b/internal/admin/repository/eventsourcing/handler/user.go @@ -2,9 +2,15 @@ package handler import ( "context" - "github.com/caos/zitadel/internal/config/systemdefaults" - iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + caos_errs "github.com/caos/zitadel/internal/errors" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_model "github.com/caos/zitadel/internal/iam/model" + "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + "github.com/caos/zitadel/internal/org/repository/view" + "github.com/caos/zitadel/internal/v2/domain" + "k8s.io/apimachinery/pkg/api/errors" "github.com/caos/logging" @@ -14,7 +20,6 @@ import ( "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" org_model "github.com/caos/zitadel/internal/org/model" - org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/user/repository/view/model" @@ -27,22 +32,16 @@ const ( type User struct { handler eventstore eventstore.Eventstore - orgEvents *org_events.OrgEventstore - iamEvents *iam_es.IAMEventstore systemDefaults systemdefaults.SystemDefaults subscription *eventstore.Subscription } func newUser( handler handler, - orgEvents *org_events.OrgEventstore, - iamEvents *iam_es.IAMEventstore, systemDefaults systemdefaults.SystemDefaults, ) *User { h := &User{ handler: handler, - orgEvents: orgEvents, - iamEvents: iamEvents, systemDefaults: systemDefaults, } @@ -184,13 +183,13 @@ func (u *User) ProcessOrg(event *models.Event) (err error) { } func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), event.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.systemDefaults.IamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -206,13 +205,13 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error { } func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), event.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.systemDefaults.IamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -231,17 +230,18 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error { } func (u *User) fillLoginNames(user *view_model.UserView) (err error) { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(user.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), user.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.systemDefaults.IamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } } + user.SetLoginNames(policy, org.Domains) user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain) return nil @@ -255,3 +255,53 @@ func (u *User) OnError(event *models.Event, err error) error { func (u *User) OnSuccess() error { return spooler.HandleSuccess(u.view.UpdateUserSpoolerRunTimestamp) } + +func (u *User) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, u.eventstore.FilterEvents, esOrg.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-kVLb2", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *User) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &model.IAM{ + ObjectRoot: models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.eventstore.FilterEvents, iam.AppendEvents, query) + if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return model.IAMToModel(iam), nil +} + +func (u *User) getDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicy, error) { + existingIAM, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if existingIAM.DefaultOrgIAMPolicy == nil { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-2Fj8s", "Errors.IAM.OrgIAMPolicy.NotExisting") + } + return existingIAM.DefaultOrgIAMPolicy, nil +} diff --git a/internal/admin/repository/eventsourcing/handler/user_external_idps.go b/internal/admin/repository/eventsourcing/handler/user_external_idps.go index 1368fa1bc8..8bc1a62c88 100644 --- a/internal/admin/repository/eventsourcing/handler/user_external_idps.go +++ b/internal/admin/repository/eventsourcing/handler/user_external_idps.go @@ -2,24 +2,25 @@ package handler import ( "context" - "github.com/caos/logging" "github.com/caos/zitadel/internal/config/systemdefaults" caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" - "github.com/caos/zitadel/internal/iam/repository/eventsourcing" - iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" - org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" - "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" - usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model" - "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" iam_model "github.com/caos/zitadel/internal/iam/model" iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model" + org_model "github.com/caos/zitadel/internal/org/model" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/org/repository/view" + "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" + usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model" + "github.com/caos/zitadel/internal/v2/domain" ) const ( @@ -29,22 +30,16 @@ const ( type ExternalIDP struct { handler systemDefaults systemdefaults.SystemDefaults - iamEvents *eventsourcing.IAMEventstore - orgEvents *org_es.OrgEventstore subscription *eventstore.Subscription } func newExternalIDP( handler handler, systemDefaults systemdefaults.SystemDefaults, - iamEvents *eventsourcing.IAMEventstore, - orgEvents *org_es.OrgEventstore, ) *ExternalIDP { h := &ExternalIDP{ handler: handler, systemDefaults: systemDefaults, - iamEvents: iamEvents, - orgEvents: orgEvents, } h.subscribe() @@ -138,9 +133,9 @@ func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) { return err } if event.AggregateType == iam_es_model.IAMAggregate { - config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) + config, err = i.getDefaultIDPConfig(context.Background(), configView.IDPConfigID) } else { - config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) + config, err = i.getOrgIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) } if err != nil { return err @@ -155,9 +150,9 @@ func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) { } func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error { - config, err := i.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID) + config, err := i.getOrgIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID) if caos_errs.IsNotFound(err) { - config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, externalIDP.IDPConfigID) + config, err = i.getDefaultIDPConfig(context.Background(), externalIDP.IDPConfigID) } if err != nil { return err @@ -178,3 +173,64 @@ func (i *ExternalIDP) OnError(event *models.Event, err error) error { func (i *ExternalIDP) OnSuccess() error { return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp) } + +func (i *ExternalIDP) getOrgIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := i.getOrgByID(ctx, aggregateID) + if err != nil { + return nil, err + } + if _, i := existing.GetIDP(idpConfigID); i != nil { + return i, nil + } + return nil, caos_errs.ThrowNotFound(nil, "EVENT-2n8Fh", "Errors.Org.IdpNotExisting") +} + +func (i *ExternalIDP) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, i.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-MOFMs", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *ExternalIDP) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &iam_es_model.IAM{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return iam_es_model.IAMToModel(iam), nil +} + +func (u *ExternalIDP) getDefaultIDPConfig(ctx context.Context, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if _, existingIDP := existing.GetIDP(idpConfigID); existingIDP != nil { + return existingIDP, nil + } + return nil, caos_errs.ThrowNotFound(nil, "EVENT-49O0f", "Errors.IAM.IdpNotExisting") +} diff --git a/internal/admin/repository/eventsourcing/repository.go b/internal/admin/repository/eventsourcing/repository.go index 631908c92c..185ffa6a2a 100644 --- a/internal/admin/repository/eventsourcing/repository.go +++ b/internal/admin/repository/eventsourcing/repository.go @@ -3,16 +3,12 @@ package eventsourcing import ( "context" "github.com/caos/zitadel/internal/admin/repository/eventsourcing/eventstore" - "github.com/caos/zitadel/internal/admin/repository/eventsourcing/handler" "github.com/caos/zitadel/internal/admin/repository/eventsourcing/spooler" admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/config/types" es_int "github.com/caos/zitadel/internal/eventstore" es_spol "github.com/caos/zitadel/internal/eventstore/spooler" - es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" - es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" - es_usr "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type Config struct { @@ -35,23 +31,6 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, r if err != nil { return nil, err } - iam, err := es_iam.StartIAM(es_iam.IAMConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, systemDefaults) - if err != nil { - return nil, err - } - - org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es, IAMDomain: conf.Domain}, systemDefaults) - - user, err := es_usr.StartUser(es_usr.UserConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, systemDefaults) - if err != nil { - return nil, err - } sqlClient, err := conf.View.Start() if err != nil { return nil, err @@ -61,22 +40,18 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, r return nil, err } - spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, handler.EventstoreRepos{UserEvents: user, OrgEvents: org, IamEvents: iam}, systemDefaults) + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults) return &EsRepository{ spooler: spool, OrgRepo: eventstore.OrgRepo{ Eventstore: es, - OrgEventstore: org, - UserEventstore: user, View: view, SearchLimit: conf.SearchLimit, SystemDefaults: systemDefaults, }, IAMRepository: eventstore.IAMRepository{ - IAMEventstore: iam, - OrgEvents: org, - UserEvents: user, + Eventstore: es, View: view, SystemDefaults: systemDefaults, SearchLimit: conf.SearchLimit, @@ -89,13 +64,5 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, r } func (repo *EsRepository) Health(ctx context.Context) error { - err := repo.Eventstore.Health(ctx) - if err != nil { - return err - } - err = repo.UserEventstore.Health(ctx) - if err != nil { - return err - } - return repo.OrgEventstore.Health(ctx) + return nil } diff --git a/internal/admin/repository/eventsourcing/spooler/spooler.go b/internal/admin/repository/eventsourcing/spooler/spooler.go index 751113082a..3ab4e2628d 100644 --- a/internal/admin/repository/eventsourcing/spooler/spooler.go +++ b/internal/admin/repository/eventsourcing/spooler/spooler.go @@ -17,12 +17,12 @@ type SpoolerConfig struct { Handlers handler.Configs } -func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, repos handler.EventstoreRepos, defaults systemdefaults.SystemDefaults) *spooler.Spooler { +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, defaults systemdefaults.SystemDefaults) *spooler.Spooler { spoolerConfig := spooler.Config{ Eventstore: es, Locker: &locker{dbClient: sql}, ConcurrentWorkers: c.ConcurrentWorkers, - ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, repos, defaults), + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, defaults), } spool := spoolerConfig.New() spool.Start() diff --git a/internal/admin/repository/org.go b/internal/admin/repository/org.go index 3614a3c461..e35cd7e5c4 100644 --- a/internal/admin/repository/org.go +++ b/internal/admin/repository/org.go @@ -10,7 +10,7 @@ import ( type OrgRepository interface { IsOrgUnique(ctx context.Context, name, domain string) (bool, error) - OrgByID(ctx context.Context, id string) (*org_model.Org, error) + OrgByID(ctx context.Context, id string) (*org_model.OrgView, error) SearchOrgs(ctx context.Context, query *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error) GetOrgIAMPolicyByID(ctx context.Context, id string) (*iam_model.OrgIAMPolicyView, error) diff --git a/internal/api/grpc/admin/org.go b/internal/api/grpc/admin/org.go index 266a3d416d..49577be718 100644 --- a/internal/api/grpc/admin/org.go +++ b/internal/api/grpc/admin/org.go @@ -14,7 +14,7 @@ func (s *Server) GetOrgByID(ctx context.Context, orgID *admin.OrgID) (_ *admin.O if err != nil { return nil, err } - return orgFromModel(org), nil + return orgViewFromModel(org), nil } func (s *Server) SearchOrgs(ctx context.Context, request *admin.OrgSearchRequest) (_ *admin.OrgSearchResponse, err error) { diff --git a/internal/api/grpc/admin/org_converter.go b/internal/api/grpc/admin/org_converter.go index f27161868d..8dd42aba26 100644 --- a/internal/api/grpc/admin/org_converter.go +++ b/internal/api/grpc/admin/org_converter.go @@ -8,7 +8,6 @@ import ( iam_model "github.com/caos/zitadel/internal/iam/model" "github.com/caos/zitadel/internal/v2/domain" - admin_model "github.com/caos/zitadel/internal/admin/model" "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/model" org_model "github.com/caos/zitadel/internal/org/model" @@ -28,13 +27,6 @@ func orgCreateRequestToDomain(org *admin.CreateOrgRequest) *domain.Org { return o } -func setUpOrgResponseFromModel(setUp *admin_model.SetupOrg) *admin.OrgSetUpResponse { - return &admin.OrgSetUpResponse{ - Org: orgFromModel(setUp.Org), - User: userFromModel(setUp.User), - } -} - func orgSearchResponseFromModel(request *org_model.OrgSearchResult) *admin.OrgSearchResponse { timestamp, err := ptypes.TimestampProto(request.Timestamp) logging.Log("GRPC-shu7s").OnError(err).Debug("unable to get timestamp from time") diff --git a/internal/api/grpc/admin/user_converter.go b/internal/api/grpc/admin/user_converter.go index 3a964161a9..4a53a08571 100644 --- a/internal/api/grpc/admin/user_converter.go +++ b/internal/api/grpc/admin/user_converter.go @@ -6,7 +6,6 @@ import ( usr_model "github.com/caos/zitadel/internal/user/model" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/pkg/grpc/admin" - "github.com/golang/protobuf/ptypes" "golang.org/x/text/language" ) @@ -77,125 +76,6 @@ func machineCreateToDomain(machine *admin.CreateMachineRequest) *domain.Machine } } -func userCreateRequestToModel(user *admin.CreateUserRequest) *usr_model.User { - var human *usr_model.Human - var machine *usr_model.Machine - - if h := user.GetHuman(); h != nil { - human = humanCreateToModel(h) - } - if m := user.GetMachine(); m != nil { - machine = machineCreateToModel(m) - } - - return &usr_model.User{ - UserName: user.UserName, - Human: human, - Machine: machine, - } -} - -func humanCreateToModel(u *admin.CreateHumanRequest) *usr_model.Human { - preferredLanguage, err := language.Parse(u.PreferredLanguage) - logging.Log("GRPC-1ouQc").OnError(err).Debug("language malformed") - - human := &usr_model.Human{ - Profile: &usr_model.Profile{ - FirstName: u.FirstName, - LastName: u.LastName, - NickName: u.NickName, - PreferredLanguage: preferredLanguage, - Gender: genderToModel(u.Gender), - }, - Email: &usr_model.Email{ - EmailAddress: u.Email, - IsEmailVerified: u.IsEmailVerified, - }, - Address: &usr_model.Address{ - Country: u.Country, - Locality: u.Locality, - PostalCode: u.PostalCode, - Region: u.Region, - StreetAddress: u.StreetAddress, - }, - } - if u.Password != "" { - human.Password = &usr_model.Password{SecretString: u.Password} - } - if u.Phone != "" { - human.Phone = &usr_model.Phone{PhoneNumber: u.Phone, IsPhoneVerified: u.IsPhoneVerified} - } - return human -} - -func machineCreateToModel(machine *admin.CreateMachineRequest) *usr_model.Machine { - return &usr_model.Machine{ - Name: machine.Name, - Description: machine.Description, - } -} - -func userFromModel(user *usr_model.User) *admin.UserResponse { - creationDate, err := ptypes.TimestampProto(user.CreationDate) - logging.Log("GRPC-yo0FW").OnError(err).Debug("unable to parse timestamp") - - changeDate, err := ptypes.TimestampProto(user.ChangeDate) - logging.Log("GRPC-jxoQr").OnError(err).Debug("unable to parse timestamp") - - userResp := &admin.UserResponse{ - Id: user.AggregateID, - State: userStateFromModel(user.State), - CreationDate: creationDate, - ChangeDate: changeDate, - Sequence: user.Sequence, - UserName: user.UserName, - } - - if user.Machine != nil { - userResp.User = &admin.UserResponse_Machine{Machine: machineFromModel(user.Machine)} - } - if user.Human != nil { - userResp.User = &admin.UserResponse_Human{Human: humanFromModel(user.Human)} - } - - return userResp -} - -func machineFromModel(account *usr_model.Machine) *admin.MachineResponse { - return &admin.MachineResponse{ - Name: account.Name, - Description: account.Description, - } -} - -func humanFromModel(user *usr_model.Human) *admin.HumanResponse { - human := &admin.HumanResponse{ - FirstName: user.FirstName, - LastName: user.LastName, - DisplayName: user.DisplayName, - NickName: user.NickName, - PreferredLanguage: user.PreferredLanguage.String(), - Gender: genderFromModel(user.Gender), - } - - if user.Email != nil { - human.Email = user.EmailAddress - human.IsEmailVerified = user.IsEmailVerified - } - if user.Phone != nil { - human.Phone = user.PhoneNumber - human.IsPhoneVerified = user.IsPhoneVerified - } - if user.Address != nil { - human.Country = user.Country - human.Locality = user.Locality - human.PostalCode = user.PostalCode - human.Region = user.Region - human.StreetAddress = user.StreetAddress - } - return human -} - func externalIDPViewsToDomain(idps []*usr_model.ExternalIDPView) []*domain.ExternalIDP { externalIDPs := make([]*domain.ExternalIDP, len(idps)) for i, idp := range idps { diff --git a/internal/api/grpc/auth/user_converter.go b/internal/api/grpc/auth/user_converter.go index adb1f5358c..c10a4c06e8 100644 --- a/internal/api/grpc/auth/user_converter.go +++ b/internal/api/grpc/auth/user_converter.go @@ -438,7 +438,7 @@ func verifyWebAuthNFromDomain(u2f *domain.WebAuthNToken) *auth.WebAuthNResponse } } -func webAuthNTokensFromModel(tokens []*usr_model.WebAuthNToken) *auth.WebAuthNTokens { +func webAuthNTokensFromModel(tokens []*usr_model.WebAuthNView) *auth.WebAuthNTokens { result := make([]*auth.WebAuthNToken, len(tokens)) for i, token := range tokens { result[i] = webAuthNTokenFromModel(token) @@ -446,10 +446,10 @@ func webAuthNTokensFromModel(tokens []*usr_model.WebAuthNToken) *auth.WebAuthNTo return &auth.WebAuthNTokens{Tokens: result} } -func webAuthNTokenFromModel(token *usr_model.WebAuthNToken) *auth.WebAuthNToken { +func webAuthNTokenFromModel(token *usr_model.WebAuthNView) *auth.WebAuthNToken { return &auth.WebAuthNToken{ - Id: token.WebAuthNTokenID, - Name: token.WebAuthNTokenName, + Id: token.TokenID, + Name: token.Name, State: auth.MFAState(token.State), } } diff --git a/internal/api/grpc/management/iam.go b/internal/api/grpc/management/iam.go index cd7f294091..f8a2a14eb7 100644 --- a/internal/api/grpc/management/iam.go +++ b/internal/api/grpc/management/iam.go @@ -9,7 +9,7 @@ import ( ) func (s *Server) GetIam(ctx context.Context, _ *empty.Empty) (*management.Iam, error) { - iam, err := s.iam.IAMByID(ctx, s.systemDefaults.IamID) + iam, err := s.project.GetIAMByID(ctx) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/user_converter.go b/internal/api/grpc/management/user_converter.go index 558c46d9a4..0638f78669 100644 --- a/internal/api/grpc/management/user_converter.go +++ b/internal/api/grpc/management/user_converter.go @@ -624,7 +624,7 @@ func userChangesToMgtAPI(changes *usr_model.UserChanges) (_ []*management.Change return result } -func webAuthNTokensFromModel(tokens []*usr_model.WebAuthNToken) *management.WebAuthNTokens { +func webAuthNTokensFromModel(tokens []*usr_model.WebAuthNView) *management.WebAuthNTokens { result := make([]*management.WebAuthNToken, len(tokens)) for i, token := range tokens { result[i] = webAuthNTokenFromModel(token) @@ -632,10 +632,10 @@ func webAuthNTokensFromModel(tokens []*usr_model.WebAuthNToken) *management.WebA return &management.WebAuthNTokens{Tokens: result} } -func webAuthNTokenFromModel(token *usr_model.WebAuthNToken) *management.WebAuthNToken { +func webAuthNTokenFromModel(token *usr_model.WebAuthNView) *management.WebAuthNToken { return &management.WebAuthNToken{ - Id: token.WebAuthNTokenID, - Name: token.WebAuthNTokenName, + Id: token.TokenID, + Name: token.Name, State: mfaStateFromModel(token.State), } } diff --git a/internal/api/grpc/management/user_human_converter.go b/internal/api/grpc/management/user_human_converter.go index b6c277ff56..7bd67b6fec 100644 --- a/internal/api/grpc/management/user_human_converter.go +++ b/internal/api/grpc/management/user_human_converter.go @@ -37,35 +37,6 @@ func humanFromDomain(user *domain.Human) *management.HumanResponse { return human } -func humanFromModel(user *usr_model.Human) *management.HumanResponse { - human := &management.HumanResponse{ - FirstName: user.FirstName, - LastName: user.LastName, - DisplayName: user.DisplayName, - NickName: user.NickName, - PreferredLanguage: user.PreferredLanguage.String(), - //TODO: User Converter - Gender: management.Gender(user.Gender), - } - - if user.Email != nil { - human.Email = user.EmailAddress - human.IsEmailVerified = user.IsEmailVerified - } - if user.Phone != nil { - human.Phone = user.PhoneNumber - human.IsPhoneVerified = user.IsPhoneVerified - } - if user.Address != nil { - human.Country = user.Country - human.Locality = user.Locality - human.PostalCode = user.PostalCode - human.Region = user.Region - human.StreetAddress = user.StreetAddress - } - return human -} - func humanViewFromModel(user *usr_model.HumanView) *management.HumanView { passwordChanged, err := ptypes.TimestampProto(user.PasswordChanged) logging.Log("MANAG-h4ByY").OnError(err).Debug("unable to parse date") diff --git a/internal/auth/model/org.go b/internal/auth/model/org.go deleted file mode 100644 index fab418f472..0000000000 --- a/internal/auth/model/org.go +++ /dev/null @@ -1,11 +0,0 @@ -package model - -import ( - org_model "github.com/caos/zitadel/internal/org/model" - usr_model "github.com/caos/zitadel/internal/user/model" -) - -type RegisterOrg struct { - *org_model.Org - *usr_model.User -} diff --git a/internal/auth/repository/eventsourcing/eventstore/application.go b/internal/auth/repository/eventsourcing/eventstore/application.go index c009c51bad..c623892040 100644 --- a/internal/auth/repository/eventsourcing/eventstore/application.go +++ b/internal/auth/repository/eventsourcing/eventstore/application.go @@ -5,16 +5,14 @@ import ( "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" "github.com/caos/zitadel/internal/project/model" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model" "github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/v2/command" ) type ApplicationRepo struct { - Commands *command.CommandSide - View *view.View - ProjectEvents *proj_event.ProjectEventstore + Commands *command.CommandSide + View *view.View } func (a *ApplicationRepo) ApplicationByClientID(ctx context.Context, clientID string) (*model.ApplicationView, error) { diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index c8d0110e21..a4aa8129bd 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -20,12 +20,10 @@ import ( iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/id" org_model "github.com/caos/zitadel/internal/org/model" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_view_model "github.com/caos/zitadel/internal/org/repository/view/model" project_view_model "github.com/caos/zitadel/internal/project/repository/view/model" "github.com/caos/zitadel/internal/telemetry/tracing" user_model "github.com/caos/zitadel/internal/user/model" - user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" user_view_model "github.com/caos/zitadel/internal/user/repository/view/model" grant_view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model" @@ -33,8 +31,6 @@ import ( type AuthRequestRepo struct { Command *command.CommandSide - UserEvents *user_event.UserEventstore - OrgEvents *org_event.OrgEventstore AuthRequests cache.AuthRequestCache View *view.View @@ -93,9 +89,6 @@ type userGrantProvider interface { } func (repo *AuthRequestRepo) Health(ctx context.Context) error { - if err := repo.UserEvents.Health(ctx); err != nil { - return err - } return repo.AuthRequests.Health(ctx) } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go index c73ad4fe4d..02798c3dac 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go @@ -21,7 +21,6 @@ import ( org_view_model "github.com/caos/zitadel/internal/org/repository/view/model" proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model" user_model "github.com/caos/zitadel/internal/user/model" - user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" user_view_model "github.com/caos/zitadel/internal/user/repository/view/model" grant_view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model" @@ -198,7 +197,6 @@ func (m *mockUserGrants) UserGrantsByProjectAndUserID(s string, s2 string) ([]*g func TestAuthRequestRepo_nextSteps(t *testing.T) { type fields struct { - UserEvents *user_event.UserEventstore AuthRequests *cache.AuthRequestCache View *view.View userSessionViewProvider userSessionViewProvider @@ -958,7 +956,6 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { repo := &AuthRequestRepo{ - UserEvents: tt.fields.UserEvents, AuthRequests: tt.fields.AuthRequests, View: tt.fields.View, UserSessionViewProvider: tt.fields.userSessionViewProvider, diff --git a/internal/auth/repository/eventsourcing/eventstore/org.go b/internal/auth/repository/eventsourcing/eventstore/org.go index 83313647b1..ebe59e21b8 100644 --- a/internal/auth/repository/eventsourcing/eventstore/org.go +++ b/internal/auth/repository/eventsourcing/eventstore/org.go @@ -14,9 +14,7 @@ import ( auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" org_model "github.com/caos/zitadel/internal/org/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/view/model" - usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) const ( @@ -24,9 +22,7 @@ const ( ) type OrgRepository struct { - SearchLimit uint64 - OrgEventstore *org_es.OrgEventstore - UserEventstore *usr_es.UserEventstore + SearchLimit uint64 View *auth_view.View SystemDefaults systemdefaults.SystemDefaults diff --git a/internal/auth/repository/eventsourcing/eventstore/project.go b/internal/auth/repository/eventsourcing/eventstore/project.go index 28fd2e916a..37f05c8aae 100644 --- a/internal/auth/repository/eventsourcing/eventstore/project.go +++ b/internal/auth/repository/eventsourcing/eventstore/project.go @@ -3,13 +3,11 @@ package eventstore import ( "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" "github.com/caos/zitadel/internal/project/model" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model" ) type ProjectRepo struct { - View *view.View - ProjectEvents *proj_event.ProjectEventstore + View *view.View } func (a *ApplicationRepo) ProjectRolesByProjectID(projectID string) ([]*model.ProjectRoleView, error) { diff --git a/internal/auth/repository/eventsourcing/eventstore/register.go b/internal/auth/repository/eventsourcing/eventstore/register.go deleted file mode 100644 index e3b06bf65c..0000000000 --- a/internal/auth/repository/eventsourcing/eventstore/register.go +++ /dev/null @@ -1,36 +0,0 @@ -package eventstore - -import ( - auth_model "github.com/caos/zitadel/internal/auth/model" - es_models "github.com/caos/zitadel/internal/eventstore/models" - "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" - usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" -) - -type Register struct { - *model.Org - *usr_es.User -} - -func (r *Register) AppendEvents(events ...*es_models.Event) error { - for _, event := range events { - var err error - switch event.AggregateType { - case model.OrgAggregate: - err = r.Org.AppendEvent(event) - case usr_es.UserAggregate: - err = r.User.AppendEvent(event) - } - if err != nil { - return err - } - } - return nil -} - -func RegisterToModel(register *Register) *auth_model.RegisterOrg { - return &auth_model.RegisterOrg{ - Org: model.OrgToModel(register.Org), - User: usr_es.UserToModel(register.User), - } -} diff --git a/internal/auth/repository/eventsourcing/eventstore/token.go b/internal/auth/repository/eventsourcing/eventstore/token.go index 47b040b3ed..4b22947688 100644 --- a/internal/auth/repository/eventsourcing/eventstore/token.go +++ b/internal/auth/repository/eventsourcing/eventstore/token.go @@ -4,21 +4,22 @@ import ( "context" "time" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + usr_view "github.com/caos/zitadel/internal/user/repository/view" + "github.com/caos/logging" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" "github.com/caos/zitadel/internal/errors" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" "github.com/caos/zitadel/internal/telemetry/tracing" usr_model "github.com/caos/zitadel/internal/user/model" - user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" "github.com/caos/zitadel/internal/user/repository/view/model" ) type TokenRepo struct { - UserEvents *user_event.UserEventstore - ProjectEvents *proj_event.ProjectEventstore - View *view.View + Eventstore eventstore.Eventstore + View *view.View } func (repo *TokenRepo) IsTokenValid(ctx context.Context, userID, tokenID string) (bool, error) { @@ -43,7 +44,7 @@ func (repo *TokenRepo) TokenByID(ctx context.Context, userID, tokenID string) (* token.UserID = userID } - events, esErr := repo.UserEvents.UserEventsByID(ctx, userID, token.Sequence) + events, esErr := repo.getUserEvents(ctx, userID, token.Sequence) if errors.IsNotFound(viewErr) && len(events) == 0 { return nil, errors.ThrowNotFound(nil, "EVENT-4T90g", "Errors.Token.NotFound") } @@ -65,11 +66,10 @@ func (repo *TokenRepo) TokenByID(ctx context.Context, userID, tokenID string) (* return model.TokenViewToModel(token), nil } -func AppendAudIfNotExisting(aud string, existingAud []string) []string { - for _, a := range existingAud { - if a == aud { - return existingAud - } +func (r *TokenRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) { + query, err := usr_view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err } - return append(existingAud, aud) + return r.Eventstore.FilterEvents(ctx, query) } diff --git a/internal/auth/repository/eventsourcing/eventstore/user.go b/internal/auth/repository/eventsourcing/eventstore/user.go index 11a54cee90..d428136173 100644 --- a/internal/auth/repository/eventsourcing/eventstore/user.go +++ b/internal/auth/repository/eventsourcing/eventstore/user.go @@ -2,6 +2,8 @@ package eventstore import ( "context" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/golang/protobuf/ptypes" "github.com/caos/zitadel/internal/config/systemdefaults" key_model "github.com/caos/zitadel/internal/key/model" @@ -12,25 +14,23 @@ import ( "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" key_view_model "github.com/caos/zitadel/internal/key/repository/view/model" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/user/model" - user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" + usr_view "github.com/caos/zitadel/internal/user/repository/view" usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) type UserRepo struct { SearchLimit uint64 Eventstore eventstore.Eventstore - UserEvents *user_event.UserEventstore - OrgEvents *org_event.OrgEventstore View *view.View SystemDefaults systemdefaults.SystemDefaults } func (repo *UserRepo) Health(ctx context.Context) error { - return repo.UserEvents.Health(ctx) + return repo.Eventstore.Health(ctx) } func (repo *UserRepo) MyUser(ctx context.Context) (*model.UserView, error) { @@ -118,12 +118,15 @@ func (repo *UserRepo) MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, err return mfas, nil } -func (repo *UserRepo) GetPasswordless(ctx context.Context, userID string) ([]*model.WebAuthNToken, error) { - return repo.UserEvents.GetPasswordless(ctx, userID) -} - -func (repo *UserRepo) GetMyPasswordless(ctx context.Context) ([]*model.WebAuthNToken, error) { - return repo.UserEvents.GetPasswordless(ctx, authz.GetCtxData(ctx).UserID) +func (repo *UserRepo) GetMyPasswordless(ctx context.Context) ([]*model.WebAuthNView, error) { + user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID) + if err != nil { + return nil, err + } + if user.HumanView == nil { + return nil, errors.ThrowPreconditionFailed(nil, "USER-9kF98", "Errors.User.NotHuman") + } + return user.HumanView.PasswordlessTokens, nil } func (repo *UserRepo) UserSessionUserIDsByAgentID(ctx context.Context, agentID string) ([]string, error) { @@ -143,7 +146,7 @@ func (repo *UserRepo) UserByID(ctx context.Context, id string) (*model.UserView, if err != nil { return nil, err } - events, err := repo.UserEvents.UserEventsByID(ctx, id, user.Sequence) + events, err := repo.getUserEvents(ctx, id, user.Sequence) if err != nil { logging.Log("EVENT-PSoc3").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("error retrieving new events") return usr_view_model.UserToModel(user), nil @@ -160,12 +163,16 @@ func (repo *UserRepo) UserByID(ctx context.Context, id string) (*model.UserView, return usr_view_model.UserToModel(&userCopy), nil } +func (repo *UserRepo) UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { + return repo.getUserEvents(ctx, id, sequence) +} + func (repo *UserRepo) UserByLoginName(ctx context.Context, loginname string) (*model.UserView, error) { user, err := repo.View.UserByLoginName(loginname) if err != nil { return nil, err } - events, err := repo.UserEvents.UserEventsByID(ctx, user.ID, user.Sequence) + events, err := repo.getUserEvents(ctx, user.ID, user.Sequence) if err != nil { logging.Log("EVENT-PSoc3").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("error retrieving new events") return usr_view_model.UserToModel(user), nil @@ -182,19 +189,19 @@ func (repo *UserRepo) UserByLoginName(ctx context.Context, loginname string) (*m return usr_view_model.UserToModel(&userCopy), nil } func (repo *UserRepo) MyUserChanges(ctx context.Context, lastSequence uint64, limit uint64, sortAscending bool) (*model.UserChanges, error) { - changes, err := repo.UserEvents.UserChanges(ctx, authz.GetCtxData(ctx).UserID, lastSequence, limit, sortAscending) + changes, err := repo.getUserChanges(ctx, authz.GetCtxData(ctx).UserID, lastSequence, limit, sortAscending) if err != nil { return nil, err } for _, change := range changes.Changes { change.ModifierName = change.ModifierID - user, _ := repo.UserEvents.UserByID(ctx, change.ModifierID) + user, _ := repo.UserByID(ctx, change.ModifierID) if user != nil { - if user.Human != nil { + if user.HumanView != nil { change.ModifierName = user.DisplayName } - if user.Machine != nil { - change.ModifierName = user.Machine.Name + if user.MachineView != nil { + change.ModifierName = user.MachineView.Name } } } @@ -208,3 +215,55 @@ func (repo *UserRepo) MachineKeyByID(ctx context.Context, keyID string) (*key_mo } return key_view_model.AuthNKeyToModel(key), nil } + +func (r *UserRepo) getUserChanges(ctx context.Context, userID string, lastSequence uint64, limit uint64, sortAscending bool) (*model.UserChanges, error) { + query := usr_view.ChangesQuery(userID, lastSequence, limit, sortAscending) + + events, err := r.Eventstore.FilterEvents(ctx, query) + if err != nil { + logging.Log("EVENT-g9HCv").WithError(err).Warn("eventstore unavailable") + return nil, errors.ThrowInternal(err, "EVENT-htuG9", "Errors.Internal") + } + if len(events) == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-6cAxe", "Errors.User.NoChanges") + } + + result := make([]*model.UserChange, len(events)) + + for i, event := range events { + creationDate, err := ptypes.TimestampProto(event.CreationDate) + logging.Log("EVENT-8GTGS").OnError(err).Debug("unable to parse timestamp") + change := &model.UserChange{ + ChangeDate: creationDate, + EventType: event.Type.String(), + ModifierID: event.EditorUser, + Sequence: event.Sequence, + } + + //TODO: now all types should be unmarshalled, e.g. password + // if len(event.Data) != 0 { + // user := new(model.User) + // err := json.Unmarshal(event.Data, user) + // logging.Log("EVENT-Rkg7X").OnError(err).Debug("unable to unmarshal data") + // change.Data = user + // } + + result[i] = change + if lastSequence < event.Sequence { + lastSequence = event.Sequence + } + } + + return &model.UserChanges{ + Changes: result, + LastSequence: lastSequence, + }, nil +} + +func (r *UserRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) { + query, err := usr_view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + return r.Eventstore.FilterEvents(ctx, query) +} diff --git a/internal/auth/repository/eventsourcing/handler/application.go b/internal/auth/repository/eventsourcing/handler/application.go index 49fa802825..68dbf4a832 100644 --- a/internal/auth/repository/eventsourcing/handler/application.go +++ b/internal/auth/repository/eventsourcing/handler/application.go @@ -5,13 +5,15 @@ import ( "github.com/caos/logging" + "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" - "github.com/caos/zitadel/internal/project/repository/eventsourcing" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_model "github.com/caos/zitadel/internal/project/model" es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" view_model "github.com/caos/zitadel/internal/project/repository/view/model" ) @@ -21,14 +23,12 @@ const ( type Application struct { handler - projectEvents *proj_event.ProjectEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } -func newApplication(handler handler, projectEvents *proj_event.ProjectEventstore) *Application { +func newApplication(handler handler) *Application { h := &Application{ - handler: handler, - projectEvents: projectEvents, + handler: handler, } h.subscribe() @@ -66,14 +66,14 @@ func (a *Application) EventQuery() (*models.SearchQuery, error) { if err != nil { return nil, err } - return eventsourcing.ProjectQuery(sequence.CurrentSequence), nil + return proj_view.ProjectQuery(sequence.CurrentSequence), nil } func (a *Application) Reduce(event *models.Event) (err error) { app := new(view_model.ApplicationView) switch event.Type { case es_model.ApplicationAdded: - project, err := a.projectEvents.ProjectByID(context.Background(), event.AggregateID) + project, err := a.getProjectByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -139,3 +139,24 @@ func (a *Application) OnError(event *models.Event, spoolerError error) error { func (a *Application) OnSuccess() error { return spooler.HandleSuccess(a.view.UpdateApplicationSpoolerRunTimestamp) } + +func (a *Application) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) { + query, err := proj_view.ProjectByIDQuery(projID, 0) + if err != nil { + return nil, err + } + esProject := &es_model.Project{ + ObjectRoot: models.ObjectRoot{ + AggregateID: projID, + }, + } + err = es_sdk.Filter(ctx, a.Eventstore().FilterEvents, esProject.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esProject.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-DBf32", "Errors.Project.NotFound") + } + + return es_model.ProjectToModel(esProject), nil +} diff --git a/internal/auth/repository/eventsourcing/handler/handler.go b/internal/auth/repository/eventsourcing/handler/handler.go index b22983587d..8280619704 100644 --- a/internal/auth/repository/eventsourcing/handler/handler.go +++ b/internal/auth/repository/eventsourcing/handler/handler.go @@ -3,16 +3,11 @@ package handler import ( "time" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/query" - iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" - org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" - - "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" - "github.com/caos/zitadel/internal/config/types" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type Configs map[string]*Config @@ -34,42 +29,24 @@ func (h *handler) Eventstore() eventstore.Eventstore { return h.es } -type EventstoreRepos struct { - UserEvents *usr_event.UserEventstore - ProjectEvents *proj_event.ProjectEventstore - OrgEvents *org_events.OrgEventstore - IamEvents *iam_events.IAMEventstore -} - -func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []query.Handler { +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, systemDefaults sd.SystemDefaults) []query.Handler { return []query.Handler{ newUser( handler{view, bulkLimit, configs.cycleDuration("User"), errorCount, es}, - repos.OrgEvents, - repos.IamEvents, systemDefaults.IamID), newUserSession( - handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount, es}, - repos.UserEvents), + handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount, es}), newUserMembership( - handler{view, bulkLimit, configs.cycleDuration("UserMembership"), errorCount, es}, - repos.OrgEvents, - repos.ProjectEvents), + handler{view, bulkLimit, configs.cycleDuration("UserMembership"), errorCount, es}), newToken( - handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount, es}, - repos.ProjectEvents), + handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount, es}), newKey( handler{view, bulkLimit, configs.cycleDuration("Key"), errorCount, es}), - newApplication(handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount, es}, - repos.ProjectEvents), + newApplication(handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount, es}), newOrg( handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount, es}), newUserGrant( handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount, es}, - repos.ProjectEvents, - repos.UserEvents, - repos.OrgEvents, - repos.IamEvents, systemDefaults.IamID), newAuthNKeys( handler{view, bulkLimit, configs.cycleDuration("MachineKey"), errorCount, es}), @@ -79,20 +56,15 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount, es}), newIDPProvider( handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount, es}, - systemDefaults, - repos.IamEvents, - repos.OrgEvents), + systemDefaults), newExternalIDP( handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount, es}, - systemDefaults, - repos.IamEvents, - repos.OrgEvents), + systemDefaults), newPasswordComplexityPolicy( handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount, es}), newOrgIAMPolicy( handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount, es}), - newProjectRole(handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount, es}, - repos.ProjectEvents), + newProjectRole(handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount, es}), } } diff --git a/internal/auth/repository/eventsourcing/handler/idp_providers.go b/internal/auth/repository/eventsourcing/handler/idp_providers.go index 77e372cd41..a4468d4ae6 100644 --- a/internal/auth/repository/eventsourcing/handler/idp_providers.go +++ b/internal/auth/repository/eventsourcing/handler/idp_providers.go @@ -2,12 +2,16 @@ package handler import ( "context" + "github.com/caos/zitadel/internal/errors" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + org_model "github.com/caos/zitadel/internal/org/model" + "github.com/caos/zitadel/internal/org/repository/view" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/logging" "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/eventstore" - "github.com/caos/zitadel/internal/iam/repository/eventsourcing" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "github.com/caos/zitadel/internal/eventstore/models" @@ -26,22 +30,16 @@ const ( type IDPProvider struct { handler systemDefaults systemdefaults.SystemDefaults - iamEvents *eventsourcing.IAMEventstore - orgEvents *org_es.OrgEventstore subscription *eventstore.Subscription } func newIDPProvider( h handler, defaults systemdefaults.SystemDefaults, - iamEvents *eventsourcing.IAMEventstore, - orgEvents *org_es.OrgEventstore, ) *IDPProvider { idpProvider := &IDPProvider{ handler: h, systemDefaults: defaults, - iamEvents: iamEvents, - orgEvents: orgEvents, } idpProvider.subscribe() @@ -121,9 +119,9 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) { } config := new(iam_model.IDPConfig) if event.AggregateID == i.systemDefaults.IamID { - config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID) + config, err = i.getDefaultIDPConfig(context.TODO(), esConfig.IDPConfigID) } else { - config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID) + config, err = i.getOrgIDPConfig(context.TODO(), event.AggregateID, esConfig.IDPConfigID) } if err != nil { return err @@ -146,9 +144,9 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) { func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) { var config *iam_model.IDPConfig if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) { - config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, provider.IDPConfigID) + config, err = i.getDefaultIDPConfig(context.Background(), provider.IDPConfigID) } else { - config, err = i.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID) + config, err = i.getOrgIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID) } if err != nil { return err @@ -172,3 +170,64 @@ func (i *IDPProvider) OnError(event *models.Event, err error) error { func (i *IDPProvider) OnSuccess() error { return spooler.HandleSuccess(i.view.UpdateIDPProviderSpoolerRunTimestamp) } + +func (i *IDPProvider) getOrgIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := i.getOrgByID(ctx, aggregateID) + if err != nil { + return nil, err + } + if _, i := existing.GetIDP(idpConfigID); i != nil { + return i, nil + } + return nil, errors.ThrowNotFound(nil, "EVENT-2m9fS", "Errors.Org.IdpNotExisting") +} + +func (i *IDPProvider) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, i.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-6m0fS", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *IDPProvider) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &model.IAM{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && errors.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return model.IAMToModel(iam), nil +} + +func (u *IDPProvider) getDefaultIDPConfig(ctx context.Context, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if _, existingIDP := existing.GetIDP(idpConfigID); existingIDP != nil { + return existingIDP, nil + } + return nil, errors.ThrowNotFound(nil, "EVENT-49O0f", "Errors.IAM.IdpNotExisting") +} diff --git a/internal/auth/repository/eventsourcing/handler/org.go b/internal/auth/repository/eventsourcing/handler/org.go index 5a92125004..57272fb08c 100644 --- a/internal/auth/repository/eventsourcing/handler/org.go +++ b/internal/auth/repository/eventsourcing/handler/org.go @@ -2,12 +2,12 @@ package handler import ( "github.com/caos/logging" + "github.com/caos/zitadel/internal/org/repository/view" "github.com/caos/zitadel/internal/eventstore" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" org_model "github.com/caos/zitadel/internal/org/repository/view/model" ) @@ -61,7 +61,7 @@ func (o *Org) EventQuery() (*es_models.SearchQuery, error) { if err != nil { return nil, err } - return eventsourcing.OrgQuery(sequence.CurrentSequence), nil + return view.OrgQuery(sequence.CurrentSequence), nil } func (o *Org) Reduce(event *es_models.Event) (err error) { diff --git a/internal/auth/repository/eventsourcing/handler/project_role.go b/internal/auth/repository/eventsourcing/handler/project_role.go index 518516e7bb..13940d45a5 100644 --- a/internal/auth/repository/eventsourcing/handler/project_role.go +++ b/internal/auth/repository/eventsourcing/handler/project_role.go @@ -7,9 +7,8 @@ import ( es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" - proj_events "github.com/caos/zitadel/internal/project/repository/eventsourcing" "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" view_model "github.com/caos/zitadel/internal/project/repository/view/model" ) @@ -19,17 +18,14 @@ const ( type ProjectRole struct { handler - projectEvents *proj_event.ProjectEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } func newProjectRole( handler handler, - projectEvents *proj_events.ProjectEventstore, ) *ProjectRole { h := &ProjectRole{ - handler: handler, - projectEvents: projectEvents, + handler: handler, } h.subscribe() @@ -67,7 +63,7 @@ func (p *ProjectRole) EventQuery() (*es_models.SearchQuery, error) { if err != nil { return nil, err } - return proj_events.ProjectQuery(sequence.CurrentSequence), nil + return proj_view.ProjectQuery(sequence.CurrentSequence), nil } func (p *ProjectRole) Reduce(event *es_models.Event) (err error) { diff --git a/internal/auth/repository/eventsourcing/handler/token.go b/internal/auth/repository/eventsourcing/handler/token.go index 1b28d5fd1d..b35893893b 100644 --- a/internal/auth/repository/eventsourcing/handler/token.go +++ b/internal/auth/repository/eventsourcing/handler/token.go @@ -5,15 +5,18 @@ import ( "encoding/json" "github.com/caos/logging" + "k8s.io/apimachinery/pkg/api/errors" caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_model "github.com/caos/zitadel/internal/project/model" project_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) @@ -24,17 +27,14 @@ const ( type Token struct { handler - ProjectEvents *proj_event.ProjectEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } func newToken( handler handler, - projectEvents *proj_event.ProjectEventstore, ) *Token { h := &Token{ - handler: handler, - ProjectEvents: projectEvents, + handler: handler, } h.subscribe() @@ -118,7 +118,7 @@ func (t *Token) Reduce(event *models.Event) (err error) { return t.view.DeleteApplicationTokens(event, application.AppID) case project_es_model.ProjectDeactivated, project_es_model.ProjectRemoved: - project, err := t.ProjectEvents.ProjectByID(context.Background(), event.AggregateID) + project, err := t.getProjectByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -158,3 +158,24 @@ func applicationFromSession(event *models.Event) (*project_es_model.Application, func (t *Token) OnSuccess() error { return spooler.HandleSuccess(t.view.UpdateTokenSpoolerRunTimestamp) } + +func (t *Token) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) { + query, err := proj_view.ProjectByIDQuery(projID, 0) + if err != nil { + return nil, err + } + esProject := &project_es_model.Project{ + ObjectRoot: models.ObjectRoot{ + AggregateID: projID, + }, + } + err = es_sdk.Filter(ctx, t.Eventstore().FilterEvents, esProject.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esProject.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-Dsdw2", "Errors.Project.NotFound") + } + + return project_es_model.ProjectToModel(esProject), nil +} diff --git a/internal/auth/repository/eventsourcing/handler/user.go b/internal/auth/repository/eventsourcing/handler/user.go index d87f8c3a2b..22bc9fed16 100644 --- a/internal/auth/repository/eventsourcing/handler/user.go +++ b/internal/auth/repository/eventsourcing/handler/user.go @@ -2,19 +2,23 @@ package handler import ( "context" - "github.com/caos/logging" + "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" - iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + iam_model "github.com/caos/zitadel/internal/iam/model" + "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" org_model "github.com/caos/zitadel/internal/org/model" - org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/org/repository/view" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/user/repository/view/model" + "github.com/caos/zitadel/internal/v2/domain" ) const ( @@ -23,23 +27,17 @@ const ( type User struct { handler - orgEvents *org_events.OrgEventstore - iamEvents *iam_es.IAMEventstore iamID string subscription *eventstore.Subscription } func newUser( handler handler, - orgEvents *org_events.OrgEventstore, - iamEvents *iam_es.IAMEventstore, iamID string, ) *User { h := &User{ - handler: handler, - orgEvents: orgEvents, - iamEvents: iamEvents, - iamID: iamID, + handler: handler, + iamID: iamID, } h.subscribe() @@ -169,13 +167,13 @@ func (u *User) ProcessUser(event *models.Event) (err error) { } func (u *User) fillLoginNames(user *view_model.UserView) (err error) { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(user.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), user.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.iamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -201,13 +199,13 @@ func (u *User) ProcessOrg(event *models.Event) (err error) { } func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), event.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.iamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -223,13 +221,13 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error { } func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), event.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.iamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -255,3 +253,53 @@ func (u *User) OnError(event *models.Event, err error) error { func (u *User) OnSuccess() error { return spooler.HandleSuccess(u.view.UpdateUserSpoolerRunTimestamp) } + +func (u *User) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-3m9vs", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *User) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &model.IAM{ + ObjectRoot: models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && errors.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return model.IAMToModel(iam), nil +} + +func (u *User) getDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicy, error) { + existingIAM, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if existingIAM.DefaultOrgIAMPolicy == nil { + return nil, errors.ThrowNotFound(nil, "EVENT-3m9fs", "Errors.IAM.OrgIAMPolicy.NotExisting") + } + return existingIAM.DefaultOrgIAMPolicy, nil +} diff --git a/internal/auth/repository/eventsourcing/handler/user_external_idps.go b/internal/auth/repository/eventsourcing/handler/user_external_idps.go index 2744137a79..7196c98b89 100644 --- a/internal/auth/repository/eventsourcing/handler/user_external_idps.go +++ b/internal/auth/repository/eventsourcing/handler/user_external_idps.go @@ -2,7 +2,6 @@ package handler import ( "context" - "github.com/caos/logging" "github.com/caos/zitadel/internal/config/systemdefaults" caos_errs "github.com/caos/zitadel/internal/errors" @@ -10,15 +9,18 @@ import ( "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" iam_model "github.com/caos/zitadel/internal/iam/model" - "github.com/caos/zitadel/internal/iam/repository/eventsourcing" iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" + org_model "github.com/caos/zitadel/internal/org/model" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/org/repository/view" "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model" + "github.com/caos/zitadel/internal/v2/domain" ) const ( @@ -28,22 +30,16 @@ const ( type ExternalIDP struct { handler systemDefaults systemdefaults.SystemDefaults - iamEvents *eventsourcing.IAMEventstore - orgEvents *org_es.OrgEventstore subscription *eventstore.Subscription } func newExternalIDP( handler handler, defaults systemdefaults.SystemDefaults, - iamEvents *eventsourcing.IAMEventstore, - orgEvents *org_es.OrgEventstore, ) *ExternalIDP { h := &ExternalIDP{ handler: handler, systemDefaults: defaults, - iamEvents: iamEvents, - orgEvents: orgEvents, } h.subscribe() @@ -137,9 +133,9 @@ func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) { return err } if event.AggregateType == iam_es_model.IAMAggregate { - config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) + config, err = i.getDefaultIDPConfig(context.Background(), configView.IDPConfigID) } else { - config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) + config, err = i.getOrgIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) } if err != nil { return err @@ -155,9 +151,9 @@ func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) { } func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error { - config, err := i.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID) + config, err := i.getOrgIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID) if caos_errs.IsNotFound(err) { - config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, externalIDP.IDPConfigID) + config, err = i.getDefaultIDPConfig(context.Background(), externalIDP.IDPConfigID) } if err != nil { return err @@ -178,3 +174,64 @@ func (i *ExternalIDP) OnError(event *models.Event, err error) error { func (i *ExternalIDP) OnSuccess() error { return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp) } + +func (i *ExternalIDP) getOrgIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := i.getOrgByID(ctx, aggregateID) + if err != nil { + return nil, err + } + if _, i := existing.GetIDP(idpConfigID); i != nil { + return i, nil + } + return nil, caos_errs.ThrowNotFound(nil, "EVENT-2m9fS", "Errors.Org.IdpNotExisting") +} + +func (i *ExternalIDP) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, i.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-6m0fS", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *ExternalIDP) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &iam_es_model.IAM{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return iam_es_model.IAMToModel(iam), nil +} + +func (u *ExternalIDP) getDefaultIDPConfig(ctx context.Context, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if _, existingIDP := existing.GetIDP(idpConfigID); existingIDP != nil { + return existingIDP, nil + } + return nil, caos_errs.ThrowNotFound(nil, "EVENT-mmk5d", "Errors.IAM.IdpNotExisting") +} diff --git a/internal/auth/repository/eventsourcing/handler/user_grant.go b/internal/auth/repository/eventsourcing/handler/user_grant.go index cc1fd98b16..c734e1f6e3 100644 --- a/internal/auth/repository/eventsourcing/handler/user_grant.go +++ b/internal/auth/repository/eventsourcing/handler/user_grant.go @@ -2,8 +2,16 @@ package handler import ( "context" + iam_model "github.com/caos/zitadel/internal/iam/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" "strings" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + org_view "github.com/caos/zitadel/internal/org/repository/view" + proj_view "github.com/caos/zitadel/internal/project/repository/view" + "github.com/caos/zitadel/internal/user/repository/view" + "github.com/caos/zitadel/internal/user/repository/view/model" + "github.com/caos/logging" "github.com/caos/zitadel/internal/errors" @@ -13,16 +21,12 @@ import ( es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" org_model "github.com/caos/zitadel/internal/org/model" - org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" proj_model "github.com/caos/zitadel/internal/project/model" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" usr_model "github.com/caos/zitadel/internal/user/model" - usr_events "github.com/caos/zitadel/internal/user/repository/eventsourcing" usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" grant_es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model" @@ -35,30 +39,18 @@ const ( type UserGrant struct { handler - projectEvents *proj_event.ProjectEventstore - userEvents *usr_events.UserEventstore - orgEvents *org_events.OrgEventstore - iamEvents *iam_events.IAMEventstore - iamID string - iamProjectID string - subscription *eventstore.Subscription + iamID string + iamProjectID string + subscription *eventstore.Subscription } func newUserGrant( handler handler, - projectEvents *proj_event.ProjectEventstore, - userEvents *usr_events.UserEventstore, - orgEvents *org_events.OrgEventstore, - iamEvents *iam_events.IAMEventstore, iamID string, ) *UserGrant { h := &UserGrant{ - handler: handler, - projectEvents: projectEvents, - userEvents: userEvents, - orgEvents: orgEvents, - iamEvents: iamEvents, - iamID: iamID, + handler: handler, + iamID: iamID, } h.subscribe() @@ -166,7 +158,7 @@ func (u *UserGrant) processUser(event *models.Event) (err error) { if len(grants) == 0 { return u.view.ProcessedUserGrantSequence(event) } - user, err := u.userEvents.UserByID(context.Background(), event.AggregateID) + user, err := u.getUserByID(event.AggregateID) if err != nil { return err } @@ -186,7 +178,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) { if err != nil { return err } - project, err := u.projectEvents.ProjectByID(context.Background(), event.AggregateID) + project, err := u.getProjectByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -348,7 +340,7 @@ func (u *UserGrant) setIamProjectID() error { if u.iamProjectID != "" { return nil } - iam, err := u.iamEvents.IAMByID(context.Background(), u.iamID) + iam, err := u.getIAMByID(context.Background()) if err != nil { return err } @@ -361,18 +353,18 @@ func (u *UserGrant) setIamProjectID() error { } func (u *UserGrant) fillData(grant *view_model.UserGrantView, resourceOwner string) (err error) { - user, err := u.userEvents.UserByID(context.Background(), grant.UserID) + user, err := u.getUserByID(grant.UserID) if err != nil { return err } u.fillUserData(grant, user) - project, err := u.projectEvents.ProjectByID(context.Background(), grant.ProjectID) + project, err := u.getProjectByID(context.Background(), grant.ProjectID) if err != nil { return err } u.fillProjectData(grant, project) - org, err := u.orgEvents.OrgByID(context.TODO(), org_model.NewOrg(resourceOwner)) + org, err := u.getOrgByID(context.TODO(), resourceOwner) if err != nil { return err } @@ -380,16 +372,16 @@ func (u *UserGrant) fillData(grant *view_model.UserGrantView, resourceOwner stri return nil } -func (u *UserGrant) fillUserData(grant *view_model.UserGrantView, user *usr_model.User) { +func (u *UserGrant) fillUserData(grant *view_model.UserGrantView, user *model.UserView) { grant.UserName = user.UserName - if user.Human != nil { + if user.HumanView != nil { grant.FirstName = user.FirstName grant.LastName = user.LastName grant.DisplayName = user.FirstName + " " + user.LastName - grant.Email = user.EmailAddress + grant.Email = user.Email } - if user.Machine != nil { - grant.DisplayName = user.Machine.Name + if user.MachineView != nil { + grant.DisplayName = user.MachineView.Name } } @@ -416,3 +408,96 @@ func (u *UserGrant) OnError(event *models.Event, err error) error { func (u *UserGrant) OnSuccess() error { return spooler.HandleSuccess(u.view.UpdateUserGrantSpoolerRunTimestamp) } + +func (u *UserGrant) getUserByID(userID string) (*model.UserView, error) { + user, usrErr := u.view.UserByID(userID) + if usrErr != nil && !caos_errs.IsNotFound(usrErr) { + return nil, usrErr + } + if user == nil { + user = &model.UserView{} + } + events, err := u.getUserEvents(userID, user.Sequence) + if err != nil { + return user, usrErr + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return user, nil + } + } + if userCopy.State == int32(usr_model.UserStateDeleted) { + return nil, caos_errs.ThrowNotFound(nil, "HANDLER-m9dos", "Errors.User.NotFound") + } + return &userCopy, nil +} + +func (u *UserGrant) getUserEvents(userID string, sequence uint64) ([]*models.Event, error) { + query, err := view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + + return u.es.FilterEvents(context.Background(), query) +} + +func (u *UserGrant) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := org_view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-3m9vs", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *UserGrant) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) { + query, err := proj_view.ProjectByIDQuery(projID, 0) + if err != nil { + return nil, err + } + esProject := &proj_es_model.Project{ + ObjectRoot: models.ObjectRoot{ + AggregateID: projID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esProject.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esProject.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-DAfng", "Errors.Project.NotFound") + } + + return proj_es_model.ProjectToModel(esProject), nil +} + +func (u *UserGrant) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &iam_es_model.IAM{ + ObjectRoot: models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && errors.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return iam_es_model.IAMToModel(iam), nil +} diff --git a/internal/auth/repository/eventsourcing/handler/user_membership.go b/internal/auth/repository/eventsourcing/handler/user_membership.go index ef76e28955..654c6387d5 100644 --- a/internal/auth/repository/eventsourcing/handler/user_membership.go +++ b/internal/auth/repository/eventsourcing/handler/user_membership.go @@ -4,17 +4,21 @@ import ( "context" "github.com/caos/logging" + + "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" org_model "github.com/caos/zitadel/internal/org/model" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + org_view "github.com/caos/zitadel/internal/org/repository/view" + proj_model "github.com/caos/zitadel/internal/project/model" proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" usr_model "github.com/caos/zitadel/internal/user/model" "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" usr_es_model "github.com/caos/zitadel/internal/user/repository/view/model" @@ -26,20 +30,14 @@ const ( type UserMembership struct { handler - orgEvents *org_event.OrgEventstore - projectEvents *proj_event.ProjectEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } func newUserMembership( handler handler, - orgEvents *org_event.OrgEventstore, - projectEvents *proj_event.ProjectEventstore, ) *UserMembership { h := &UserMembership{ - handler: handler, - orgEvents: orgEvents, - projectEvents: projectEvents, + handler: handler, } h.subscribe() @@ -156,7 +154,7 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) { } func (m *UserMembership) fillOrgName(member *usr_es_model.UserMembershipView) (err error) { - org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(member.ResourceOwner)) + org, err := m.getOrgByID(context.Background(), member.ResourceOwner) if err != nil { return err } @@ -168,7 +166,7 @@ func (m *UserMembership) fillOrgName(member *usr_es_model.UserMembershipView) (e } func (m *UserMembership) updateOrgName(event *models.Event) error { - org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.AggregateID)) + org, err := m.getOrgByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -231,7 +229,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) { } func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) { - project, err := m.projectEvents.ProjectByID(context.Background(), member.AggregateID) + project, err := m.getProjectByID(context.Background(), member.AggregateID) if err != nil { return err } @@ -240,7 +238,7 @@ func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembers } func (m *UserMembership) updateProjectDisplayName(event *models.Event) error { - project, err := m.projectEvents.ProjectByID(context.Background(), event.AggregateID) + project, err := m.getProjectByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -272,3 +270,45 @@ func (m *UserMembership) OnError(event *models.Event, err error) error { func (m *UserMembership) OnSuccess() error { return spooler.HandleSuccess(m.view.UpdateUserMembershipSpoolerRunTimestamp) } + +func (u *UserMembership) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := org_view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-3m9vs", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *UserMembership) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) { + query, err := proj_view.ProjectByIDQuery(projID, 0) + if err != nil { + return nil, err + } + esProject := &proj_es_model.Project{ + ObjectRoot: models.ObjectRoot{ + AggregateID: projID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esProject.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esProject.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-Dbfw2", "Errors.Project.NotFound") + } + + return proj_es_model.ProjectToModel(esProject), nil +} diff --git a/internal/auth/repository/eventsourcing/handler/user_session.go b/internal/auth/repository/eventsourcing/handler/user_session.go index ac099cf4bd..17c8ec594c 100644 --- a/internal/auth/repository/eventsourcing/handler/user_session.go +++ b/internal/auth/repository/eventsourcing/handler/user_session.go @@ -8,9 +8,8 @@ import ( "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - "github.com/caos/zitadel/internal/user/repository/eventsourcing" - user_events "github.com/caos/zitadel/internal/user/repository/eventsourcing" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/user/repository/view" view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) @@ -20,17 +19,14 @@ const ( type UserSession struct { handler - userEvents *user_events.UserEventstore subscription *eventstore.Subscription } func newUserSession( handler handler, - userEvents *user_events.UserEventstore, ) *UserSession { h := &UserSession{ - handler: handler, - userEvents: userEvents, + handler: handler, } h.subscribe() @@ -68,7 +64,7 @@ func (u *UserSession) EventQuery() (*models.SearchQuery, error) { if err != nil { return nil, err } - return eventsourcing.UserQuery(sequence.CurrentSequence), nil + return view.UserQuery(sequence.CurrentSequence), nil } func (u *UserSession) Reduce(event *models.Event) (err error) { diff --git a/internal/auth/repository/eventsourcing/repository.go b/internal/auth/repository/eventsourcing/repository.go index 28cac3540f..1719544645 100644 --- a/internal/auth/repository/eventsourcing/repository.go +++ b/internal/auth/repository/eventsourcing/repository.go @@ -5,7 +5,6 @@ import ( "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/eventstore" - "github.com/caos/zitadel/internal/auth/repository/eventsourcing/handler" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/spooler" auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" "github.com/caos/zitadel/internal/auth_request/repository/cache" @@ -15,11 +14,7 @@ import ( "github.com/caos/zitadel/internal/crypto" es_int "github.com/caos/zitadel/internal/eventstore" es_spol "github.com/caos/zitadel/internal/eventstore/spooler" - es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "github.com/caos/zitadel/internal/id" - es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" - es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing" - es_user "github.com/caos/zitadel/internal/user/repository/eventsourcing" "github.com/caos/zitadel/internal/v2/command" "github.com/caos/zitadel/internal/v2/query" ) @@ -34,7 +29,8 @@ type Config struct { } type EsRepository struct { - spooler *es_spol.Spooler + spooler *es_spol.Spooler + Eventstore es_int.Eventstore eventstore.UserRepo eventstore.AuthRequestRepo eventstore.TokenRepo @@ -69,73 +65,36 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co return nil, err } - user, err := es_user.StartUser( - es_user.UserConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, - systemDefaults, - ) - if err != nil { - return nil, err - } authReq, err := cache.Start(conf.AuthRequest) if err != nil { return nil, err } - iam, err := es_iam.StartIAM( - es_iam.IAMConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, - systemDefaults, - ) - if err != nil { - return nil, err - } - - project, err := es_proj.StartProject( - es_proj.ProjectConfig{ - Cache: conf.Eventstore.Cache, - Eventstore: es, - }, - systemDefaults, - ) - if err != nil { - return nil, err - } - iamV2Query, err := query.StartQuerySide(&query.Config{Eventstore: esV2, SystemDefaults: systemDefaults}) if err != nil { return nil, err } - org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es, IAMDomain: conf.Domain}, systemDefaults) - - repos := handler.EventstoreRepos{UserEvents: user, ProjectEvents: project, OrgEvents: org, IamEvents: iam} - spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos, systemDefaults) + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults) + userRepo := eventstore.UserRepo{ + SearchLimit: conf.SearchLimit, + Eventstore: es, + View: view, + SystemDefaults: systemDefaults, + } return &EsRepository{ spool, - eventstore.UserRepo{ - SearchLimit: conf.SearchLimit, - Eventstore: es, - UserEvents: user, - OrgEvents: org, - View: view, - SystemDefaults: systemDefaults, - }, + es, + userRepo, eventstore.AuthRequestRepo{ Command: command, - UserEvents: user, - OrgEvents: org, AuthRequests: authReq, View: view, UserSessionViewProvider: view, UserViewProvider: view, UserCommandProvider: command, - UserEventProvider: user, + UserEventProvider: &userRepo, OrgViewProvider: view, IDPProviderViewProvider: view, LoginPolicyViewProvider: view, @@ -149,18 +108,16 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co IAMID: systemDefaults.IamID, }, eventstore.TokenRepo{ - UserEvents: user, - ProjectEvents: project, - View: view, + Eventstore: es, + View: view, }, eventstore.KeyRepository{ View: view, SigningKeyRotation: systemDefaults.KeyConfig.SigningKeyRotation.Duration, }, eventstore.ApplicationRepo{ - Commands: command, - View: view, - ProjectEvents: project, + Commands: command, + View: view, }, eventstore.UserSessionRepo{ @@ -176,8 +133,6 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co eventstore.OrgRepository{ SearchLimit: conf.SearchLimit, View: view, - OrgEventstore: org, - UserEventstore: user, SystemDefaults: systemDefaults, }, eventstore.IAMRepository{ diff --git a/internal/auth/repository/eventsourcing/spooler/spooler.go b/internal/auth/repository/eventsourcing/spooler/spooler.go index 7fc95d4247..2080d65f61 100644 --- a/internal/auth/repository/eventsourcing/spooler/spooler.go +++ b/internal/auth/repository/eventsourcing/spooler/spooler.go @@ -19,12 +19,12 @@ type SpoolerConfig struct { Handlers handler.Configs } -func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, client *sql.DB, repos handler.EventstoreRepos, systemDefaults sd.SystemDefaults) *spooler.Spooler { +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, client *sql.DB, systemDefaults sd.SystemDefaults) *spooler.Spooler { spoolerConfig := spooler.Config{ Eventstore: es, Locker: &locker{dbClient: client}, ConcurrentWorkers: c.ConcurrentWorkers, - ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, repos, systemDefaults), + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, systemDefaults), } spool := spoolerConfig.New() spool.Start() diff --git a/internal/auth/repository/user.go b/internal/auth/repository/user.go index 90bad714e4..91cc618366 100644 --- a/internal/auth/repository/user.go +++ b/internal/auth/repository/user.go @@ -11,8 +11,6 @@ import ( type UserRepository interface { myUserRepo - GetPasswordless(ctx context.Context, id string) ([]*model.WebAuthNToken, error) - UserSessionUserIDsByAgentID(ctx context.Context, agentID string) ([]string, error) UserByID(ctx context.Context, userID string) (*model.UserView, error) @@ -36,7 +34,7 @@ type myUserRepo interface { MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, error) - GetMyPasswordless(ctx context.Context) ([]*model.WebAuthNToken, error) + GetMyPasswordless(ctx context.Context) ([]*model.WebAuthNView, error) MyUserChanges(ctx context.Context, lastSequence uint64, limit uint64, sortAscending bool) (*model.UserChanges, error) diff --git a/internal/authz/repository/eventsourcing/eventstore/iam.go b/internal/authz/repository/eventsourcing/eventstore/iam.go index 78c2f1c1e3..505b8e891a 100644 --- a/internal/authz/repository/eventsourcing/eventstore/iam.go +++ b/internal/authz/repository/eventsourcing/eventstore/iam.go @@ -5,18 +5,16 @@ import ( "github.com/caos/zitadel/internal/v2/query" "github.com/caos/zitadel/internal/iam/model" - iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" ) type IamRepo struct { - IAMID string - IAMEvents *iam_event.IAMEventstore + IAMID string IAMV2Query *query.QuerySide } func (repo *IamRepo) Health(ctx context.Context) error { - return repo.IAMEvents.Health(ctx) + return nil } func (repo *IamRepo) IamByID(ctx context.Context) (*model.IAM, error) { diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go index 86bbdf476f..f9bc9b7304 100644 --- a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -2,28 +2,33 @@ package eventstore import ( "context" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_model "github.com/caos/zitadel/internal/iam/model" + iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + "github.com/caos/zitadel/internal/v2/domain" + "k8s.io/apimachinery/pkg/api/errors" "strings" "time" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + usr_view "github.com/caos/zitadel/internal/user/repository/view" + "github.com/caos/logging" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" "github.com/caos/zitadel/internal/crypto" caos_errs "github.com/caos/zitadel/internal/errors" - iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" "github.com/caos/zitadel/internal/telemetry/tracing" usr_model "github.com/caos/zitadel/internal/user/model" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" "github.com/caos/zitadel/internal/user/repository/view/model" ) type TokenVerifierRepo struct { TokenVerificationKey [32]byte IAMID string - IAMEvents *iam_event.IAMEventstore - ProjectEvents *proj_event.ProjectEventstore - UserEvents *usr_event.UserEventstore + Eventstore eventstore.Eventstore View *view.View } @@ -38,7 +43,7 @@ func (repo *TokenVerifierRepo) TokenByID(ctx context.Context, tokenID, userID st token.UserID = userID } - events, esErr := repo.UserEvents.UserEventsByID(ctx, userID, token.Sequence) + events, esErr := repo.getUserEvents(ctx, userID, token.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-4T90g", "Errors.Token.NotFound") } @@ -110,7 +115,7 @@ func (repo *TokenVerifierRepo) VerifierClientID(ctx context.Context, appName str ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - iam, err := repo.IAMEvents.IAMByID(ctx, repo.IAMID) + iam, err := repo.getIAMByID(ctx) if err != nil { return "", err } @@ -120,3 +125,28 @@ func (repo *TokenVerifierRepo) VerifierClientID(ctx context.Context, appName str } return app.OIDCClientID, nil } + +func (r *TokenVerifierRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) { + query, err := usr_view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + return r.Eventstore.FilterEvents(ctx, query) +} + +func (u *TokenVerifierRepo) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &iam_es_model.IAM{ + ObjectRoot: models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore.FilterEvents, iam.AppendEvents, query) + if err != nil && errors.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return iam_es_model.IAMToModel(iam), nil +} diff --git a/internal/authz/repository/eventsourcing/eventstore/user_grant.go b/internal/authz/repository/eventsourcing/eventstore/user_grant.go index 28370187ac..0f0e579c7c 100644 --- a/internal/authz/repository/eventsourcing/eventstore/user_grant.go +++ b/internal/authz/repository/eventsourcing/eventstore/user_grant.go @@ -2,11 +2,17 @@ package eventstore import ( "context" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_model "github.com/caos/zitadel/internal/iam/model" + iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + "k8s.io/apimachinery/pkg/api/errors" "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" caos_errs "github.com/caos/zitadel/internal/errors" - iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" global_model "github.com/caos/zitadel/internal/model" user_model "github.com/caos/zitadel/internal/user/model" user_view_model "github.com/caos/zitadel/internal/user/repository/view/model" @@ -19,7 +25,7 @@ type UserGrantRepo struct { IamID string IamProjectID string Auth authz.Config - IamEvents *iam_event.IAMEventstore + Eventstore eventstore.Eventstore } func (repo *UserGrantRepo) Health() error { @@ -94,7 +100,7 @@ func (repo *UserGrantRepo) FillIamProjectID(ctx context.Context) error { if repo.IamProjectID != "" { return nil } - iam, err := repo.IamEvents.IAMByID(ctx, repo.IamID) + iam, err := repo.getIAMByID(ctx) if err != nil { return err } @@ -118,6 +124,23 @@ func (repo *UserGrantRepo) mapRoleToPermission(permissions *grant_model.Permissi return permissions } +func (u *UserGrantRepo) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &iam_es_model.IAM{ + ObjectRoot: models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore.FilterEvents, iam.AppendEvents, query) + if err != nil && errors.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return iam_es_model.IAMToModel(iam), nil +} + func userMembershipToMembership(membership *user_view_model.UserMembershipView) *authz.Membership { return &authz.Membership{ MemberType: authz.MemberType(membership.MemberType), diff --git a/internal/authz/repository/eventsourcing/handler/application.go b/internal/authz/repository/eventsourcing/handler/application.go index bb7bda0585..45203b1259 100644 --- a/internal/authz/repository/eventsourcing/handler/application.go +++ b/internal/authz/repository/eventsourcing/handler/application.go @@ -7,8 +7,8 @@ import ( "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - "github.com/caos/zitadel/internal/project/repository/eventsourcing" es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/project/repository/view" view_model "github.com/caos/zitadel/internal/project/repository/view/model" ) @@ -61,7 +61,7 @@ func (a *Application) EventQuery() (*models.SearchQuery, error) { if err != nil { return nil, err } - return eventsourcing.ProjectQuery(sequence.CurrentSequence), nil + return view.ProjectQuery(sequence.CurrentSequence), nil } func (a *Application) Reduce(event *models.Event) (err error) { diff --git a/internal/authz/repository/eventsourcing/handler/handler.go b/internal/authz/repository/eventsourcing/handler/handler.go index b18098de16..f27207fd93 100644 --- a/internal/authz/repository/eventsourcing/handler/handler.go +++ b/internal/authz/repository/eventsourcing/handler/handler.go @@ -1,7 +1,6 @@ package handler import ( - "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "time" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" @@ -9,8 +8,6 @@ import ( "github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/query" - org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" - project_events "github.com/caos/zitadel/internal/project/repository/eventsourcing" ) type Configs map[string]*Config @@ -32,22 +29,13 @@ func (h *handler) Eventstore() eventstore.Eventstore { return h.es } -type EventstoreRepos struct { - IAMEvents *eventsourcing.IAMEventstore - OrgEvents *org_events.OrgEventstore - ProjectEvents *project_events.ProjectEventstore -} - -func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []query.Handler { +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, systemDefaults sd.SystemDefaults) []query.Handler { return []query.Handler{ newUserGrant( handler{view, bulkLimit, configs.cycleDuration("UserGrants"), errorCount, es}, - repos.IAMEvents, systemDefaults.IamID), newUserMembership( - handler{view, bulkLimit, configs.cycleDuration("UserMemberships"), errorCount, es}, - repos.OrgEvents, - repos.ProjectEvents), + handler{view, bulkLimit, configs.cycleDuration("UserMemberships"), errorCount, es}), newApplication( handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount, es}), newOrg( diff --git a/internal/authz/repository/eventsourcing/handler/org.go b/internal/authz/repository/eventsourcing/handler/org.go index 184316eec9..08321e37af 100644 --- a/internal/authz/repository/eventsourcing/handler/org.go +++ b/internal/authz/repository/eventsourcing/handler/org.go @@ -2,12 +2,12 @@ package handler import ( "github.com/caos/logging" + "github.com/caos/zitadel/internal/org/repository/view" "github.com/caos/zitadel/internal/eventstore" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" org_model "github.com/caos/zitadel/internal/org/repository/view/model" ) @@ -61,7 +61,7 @@ func (o *Org) EventQuery() (*es_models.SearchQuery, error) { if err != nil { return nil, err } - return eventsourcing.OrgQuery(sequence.CurrentSequence), nil + return view.OrgQuery(sequence.CurrentSequence), nil } func (o *Org) Reduce(event *es_models.Event) error { diff --git a/internal/authz/repository/eventsourcing/handler/user_grant.go b/internal/authz/repository/eventsourcing/handler/user_grant.go index 78c894ea75..4911a1f76b 100644 --- a/internal/authz/repository/eventsourcing/handler/user_grant.go +++ b/internal/authz/repository/eventsourcing/handler/user_grant.go @@ -2,6 +2,9 @@ package handler import ( "context" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_model "github.com/caos/zitadel/internal/iam/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" "strings" "github.com/caos/logging" @@ -13,7 +16,6 @@ import ( es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" @@ -27,7 +29,6 @@ const ( type UserGrant struct { handler - iamEvents *iam_events.IAMEventstore iamID string iamProjectID string subscription *eventstore.Subscription @@ -35,13 +36,11 @@ type UserGrant struct { func newUserGrant( handler handler, - iamEvents *iam_events.IAMEventstore, iamID string, ) *UserGrant { h := &UserGrant{ - handler: handler, - iamEvents: iamEvents, - iamID: iamID, + handler: handler, + iamID: iamID, } h.subscribe() @@ -258,7 +257,7 @@ func (u *UserGrant) setIamProjectID() error { if u.iamProjectID != "" { return nil } - iam, err := u.iamEvents.IAMByID(context.Background(), u.iamID) + iam, err := u.getIAMByID(context.Background()) if err != nil { return err } @@ -277,3 +276,20 @@ func (u *UserGrant) OnError(event *models.Event, err error) error { func (u *UserGrant) OnSuccess() error { return spooler.HandleSuccess(u.view.UpdateUserGrantSpoolerRunTimestamp) } + +func (u *UserGrant) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &iam_es_model.IAM{ + ObjectRoot: models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && errors.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return iam_es_model.IAMToModel(iam), nil +} diff --git a/internal/authz/repository/eventsourcing/handler/user_membership.go b/internal/authz/repository/eventsourcing/handler/user_membership.go index 4e1b5a81cf..4081d58e57 100644 --- a/internal/authz/repository/eventsourcing/handler/user_membership.go +++ b/internal/authz/repository/eventsourcing/handler/user_membership.go @@ -4,17 +4,21 @@ import ( "context" "github.com/caos/logging" + + "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" org_model "github.com/caos/zitadel/internal/org/model" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + org_view "github.com/caos/zitadel/internal/org/repository/view" + proj_model "github.com/caos/zitadel/internal/project/model" proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" usr_model "github.com/caos/zitadel/internal/user/model" "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" usr_es_model "github.com/caos/zitadel/internal/user/repository/view/model" @@ -26,20 +30,14 @@ const ( type UserMembership struct { handler - orgEvents *org_event.OrgEventstore - projectEvents *proj_event.ProjectEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } func newUserMembership( handler handler, - orgEvents *org_event.OrgEventstore, - projectEvents *proj_event.ProjectEventstore, ) *UserMembership { h := &UserMembership{ - handler: handler, - orgEvents: orgEvents, - projectEvents: projectEvents, + handler: handler, } h.subscribe() @@ -156,7 +154,7 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) { } func (m *UserMembership) fillOrgName(member *usr_es_model.UserMembershipView) (err error) { - org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(member.ResourceOwner)) + org, err := m.getOrgByID(context.Background(), member.ResourceOwner) if err != nil { return err } @@ -168,7 +166,7 @@ func (m *UserMembership) fillOrgName(member *usr_es_model.UserMembershipView) (e } func (m *UserMembership) updateOrgName(event *models.Event) error { - org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.AggregateID)) + org, err := m.getOrgByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -231,7 +229,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) { } func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) { - project, err := m.projectEvents.ProjectByID(context.Background(), member.AggregateID) + project, err := m.getProjectByID(context.Background(), member.AggregateID) if err != nil { return err } @@ -240,7 +238,7 @@ func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembers } func (m *UserMembership) updateProjectDisplayName(event *models.Event) error { - project, err := m.projectEvents.ProjectByID(context.Background(), event.AggregateID) + project, err := m.getProjectByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -272,3 +270,42 @@ func (m *UserMembership) OnError(event *models.Event, err error) error { func (m *UserMembership) OnSuccess() error { return spooler.HandleSuccess(m.view.UpdateUserMembershipSpoolerRunTimestamp) } + +func (u *UserMembership) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := org_view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + var esOrg *org_es_model.Org + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-3m9vs", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *UserMembership) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) { + query, err := proj_view.ProjectByIDQuery(projID, 0) + if err != nil { + return nil, err + } + esProject := &proj_es_model.Project{ + ObjectRoot: models.ObjectRoot{ + AggregateID: projID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esProject.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esProject.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-Dfrt2", "Errors.Project.NotFound") + } + + return proj_es_model.ProjectToModel(esProject), nil +} diff --git a/internal/authz/repository/eventsourcing/repository.go b/internal/authz/repository/eventsourcing/repository.go index 73821aa71e..f569d9ff8e 100644 --- a/internal/authz/repository/eventsourcing/repository.go +++ b/internal/authz/repository/eventsourcing/repository.go @@ -2,24 +2,19 @@ package eventsourcing import ( "context" - "github.com/caos/zitadel/internal/v2/query" - es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" - es_user "github.com/caos/zitadel/internal/user/repository/eventsourcing" + "github.com/caos/zitadel/internal/v2/query" "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/auth_request/repository/cache" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/eventstore" - "github.com/caos/zitadel/internal/authz/repository/eventsourcing/handler" "github.com/caos/zitadel/internal/authz/repository/eventsourcing/spooler" authz_view "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/config/types" es_int "github.com/caos/zitadel/internal/eventstore" es_spol "github.com/caos/zitadel/internal/eventstore/spooler" - es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "github.com/caos/zitadel/internal/id" - es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing" ) type Config struct { @@ -55,60 +50,30 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults) (* return nil, err } - iam, err := es_iam.StartIAM(es_iam.IAMConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, systemDefaults) - if err != nil { - return nil, err - } - org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es, IAMDomain: conf.Domain}, systemDefaults) - - project, err := es_proj.StartProject(es_proj.ProjectConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, systemDefaults) - if err != nil { - return nil, err - } - user, err := es_user.StartUser( - es_user.UserConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, - systemDefaults, - ) - if err != nil { - return nil, err - } iamV2, err := query.StartQuerySide(&query.Config{Eventstore: esV2, SystemDefaults: systemDefaults}) if err != nil { return nil, err } - repos := handler.EventstoreRepos{IAMEvents: iam, OrgEvents: org, ProjectEvents: project} - spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos, systemDefaults) + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults) return &EsRepository{ spool, eventstore.UserGrantRepo{ - View: view, - IamID: systemDefaults.IamID, - Auth: authZ, - IamEvents: iam, + View: view, + IamID: systemDefaults.IamID, + Auth: authZ, + Eventstore: es, }, eventstore.IamRepo{ IAMID: systemDefaults.IamID, - IAMEvents: iam, IAMV2Query: iamV2, }, eventstore.TokenVerifierRepo{ //TODO: Add Token Verification Key - IAMID: systemDefaults.IamID, - IAMEvents: iam, - ProjectEvents: project, - UserEvents: user, - View: view, + Eventstore: es, + IAMID: systemDefaults.IamID, + View: view, }, }, nil } diff --git a/internal/authz/repository/eventsourcing/spooler/spooler.go b/internal/authz/repository/eventsourcing/spooler/spooler.go index e1b7fb059d..e8f8322398 100644 --- a/internal/authz/repository/eventsourcing/spooler/spooler.go +++ b/internal/authz/repository/eventsourcing/spooler/spooler.go @@ -19,12 +19,12 @@ type SpoolerConfig struct { Handlers handler.Configs } -func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, repos handler.EventstoreRepos, systemDefaults sd.SystemDefaults) *spooler.Spooler { +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, systemDefaults sd.SystemDefaults) *spooler.Spooler { spoolerConfig := spooler.Config{ Eventstore: es, Locker: &locker{dbClient: sql}, ConcurrentWorkers: c.ConcurrentWorkers, - ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, repos, systemDefaults), + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, systemDefaults), } spool := spoolerConfig.New() spool.Start() diff --git a/internal/iam/repository/eventsourcing/eventstore.go b/internal/iam/repository/eventsourcing/eventstore.go index 40e4d4b604..65b098d69c 100644 --- a/internal/iam/repository/eventsourcing/eventstore.go +++ b/internal/iam/repository/eventsourcing/eventstore.go @@ -1,85 +1,11 @@ package eventsourcing import ( - "context" - "github.com/caos/zitadel/internal/cache/config" - sd "github.com/caos/zitadel/internal/config/systemdefaults" - caos_errs "github.com/caos/zitadel/internal/errors" es_int "github.com/caos/zitadel/internal/eventstore" - es_models "github.com/caos/zitadel/internal/eventstore/models" - es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" - iam_model "github.com/caos/zitadel/internal/iam/model" - "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" - "github.com/caos/zitadel/internal/telemetry/tracing" ) -type IAMEventstore struct { - es_int.Eventstore - iamCache *IAMCache -} - type IAMConfig struct { es_int.Eventstore Cache *config.CacheConfig } - -func StartIAM(conf IAMConfig, systemDefaults sd.SystemDefaults) (*IAMEventstore, error) { - iamCache, err := StartCache(conf.Cache) - if err != nil { - return nil, err - } - - return &IAMEventstore{ - Eventstore: conf.Eventstore, - iamCache: iamCache, - }, nil -} - -func (es *IAMEventstore) IAMByID(ctx context.Context, id string) (_ *iam_model.IAM, err error) { - ctx, span := tracing.NewSpan(ctx) - defer func() { span.EndWithError(err) }() - - iam := es.iamCache.getIAM(id) - - query, err := IAMByIDQuery(iam.AggregateID, iam.Sequence) - if err != nil { - return nil, err - } - err = es_sdk.Filter(ctx, es.FilterEvents, iam.AppendEvents, query) - if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 { - return nil, err - } - es.iamCache.cacheIAM(iam) - return model.IAMToModel(iam), nil -} - -func (es *IAMEventstore) IAMEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { - query, err := IAMByIDQuery(id, sequence) - if err != nil { - return nil, err - } - return es.FilterEvents(ctx, query) -} - -func (es *IAMEventstore) GetIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*iam_model.IDPConfig, error) { - existing, err := es.IAMByID(ctx, aggregateID) - if err != nil { - return nil, err - } - if _, existingIDP := existing.GetIDP(idpConfigID); existingIDP != nil { - return existingIDP, nil - } - return nil, caos_errs.ThrowNotFound(nil, "EVENT-Scj8s", "Errors.IAM.IdpNotExisting") -} - -func (es *IAMEventstore) GetOrgIAMPolicy(ctx context.Context, iamID string) (*iam_model.OrgIAMPolicy, error) { - existingIAM, err := es.IAMByID(ctx, iamID) - if err != nil { - return nil, err - } - if existingIAM.DefaultOrgIAMPolicy == nil { - return nil, caos_errs.ThrowNotFound(nil, "EVENT-2Fj8s", "Errors.IAM.OrgIAMPolicy.NotExisting") - } - return existingIAM.DefaultOrgIAMPolicy, nil -} diff --git a/internal/iam/repository/view/query.go b/internal/iam/repository/view/query.go new file mode 100644 index 0000000000..7a40b7b92f --- /dev/null +++ b/internal/iam/repository/view/query.go @@ -0,0 +1,21 @@ +package view + +import ( + "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" +) + +func IAMByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) { + if id == "" { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-4ng8sd", "id should be filled") + } + return IAMQuery(latestSequence). + AggregateIDFilter(id), nil +} + +func IAMQuery(latestSequence uint64) *es_models.SearchQuery { + return es_models.NewSearchQuery(). + AggregateTypeFilter(iam_es_model.IAMAggregate). + LatestSequenceFilter(latestSequence) +} diff --git a/internal/management/repository/eventsourcing/eventstore/org.go b/internal/management/repository/eventsourcing/eventstore/org.go index 2729d8f398..5ab5e9602f 100644 --- a/internal/management/repository/eventsourcing/eventstore/org.go +++ b/internal/management/repository/eventsourcing/eventstore/org.go @@ -2,11 +2,17 @@ package eventstore import ( "context" + "encoding/json" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + org_view "github.com/caos/zitadel/internal/org/repository/view" + usr_model "github.com/caos/zitadel/internal/user/model" + "github.com/caos/zitadel/internal/user/repository/view" "github.com/caos/zitadel/internal/v2/domain" + "github.com/golang/protobuf/ptypes" "strings" - iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing" - "github.com/caos/logging" "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/config/systemdefaults" @@ -17,10 +23,10 @@ import ( mgmt_view "github.com/caos/zitadel/internal/management/repository/eventsourcing/view" global_model "github.com/caos/zitadel/internal/model" org_model "github.com/caos/zitadel/internal/org/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "github.com/caos/zitadel/internal/org/repository/view/model" "github.com/caos/zitadel/internal/telemetry/tracing" - usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing" + usr_es_model "github.com/caos/zitadel/internal/user/repository/view/model" ) const ( @@ -28,10 +34,8 @@ const ( ) type OrgRepository struct { - SearchLimit uint64 - *org_es.OrgEventstore - UserEvents *usr_es.UserEventstore - IAMEventstore *iam_es.IAMEventstore + SearchLimit uint64 + Eventstore eventstore.Eventstore View *mgmt_view.View Roles []string SystemDefaults systemdefaults.SystemDefaults @@ -91,19 +95,19 @@ func (repo *OrgRepository) SearchMyOrgDomains(ctx context.Context, request *org_ } func (repo *OrgRepository) OrgChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*org_model.OrgChanges, error) { - changes, err := repo.OrgEventstore.OrgChanges(ctx, id, lastSequence, limit, sortAscending) + changes, err := repo.getOrgChanges(ctx, id, lastSequence, limit, sortAscending) if err != nil { return nil, err } for _, change := range changes.Changes { change.ModifierName = change.ModifierId - user, _ := repo.UserEvents.UserByID(ctx, change.ModifierId) + user, _ := repo.userByID(ctx, change.ModifierId) if user != nil { - if user.Human != nil { + if user.HumanView != nil { change.ModifierName = user.DisplayName } - if user.Machine != nil { - change.ModifierName = user.Machine.Name + if user.MachineView != nil { + change.ModifierName = user.MachineView.Name } } } @@ -204,7 +208,7 @@ func (repo *OrgRepository) GetLoginPolicy(ctx context.Context) (*iam_model.Login if errors.IsNotFound(viewErr) { policy = new(iam_es_model.LoginPolicyView) } - events, esErr := repo.OrgEventstore.OrgEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getOrgEvents(ctx, repo.SystemDefaults.IamID, policy.Sequence) if errors.IsNotFound(viewErr) && len(events) == 0 { return repo.GetDefaultLoginPolicy(ctx) } @@ -237,7 +241,7 @@ func (repo *OrgRepository) GetDefaultLoginPolicy(ctx context.Context) (*iam_mode if errors.IsNotFound(viewErr) { policy = new(iam_es_model.LoginPolicyView) } - events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, domain.IAMID, policy.Sequence) + events, esErr := repo.getIAMEvents(ctx, policy.Sequence) if errors.IsNotFound(viewErr) && len(events) == 0 { return nil, errors.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.LoginPolicy.NotFound") } @@ -315,7 +319,7 @@ func (repo *OrgRepository) GetPasswordComplexityPolicy(ctx context.Context) (*ia if errors.IsNotFound(viewErr) { policy = new(iam_es_model.PasswordComplexityPolicyView) } - events, esErr := repo.OrgEventstore.OrgEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getOrgEvents(ctx, repo.SystemDefaults.IamID, policy.Sequence) if errors.IsNotFound(viewErr) && len(events) == 0 { return repo.GetDefaultPasswordComplexityPolicy(ctx) } @@ -340,7 +344,7 @@ func (repo *OrgRepository) GetDefaultPasswordComplexityPolicy(ctx context.Contex if errors.IsNotFound(viewErr) { policy = new(iam_es_model.PasswordComplexityPolicyView) } - events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getIAMEvents(ctx, policy.Sequence) if errors.IsNotFound(viewErr) && len(events) == 0 { return nil, errors.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.PasswordComplexityPolicy.NotFound") } @@ -366,7 +370,7 @@ func (repo *OrgRepository) GetPasswordAgePolicy(ctx context.Context) (*iam_model if errors.IsNotFound(viewErr) { policy = new(iam_es_model.PasswordAgePolicyView) } - events, esErr := repo.OrgEventstore.OrgEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getOrgEvents(ctx, repo.SystemDefaults.IamID, policy.Sequence) if errors.IsNotFound(viewErr) && len(events) == 0 { return repo.GetDefaultPasswordAgePolicy(ctx) } @@ -391,7 +395,7 @@ func (repo *OrgRepository) GetDefaultPasswordAgePolicy(ctx context.Context) (*ia if errors.IsNotFound(viewErr) { policy = new(iam_es_model.PasswordAgePolicyView) } - events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getIAMEvents(ctx, policy.Sequence) if errors.IsNotFound(viewErr) && len(events) == 0 { return nil, errors.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.PasswordAgePolicy.NotFound") } @@ -417,7 +421,7 @@ func (repo *OrgRepository) GetPasswordLockoutPolicy(ctx context.Context) (*iam_m if errors.IsNotFound(viewErr) { policy = new(iam_es_model.PasswordLockoutPolicyView) } - events, esErr := repo.OrgEventstore.OrgEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getOrgEvents(ctx, repo.SystemDefaults.IamID, policy.Sequence) if errors.IsNotFound(viewErr) && len(events) == 0 { return repo.GetDefaultPasswordLockoutPolicy(ctx) } @@ -442,7 +446,7 @@ func (repo *OrgRepository) GetDefaultPasswordLockoutPolicy(ctx context.Context) if errors.IsNotFound(viewErr) { policy = new(iam_es_model.PasswordLockoutPolicyView) } - events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence) + events, esErr := repo.getIAMEvents(ctx, policy.Sequence) if errors.IsNotFound(viewErr) && len(events) == 0 { return nil, errors.ThrowNotFound(nil, "EVENT-cmO9s", "Errors.IAM.PasswordLockoutPolicy.NotFound") } @@ -507,3 +511,99 @@ func (repo *OrgRepository) GetMailTexts(ctx context.Context) (*iam_model.MailTex } return iam_es_model.MailTextsViewToModel(texts, defaultIn), err } + +func (repo *OrgRepository) getOrgChanges(ctx context.Context, orgID string, lastSequence uint64, limit uint64, sortAscending bool) (*org_model.OrgChanges, error) { + query := org_view.ChangesQuery(orgID, lastSequence, limit, sortAscending) + + events, err := repo.Eventstore.FilterEvents(context.Background(), query) + if err != nil { + logging.Log("EVENT-ZRffs").WithError(err).Warn("eventstore unavailable") + return nil, errors.ThrowInternal(err, "EVENT-328b1", "Errors.Org.NotFound") + } + if len(events) == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-FpQqK", "Errors.Changes.NotFound") + } + + changes := make([]*org_model.OrgChange, len(events)) + + for i, event := range events { + creationDate, err := ptypes.TimestampProto(event.CreationDate) + logging.Log("EVENT-qxIR7").OnError(err).Debug("unable to parse timestamp") + change := &org_model.OrgChange{ + ChangeDate: creationDate, + EventType: event.Type.String(), + ModifierId: event.EditorUser, + Sequence: event.Sequence, + } + + if event.Data != nil { + org := new(org_es_model.Org) + err := json.Unmarshal(event.Data, org) + logging.Log("EVENT-XCLEm").OnError(err).Debug("unable to unmarshal data") + change.Data = org + } + + changes[i] = change + if lastSequence < event.Sequence { + lastSequence = event.Sequence + } + } + + return &org_model.OrgChanges{ + Changes: changes, + LastSequence: lastSequence, + }, nil +} + +func (repo *OrgRepository) userByID(ctx context.Context, id string) (*usr_model.UserView, error) { + user, viewErr := repo.View.UserByID(id) + if viewErr != nil && !errors.IsNotFound(viewErr) { + return nil, viewErr + } + if errors.IsNotFound(viewErr) { + user = new(usr_es_model.UserView) + } + events, esErr := repo.getUserEvents(ctx, id, user.Sequence) + if errors.IsNotFound(viewErr) && len(events) == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-3nF8s", "Errors.User.NotFound") + } + if esErr != nil { + logging.Log("EVENT-PSoc3").WithError(esErr).Debug("error retrieving new events") + return usr_es_model.UserToModel(user), nil + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return usr_es_model.UserToModel(user), nil + } + } + if userCopy.State == int32(usr_es_model.UserStateDeleted) { + return nil, errors.ThrowNotFound(nil, "EVENT-3n8Fs", "Errors.User.NotFound") + } + return usr_es_model.UserToModel(&userCopy), nil +} + +func (r *OrgRepository) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) { + query, err := view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + + return r.Eventstore.FilterEvents(ctx, query) +} + +func (es *OrgRepository) getOrgEvents(ctx context.Context, id string, sequence uint64) ([]*models.Event, error) { + query, err := org_view.OrgByIDQuery(id, sequence) + if err != nil { + return nil, err + } + return es.Eventstore.FilterEvents(ctx, query) +} + +func (repo *OrgRepository) getIAMEvents(ctx context.Context, sequence uint64) ([]*models.Event, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, sequence) + if err != nil { + return nil, err + } + return repo.Eventstore.FilterEvents(ctx, query) +} diff --git a/internal/management/repository/eventsourcing/eventstore/project.go b/internal/management/repository/eventsourcing/eventstore/project.go index 4371f2693b..e67082394d 100644 --- a/internal/management/repository/eventsourcing/eventstore/project.go +++ b/internal/management/repository/eventsourcing/eventstore/project.go @@ -2,33 +2,40 @@ package eventstore import ( "context" + "encoding/json" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_model "github.com/caos/zitadel/internal/iam/model" + iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + "github.com/caos/zitadel/internal/v2/domain" "strings" "github.com/caos/logging" + "github.com/golang/protobuf/ptypes" + "k8s.io/apimachinery/pkg/api/errors" "github.com/caos/zitadel/internal/api/authz" caos_errs "github.com/caos/zitadel/internal/errors" es_int "github.com/caos/zitadel/internal/eventstore" - iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + "github.com/caos/zitadel/internal/eventstore/models" key_model "github.com/caos/zitadel/internal/key/model" key_view_model "github.com/caos/zitadel/internal/key/repository/view/model" "github.com/caos/zitadel/internal/management/repository/eventsourcing/view" global_model "github.com/caos/zitadel/internal/model" proj_model "github.com/caos/zitadel/internal/project/model" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_view "github.com/caos/zitadel/internal/project/repository/view" "github.com/caos/zitadel/internal/project/repository/view/model" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" + usr_model "github.com/caos/zitadel/internal/user/model" + usr_view "github.com/caos/zitadel/internal/user/repository/view" + usr_es_model "github.com/caos/zitadel/internal/user/repository/view/model" ) type ProjectRepo struct { es_int.Eventstore - SearchLimit uint64 - ProjectEvents *proj_event.ProjectEventstore - UserEvents *usr_event.UserEventstore - IAMEvents *iam_event.IAMEventstore - View *view.View - Roles []string - IAMID string + SearchLimit uint64 + View *view.View + Roles []string + IAMID string } func (repo *ProjectRepo) ProjectByID(ctx context.Context, id string) (*proj_model.ProjectView, error) { @@ -40,7 +47,7 @@ func (repo *ProjectRepo) ProjectByID(ctx context.Context, id string) (*proj_mode project = new(model.ProjectView) } - events, esErr := repo.ProjectEvents.ProjectEventsByID(ctx, id, project.Sequence) + events, esErr := repo.getProjectEvents(ctx, id, project.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-8yfKu", "Errors.Project.NotFound") } @@ -175,19 +182,19 @@ func (repo *ProjectRepo) SearchProjectRoles(ctx context.Context, projectID strin } func (repo *ProjectRepo) ProjectChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*proj_model.ProjectChanges, error) { - changes, err := repo.ProjectEvents.ProjectChanges(ctx, id, lastSequence, limit, sortAscending) + changes, err := repo.getProjectChanges(ctx, id, lastSequence, limit, sortAscending) if err != nil { return nil, err } for _, change := range changes.Changes { change.ModifierName = change.ModifierId - user, _ := repo.UserEvents.UserByID(ctx, change.ModifierId) + user, _ := repo.userByID(ctx, change.ModifierId) if user != nil { - if user.Human != nil { + if user.HumanView != nil { change.ModifierName = user.DisplayName } - if user.Machine != nil { - change.ModifierName = user.Machine.Name + if user.MachineView != nil { + change.ModifierName = user.MachineView.Name } } } @@ -204,7 +211,7 @@ func (repo *ProjectRepo) ApplicationByID(ctx context.Context, projectID, appID s app.ID = appID } - events, esErr := repo.ProjectEvents.ProjectEventsByID(ctx, projectID, app.Sequence) + events, esErr := repo.getProjectEvents(ctx, projectID, app.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-Fshu8", "Errors.Application.NotFound") } @@ -249,19 +256,19 @@ func (repo *ProjectRepo) SearchApplications(ctx context.Context, request *proj_m } func (repo *ProjectRepo) ApplicationChanges(ctx context.Context, id string, appId string, lastSequence uint64, limit uint64, sortAscending bool) (*proj_model.ApplicationChanges, error) { - changes, err := repo.ProjectEvents.ApplicationChanges(ctx, id, appId, lastSequence, limit, sortAscending) + changes, err := repo.getApplicationChanges(ctx, id, appId, lastSequence, limit, sortAscending) if err != nil { return nil, err } for _, change := range changes.Changes { change.ModifierName = change.ModifierId - user, _ := repo.UserEvents.UserByID(ctx, change.ModifierId) + user, _ := repo.userByID(ctx, change.ModifierId) if user != nil { - if user.Human != nil { + if user.HumanView != nil { change.ModifierName = user.DisplayName } - if user.Machine != nil { - change.ModifierName = user.Machine.Name + if user.MachineView != nil { + change.ModifierName = user.MachineView.Name } } } @@ -295,7 +302,7 @@ func (repo *ProjectRepo) GetClientKey(ctx context.Context, projectID, applicatio return nil, viewErr } - events, esErr := repo.ProjectEvents.ProjectEventsByID(ctx, projectID, key.Sequence) + events, esErr := repo.getProjectEvents(ctx, projectID, key.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-SFf2g", "Errors.User.KeyNotFound") } @@ -436,7 +443,7 @@ func (repo *ProjectRepo) SearchProjectGrantMembers(ctx context.Context, request } func (repo *ProjectRepo) GetProjectMemberRoles(ctx context.Context) ([]string, error) { - iam, err := repo.IAMEvents.IAMByID(ctx, repo.IAMID) + iam, err := repo.GetIAMByID(ctx) if err != nil { return nil, err } @@ -462,3 +469,158 @@ func (repo *ProjectRepo) GetProjectGrantMemberRoles() []string { } return roles } + +func (repo *ProjectRepo) userByID(ctx context.Context, id string) (*usr_model.UserView, error) { + user, viewErr := repo.View.UserByID(id) + if viewErr != nil && !caos_errs.IsNotFound(viewErr) { + return nil, viewErr + } + if caos_errs.IsNotFound(viewErr) { + user = new(usr_es_model.UserView) + } + events, esErr := repo.getUserEvents(ctx, id, user.Sequence) + if errors.IsNotFound(viewErr) && len(events) == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-4n8Fs", "Errors.User.NotFound") + } + if esErr != nil { + logging.Log("EVENT-PSoc3").WithError(esErr).Debug("error retrieving new events") + return usr_es_model.UserToModel(user), nil + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return usr_es_model.UserToModel(user), nil + } + } + if userCopy.State == int32(usr_model.UserStateDeleted) { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-2m0Fs", "Errors.User.NotFound") + } + return usr_es_model.UserToModel(&userCopy), nil +} + +func (r *ProjectRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) { + query, err := usr_view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + return r.Eventstore.FilterEvents(ctx, query) +} + +func (repo *ProjectRepo) getProjectChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*proj_model.ProjectChanges, error) { + query := proj_view.ChangesQuery(id, lastSequence, limit, sortAscending) + + events, err := repo.Eventstore.FilterEvents(context.Background(), query) + if err != nil { + logging.Log("EVENT-ZRffs").WithError(err).Warn("eventstore unavailable") + return nil, caos_errs.ThrowInternal(err, "EVENT-328b1", "Errors.Internal") + } + if len(events) == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-FpQqK", "Errors.Changes.NotFound") + } + + changes := make([]*proj_model.ProjectChange, len(events)) + + for i, event := range events { + creationDate, err := ptypes.TimestampProto(event.CreationDate) + logging.Log("EVENT-qxIR7").OnError(err).Debug("unable to parse timestamp") + change := &proj_model.ProjectChange{ + ChangeDate: creationDate, + EventType: event.Type.String(), + ModifierId: event.EditorUser, + Sequence: event.Sequence, + } + + if event.Data != nil { + var data interface{} + if strings.Contains(change.EventType, "application") { + data = new(proj_model.Application) + } else { + data = new(proj_model.Project) + } + err = json.Unmarshal(event.Data, data) + logging.Log("EVENT-NCkpN").OnError(err).Debug("unable to unmarshal data") + change.Data = data + } + + changes[i] = change + if lastSequence < event.Sequence { + lastSequence = event.Sequence + } + } + + return &proj_model.ProjectChanges{ + Changes: changes, + LastSequence: lastSequence, + }, nil +} + +func (repo *ProjectRepo) getProjectEvents(ctx context.Context, id string, sequence uint64) ([]*models.Event, error) { + query, err := proj_view.ProjectByIDQuery(id, sequence) + if err != nil { + return nil, err + } + return repo.Eventstore.FilterEvents(ctx, query) +} + +func (repo *ProjectRepo) getApplicationChanges(ctx context.Context, projectID string, appID string, lastSequence uint64, limit uint64, sortAscending bool) (*proj_model.ApplicationChanges, error) { + query := proj_view.ChangesQuery(projectID, lastSequence, limit, sortAscending) + + events, err := repo.Eventstore.FilterEvents(ctx, query) + if err != nil { + logging.Log("EVENT-ZRffs").WithError(err).Warn("eventstore unavailable") + return nil, caos_errs.ThrowInternal(err, "EVENT-sw6Ku", "Errors.Internal") + } + if len(events) == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-9IHLP", "Errors.Changes.NotFound") + } + + result := make([]*proj_model.ApplicationChange, 0) + for _, event := range events { + if !strings.Contains(event.Type.String(), "application") || event.Data == nil { + continue + } + + app := new(proj_model.Application) + err := json.Unmarshal(event.Data, app) + logging.Log("EVENT-GIiKD").OnError(err).Debug("unable to unmarshal data") + if app.AppID != appID { + continue + } + + creationDate, err := ptypes.TimestampProto(event.CreationDate) + logging.Log("EVENT-MJzeN").OnError(err).Debug("unable to parse timestamp") + + result = append(result, &proj_model.ApplicationChange{ + ChangeDate: creationDate, + EventType: event.Type.String(), + ModifierId: event.EditorUser, + Sequence: event.Sequence, + Data: app, + }) + if lastSequence < event.Sequence { + lastSequence = event.Sequence + } + } + + return &proj_model.ApplicationChanges{ + Changes: result, + LastSequence: lastSequence, + }, nil +} + +func (u *ProjectRepo) GetIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &iam_es_model.IAM{ + ObjectRoot: models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore.FilterEvents, iam.AppendEvents, query) + if err != nil && errors.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return iam_es_model.IAMToModel(iam), nil +} diff --git a/internal/management/repository/eventsourcing/eventstore/user.go b/internal/management/repository/eventsourcing/eventstore/user.go index b9d51e3796..cbf16b5b72 100644 --- a/internal/management/repository/eventsourcing/eventstore/user.go +++ b/internal/management/repository/eventsourcing/eventstore/user.go @@ -2,6 +2,9 @@ package eventstore import ( "context" + "github.com/caos/zitadel/internal/eventstore/models" + usr_view "github.com/caos/zitadel/internal/user/repository/view" + "github.com/golang/protobuf/ptypes" "github.com/caos/logging" @@ -14,9 +17,7 @@ import ( key_view_model "github.com/caos/zitadel/internal/key/repository/view/model" "github.com/caos/zitadel/internal/management/repository/eventsourcing/view" global_model "github.com/caos/zitadel/internal/model" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" usr_model "github.com/caos/zitadel/internal/user/model" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" "github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/zitadel/internal/view/repository" ) @@ -24,8 +25,6 @@ import ( type UserRepo struct { es_int.Eventstore SearchLimit uint64 - UserEvents *usr_event.UserEventstore - OrgEvents *org_event.OrgEventstore View *view.View SystemDefaults systemdefaults.SystemDefaults } @@ -38,7 +37,7 @@ func (repo *UserRepo) UserByID(ctx context.Context, id string) (*usr_model.UserV if caos_errs.IsNotFound(viewErr) { user = new(model.UserView) } - events, esErr := repo.UserEvents.UserEventsByID(ctx, id, user.Sequence) + events, esErr := repo.getUserEvents(ctx, id, user.Sequence) if caos_errs.IsNotFound(viewErr) && len(events) == 0 { return nil, caos_errs.ThrowNotFound(nil, "EVENT-Lsoj7", "Errors.User.NotFound") } @@ -84,19 +83,19 @@ func (repo *UserRepo) UserIDsByDomain(ctx context.Context, domain string) ([]str } func (repo *UserRepo) UserChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*usr_model.UserChanges, error) { - changes, err := repo.UserEvents.UserChanges(ctx, id, lastSequence, limit, sortAscending) + changes, err := repo.getUserChanges(ctx, id, lastSequence, limit, sortAscending) if err != nil { return nil, err } for _, change := range changes.Changes { change.ModifierName = change.ModifierID - user, _ := repo.UserEvents.UserByID(ctx, change.ModifierID) + user, _ := repo.UserByID(ctx, change.ModifierID) if user != nil { - if user.Human != nil { - change.ModifierName = user.Human.DisplayName + if user.HumanView != nil { + change.ModifierName = user.HumanView.DisplayName } - if user.Machine != nil { - change.ModifierName = user.Machine.Name + if user.MachineView != nil { + change.ModifierName = user.MachineView.Name } } } @@ -133,8 +132,15 @@ func (repo *UserRepo) UserMFAs(ctx context.Context, userID string) ([]*usr_model return mfas, nil } -func (repo *UserRepo) GetPasswordless(ctx context.Context, userID string) ([]*usr_model.WebAuthNToken, error) { - return repo.UserEvents.GetPasswordless(ctx, userID) +func (repo *UserRepo) GetPasswordless(ctx context.Context, userID string) ([]*usr_model.WebAuthNView, error) { + user, err := repo.UserByID(ctx, userID) + if err != nil { + return nil, err + } + if user.HumanView == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-9anf8", "Errors.User.NotHuman") + } + return user.HumanView.PasswordlessTokens, nil } func (repo *UserRepo) ProfileByID(ctx context.Context, userID string) (*usr_model.Profile, error) { @@ -274,6 +280,58 @@ func (repo *UserRepo) SearchUserMemberships(ctx context.Context, request *usr_mo return result, nil } +func (r *UserRepo) getUserChanges(ctx context.Context, userID string, lastSequence uint64, limit uint64, sortAscending bool) (*usr_model.UserChanges, error) { + query := usr_view.ChangesQuery(userID, lastSequence, limit, sortAscending) + + events, err := r.Eventstore.FilterEvents(ctx, query) + if err != nil { + logging.Log("EVENT-g9HCv").WithError(err).Warn("eventstore unavailable") + return nil, errors.ThrowInternal(err, "EVENT-htuG9", "Errors.Internal") + } + if len(events) == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-6cAxe", "Errors.User.NoChanges") + } + + result := make([]*usr_model.UserChange, len(events)) + + for i, event := range events { + creationDate, err := ptypes.TimestampProto(event.CreationDate) + logging.Log("EVENT-8GTGS").OnError(err).Debug("unable to parse timestamp") + change := &usr_model.UserChange{ + ChangeDate: creationDate, + EventType: event.Type.String(), + ModifierID: event.EditorUser, + Sequence: event.Sequence, + } + + //TODO: now all types should be unmarshalled, e.g. password + // if len(event.Data) != 0 { + // user := new(model.User) + // err := json.Unmarshal(event.Data, user) + // logging.Log("EVENT-Rkg7X").OnError(err).Debug("unable to unmarshal data") + // change.Data = user + // } + + result[i] = change + if lastSequence < event.Sequence { + lastSequence = event.Sequence + } + } + + return &usr_model.UserChanges{ + Changes: result, + LastSequence: lastSequence, + }, nil +} + +func (r *UserRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) { + query, err := usr_view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + return r.Eventstore.FilterEvents(ctx, query) +} + func handleSearchUserMembershipsPermissions(ctx context.Context, request *usr_model.UserMembershipSearchRequest, sequence *repository.CurrentSequence) *usr_model.UserMembershipSearchResponse { permissions := authz.GetAllPermissionsFromCtx(ctx) iamPerm := authz.HasGlobalExplicitPermission(permissions, iamMemberReadPerm) diff --git a/internal/management/repository/eventsourcing/handler/application.go b/internal/management/repository/eventsourcing/handler/application.go index 71e4c2af07..3f2b32394e 100644 --- a/internal/management/repository/eventsourcing/handler/application.go +++ b/internal/management/repository/eventsourcing/handler/application.go @@ -5,13 +5,15 @@ import ( "github.com/caos/logging" + "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" - "github.com/caos/zitadel/internal/project/repository/eventsourcing" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_model "github.com/caos/zitadel/internal/project/model" es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" view_model "github.com/caos/zitadel/internal/project/repository/view/model" ) @@ -21,17 +23,14 @@ const ( type Application struct { handler - projectEvents *proj_event.ProjectEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } func newApplication( handler handler, - projectEvents *proj_event.ProjectEventstore, ) *Application { h := &Application{ - handler: handler, - projectEvents: projectEvents, + handler: handler, } h.subscribe() @@ -69,14 +68,14 @@ func (a *Application) EventQuery() (*models.SearchQuery, error) { if err != nil { return nil, err } - return eventsourcing.ProjectQuery(sequence.CurrentSequence), nil + return proj_view.ProjectQuery(sequence.CurrentSequence), nil } func (a *Application) Reduce(event *models.Event) (err error) { app := new(view_model.ApplicationView) switch event.Type { case es_model.ApplicationAdded: - project, err := a.projectEvents.ProjectByID(context.Background(), event.AggregateID) + project, err := a.getProjectByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -139,3 +138,24 @@ func (a *Application) OnError(event *models.Event, spoolerError error) error { func (a *Application) OnSuccess() error { return spooler.HandleSuccess(a.view.UpdateApplicationSpoolerRunTimestamp) } + +func (a *Application) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) { + query, err := proj_view.ProjectByIDQuery(projID, 0) + if err != nil { + return nil, err + } + esProject := &es_model.Project{ + ObjectRoot: models.ObjectRoot{ + AggregateID: projID, + }, + } + err = es_sdk.Filter(ctx, a.Eventstore().FilterEvents, esProject.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esProject.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-ADvfs", "Errors.Project.NotFound") + } + + return es_model.ProjectToModel(esProject), nil +} diff --git a/internal/management/repository/eventsourcing/handler/handler.go b/internal/management/repository/eventsourcing/handler/handler.go index 10aa729250..0d0248a4b5 100644 --- a/internal/management/repository/eventsourcing/handler/handler.go +++ b/internal/management/repository/eventsourcing/handler/handler.go @@ -7,11 +7,7 @@ import ( "github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/query" - iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "github.com/caos/zitadel/internal/management/repository/eventsourcing/view" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type Configs map[string]*Config @@ -33,48 +29,27 @@ func (h *handler) Eventstore() eventstore.Eventstore { return h.es } -type EventstoreRepos struct { - ProjectEvents *proj_event.ProjectEventstore - UserEvents *usr_event.UserEventstore - OrgEvents *org_event.OrgEventstore - IamEvents *iam_event.IAMEventstore -} - -func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, repos EventstoreRepos, defaults systemdefaults.SystemDefaults) []query.Handler { +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, defaults systemdefaults.SystemDefaults) []query.Handler { return []query.Handler{ newProject( handler{view, bulkLimit, configs.cycleDuration("Project"), errorCount, es}), newProjectGrant( - handler{view, bulkLimit, configs.cycleDuration("ProjectGrant"), errorCount, es}, - repos.ProjectEvents, - repos.OrgEvents), - newProjectRole(handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount, es}, - repos.ProjectEvents), - newProjectMember(handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), errorCount, es}, - repos.UserEvents), - newProjectGrantMember(handler{view, bulkLimit, configs.cycleDuration("ProjectGrantMember"), errorCount, es}, - repos.UserEvents), - newApplication(handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount, es}, - repos.ProjectEvents), + handler{view, bulkLimit, configs.cycleDuration("ProjectGrant"), errorCount, es}), + newProjectRole(handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount, es}), + newProjectMember(handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), errorCount, es}), + newProjectGrantMember(handler{view, bulkLimit, configs.cycleDuration("ProjectGrantMember"), errorCount, es}), + newApplication(handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount, es}), newUser(handler{view, bulkLimit, configs.cycleDuration("User"), errorCount, es}, - repos.OrgEvents, - repos.IamEvents, defaults.IamID), - newUserGrant(handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount, es}, - repos.ProjectEvents, - repos.UserEvents, - repos.OrgEvents), + newUserGrant(handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount, es}), newOrg( handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount, es}), newOrgMember( - handler{view, bulkLimit, configs.cycleDuration("OrgMember"), errorCount, es}, - repos.UserEvents), + handler{view, bulkLimit, configs.cycleDuration("OrgMember"), errorCount, es}), newOrgDomain( handler{view, bulkLimit, configs.cycleDuration("OrgDomain"), errorCount, es}), newUserMembership( - handler{view, bulkLimit, configs.cycleDuration("UserMembership"), errorCount, es}, - repos.OrgEvents, - repos.ProjectEvents), + handler{view, bulkLimit, configs.cycleDuration("UserMembership"), errorCount, es}), newAuthNKeys( handler{view, bulkLimit, configs.cycleDuration("MachineKeys"), errorCount, es}), newIDPConfig( @@ -85,16 +60,10 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount, es}), newIDPProvider( handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount, es}, - - defaults, - repos.IamEvents, - repos.OrgEvents), + defaults), newExternalIDP( handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount, es}, - - defaults, - repos.IamEvents, - repos.OrgEvents), + defaults), newPasswordComplexityPolicy( handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount, es}), newPasswordAgePolicy( diff --git a/internal/management/repository/eventsourcing/handler/idp_providers.go b/internal/management/repository/eventsourcing/handler/idp_providers.go index 89d82a1d47..e8bfcd0206 100644 --- a/internal/management/repository/eventsourcing/handler/idp_providers.go +++ b/internal/management/repository/eventsourcing/handler/idp_providers.go @@ -2,19 +2,22 @@ package handler import ( "context" - "github.com/caos/logging" "github.com/caos/zitadel/internal/config/systemdefaults" + caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" iam_model "github.com/caos/zitadel/internal/iam/model" - "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" + org_model "github.com/caos/zitadel/internal/org/model" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/org/repository/view" + "github.com/caos/zitadel/internal/v2/domain" ) const ( @@ -24,22 +27,16 @@ const ( type IDPProvider struct { handler systemDefaults systemdefaults.SystemDefaults - iamEvents *eventsourcing.IAMEventstore - orgEvents *org_es.OrgEventstore subscription *eventstore.Subscription } func newIDPProvider( handler handler, systemDefaults systemdefaults.SystemDefaults, - iamEvents *eventsourcing.IAMEventstore, - orgEvents *org_es.OrgEventstore, ) *IDPProvider { h := &IDPProvider{ handler: handler, systemDefaults: systemDefaults, - iamEvents: iamEvents, - orgEvents: orgEvents, } h.subscribe() @@ -119,9 +116,9 @@ func (m *IDPProvider) processIdpProvider(event *es_models.Event) (err error) { } config := new(iam_model.IDPConfig) if event.AggregateID == m.systemDefaults.IamID { - config, err = m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID) + config, err = m.getDefaultIDPConfig(context.Background(), esConfig.IDPConfigID) } else { - config, err = m.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID) + config, err = m.getOrgIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID) } if err != nil { return err @@ -144,9 +141,9 @@ func (m *IDPProvider) processIdpProvider(event *es_models.Event) (err error) { func (m *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) { var config *iam_model.IDPConfig if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) { - config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, provider.IDPConfigID) + config, err = m.getDefaultIDPConfig(context.Background(), provider.IDPConfigID) } else { - config, err = m.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID) + config, err = m.getOrgIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID) } if err != nil { return err @@ -170,3 +167,64 @@ func (m *IDPProvider) OnError(event *es_models.Event, err error) error { func (m *IDPProvider) OnSuccess() error { return spooler.HandleSuccess(m.view.UpdateIDPProviderSpoolerRunTimestamp) } + +func (i *IDPProvider) getOrgIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := i.getOrgByID(ctx, aggregateID) + if err != nil { + return nil, err + } + if _, i := existing.GetIDP(idpConfigID); i != nil { + return i, nil + } + return nil, caos_errs.ThrowNotFound(nil, "EVENT-2m9dS", "Errors.Org.IdpNotExisting") +} + +func (i *IDPProvider) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, i.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-4n9fs", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *IDPProvider) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &model.IAM{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return model.IAMToModel(iam), nil +} + +func (u *IDPProvider) getDefaultIDPConfig(ctx context.Context, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if _, existingIDP := existing.GetIDP(idpConfigID); existingIDP != nil { + return existingIDP, nil + } + return nil, caos_errs.ThrowNotFound(nil, "EVENT-4M0fs", "Errors.IAM.IdpNotExisting") +} diff --git a/internal/management/repository/eventsourcing/handler/org.go b/internal/management/repository/eventsourcing/handler/org.go index af950ffa8c..16ba3c228d 100644 --- a/internal/management/repository/eventsourcing/handler/org.go +++ b/internal/management/repository/eventsourcing/handler/org.go @@ -2,12 +2,12 @@ package handler import ( "github.com/caos/logging" + "github.com/caos/zitadel/internal/org/repository/view" "github.com/caos/zitadel/internal/eventstore" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" org_model "github.com/caos/zitadel/internal/org/repository/view/model" ) @@ -61,7 +61,7 @@ func (o *Org) EventQuery() (*es_models.SearchQuery, error) { if err != nil { return nil, err } - return eventsourcing.OrgQuery(sequence.CurrentSequence), nil + return view.OrgQuery(sequence.CurrentSequence), nil } func (o *Org) Reduce(event *es_models.Event) (err error) { diff --git a/internal/management/repository/eventsourcing/handler/org_member.go b/internal/management/repository/eventsourcing/handler/org_member.go index f4e8743b6d..eef888e5ec 100644 --- a/internal/management/repository/eventsourcing/handler/org_member.go +++ b/internal/management/repository/eventsourcing/handler/org_member.go @@ -2,6 +2,8 @@ package handler import ( "context" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/user/repository/view" "github.com/caos/logging" "github.com/caos/zitadel/internal/eventstore" @@ -12,8 +14,8 @@ import ( "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" org_model "github.com/caos/zitadel/internal/org/repository/view/model" usr_model "github.com/caos/zitadel/internal/user/model" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" + usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) const ( @@ -22,17 +24,14 @@ const ( type OrgMember struct { handler - userEvents *usr_event.UserEventstore subscription *eventstore.Subscription } func newOrgMember( handler handler, - userEvents *usr_event.UserEventstore, ) *OrgMember { h := &OrgMember{ - handler: handler, - userEvents: userEvents, + handler: handler, } h.subscribe() @@ -133,7 +132,7 @@ func (m *OrgMember) processUser(event *models.Event) (err error) { if len(members) == 0 { return m.view.ProcessedOrgMemberSequence(event) } - user, err := m.userEvents.UserByID(context.Background(), event.AggregateID) + user, err := m.getUserByID(event.AggregateID) if err != nil { return err } @@ -149,7 +148,7 @@ func (m *OrgMember) processUser(event *models.Event) (err error) { } func (m *OrgMember) fillData(member *org_model.OrgMemberView) (err error) { - user, err := m.userEvents.UserByID(context.Background(), member.UserID) + user, err := m.getUserByID(member.UserID) if err != nil { return err } @@ -157,16 +156,16 @@ func (m *OrgMember) fillData(member *org_model.OrgMemberView) (err error) { return nil } -func (m *OrgMember) fillUserData(member *org_model.OrgMemberView, user *usr_model.User) { +func (m *OrgMember) fillUserData(member *org_model.OrgMemberView, user *usr_view_model.UserView) { member.UserName = user.UserName - if user.Human != nil { + if user.HumanView != nil { member.FirstName = user.FirstName member.LastName = user.LastName member.DisplayName = user.FirstName + " " + user.LastName - member.Email = user.EmailAddress + member.Email = user.Email } - if user.Machine != nil { - member.DisplayName = user.Machine.Name + if user.MachineView != nil { + member.DisplayName = user.MachineView.Name } } func (m *OrgMember) OnError(event *models.Event, err error) error { @@ -177,3 +176,36 @@ func (m *OrgMember) OnError(event *models.Event, err error) error { func (o *OrgMember) OnSuccess() error { return spooler.HandleSuccess(o.view.UpdateOrgMemberSpoolerRunTimestamp) } + +func (u *OrgMember) getUserByID(userID string) (*usr_view_model.UserView, error) { + user, usrErr := u.view.UserByID(userID) + if usrErr != nil && !caos_errs.IsNotFound(usrErr) { + return nil, usrErr + } + if user == nil { + user = &usr_view_model.UserView{} + } + events, err := u.getUserEvents(userID, user.Sequence) + if err != nil { + return user, usrErr + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return user, nil + } + } + if userCopy.State == int32(usr_model.UserStateDeleted) { + return nil, caos_errs.ThrowNotFound(nil, "HANDLER-m9dos", "Errors.User.NotFound") + } + return &userCopy, nil +} + +func (u *OrgMember) getUserEvents(userID string, sequence uint64) ([]*models.Event, error) { + query, err := view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + + return u.es.FilterEvents(context.Background(), query) +} diff --git a/internal/management/repository/eventsourcing/handler/project.go b/internal/management/repository/eventsourcing/handler/project.go index d123b62091..8c25315c07 100644 --- a/internal/management/repository/eventsourcing/handler/project.go +++ b/internal/management/repository/eventsourcing/handler/project.go @@ -7,8 +7,8 @@ import ( "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" view_model "github.com/caos/zitadel/internal/project/repository/view/model" ) @@ -61,7 +61,7 @@ func (p *Project) EventQuery() (*models.SearchQuery, error) { if err != nil { return nil, err } - return proj_event.ProjectQuery(sequence.CurrentSequence), nil + return proj_view.ProjectQuery(sequence.CurrentSequence), nil } func (p *Project) Reduce(event *models.Event) (err error) { diff --git a/internal/management/repository/eventsourcing/handler/project_grant.go b/internal/management/repository/eventsourcing/handler/project_grant.go index 1c96a8a80b..88ed702791 100644 --- a/internal/management/repository/eventsourcing/handler/project_grant.go +++ b/internal/management/repository/eventsourcing/handler/project_grant.go @@ -5,15 +5,18 @@ import ( "github.com/caos/logging" + "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" org_model "github.com/caos/zitadel/internal/org/model" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/org/repository/view" proj_model "github.com/caos/zitadel/internal/project/model" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" view_model "github.com/caos/zitadel/internal/project/repository/view/model" ) @@ -23,20 +26,14 @@ const ( type ProjectGrant struct { handler - projectEvents *proj_event.ProjectEventstore - orgEvents *org_event.OrgEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } func newProjectGrant( handler handler, - projectEvents *proj_event.ProjectEventstore, - orgEvents *org_event.OrgEventstore, ) *ProjectGrant { h := &ProjectGrant{ - handler: handler, - projectEvents: projectEvents, - orgEvents: orgEvents, + handler: handler, } h.subscribe() @@ -74,7 +71,7 @@ func (p *ProjectGrant) EventQuery() (*models.SearchQuery, error) { if err != nil { return nil, err } - return proj_event.ProjectQuery(sequence.CurrentSequence), nil + return proj_view.ProjectQuery(sequence.CurrentSequence), nil } func (p *ProjectGrant) Reduce(event *models.Event) (err error) { @@ -97,11 +94,11 @@ func (p *ProjectGrant) Reduce(event *models.Event) (err error) { } grantedProject.Name = project.Name - org, err := p.orgEvents.OrgByID(context.TODO(), org_model.NewOrg(grantedProject.OrgID)) + org, err := p.getOrgByID(context.TODO(), grantedProject.OrgID) if err != nil { return err } - resourceOwner, err := p.orgEvents.OrgByID(context.TODO(), org_model.NewOrg(grantedProject.ResourceOwner)) + resourceOwner, err := p.getOrgByID(context.TODO(), grantedProject.ResourceOwner) if err != nil { return err } @@ -145,7 +142,7 @@ func (p *ProjectGrant) fillOrgData(grantedProject *view_model.ProjectGrantView, } func (p *ProjectGrant) getProject(projectID string) (*proj_model.Project, error) { - return p.projectEvents.ProjectByID(context.Background(), projectID) + return p.getProjectByID(context.Background(), projectID) } func (p *ProjectGrant) updateExistingProjects(project *view_model.ProjectView, event *models.Event) error { @@ -167,3 +164,46 @@ func (p *ProjectGrant) OnError(event *models.Event, err error) error { func (p *ProjectGrant) OnSuccess() error { return spooler.HandleSuccess(p.view.UpdateProjectGrantSpoolerRunTimestamp) } + +func (u *ProjectGrant) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-3m9vs", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *ProjectGrant) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) { + query, err := proj_view.ProjectByIDQuery(projID, 0) + if err != nil { + return nil, err + } + esProject := &es_model.Project{ + ObjectRoot: models.ObjectRoot{ + AggregateID: projID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esProject.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esProject.Sequence == 0 { + return nil, errors.ThrowNotFound(nil, "EVENT-NBrw2", "Errors.Project.NotFound") + } + + return es_model.ProjectToModel(esProject), nil +} diff --git a/internal/management/repository/eventsourcing/handler/project_grant_member.go b/internal/management/repository/eventsourcing/handler/project_grant_member.go index 6897568ea8..69bef0679a 100644 --- a/internal/management/repository/eventsourcing/handler/project_grant_member.go +++ b/internal/management/repository/eventsourcing/handler/project_grant_member.go @@ -2,6 +2,9 @@ package handler import ( "context" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/user/repository/view" + usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/logging" @@ -13,7 +16,6 @@ import ( proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/project/repository/view/model" usr_model "github.com/caos/zitadel/internal/user/model" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) @@ -23,17 +25,14 @@ const ( type ProjectGrantMember struct { handler - userEvents *usr_event.UserEventstore subscription *eventstore.Subscription } func newProjectGrantMember( handler handler, - userEvents *usr_event.UserEventstore, ) *ProjectGrantMember { h := &ProjectGrantMember{ - handler: handler, - userEvents: userEvents, + handler: handler, } h.subscribe() @@ -140,7 +139,7 @@ func (p *ProjectGrantMember) processUser(event *models.Event) (err error) { if len(members) == 0 { return p.view.ProcessedProjectGrantMemberSequence(event) } - user, err := p.userEvents.UserByID(context.Background(), event.AggregateID) + user, err := p.getUserByID(event.AggregateID) if err != nil { return err } @@ -154,7 +153,7 @@ func (p *ProjectGrantMember) processUser(event *models.Event) (err error) { } func (p *ProjectGrantMember) fillData(member *view_model.ProjectGrantMemberView) (err error) { - user, err := p.userEvents.UserByID(context.Background(), member.UserID) + user, err := p.getUserByID(member.UserID) if err != nil { return err } @@ -162,16 +161,16 @@ func (p *ProjectGrantMember) fillData(member *view_model.ProjectGrantMemberView) return nil } -func (p *ProjectGrantMember) fillUserData(member *view_model.ProjectGrantMemberView, user *usr_model.User) { +func (p *ProjectGrantMember) fillUserData(member *view_model.ProjectGrantMemberView, user *usr_view_model.UserView) { member.UserName = user.UserName - if user.Human != nil { + if user.HumanView != nil { member.FirstName = user.FirstName member.LastName = user.LastName member.DisplayName = user.FirstName + " " + user.LastName - member.Email = user.EmailAddress + member.Email = user.Email } - if user.Machine != nil { - member.DisplayName = user.Machine.Name + if user.MachineView != nil { + member.DisplayName = user.MachineView.Name } } @@ -183,3 +182,36 @@ func (p *ProjectGrantMember) OnError(event *models.Event, err error) error { func (p *ProjectGrantMember) OnSuccess() error { return spooler.HandleSuccess(p.view.UpdateProjectGrantMemberSpoolerRunTimestamp) } + +func (u *ProjectGrantMember) getUserByID(userID string) (*usr_view_model.UserView, error) { + user, usrErr := u.view.UserByID(userID) + if usrErr != nil && !caos_errs.IsNotFound(usrErr) { + return nil, usrErr + } + if user == nil { + user = &usr_view_model.UserView{} + } + events, err := u.getUserEvents(userID, user.Sequence) + if err != nil { + return user, usrErr + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return user, nil + } + } + if userCopy.State == int32(usr_model.UserStateDeleted) { + return nil, caos_errs.ThrowNotFound(nil, "HANDLER-m9dos", "Errors.User.NotFound") + } + return &userCopy, nil +} + +func (u *ProjectGrantMember) getUserEvents(userID string, sequence uint64) ([]*models.Event, error) { + query, err := view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + + return u.es.FilterEvents(context.Background(), query) +} diff --git a/internal/management/repository/eventsourcing/handler/project_member.go b/internal/management/repository/eventsourcing/handler/project_member.go index 0e8bf87f1a..e3cd29149e 100644 --- a/internal/management/repository/eventsourcing/handler/project_member.go +++ b/internal/management/repository/eventsourcing/handler/project_member.go @@ -2,6 +2,8 @@ package handler import ( "context" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/user/repository/view" "github.com/caos/logging" @@ -13,8 +15,8 @@ import ( proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/project/repository/view/model" usr_model "github.com/caos/zitadel/internal/user/model" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" + usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) const ( @@ -23,17 +25,14 @@ const ( type ProjectMember struct { handler - userEvents *usr_event.UserEventstore subscription *eventstore.Subscription } func newProjectMember( handler handler, - userEvents *usr_event.UserEventstore, ) *ProjectMember { h := &ProjectMember{ - handler: handler, - userEvents: userEvents, + handler: handler, } h.subscribe() @@ -136,7 +135,7 @@ func (p *ProjectMember) processUser(event *models.Event) (err error) { if len(members) == 0 { return p.view.ProcessedProjectMemberSequence(event) } - user, err := p.userEvents.UserByID(context.Background(), event.AggregateID) + user, err := p.getUserByID(event.AggregateID) if err != nil { return err } @@ -151,7 +150,7 @@ func (p *ProjectMember) processUser(event *models.Event) (err error) { } func (p *ProjectMember) fillData(member *view_model.ProjectMemberView) (err error) { - user, err := p.userEvents.UserByID(context.Background(), member.UserID) + user, err := p.getUserByID(member.UserID) if err != nil { return err } @@ -159,16 +158,16 @@ func (p *ProjectMember) fillData(member *view_model.ProjectMemberView) (err erro return nil } -func (p *ProjectMember) fillUserData(member *view_model.ProjectMemberView, user *usr_model.User) { +func (p *ProjectMember) fillUserData(member *view_model.ProjectMemberView, user *usr_view_model.UserView) { member.UserName = user.UserName - if user.Human != nil { + if user.HumanView != nil { member.FirstName = user.FirstName member.LastName = user.LastName - member.Email = user.EmailAddress + member.Email = user.Email member.DisplayName = user.FirstName + " " + user.LastName } - if user.Machine != nil { - member.DisplayName = user.Machine.Name + if user.MachineView != nil { + member.DisplayName = user.MachineView.Name } } func (p *ProjectMember) OnError(event *models.Event, err error) error { @@ -179,3 +178,36 @@ func (p *ProjectMember) OnError(event *models.Event, err error) error { func (p *ProjectMember) OnSuccess() error { return spooler.HandleSuccess(p.view.UpdateProjectMemberSpoolerRunTimestamp) } + +func (u *ProjectMember) getUserByID(userID string) (*usr_view_model.UserView, error) { + user, usrErr := u.view.UserByID(userID) + if usrErr != nil && !caos_errs.IsNotFound(usrErr) { + return nil, usrErr + } + if user == nil { + user = &usr_view_model.UserView{} + } + events, err := u.getUserEvents(userID, user.Sequence) + if err != nil { + return user, usrErr + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return user, nil + } + } + if userCopy.State == int32(usr_model.UserStateDeleted) { + return nil, caos_errs.ThrowNotFound(nil, "HANDLER-m9dos", "Errors.User.NotFound") + } + return &userCopy, nil +} + +func (u *ProjectMember) getUserEvents(userID string, sequence uint64) ([]*models.Event, error) { + query, err := view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + + return u.es.FilterEvents(context.Background(), query) +} diff --git a/internal/management/repository/eventsourcing/handler/project_role.go b/internal/management/repository/eventsourcing/handler/project_role.go index b6f64f075a..6945bae3c8 100644 --- a/internal/management/repository/eventsourcing/handler/project_role.go +++ b/internal/management/repository/eventsourcing/handler/project_role.go @@ -7,9 +7,8 @@ import ( "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - "github.com/caos/zitadel/internal/project/repository/eventsourcing" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" view_model "github.com/caos/zitadel/internal/project/repository/view/model" ) @@ -19,17 +18,14 @@ const ( type ProjectRole struct { handler - projectEvents *proj_event.ProjectEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } func newProjectRole( handler handler, - projectEvents *proj_event.ProjectEventstore, ) *ProjectRole { h := &ProjectRole{ - handler: handler, - projectEvents: projectEvents, + handler: handler, } h.subscribe() @@ -67,7 +63,7 @@ func (p *ProjectRole) EventQuery() (*models.SearchQuery, error) { if err != nil { return nil, err } - return eventsourcing.ProjectQuery(sequence.CurrentSequence), nil + return proj_view.ProjectQuery(sequence.CurrentSequence), nil } func (p *ProjectRole) Reduce(event *models.Event) (err error) { diff --git a/internal/management/repository/eventsourcing/handler/user.go b/internal/management/repository/eventsourcing/handler/user.go index fdfe7f44af..5e1269dc39 100644 --- a/internal/management/repository/eventsourcing/handler/user.go +++ b/internal/management/repository/eventsourcing/handler/user.go @@ -2,19 +2,23 @@ package handler import ( "context" - "github.com/caos/logging" + caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/spooler" - iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + iam_model "github.com/caos/zitadel/internal/iam/model" + "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" org_model "github.com/caos/zitadel/internal/org/model" - org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/org/repository/view" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/user/repository/view/model" + "github.com/caos/zitadel/internal/v2/domain" ) const ( @@ -23,23 +27,17 @@ const ( type User struct { handler - orgEvents *org_events.OrgEventstore - iamEvents *iam_es.IAMEventstore iamID string subscription *eventstore.Subscription } func newUser( handler handler, - orgEvents *org_events.OrgEventstore, - iamEvents *iam_es.IAMEventstore, iamID string, ) *User { h := &User{ - handler: handler, - orgEvents: orgEvents, - iamEvents: iamEvents, - iamID: iamID, + handler: handler, + iamID: iamID, } h.subscribe() @@ -180,13 +178,13 @@ func (u *User) ProcessOrg(event *models.Event) (err error) { } func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), event.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.iamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -202,13 +200,13 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error { } func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), event.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.iamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -227,13 +225,13 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error { } func (u *User) fillLoginNames(user *view_model.UserView) (err error) { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(user.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), user.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.iamID) + policy, err = u.getDefaultOrgIAMPolicy(context.TODO()) if err != nil { return err } @@ -251,3 +249,53 @@ func (u *User) OnError(event *models.Event, err error) error { func (u *User) OnSuccess() error { return spooler.HandleSuccess(u.view.UpdateUserSpoolerRunTimestamp) } + +func (u *User) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-kVLb2", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *User) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &model.IAM{ + ObjectRoot: models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return model.IAMToModel(iam), nil +} + +func (u *User) getDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicy, error) { + existingIAM, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if existingIAM.DefaultOrgIAMPolicy == nil { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-2Fj8s", "Errors.IAM.OrgIAMPolicy.NotExisting") + } + return existingIAM.DefaultOrgIAMPolicy, nil +} diff --git a/internal/management/repository/eventsourcing/handler/user_external_idps.go b/internal/management/repository/eventsourcing/handler/user_external_idps.go index b25c32d803..acbb804f26 100644 --- a/internal/management/repository/eventsourcing/handler/user_external_idps.go +++ b/internal/management/repository/eventsourcing/handler/user_external_idps.go @@ -2,6 +2,11 @@ package handler import ( "context" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + org_model "github.com/caos/zitadel/internal/org/model" + "github.com/caos/zitadel/internal/org/repository/view" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/logging" @@ -12,10 +17,8 @@ import ( "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" iam_model "github.com/caos/zitadel/internal/iam/model" - "github.com/caos/zitadel/internal/iam/repository/eventsourcing" iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model" @@ -28,22 +31,16 @@ const ( type ExternalIDP struct { handler systemDefaults systemdefaults.SystemDefaults - iamEvents *eventsourcing.IAMEventstore - orgEvents *org_es.OrgEventstore subscription *eventstore.Subscription } func newExternalIDP( handler handler, systemDefaults systemdefaults.SystemDefaults, - iamEvents *eventsourcing.IAMEventstore, - orgEvents *org_es.OrgEventstore, ) *ExternalIDP { h := &ExternalIDP{ handler: handler, systemDefaults: systemDefaults, - iamEvents: iamEvents, - orgEvents: orgEvents, } h.subscribe() @@ -137,9 +134,9 @@ func (i *ExternalIDP) processIdpConfig(event *es_models.Event) (err error) { return err } if event.AggregateType == iam_es_model.IAMAggregate { - config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) + config, err = i.getDefaultIDPConfig(context.Background(), configView.IDPConfigID) } else { - config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) + config, err = i.getOrgIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) } if err != nil { return err @@ -155,9 +152,9 @@ func (i *ExternalIDP) processIdpConfig(event *es_models.Event) (err error) { } func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error { - config, err := i.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID) + config, err := i.getOrgIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID) if caos_errs.IsNotFound(err) { - config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, externalIDP.IDPConfigID) + config, err = i.getDefaultIDPConfig(context.Background(), externalIDP.IDPConfigID) } if err != nil { return err @@ -178,3 +175,64 @@ func (i *ExternalIDP) OnError(event *es_models.Event, err error) error { func (i *ExternalIDP) OnSuccess() error { return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp) } + +func (i *ExternalIDP) getOrgIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := i.getOrgByID(ctx, aggregateID) + if err != nil { + return nil, err + } + if _, i := existing.GetIDP(idpConfigID); i != nil { + return i, nil + } + return nil, caos_errs.ThrowNotFound(nil, "EVENT-22n7G", "Errors.Org.IdpNotExisting") +} + +func (i *ExternalIDP) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, i.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-4m0fs", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *ExternalIDP) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &iam_es_model.IAM{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return iam_es_model.IAMToModel(iam), nil +} + +func (u *ExternalIDP) getDefaultIDPConfig(ctx context.Context, idpConfigID string) (*iam_model.IDPConfig, error) { + existing, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if _, existingIDP := existing.GetIDP(idpConfigID); existingIDP != nil { + return existingIDP, nil + } + return nil, caos_errs.ThrowNotFound(nil, "EVENT-22Nv8", "Errors.IAM.IdpNotExisting") +} diff --git a/internal/management/repository/eventsourcing/handler/user_grant.go b/internal/management/repository/eventsourcing/handler/user_grant.go index c9fc00e3c6..7043d32309 100644 --- a/internal/management/repository/eventsourcing/handler/user_grant.go +++ b/internal/management/repository/eventsourcing/handler/user_grant.go @@ -4,18 +4,25 @@ import ( "context" "github.com/caos/logging" + "k8s.io/apimachinery/pkg/api/errors" + + caos_errs "github.com/caos/zitadel/internal/errors" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + org_view "github.com/caos/zitadel/internal/org/repository/view" + proj_view "github.com/caos/zitadel/internal/project/repository/view" + "github.com/caos/zitadel/internal/user/repository/view" + usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" org_model "github.com/caos/zitadel/internal/org/model" - org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" proj_model "github.com/caos/zitadel/internal/project/model" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" usr_model "github.com/caos/zitadel/internal/user/model" - usr_events "github.com/caos/zitadel/internal/user/repository/eventsourcing" usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" grant_es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model" @@ -27,23 +34,14 @@ const ( type UserGrant struct { handler - projectEvents *proj_event.ProjectEventstore - userEvents *usr_events.UserEventstore - orgEvents *org_events.OrgEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } func newUserGrant( handler handler, - projectEvents *proj_event.ProjectEventstore, - userEvents *usr_events.UserEventstore, - orgEvents *org_events.OrgEventstore, ) *UserGrant { h := &UserGrant{ - handler: handler, - projectEvents: projectEvents, - userEvents: userEvents, - orgEvents: orgEvents, + handler: handler, } h.subscribe() @@ -141,7 +139,7 @@ func (u *UserGrant) processUser(event *es_models.Event) (err error) { if len(grants) == 0 { return u.view.ProcessedUserGrantSequence(event) } - user, err := u.userEvents.UserByID(context.Background(), event.AggregateID) + user, err := u.getUserByID(event.AggregateID) if err != nil { return err } @@ -164,7 +162,7 @@ func (u *UserGrant) processProject(event *es_models.Event) (err error) { if len(grants) == 0 { return u.view.ProcessedUserGrantSequence(event) } - project, err := u.projectEvents.ProjectByID(context.Background(), event.AggregateID) + project, err := u.getProjectByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -178,18 +176,18 @@ func (u *UserGrant) processProject(event *es_models.Event) (err error) { } func (u *UserGrant) fillData(grant *view_model.UserGrantView, resourceOwner string) (err error) { - user, err := u.userEvents.UserByID(context.Background(), grant.UserID) + user, err := u.getUserByID(grant.UserID) if err != nil { return err } u.fillUserData(grant, user) - project, err := u.projectEvents.ProjectByID(context.Background(), grant.ProjectID) + project, err := u.getProjectByID(context.Background(), grant.ProjectID) if err != nil { return err } u.fillProjectData(grant, project) - org, err := u.orgEvents.OrgByID(context.TODO(), org_model.NewOrg(resourceOwner)) + org, err := u.getOrgByID(context.TODO(), resourceOwner) if err != nil { return err } @@ -197,16 +195,16 @@ func (u *UserGrant) fillData(grant *view_model.UserGrantView, resourceOwner stri return nil } -func (u *UserGrant) fillUserData(grant *view_model.UserGrantView, user *usr_model.User) { +func (u *UserGrant) fillUserData(grant *view_model.UserGrantView, user *usr_view_model.UserView) { grant.UserName = user.UserName - if user.Human != nil { + if user.HumanView != nil { grant.FirstName = user.FirstName grant.LastName = user.LastName grant.DisplayName = user.FirstName + " " + user.LastName - grant.Email = user.EmailAddress + grant.Email = user.Email } - if user.Machine != nil { - grant.DisplayName = user.Machine.Name + if user.MachineView != nil { + grant.DisplayName = user.MachineView.Name } } @@ -233,3 +231,79 @@ func (u *UserGrant) OnError(event *es_models.Event, err error) error { func (u *UserGrant) OnSuccess() error { return spooler.HandleSuccess(u.view.UpdateUserGrantSpoolerRunTimestamp) } + +func (u *UserGrant) getUserByID(userID string) (*usr_view_model.UserView, error) { + user, usrErr := u.view.UserByID(userID) + if usrErr != nil && !caos_errs.IsNotFound(usrErr) { + return nil, usrErr + } + if user == nil { + user = &usr_view_model.UserView{} + } + events, err := u.getUserEvents(userID, user.Sequence) + if err != nil { + return user, usrErr + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return user, nil + } + } + if userCopy.State == int32(usr_model.UserStateDeleted) { + return nil, caos_errs.ThrowNotFound(nil, "HANDLER-m9dos", "Errors.User.NotFound") + } + return &userCopy, nil +} + +func (u *UserGrant) getUserEvents(userID string, sequence uint64) ([]*models.Event, error) { + query, err := view.UserByIDQuery(userID, sequence) + if err != nil { + return nil, err + } + + return u.es.FilterEvents(context.Background(), query) +} + +func (u *UserGrant) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := org_view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-kVLb2", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *UserGrant) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) { + query, err := proj_view.ProjectByIDQuery(projID, 0) + if err != nil { + return nil, err + } + esProject := &proj_es_model.Project{ + ObjectRoot: models.ObjectRoot{ + AggregateID: projID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esProject.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esProject.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-Dfb42", "Errors.Project.NotFound") + } + + return proj_es_model.ProjectToModel(esProject), nil +} diff --git a/internal/management/repository/eventsourcing/handler/user_membership.go b/internal/management/repository/eventsourcing/handler/user_membership.go index 520479f665..4716d158fc 100644 --- a/internal/management/repository/eventsourcing/handler/user_membership.go +++ b/internal/management/repository/eventsourcing/handler/user_membership.go @@ -3,6 +3,14 @@ package handler import ( "context" + "k8s.io/apimachinery/pkg/api/errors" + + caos_errs "github.com/caos/zitadel/internal/errors" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + org_view "github.com/caos/zitadel/internal/org/repository/view" + proj_model "github.com/caos/zitadel/internal/project/model" + proj_view "github.com/caos/zitadel/internal/project/repository/view" + "github.com/caos/logging" "github.com/caos/zitadel/internal/eventstore" @@ -11,9 +19,7 @@ import ( "github.com/caos/zitadel/internal/eventstore/spooler" iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" org_model "github.com/caos/zitadel/internal/org/model" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" - proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" usr_model "github.com/caos/zitadel/internal/user/model" "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" @@ -26,20 +32,14 @@ const ( type UserMembership struct { handler - orgEvents *org_event.OrgEventstore - projectEvents *proj_event.ProjectEventstore - subscription *eventstore.Subscription + subscription *eventstore.Subscription } func newUserMembership( handler handler, - orgEvents *org_event.OrgEventstore, - projectEvents *proj_event.ProjectEventstore, ) *UserMembership { h := &UserMembership{ - handler: handler, - orgEvents: orgEvents, - projectEvents: projectEvents, + handler: handler, } h.subscribe() @@ -155,7 +155,7 @@ func (m *UserMembership) processOrg(event *es_models.Event) (err error) { } func (m *UserMembership) fillOrgDisplayName(member *usr_es_model.UserMembershipView) (err error) { - org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(member.AggregateID)) + org, err := m.getOrgByID(context.Background(), member.AggregateID) if err != nil { return err } @@ -164,7 +164,7 @@ func (m *UserMembership) fillOrgDisplayName(member *usr_es_model.UserMembershipV } func (m *UserMembership) updateOrgDisplayName(event *es_models.Event) error { - org, err := m.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.AggregateID)) + org, err := m.getOrgByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -220,7 +220,7 @@ func (m *UserMembership) processProject(event *es_models.Event) (err error) { } func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) { - project, err := m.projectEvents.ProjectByID(context.Background(), member.AggregateID) + project, err := m.getProjectByID(context.Background(), member.AggregateID) if err != nil { return err } @@ -229,7 +229,7 @@ func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembers } func (m *UserMembership) updateProjectDisplayName(event *es_models.Event) error { - project, err := m.projectEvents.ProjectByID(context.Background(), event.AggregateID) + project, err := m.getProjectByID(context.Background(), event.AggregateID) if err != nil { return err } @@ -261,3 +261,46 @@ func (m *UserMembership) OnError(event *es_models.Event, err error) error { func (m *UserMembership) OnSuccess() error { return spooler.HandleSuccess(m.view.UpdateUserMembershipSpoolerRunTimestamp) } + +func (u *UserMembership) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := org_view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + esOrg := &org_es_model.Org{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: orgID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-kVLb2", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *UserMembership) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) { + query, err := proj_view.ProjectByIDQuery(projID, 0) + if err != nil { + return nil, err + } + esProject := &proj_es_model.Project{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: projID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esProject.AppendEvents, query) + if err != nil && !errors.IsNotFound(err) { + return nil, err + } + if esProject.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-Bg32b", "Errors.Project.NotFound") + } + + return proj_es_model.ProjectToModel(esProject), nil +} diff --git a/internal/management/repository/eventsourcing/repository.go b/internal/management/repository/eventsourcing/repository.go index d20a01fb3d..c989f55858 100644 --- a/internal/management/repository/eventsourcing/repository.go +++ b/internal/management/repository/eventsourcing/repository.go @@ -1,22 +1,15 @@ package eventsourcing import ( - "context" "github.com/caos/zitadel/internal/v2/query" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/config/types" es_int "github.com/caos/zitadel/internal/eventstore" es_spol "github.com/caos/zitadel/internal/eventstore/spooler" - iam_model "github.com/caos/zitadel/internal/iam/model" - es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "github.com/caos/zitadel/internal/management/repository/eventsourcing/eventstore" - "github.com/caos/zitadel/internal/management/repository/eventsourcing/handler" "github.com/caos/zitadel/internal/management/repository/eventsourcing/spooler" mgmt_view "github.com/caos/zitadel/internal/management/repository/eventsourcing/view" - es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" - es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing" - es_usr "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type Config struct { @@ -34,6 +27,7 @@ type EsRepository struct { eventstore.UserRepo eventstore.UserGrantRepo eventstore.IAMRepository + view *mgmt_view.View } func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string) (*EsRepository, error) { @@ -53,55 +47,25 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string) (*EsRe return nil, err } - project, err := es_proj.StartProject(es_proj.ProjectConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, systemDefaults) - if err != nil { - return nil, err - } - user, err := es_usr.StartUser(es_usr.UserConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, systemDefaults) - if err != nil { - return nil, err - } - if err != nil { - return nil, err - } iamV2Query, err := query.StartQuerySide(&query.Config{Eventstore: esV2, SystemDefaults: systemDefaults}) if err != nil { return nil, err } - org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es, IAMDomain: conf.Domain}, systemDefaults) - - iam, err := es_iam.StartIAM(es_iam.IAMConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, systemDefaults) - if err != nil { - return nil, err - } - eventstoreRepos := handler.EventstoreRepos{ProjectEvents: project, UserEvents: user, OrgEvents: org, IamEvents: iam} - spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, eventstoreRepos, systemDefaults) + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, systemDefaults) return &EsRepository{ spooler: spool, - OrgRepository: eventstore.OrgRepository{conf.SearchLimit, org, user, iam, view, roles, systemDefaults}, - ProjectRepo: eventstore.ProjectRepo{es, conf.SearchLimit, project, user, iam, view, roles, systemDefaults.IamID}, - UserRepo: eventstore.UserRepo{es, conf.SearchLimit, user, org, view, systemDefaults}, + OrgRepository: eventstore.OrgRepository{conf.SearchLimit, es, view, roles, systemDefaults}, + ProjectRepo: eventstore.ProjectRepo{es, conf.SearchLimit, view, roles, systemDefaults.IamID}, + UserRepo: eventstore.UserRepo{es, conf.SearchLimit, view, systemDefaults}, UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, view}, IAMRepository: eventstore.IAMRepository{ IAMV2Query: iamV2Query, }, + view: view, }, nil } func (repo *EsRepository) Health() error { - return repo.ProjectEvents.Health(context.Background()) -} - -func (repo *EsRepository) IAMByID(ctx context.Context, id string) (*iam_model.IAM, error) { - return repo.IAMRepository.IAMByID(ctx, id) + return repo.view.Health() } diff --git a/internal/management/repository/eventsourcing/spooler/spooler.go b/internal/management/repository/eventsourcing/spooler/spooler.go index 1ffb125380..8954b5f170 100644 --- a/internal/management/repository/eventsourcing/spooler/spooler.go +++ b/internal/management/repository/eventsourcing/spooler/spooler.go @@ -17,12 +17,12 @@ type SpoolerConfig struct { Handlers handler.Configs } -func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, eventstoreRepos handler.EventstoreRepos, defaults systemdefaults.SystemDefaults) *spooler.Spooler { +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, defaults systemdefaults.SystemDefaults) *spooler.Spooler { spoolerConfig := spooler.Config{ Eventstore: es, Locker: &locker{dbClient: sql}, ConcurrentWorkers: c.ConcurrentWorkers, - ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, eventstoreRepos, defaults), + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, defaults), } spool := spoolerConfig.New() spool.Start() diff --git a/internal/management/repository/project.go b/internal/management/repository/project.go index 4baa59690a..67685996d7 100644 --- a/internal/management/repository/project.go +++ b/internal/management/repository/project.go @@ -2,6 +2,7 @@ package repository import ( "context" + iam_model "github.com/caos/zitadel/internal/iam/model" key_model "github.com/caos/zitadel/internal/key/model" "github.com/caos/zitadel/internal/project/model" @@ -28,12 +29,12 @@ type ProjectRepository interface { ApplicationChanges(ctx context.Context, id string, secId string, lastSequence uint64, limit uint64, sortAscending bool) (*model.ApplicationChanges, error) SearchClientKeys(ctx context.Context, request *key_model.AuthNKeySearchRequest) (*key_model.AuthNKeySearchResponse, error) GetClientKey(ctx context.Context, projectID, applicationID, keyID string) (*key_model.AuthNKeyView, error) - AddClientKey(ctx context.Context, key *model.ClientKey) (*model.ClientKey, error) - RemoveClientKey(ctx context.Context, projectID, applicationID, keyID string) error ProjectGrantByID(ctx context.Context, grantID string) (*model.ProjectGrantView, error) SearchProjectGrantMembers(ctx context.Context, request *model.ProjectGrantMemberSearchRequest) (*model.ProjectGrantMemberSearchResponse, error) ProjectGrantMemberByID(ctx context.Context, projectID, userID string) (*model.ProjectGrantMemberView, error) GetProjectGrantMemberRoles() []string + + GetIAMByID(ctx context.Context) (*iam_model.IAM, error) } diff --git a/internal/management/repository/user.go b/internal/management/repository/user.go index 0eafac5ac7..5a65b5774b 100644 --- a/internal/management/repository/user.go +++ b/internal/management/repository/user.go @@ -21,7 +21,7 @@ type UserRepository interface { UserMFAs(ctx context.Context, userID string) ([]*model.MultiFactor, error) - GetPasswordless(ctx context.Context, userID string) ([]*model.WebAuthNToken, error) + GetPasswordless(ctx context.Context, userID string) ([]*model.WebAuthNView, error) SearchExternalIDPs(ctx context.Context, request *model.ExternalIDPSearchRequest) (*model.ExternalIDPSearchResponse, error) ExternalIDPsByIDPConfigID(ctx context.Context, idpConfigID string) ([]*model.ExternalIDPView, error) diff --git a/internal/notification/repository/eventsourcing/handler/handler.go b/internal/notification/repository/eventsourcing/handler/handler.go index ef91b94256..eb3affa5c2 100644 --- a/internal/notification/repository/eventsourcing/handler/handler.go +++ b/internal/notification/repository/eventsourcing/handler/handler.go @@ -12,10 +12,7 @@ import ( "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/i18n" - iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "github.com/caos/zitadel/internal/notification/repository/eventsourcing/view" - org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type Configs map[string]*Config @@ -37,13 +34,7 @@ func (h *handler) Eventstore() eventstore.Eventstore { return h.es } -type EventstoreRepos struct { - UserEvents *usr_event.UserEventstore - OrgEvents *org_event.OrgEventstore - IAMEvents *iam_es.IAMEventstore -} - -func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, command *command.CommandSide, repos EventstoreRepos, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) []query.Handler { +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es eventstore.Eventstore, command *command.CommandSide, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) []query.Handler { aesCrypto, err := crypto.NewAESCrypto(systemDefaults.UserVerificationKey) if err != nil { logging.Log("HANDL-s90ew").WithError(err).Debug("error create new aes crypto") @@ -51,14 +42,11 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es return []query.Handler{ newNotifyUser( handler{view, bulkLimit, configs.cycleDuration("User"), errorCount, es}, - repos.OrgEvents, - repos.IAMEvents, systemDefaults.IamID, ), newNotification( handler{view, bulkLimit, configs.cycleDuration("Notification"), errorCount, es}, command, - repos.UserEvents, systemDefaults, aesCrypto, i18n, diff --git a/internal/notification/repository/eventsourcing/handler/notification.go b/internal/notification/repository/eventsourcing/handler/notification.go index 7d2b3534bd..266e056f96 100644 --- a/internal/notification/repository/eventsourcing/handler/notification.go +++ b/internal/notification/repository/eventsourcing/handler/notification.go @@ -3,6 +3,7 @@ package handler import ( "context" "encoding/json" + "github.com/caos/zitadel/internal/user/repository/view" "github.com/caos/zitadel/internal/user/repository/view/model" view_model "github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/zitadel/internal/v2/command" @@ -24,7 +25,6 @@ import ( iam_model "github.com/caos/zitadel/internal/iam/model" iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/notification/types" - usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) @@ -47,7 +47,6 @@ const ( type Notification struct { handler command *command.CommandSide - userEvents *usr_event.UserEventstore systemDefaults sd.SystemDefaults AesCrypto crypto.EncryptionAlgorithm i18n *i18n.Translator @@ -58,7 +57,6 @@ type Notification struct { func newNotification( handler handler, command *command.CommandSide, - userEvents *usr_event.UserEventstore, defaults sd.SystemDefaults, aesCrypto crypto.EncryptionAlgorithm, translator *i18n.Translator, @@ -67,7 +65,6 @@ func newNotification( h := &Notification{ handler: handler, command: command, - userEvents: userEvents, systemDefaults: defaults, i18n: translator, statikDir: statikDir, @@ -109,7 +106,7 @@ func (n *Notification) EventQuery() (*models.SearchQuery, error) { if err != nil { return nil, err } - return usr_event.UserQuery(sequence.CurrentSequence), nil + return view.UserQuery(sequence.CurrentSequence), nil } func (n *Notification) Reduce(event *models.Event) (err error) { @@ -331,7 +328,7 @@ func (n *Notification) checkIfAlreadyHandled(userID string, sequence uint64, eve } func (n *Notification) getUserEvents(userID string, sequence uint64) ([]*models.Event, error) { - query, err := usr_event.UserByIDQuery(userID, sequence) + query, err := view.UserByIDQuery(userID, sequence) if err != nil { return nil, err } diff --git a/internal/notification/repository/eventsourcing/handler/notify_user.go b/internal/notification/repository/eventsourcing/handler/notify_user.go index 7d774d19ea..90ef1a3daa 100644 --- a/internal/notification/repository/eventsourcing/handler/notify_user.go +++ b/internal/notification/repository/eventsourcing/handler/notify_user.go @@ -2,15 +2,20 @@ package handler import ( "context" + caos_errs "github.com/caos/zitadel/internal/errors" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + iam_model "github.com/caos/zitadel/internal/iam/model" + "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + iam_view "github.com/caos/zitadel/internal/iam/repository/view" + org_view "github.com/caos/zitadel/internal/org/repository/view" + "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/logging" "github.com/caos/zitadel/internal/eventstore" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/query" "github.com/caos/zitadel/internal/eventstore/spooler" - iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing" org_model "github.com/caos/zitadel/internal/org/model" - org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/user/repository/view/model" @@ -22,23 +27,17 @@ const ( type NotifyUser struct { handler - orgEvents *org_events.OrgEventstore - iamEvents *iam_es.IAMEventstore iamID string subscription *eventstore.Subscription } func newNotifyUser( handler handler, - orgEvents *org_events.OrgEventstore, - iamEvents *iam_es.IAMEventstore, iamID string, ) *NotifyUser { h := &NotifyUser{ - handler: handler, - orgEvents: orgEvents, - iamEvents: iamEvents, - iamID: iamID, + handler: handler, + iamID: iamID, } h.subscribe() @@ -157,13 +156,13 @@ func (u *NotifyUser) ProcessOrg(event *es_models.Event) (err error) { } func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *es_models.Event) error { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), event.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.iamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -183,13 +182,13 @@ func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *es_models.Event) error { } func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(event.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), event.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.iamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -212,13 +211,13 @@ func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) e } func (u *NotifyUser) fillLoginNames(user *view_model.NotifyUser) (err error) { - org, err := u.orgEvents.OrgByID(context.Background(), org_model.NewOrg(user.ResourceOwner)) + org, err := u.getOrgByID(context.Background(), user.ResourceOwner) if err != nil { return err } policy := org.OrgIamPolicy if policy == nil { - policy, err = u.iamEvents.GetOrgIAMPolicy(context.Background(), u.iamID) + policy, err = u.getDefaultOrgIAMPolicy(context.Background()) if err != nil { return err } @@ -236,3 +235,49 @@ func (p *NotifyUser) OnError(event *es_models.Event, err error) error { func (u *NotifyUser) OnSuccess() error { return spooler.HandleSuccess(u.view.UpdateNotifyUserSpoolerRunTimestamp) } + +func (u *NotifyUser) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, error) { + query, err := org_view.OrgByIDQuery(orgID, 0) + if err != nil { + return nil, err + } + + var esOrg *org_es_model.Org + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, esOrg.AppendEvents, query) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + if esOrg.Sequence == 0 { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-kVLb2", "Errors.Org.NotFound") + } + + return org_es_model.OrgToModel(esOrg), nil +} + +func (u *NotifyUser) getIAMByID(ctx context.Context) (*iam_model.IAM, error) { + query, err := iam_view.IAMByIDQuery(domain.IAMID, 0) + if err != nil { + return nil, err + } + iam := &model.IAM{ + ObjectRoot: es_models.ObjectRoot{ + AggregateID: domain.IAMID, + }, + } + err = es_sdk.Filter(ctx, u.Eventstore().FilterEvents, iam.AppendEvents, query) + if err != nil && caos_errs.IsNotFound(err) && iam.Sequence == 0 { + return nil, err + } + return model.IAMToModel(iam), nil +} + +func (u *NotifyUser) getDefaultOrgIAMPolicy(ctx context.Context) (*iam_model.OrgIAMPolicy, error) { + existingIAM, err := u.getIAMByID(ctx) + if err != nil { + return nil, err + } + if existingIAM.DefaultOrgIAMPolicy == nil { + return nil, caos_errs.ThrowNotFound(nil, "EVENT-2Fj8s", "Errors.IAM.OrgIAMPolicy.NotExisting") + } + return existingIAM.DefaultOrgIAMPolicy, nil +} diff --git a/internal/notification/repository/eventsourcing/repository.go b/internal/notification/repository/eventsourcing/repository.go index 548ea68297..afd09bc2a9 100644 --- a/internal/notification/repository/eventsourcing/repository.go +++ b/internal/notification/repository/eventsourcing/repository.go @@ -1,7 +1,6 @@ package eventsourcing import ( - es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" "github.com/caos/zitadel/internal/v2/command" "net/http" @@ -10,11 +9,8 @@ import ( es_int "github.com/caos/zitadel/internal/eventstore" es_spol "github.com/caos/zitadel/internal/eventstore/spooler" "github.com/caos/zitadel/internal/i18n" - "github.com/caos/zitadel/internal/notification/repository/eventsourcing/handler" "github.com/caos/zitadel/internal/notification/repository/eventsourcing/spooler" noti_view "github.com/caos/zitadel/internal/notification/repository/eventsourcing/view" - es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" - es_usr "github.com/caos/zitadel/internal/user/repository/eventsourcing" "golang.org/x/text/language" ) @@ -45,28 +41,11 @@ func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults, c return nil, err } - user, err := es_usr.StartUser(es_usr.UserConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, systemDefaults) - if err != nil { - return nil, err - } - org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es, IAMDomain: conf.Domain}, systemDefaults) - translator, err := i18n.NewTranslator(dir, i18n.TranslatorConfig{DefaultLanguage: conf.DefaultLanguage}) if err != nil { return nil, err } - iam, err := es_iam.StartIAM(es_iam.IAMConfig{ - Eventstore: es, - Cache: conf.Eventstore.Cache, - }, systemDefaults) - if err != nil { - return nil, err - } - eventstoreRepos := handler.EventstoreRepos{UserEvents: user, OrgEvents: org, IAMEvents: iam} - spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, command, eventstoreRepos, systemDefaults, translator, dir) + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, command, systemDefaults, translator, dir) return &EsRepository{ spool, diff --git a/internal/notification/repository/eventsourcing/spooler/spooler.go b/internal/notification/repository/eventsourcing/spooler/spooler.go index 86255a6d46..01d64e5afa 100644 --- a/internal/notification/repository/eventsourcing/spooler/spooler.go +++ b/internal/notification/repository/eventsourcing/spooler/spooler.go @@ -20,12 +20,12 @@ type SpoolerConfig struct { Handlers handler.Configs } -func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, command *command.CommandSide, eventstoreRepos handler.EventstoreRepos, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) *spooler.Spooler { +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, command *command.CommandSide, systemDefaults sd.SystemDefaults, i18n *i18n.Translator, dir http.FileSystem) *spooler.Spooler { spoolerConfig := spooler.Config{ Eventstore: es, Locker: &locker{dbClient: sql}, ConcurrentWorkers: c.ConcurrentWorkers, - ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, command, eventstoreRepos, systemDefaults, i18n, dir), + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, command, systemDefaults, i18n, dir), } spool := spoolerConfig.New() spool.Start() diff --git a/internal/org/repository/eventsourcing/eventstore.go b/internal/org/repository/eventsourcing/eventstore.go deleted file mode 100644 index 575a5beee2..0000000000 --- a/internal/org/repository/eventsourcing/eventstore.go +++ /dev/null @@ -1,191 +0,0 @@ -package eventsourcing - -import ( - "context" - "encoding/json" - - "github.com/caos/logging" - http_utils "github.com/caos/zitadel/internal/api/http" - "github.com/caos/zitadel/internal/config/systemdefaults" - "github.com/caos/zitadel/internal/crypto" - "github.com/caos/zitadel/internal/errors" - "github.com/caos/zitadel/internal/eventstore" - es_models "github.com/caos/zitadel/internal/eventstore/models" - es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" - iam_model "github.com/caos/zitadel/internal/iam/model" - "github.com/caos/zitadel/internal/id" - org_model "github.com/caos/zitadel/internal/org/model" - "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" - "github.com/golang/protobuf/ptypes" -) - -type OrgEventstore struct { - eventstore.Eventstore - IAMDomain string - IamID string - idGenerator id.Generator - verificationAlgorithm crypto.EncryptionAlgorithm - verificationGenerator crypto.Generator - verificationValidator func(domain string, token string, verifier string, checkType http_utils.CheckType) error - secretCrypto crypto.Crypto -} - -type OrgConfig struct { - eventstore.Eventstore - IAMDomain string - VerificationConfig *crypto.KeyConfig -} - -func StartOrg(conf OrgConfig, defaults systemdefaults.SystemDefaults) *OrgEventstore { - verificationAlg, err := crypto.NewAESCrypto(defaults.DomainVerification.VerificationKey) - logging.Log("EVENT-aZ22d").OnError(err).Panic("cannot create verificationAlgorithm for domain verification") - verificationGen := crypto.NewEncryptionGenerator(defaults.DomainVerification.VerificationGenerator, verificationAlg) - - aesCrypto, err := crypto.NewAESCrypto(defaults.IDPConfigVerificationKey) - logging.Log("EVENT-Sn8du").OnError(err).Panic("cannot create verificationAlgorithm for idp config verification") - - return &OrgEventstore{ - Eventstore: conf.Eventstore, - idGenerator: id.SonyFlakeGenerator, - verificationAlgorithm: verificationAlg, - verificationGenerator: verificationGen, - verificationValidator: http_utils.ValidateDomain, - IAMDomain: conf.IAMDomain, - IamID: defaults.IamID, - secretCrypto: aesCrypto, - } -} - -func (es *OrgEventstore) OrgByID(ctx context.Context, org *org_model.Org) (*org_model.Org, error) { - if org == nil { - return nil, errors.ThrowInvalidArgument(nil, "EVENT-gQTYP", "Errors.Org.Empty") - } - query, err := OrgByIDQuery(org.AggregateID, org.Sequence) - if err != nil { - return nil, err - } - - esOrg := model.OrgFromModel(org) - err = es_sdk.Filter(ctx, es.FilterEvents, esOrg.AppendEvents, query) - if err != nil && !errors.IsNotFound(err) { - return nil, err - } - if esOrg.Sequence == 0 { - return nil, errors.ThrowNotFound(nil, "EVENT-kVLb2", "Errors.Org.NotFound") - } - - return model.OrgToModel(esOrg), nil -} - -func (es *OrgEventstore) OrgEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { - query, err := OrgByIDQuery(id, sequence) - if err != nil { - return nil, err - } - return es.FilterEvents(ctx, query) -} - -func (es *OrgEventstore) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) { - var found bool - err = es_sdk.Filter(ctx, es.FilterEvents, isUniqueValidation(&found), OrgNameUniqueQuery(name)) - if (err != nil && !errors.IsNotFound(err)) || found { - return false, err - } - - err = es_sdk.Filter(ctx, es.FilterEvents, isUniqueValidation(&found), OrgDomainUniqueQuery(domain)) - if err != nil && !errors.IsNotFound(err) { - return false, err - } - - return !found, nil -} - -func isUniqueValidation(unique *bool) func(events ...*es_models.Event) error { - return func(events ...*es_models.Event) error { - if len(events) == 0 { - return nil - } - *unique = *unique || events[0].Type == model.OrgDomainReserved || events[0].Type == model.OrgNameReserved - - return nil - } -} - -func (es *OrgEventstore) OrgChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*org_model.OrgChanges, error) { - query := ChangesQuery(id, lastSequence, limit, sortAscending) - - events, err := es.Eventstore.FilterEvents(context.Background(), query) - if err != nil { - logging.Log("EVENT-ZRffs").WithError(err).Warn("eventstore unavailable") - return nil, errors.ThrowInternal(err, "EVENT-328b1", "Errors.Org.NotFound") - } - if len(events) == 0 { - return nil, errors.ThrowNotFound(nil, "EVENT-FpQqK", "Errors.Changes.NotFound") - } - - changes := make([]*org_model.OrgChange, len(events)) - - for i, event := range events { - creationDate, err := ptypes.TimestampProto(event.CreationDate) - logging.Log("EVENT-qxIR7").OnError(err).Debug("unable to parse timestamp") - change := &org_model.OrgChange{ - ChangeDate: creationDate, - EventType: event.Type.String(), - ModifierId: event.EditorUser, - Sequence: event.Sequence, - } - - if event.Data != nil { - org := new(model.Org) - err := json.Unmarshal(event.Data, org) - logging.Log("EVENT-XCLEm").OnError(err).Debug("unable to unmarshal data") - change.Data = org - } - - changes[i] = change - if lastSequence < event.Sequence { - lastSequence = event.Sequence - } - } - - return &org_model.OrgChanges{ - Changes: changes, - LastSequence: lastSequence, - }, nil -} - -func ChangesQuery(orgID string, latestSequence, limit uint64, sortAscending bool) *es_models.SearchQuery { - query := es_models.NewSearchQuery(). - AggregateTypeFilter(model.OrgAggregate) - - if !sortAscending { - query.OrderDesc() - } - - query.LatestSequenceFilter(latestSequence). - AggregateIDFilter(orgID). - SetLimit(limit) - return query -} - -func (es *OrgEventstore) GetOrgIAMPolicy(ctx context.Context, orgID string) (*iam_model.OrgIAMPolicy, error) { - existingOrg, err := es.OrgByID(ctx, org_model.NewOrg(orgID)) - if err != nil { - return nil, err - } - if existingOrg.OrgIamPolicy == nil { - return nil, errors.ThrowNotFound(nil, "EVENT-3F9sf", "Errors.Org.OrgIAM.NotExisting") - } - return existingOrg.OrgIamPolicy, nil -} - -func (es *OrgEventstore) GetIDPConfig(ctx context.Context, aggregateID, idpConfigID string) (*iam_model.IDPConfig, error) { - existing, err := es.OrgByID(ctx, org_model.NewOrg(aggregateID)) - if err != nil { - return nil, err - } - if _, i := existing.GetIDP(idpConfigID); i != nil { - return i, nil - } - return nil, errors.ThrowNotFound(nil, "EVENT-Qlo0d", "Errors.Org.IdpNotExisting") -} diff --git a/internal/org/repository/model.go b/internal/org/repository/model.go deleted file mode 100644 index eb1f4d0969..0000000000 --- a/internal/org/repository/model.go +++ /dev/null @@ -1,10 +0,0 @@ -package repository - -import es_models "github.com/caos/zitadel/internal/eventstore/models" - -type Org struct { - es_models.ObjectRoot - - Name string - Domain string -} diff --git a/internal/org/repository/eventsourcing/org.go b/internal/org/repository/view/query.go similarity index 75% rename from internal/org/repository/eventsourcing/org.go rename to internal/org/repository/view/query.go index 9e112ec618..d8ff2aa6da 100644 --- a/internal/org/repository/eventsourcing/org.go +++ b/internal/org/repository/view/query.go @@ -1,8 +1,6 @@ -package eventsourcing +package view import ( - "context" - "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" @@ -16,6 +14,12 @@ func OrgByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, err AggregateIDFilter(id), nil } +func OrgQuery(latestSequence uint64) *es_models.SearchQuery { + return es_models.NewSearchQuery(). + AggregateTypeFilter(model.OrgAggregate). + LatestSequenceFilter(latestSequence) +} + func OrgDomainUniqueQuery(domain string) *es_models.SearchQuery { return es_models.NewSearchQuery(). AggregateTypeFilter(model.OrgDomainAggregate). @@ -32,12 +36,16 @@ func OrgNameUniqueQuery(name string) *es_models.SearchQuery { SetLimit(1) } -func OrgQuery(latestSequence uint64) *es_models.SearchQuery { - return es_models.NewSearchQuery(). - AggregateTypeFilter(model.OrgAggregate). - LatestSequenceFilter(latestSequence) -} +func ChangesQuery(orgID string, latestSequence, limit uint64, sortAscending bool) *es_models.SearchQuery { + query := es_models.NewSearchQuery(). + AggregateTypeFilter(model.OrgAggregate) -func OrgAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, id string, sequence uint64) (*es_models.Aggregate, error) { - return aggCreator.NewAggregate(ctx, id, model.OrgAggregate, model.OrgVersion, sequence, es_models.OverwriteResourceOwner(id)) + if !sortAscending { + query.OrderDesc() + } + + query.LatestSequenceFilter(latestSequence). + AggregateIDFilter(orgID). + SetLimit(limit) + return query } diff --git a/internal/project/repository/eventsourcing/eventstore.go b/internal/project/repository/eventsourcing/eventstore.go index 3a44e83e09..4c1161b49b 100644 --- a/internal/project/repository/eventsourcing/eventstore.go +++ b/internal/project/repository/eventsourcing/eventstore.go @@ -1,206 +1,46 @@ package eventsourcing -import ( - "context" - "encoding/json" - "strings" - - "github.com/caos/logging" - "github.com/golang/protobuf/ptypes" - - "github.com/caos/zitadel/internal/cache/config" - sd "github.com/caos/zitadel/internal/config/systemdefaults" - "github.com/caos/zitadel/internal/crypto" - "github.com/caos/zitadel/internal/errors" - caos_errs "github.com/caos/zitadel/internal/errors" - es_int "github.com/caos/zitadel/internal/eventstore" - es_models "github.com/caos/zitadel/internal/eventstore/models" - es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" - "github.com/caos/zitadel/internal/id" - proj_model "github.com/caos/zitadel/internal/project/model" - "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" -) - -const ( - projectOwnerRole = "PROJECT_OWNER" - projectOwnerGlobalRole = "PROJECT_OWNER_GLOBAL" -) - -type ProjectEventstore struct { - es_int.Eventstore - projectCache *ProjectCache - passwordAlg crypto.HashAlgorithm - pwGenerator crypto.Generator - idGenerator id.Generator - ClientKeySize int -} - -type ProjectConfig struct { - es_int.Eventstore - Cache *config.CacheConfig -} - -func StartProject(conf ProjectConfig, systemDefaults sd.SystemDefaults) (*ProjectEventstore, error) { - projectCache, err := StartCache(conf.Cache) - if err != nil { - return nil, err - } - passwordAlg := crypto.NewBCrypt(systemDefaults.SecretGenerators.PasswordSaltCost) - pwGenerator := crypto.NewHashGenerator(systemDefaults.SecretGenerators.ClientSecretGenerator, passwordAlg) - return &ProjectEventstore{ - Eventstore: conf.Eventstore, - projectCache: projectCache, - passwordAlg: passwordAlg, - pwGenerator: pwGenerator, - idGenerator: id.SonyFlakeGenerator, - ClientKeySize: int(systemDefaults.SecretGenerators.ApplicationKeySize), - }, nil -} - -func (es *ProjectEventstore) ProjectByID(ctx context.Context, id string) (*proj_model.Project, error) { - project := es.projectCache.getProject(id) - - query, err := ProjectByIDQuery(project.AggregateID, project.Sequence) - if err != nil { - return nil, err - } - err = es_sdk.Filter(ctx, es.FilterEvents, project.AppendEvents, query) - if err != nil && !(caos_errs.IsNotFound(err) && project.Sequence != 0) { - return nil, err - } - if project.State == int32(proj_model.ProjectStateRemoved) { - return nil, caos_errs.ThrowNotFound(nil, "EVENT-dG8ie", "Errors.Project.NotFound") - } - es.projectCache.cacheProject(project) - return model.ProjectToModel(project), nil -} - -func (es *ProjectEventstore) ProjectEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { - query, err := ProjectByIDQuery(id, sequence) - if err != nil { - return nil, err - } - return es.FilterEvents(ctx, query) -} - -func (es *ProjectEventstore) ProjectChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*proj_model.ProjectChanges, error) { - query := ChangesQuery(id, lastSequence, limit, sortAscending) - - events, err := es.Eventstore.FilterEvents(context.Background(), query) - if err != nil { - logging.Log("EVENT-ZRffs").WithError(err).Warn("eventstore unavailable") - return nil, errors.ThrowInternal(err, "EVENT-328b1", "Errors.Internal") - } - if len(events) == 0 { - return nil, caos_errs.ThrowNotFound(nil, "EVENT-FpQqK", "Errors.Changes.NotFound") - } - - changes := make([]*proj_model.ProjectChange, len(events)) - - for i, event := range events { - creationDate, err := ptypes.TimestampProto(event.CreationDate) - logging.Log("EVENT-qxIR7").OnError(err).Debug("unable to parse timestamp") - change := &proj_model.ProjectChange{ - ChangeDate: creationDate, - EventType: event.Type.String(), - ModifierId: event.EditorUser, - Sequence: event.Sequence, - } - - if event.Data != nil { - var data interface{} - if strings.Contains(change.EventType, "application") { - data = new(model.Application) - } else { - data = new(model.Project) - } - err = json.Unmarshal(event.Data, data) - logging.Log("EVENT-NCkpN").OnError(err).Debug("unable to unmarshal data") - change.Data = data - } - - changes[i] = change - if lastSequence < event.Sequence { - lastSequence = event.Sequence - } - } - - return &proj_model.ProjectChanges{ - Changes: changes, - LastSequence: lastSequence, - }, nil -} - -func ChangesQuery(projectID string, latestSequence, limit uint64, sortAscending bool) *es_models.SearchQuery { - query := es_models.NewSearchQuery(). - AggregateTypeFilter(model.ProjectAggregate) - if !sortAscending { - query.OrderDesc() - } - - query.LatestSequenceFilter(latestSequence). - AggregateIDFilter(projectID). - SetLimit(limit) - return query -} - -func (es *ProjectEventstore) ApplicationByIDs(ctx context.Context, projectID, appID string) (*proj_model.Application, error) { - if projectID == "" || appID == "" { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-ld93d", "Errors.Project.IDMissing") - } - project, err := es.ProjectByID(ctx, projectID) - if err != nil { - return nil, err - } - - if _, a := project.GetApp(appID); a != nil { - return a, nil - } - return nil, caos_errs.ThrowNotFound(nil, "EVENT-8ei2s", "Errors.Project.App.NotFound") -} - -func (es *ProjectEventstore) ApplicationChanges(ctx context.Context, projectID string, appID string, lastSequence uint64, limit uint64, sortAscending bool) (*proj_model.ApplicationChanges, error) { - query := ChangesQuery(projectID, lastSequence, limit, sortAscending) - - events, err := es.Eventstore.FilterEvents(ctx, query) - if err != nil { - logging.Log("EVENT-ZRffs").WithError(err).Warn("eventstore unavailable") - return nil, errors.ThrowInternal(err, "EVENT-sw6Ku", "Errors.Internal") - } - if len(events) == 0 { - return nil, caos_errs.ThrowNotFound(nil, "EVENT-9IHLP", "Errors.Changes.NotFound") - } - - result := make([]*proj_model.ApplicationChange, 0) - for _, event := range events { - if !strings.Contains(event.Type.String(), "application") || event.Data == nil { - continue - } - - app := new(model.Application) - err := json.Unmarshal(event.Data, app) - logging.Log("EVENT-GIiKD").OnError(err).Debug("unable to unmarshal data") - if app.AppID != appID { - continue - } - - creationDate, err := ptypes.TimestampProto(event.CreationDate) - logging.Log("EVENT-MJzeN").OnError(err).Debug("unable to parse timestamp") - - result = append(result, &proj_model.ApplicationChange{ - ChangeDate: creationDate, - EventType: event.Type.String(), - ModifierId: event.EditorUser, - Sequence: event.Sequence, - Data: app, - }) - if lastSequence < event.Sequence { - lastSequence = event.Sequence - } - } - - return &proj_model.ApplicationChanges{ - Changes: result, - LastSequence: lastSequence, - }, nil -} +// +//import ( +// "github.com/caos/zitadel/internal/cache/config" +// sd "github.com/caos/zitadel/internal/config/systemdefaults" +// "github.com/caos/zitadel/internal/crypto" +// es_int "github.com/caos/zitadel/internal/eventstore" +// "github.com/caos/zitadel/internal/id" +//) +// +//const ( +// projectOwnerRole = "PROJECT_OWNER" +// projectOwnerGlobalRole = "PROJECT_OWNER_GLOBAL" +//) +// +//type ProjectEventstore struct { +// es_int.Eventstore +// projectCache *ProjectCache +// passwordAlg crypto.HashAlgorithm +// pwGenerator crypto.Generator +// idGenerator id.Generator +// ClientKeySize int +//} +// +//type ProjectConfig struct { +// es_int.Eventstore +// Cache *config.CacheConfig +//} +// +//func StartProject(conf ProjectConfig, systemDefaults sd.SystemDefaults) (*ProjectEventstore, error) { +// projectCache, err := StartCache(conf.Cache) +// if err != nil { +// return nil, err +// } +// passwordAlg := crypto.NewBCrypt(systemDefaults.SecretGenerators.PasswordSaltCost) +// pwGenerator := crypto.NewHashGenerator(systemDefaults.SecretGenerators.ClientSecretGenerator, passwordAlg) +// return &ProjectEventstore{ +// Eventstore: conf.Eventstore, +// projectCache: projectCache, +// passwordAlg: passwordAlg, +// pwGenerator: pwGenerator, +// idGenerator: id.SonyFlakeGenerator, +// ClientKeySize: int(systemDefaults.SecretGenerators.ApplicationKeySize), +// }, nil +//} diff --git a/internal/project/repository/eventsourcing/project.go b/internal/project/repository/eventsourcing/project.go index c7655b1b97..5a74cf6a61 100644 --- a/internal/project/repository/eventsourcing/project.go +++ b/internal/project/repository/eventsourcing/project.go @@ -10,20 +10,6 @@ import ( "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" ) -func ProjectByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) { - if id == "" { - return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "Errors.Project.ProjectIDMissing") - } - return ProjectQuery(latestSequence). - AggregateIDFilter(id), nil -} - -func ProjectQuery(latestSequence uint64) *es_models.SearchQuery { - return es_models.NewSearchQuery(). - AggregateTypeFilter(model.ProjectAggregate). - LatestSequenceFilter(latestSequence) -} - func ProjectAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, project *model.Project) (*es_models.Aggregate, error) { if project == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-doe93", "Errors.Internal") diff --git a/internal/project/repository/view/query.go b/internal/project/repository/view/query.go new file mode 100644 index 0000000000..3659b27116 --- /dev/null +++ b/internal/project/repository/view/query.go @@ -0,0 +1,34 @@ +package view + +import ( + "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" +) + +func ProjectByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) { + if id == "" { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "Errors.Project.ProjectIDMissing") + } + return ProjectQuery(latestSequence). + AggregateIDFilter(id), nil +} + +func ProjectQuery(latestSequence uint64) *es_models.SearchQuery { + return es_models.NewSearchQuery(). + AggregateTypeFilter(model.ProjectAggregate). + LatestSequenceFilter(latestSequence) +} + +func ChangesQuery(projectID string, latestSequence, limit uint64, sortAscending bool) *es_models.SearchQuery { + query := es_models.NewSearchQuery(). + AggregateTypeFilter(model.ProjectAggregate) + if !sortAscending { + query.OrderDesc() + } + + query.LatestSequenceFilter(latestSequence). + AggregateIDFilter(projectID). + SetLimit(limit) + return query +} diff --git a/internal/user/model/otp.go b/internal/user/model/otp.go index 78e4626297..8f8c48034a 100644 --- a/internal/user/model/otp.go +++ b/internal/user/model/otp.go @@ -1,19 +1,5 @@ package model -import ( - "github.com/caos/zitadel/internal/crypto" - es_models "github.com/caos/zitadel/internal/eventstore/models" -) - -type OTP struct { - es_models.ObjectRoot - - Secret *crypto.CryptoValue - SecretString string - Url string - State MFAState -} - type MFAState int32 const ( diff --git a/internal/user/model/user.go b/internal/user/model/user.go deleted file mode 100644 index 197f6c5d49..0000000000 --- a/internal/user/model/user.go +++ /dev/null @@ -1,103 +0,0 @@ -package model - -import ( - iam_model "github.com/caos/zitadel/internal/iam/model" - "strings" - - caos_errors "github.com/caos/zitadel/internal/errors" - es_models "github.com/caos/zitadel/internal/eventstore/models" - "github.com/golang/protobuf/ptypes/timestamp" -) - -type User struct { - es_models.ObjectRoot - State UserState - UserName string - - *Human - *Machine -} - -type UserState int32 - -const ( - UserStateUnspecified UserState = iota - UserStateActive - UserStateInactive - UserStateDeleted - UserStateLocked - UserStateSuspend - UserStateInitial -) - -func (u *User) CheckOrgIAMPolicy(policy *iam_model.OrgIAMPolicyView) error { - if policy == nil { - return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Errors.Users.OrgIamPolicyNil") - } - if policy.UserLoginMustBeDomain && strings.Contains(u.UserName, "@") { - return caos_errors.ThrowPreconditionFailed(nil, "MODEL-se4sJ", "Errors.User.EmailAsUsernameNotAllowed") - } - if !policy.UserLoginMustBeDomain && u.Profile != nil && u.UserName == "" && u.Email != nil { - u.UserName = u.EmailAddress - } - return nil -} - -func (u *User) SetNamesAsDisplayname() { - if u.Profile != nil && u.DisplayName == "" && u.FirstName != "" && u.LastName != "" { - u.DisplayName = u.FirstName + " " + u.LastName - } -} - -type UserChanges struct { - Changes []*UserChange - LastSequence uint64 -} - -type UserChange struct { - ChangeDate *timestamp.Timestamp `json:"changeDate,omitempty"` - EventType string `json:"eventType,omitempty"` - Sequence uint64 `json:"sequence,omitempty"` - ModifierID string `json:"modifierUser,omitempty"` - ModifierName string `json:"-"` - Data interface{} `json:"data,omitempty"` -} - -func (u *User) IsActive() bool { - return u.State == UserStateActive -} - -func (u *User) IsInitial() bool { - return u.State == UserStateInitial -} - -func (u *User) IsInactive() bool { - return u.State == UserStateInactive -} - -func (u *User) IsLocked() bool { - return u.State == UserStateLocked -} - -func (u *User) IsValid() bool { - if u.Human == nil && u.Machine == nil || u.UserName == "" { - return false - } - if u.Human != nil { - return u.Human.IsValid() - } - return u.Machine.IsValid() -} - -func (u *User) CheckOrgIamPolicy(policy *iam_model.OrgIAMPolicy) error { - if policy == nil { - return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Errors.Users.OrgIamPolicyNil") - } - if policy.UserLoginMustBeDomain && strings.Contains(u.UserName, "@") { - return caos_errors.ThrowPreconditionFailed(nil, "MODEL-se4sJ", "Errors.User.EmailAsUsernameNotAllowed") - } - if !policy.UserLoginMustBeDomain && u.Profile != nil && u.UserName == "" && u.Email != nil { - u.UserName = u.EmailAddress - } - return nil -} diff --git a/internal/user/model/user_changes.go b/internal/user/model/user_changes.go new file mode 100644 index 0000000000..9b180c746a --- /dev/null +++ b/internal/user/model/user_changes.go @@ -0,0 +1,19 @@ +package model + +import ( + "github.com/golang/protobuf/ptypes/timestamp" +) + +type UserChanges struct { + Changes []*UserChange + LastSequence uint64 +} + +type UserChange struct { + ChangeDate *timestamp.Timestamp `json:"changeDate,omitempty"` + EventType string `json:"eventType,omitempty"` + Sequence uint64 `json:"sequence,omitempty"` + ModifierID string `json:"modifierUser,omitempty"` + ModifierName string `json:"-"` + Data interface{} `json:"data,omitempty"` +} diff --git a/internal/user/model/user_human.go b/internal/user/model/user_human.go deleted file mode 100644 index c5e8269da5..0000000000 --- a/internal/user/model/user_human.go +++ /dev/null @@ -1,203 +0,0 @@ -package model - -import ( - "bytes" - caos_errors "github.com/caos/zitadel/internal/errors" - "github.com/caos/zitadel/internal/v2/domain" - "strings" - "time" - - iam_model "github.com/caos/zitadel/internal/iam/model" - - "github.com/caos/zitadel/internal/crypto" - es_models "github.com/caos/zitadel/internal/eventstore/models" -) - -type Human struct { - es_models.ObjectRoot - - *Password - *Profile - *Email - *Phone - *Address - ExternalIDPs []*ExternalIDP - InitCode *InitUserCode - EmailCode *EmailCode - PhoneCode *PhoneCode - PasswordCode *PasswordCode - OTP *OTP - U2FTokens []*WebAuthNToken - PasswordlessTokens []*WebAuthNToken - U2FLogins []*WebAuthNLogin - PasswordlessLogins []*WebAuthNLogin -} - -type InitUserCode struct { - es_models.ObjectRoot - - Code *crypto.CryptoValue - Expiry time.Duration -} - -type Gender int32 - -const ( - GenderUnspecified Gender = iota - GenderFemale - GenderMale - GenderDiverse -) - -func (u *Human) CheckOrgIAMPolicy(userName string, policy *domain.OrgIAMPolicy) error { - if policy == nil { - return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Errors.Users.OrgIamPolicyNil") - } - if policy.UserLoginMustBeDomain && strings.Contains(userName, "@") { - return caos_errors.ThrowPreconditionFailed(nil, "MODEL-se4sJ", "Errors.User.EmailAsUsernameNotAllowed") - } - if !policy.UserLoginMustBeDomain && u.Profile != nil && userName == "" && u.Email != nil { - userName = u.EmailAddress - } - return nil -} - -func (u *Human) SetNamesAsDisplayname() { - if u.Profile != nil && u.DisplayName == "" && u.FirstName != "" && u.LastName != "" { - u.DisplayName = u.FirstName + " " + u.LastName - } -} - -func (u *Human) IsValid() bool { - return u.Profile != nil && u.FirstName != "" && u.LastName != "" && u.Email != nil && u.Email.IsValid() && u.Phone == nil || (u.Phone != nil && u.Phone.PhoneNumber != "" && u.Phone.IsValid()) -} - -func (u *Human) IsInitialState() bool { - return u.Email == nil || !u.IsEmailVerified || (u.ExternalIDPs == nil || len(u.ExternalIDPs) == 0) && (u.Password == nil || u.SecretString == "") -} - -func (u *Human) IsOTPReady() bool { - return u.OTP != nil && u.OTP.State == MFAStateReady -} - -func (u *Human) HashPasswordIfExisting(policy *iam_model.PasswordComplexityPolicyView, passwordAlg crypto.HashAlgorithm, onetime bool) error { - if u.Password != nil { - return u.Password.HashPasswordIfExisting(policy, passwordAlg, onetime) - } - return nil -} - -func (u *Human) GenerateInitCodeIfNeeded(initGenerator crypto.Generator) error { - if !u.IsInitialState() { - return nil - } - u.InitCode = new(InitUserCode) - return u.InitCode.GenerateInitUserCode(initGenerator) -} - -func (u *Human) GeneratePhoneCodeIfNeeded(phoneGenerator crypto.Generator) error { - if u.Phone == nil || u.IsPhoneVerified { - return nil - } - u.PhoneCode = new(PhoneCode) - return u.PhoneCode.GeneratePhoneCode(phoneGenerator) -} - -func (u *Human) GenerateEmailCodeIfNeeded(emailGenerator crypto.Generator) error { - if u.Email == nil || u.IsEmailVerified { - return nil - } - u.EmailCode = new(EmailCode) - return u.EmailCode.GenerateEmailCode(emailGenerator) -} - -func (init *InitUserCode) GenerateInitUserCode(generator crypto.Generator) error { - initCodeCrypto, _, err := crypto.NewCode(generator) - if err != nil { - return err - } - init.Code = initCodeCrypto - init.Expiry = generator.Expiry() - return nil -} - -func (u *Human) GetExternalIDP(externalIDP *ExternalIDP) (int, *ExternalIDP) { - for i, idp := range u.ExternalIDPs { - if idp.UserID == externalIDP.UserID { - return i, idp - } - } - return -1, nil -} - -func (u *Human) GetU2F(webAuthNTokenID string) (int, *WebAuthNToken) { - for i, u2f := range u.U2FTokens { - if u2f.WebAuthNTokenID == webAuthNTokenID { - return i, u2f - } - } - return -1, nil -} - -func (u *Human) GetU2FByKeyID(keyID []byte) (int, *WebAuthNToken) { - for i, u2f := range u.U2FTokens { - if bytes.Compare(u2f.KeyID, keyID) == 0 { - return i, u2f - } - } - return -1, nil -} - -func (u *Human) GetU2FToVerify() (int, *WebAuthNToken) { - for i, u2f := range u.U2FTokens { - if u2f.State == MFAStateNotReady { - return i, u2f - } - } - return -1, nil -} - -func (u *Human) GetPasswordless(webAuthNTokenID string) (int, *WebAuthNToken) { - for i, u2f := range u.PasswordlessTokens { - if u2f.WebAuthNTokenID == webAuthNTokenID { - return i, u2f - } - } - return -1, nil -} - -func (u *Human) GetPasswordlessByKeyID(keyID []byte) (int, *WebAuthNToken) { - for i, pwl := range u.PasswordlessTokens { - if bytes.Compare(pwl.KeyID, keyID) == 0 { - return i, pwl - } - } - return -1, nil -} - -func (u *Human) GetPasswordlessToVerify() (int, *WebAuthNToken) { - for i, u2f := range u.PasswordlessTokens { - if u2f.State == MFAStateNotReady { - return i, u2f - } - } - return -1, nil -} - -func (u *Human) GetU2FLogin(authReqID string) (int, *WebAuthNLogin) { - for i, u2f := range u.U2FLogins { - if u2f.AuthRequest.ID == authReqID { - return i, u2f - } - } - return -1, nil -} - -func (u *Human) GetPasswordlessLogin(authReqID string) (int, *WebAuthNLogin) { - for i, pw := range u.PasswordlessLogins { - if pw.AuthRequest.ID == authReqID { - return i, pw - } - } - return -1, nil -} diff --git a/internal/user/model/user_human_test.go b/internal/user/model/user_human_test.go deleted file mode 100644 index 1b6c0e8dc5..0000000000 --- a/internal/user/model/user_human_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package model - -import ( - "testing" -) - -func TestIsUserValid(t *testing.T) { - type args struct { - user *Human - } - tests := []struct { - name string - args args - result bool - errFunc func(err error) bool - }{ - { - name: "user with minimal data", - args: args{ - user: &Human{ - Profile: &Profile{ - FirstName: "FirstName", - LastName: "LastName", - }, - Email: &Email{ - EmailAddress: "Email", - }, - }, - }, - result: true, - }, - { - name: "user with phone data", - args: args{ - user: &Human{ - Profile: &Profile{ - FirstName: "FirstName", - LastName: "LastName", - }, - Email: &Email{ - EmailAddress: "Email", - }, - Phone: &Phone{ - PhoneNumber: "+41711234569", - }, - }, - }, - result: true, - }, - { - name: "user with address data", - args: args{ - user: &Human{ - Profile: &Profile{ - FirstName: "FirstName", - LastName: "LastName", - }, - Email: &Email{ - EmailAddress: "Email", - }, - Address: &Address{ - StreetAddress: "Teufenerstrasse 19", - PostalCode: "9000", - Locality: "St. Gallen", - Country: "Switzerland", - }, - }, - }, - result: true, - }, - { - name: "user with all data", - args: args{ - user: &Human{ - Profile: &Profile{ - FirstName: "FirstName", - LastName: "LastName", - }, - Email: &Email{ - EmailAddress: "Email", - }, - Phone: &Phone{ - PhoneNumber: "+41711234569", - }, - Address: &Address{ - StreetAddress: "Teufenerstrasse 19", - PostalCode: "9000", - Locality: "St. Gallen", - Country: "Switzerland", - }, - }, - }, - result: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - isValid := tt.args.user.IsValid() - - if tt.result != isValid { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, isValid) - } - }) - } -} diff --git a/internal/user/model/user_machine.go b/internal/user/model/user_machine.go deleted file mode 100644 index 1f1c06a696..0000000000 --- a/internal/user/model/user_machine.go +++ /dev/null @@ -1,28 +0,0 @@ -package model - -import ( - "time" - - "github.com/caos/zitadel/internal/eventstore/models" - key_model "github.com/caos/zitadel/internal/key/model" -) - -type Machine struct { - models.ObjectRoot - - Name string - Description string -} - -func (sa *Machine) IsValid() bool { - return sa.Name != "" -} - -type MachineKey struct { - models.ObjectRoot - - KeyID string - Type key_model.AuthNKeyType - ExpirationDate time.Time - PrivateKey []byte -} diff --git a/internal/user/model/user_view.go b/internal/user/model/user_view.go index afc7fa3a86..f75aae7afc 100644 --- a/internal/user/model/user_view.go +++ b/internal/user/model/user_view.go @@ -108,6 +108,27 @@ type UserSearchResponse struct { Timestamp time.Time } +type UserState int32 + +const ( + UserStateUnspecified UserState = iota + UserStateActive + UserStateInactive + UserStateDeleted + UserStateLocked + UserStateSuspend + UserStateInitial +) + +type Gender int32 + +const ( + GenderUnspecified Gender = iota + GenderFemale + GenderMale + GenderDiverse +) + func (r *UserSearchRequest) EnsureLimit(limit uint64) { if r.Limit == 0 || r.Limit > limit { r.Limit = limit diff --git a/internal/user/model/web_auth_n.go b/internal/user/model/web_auth_n.go deleted file mode 100644 index 9164480aae..0000000000 --- a/internal/user/model/web_auth_n.go +++ /dev/null @@ -1,58 +0,0 @@ -package model - -import ( - "github.com/caos/zitadel/internal/auth_request/model" - es_models "github.com/caos/zitadel/internal/eventstore/models" -) - -type WebAuthNToken struct { - es_models.ObjectRoot - - WebAuthNTokenID string - CredentialCreationData []byte - State MFAState - Challenge string - AllowedCredentialIDs [][]byte - UserVerification UserVerificationRequirement - KeyID []byte - PublicKey []byte - AttestationType string - AAGUID []byte - SignCount uint32 - WebAuthNTokenName string -} - -type WebAuthNLogin struct { - es_models.ObjectRoot - - CredentialAssertionData []byte - Challenge string - AllowedCredentialIDs [][]byte - UserVerification UserVerificationRequirement - *model.AuthRequest -} - -type WebAuthNMethod int32 - -const ( - WebAuthNMethodUnspecified WebAuthNMethod = iota - WebAuthNMethodU2F - WebAuthNMethodPasswordless -) - -type UserVerificationRequirement int32 - -const ( - UserVerificationRequirementUnspecified UserVerificationRequirement = iota - UserVerificationRequirementRequired - UserVerificationRequirementPreferred - UserVerificationRequirementDiscouraged -) - -type AuthenticatorAttachment int32 - -const ( - AuthenticatorAttachmentUnspecified AuthenticatorAttachment = iota - AuthenticatorAttachmentPlattform - AuthenticatorAttachmentCrossPlattform -) diff --git a/internal/user/repository/eventsourcing/cache.go b/internal/user/repository/eventsourcing/cache.go deleted file mode 100644 index 1ca5e0e423..0000000000 --- a/internal/user/repository/eventsourcing/cache.go +++ /dev/null @@ -1,35 +0,0 @@ -package eventsourcing - -import ( - "github.com/caos/logging" - "github.com/caos/zitadel/internal/cache" - "github.com/caos/zitadel/internal/cache/config" - "github.com/caos/zitadel/internal/eventstore/models" - "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" -) - -type UserCache struct { - userCache cache.Cache -} - -func StartCache(conf *config.CacheConfig) (*UserCache, error) { - userCache, err := conf.Config.NewCache() - logging.Log("EVENT-vJG2j").OnError(err).Panic("unable to create user cache") - - return &UserCache{userCache: userCache}, nil -} - -func (c *UserCache) getUser(id string) *model.User { - user := &model.User{ObjectRoot: models.ObjectRoot{AggregateID: id}} - if err := c.userCache.Get(id, user); err != nil { - logging.Log("EVENT-AtS0S").WithError(err).Debug("error in getting cache") - } - return user -} - -func (c *UserCache) cacheUser(user *model.User) { - err := c.userCache.Set(user.AggregateID, user) - if err != nil { - logging.Log("EVENT-0V2gX").WithError(err).Debug("error in setting project cache") - } -} diff --git a/internal/user/repository/eventsourcing/eventstore.go b/internal/user/repository/eventsourcing/eventstore.go deleted file mode 100644 index 6ff897b525..0000000000 --- a/internal/user/repository/eventsourcing/eventstore.go +++ /dev/null @@ -1,143 +0,0 @@ -package eventsourcing - -import ( - "context" - "github.com/caos/logging" - "github.com/caos/zitadel/internal/cache/config" - sd "github.com/caos/zitadel/internal/config/systemdefaults" - "github.com/caos/zitadel/internal/errors" - caos_errs "github.com/caos/zitadel/internal/errors" - es_int "github.com/caos/zitadel/internal/eventstore" - es_models "github.com/caos/zitadel/internal/eventstore/models" - es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" - usr_model "github.com/caos/zitadel/internal/user/model" - "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" - "github.com/golang/protobuf/ptypes" -) - -type UserEventstore struct { - es_int.Eventstore - userCache *UserCache -} - -type UserConfig struct { - es_int.Eventstore - Cache *config.CacheConfig - PasswordSaltCost int -} - -func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventstore, error) { - userCache, err := StartCache(conf.Cache) - if err != nil { - return nil, err - } - return &UserEventstore{ - Eventstore: conf.Eventstore, - userCache: userCache, - }, nil -} - -func (es *UserEventstore) UserByID(ctx context.Context, id string) (*usr_model.User, error) { - user := es.userCache.getUser(id) - - query, err := UserByIDQuery(user.AggregateID, user.Sequence) - if err != nil { - return nil, err - } - err = es_sdk.Filter(ctx, es.FilterEvents, user.AppendEvents, query) - if err != nil && caos_errs.IsNotFound(err) && user.Sequence == 0 { - return nil, err - } - if user.State == int32(usr_model.UserStateDeleted) { - return nil, caos_errs.ThrowNotFound(nil, "EVENT-6hsK9", "Errors.User.NotFound") - } - es.userCache.cacheUser(user) - return model.UserToModel(user), nil -} - -func (es *UserEventstore) HumanByID(ctx context.Context, userID string) (*usr_model.User, error) { - if userID == "" { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-3M9sf", "Errors.User.UserIDMissing") - } - user, err := es.UserByID(ctx, userID) - if err != nil { - return nil, err - } - if user.Human == nil { - return nil, errors.ThrowPreconditionFailed(nil, "EVENT-jLHYG", "Errors.User.NotHuman") - } - return user, nil -} - -func (es *UserEventstore) UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { - query, err := UserByIDQuery(id, sequence) - if err != nil { - return nil, err - } - return es.FilterEvents(ctx, query) -} - -func (es *UserEventstore) UserChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*usr_model.UserChanges, error) { - query := ChangesQuery(id, lastSequence, limit, sortAscending) - - events, err := es.Eventstore.FilterEvents(ctx, query) - if err != nil { - logging.Log("EVENT-g9HCv").WithError(err).Warn("eventstore unavailable") - return nil, errors.ThrowInternal(err, "EVENT-htuG9", "Errors.Internal") - } - if len(events) == 0 { - return nil, caos_errs.ThrowNotFound(nil, "EVENT-6cAxe", "Errors.User.NoChanges") - } - - result := make([]*usr_model.UserChange, len(events)) - - for i, event := range events { - creationDate, err := ptypes.TimestampProto(event.CreationDate) - logging.Log("EVENT-8GTGS").OnError(err).Debug("unable to parse timestamp") - change := &usr_model.UserChange{ - ChangeDate: creationDate, - EventType: event.Type.String(), - ModifierID: event.EditorUser, - Sequence: event.Sequence, - } - - //TODO: now all types should be unmarshalled, e.g. password - // if len(event.Data) != 0 { - // user := new(model.User) - // err := json.Unmarshal(event.Data, user) - // logging.Log("EVENT-Rkg7X").OnError(err).Debug("unable to unmarshal data") - // change.Data = user - // } - - result[i] = change - if lastSequence < event.Sequence { - lastSequence = event.Sequence - } - } - - return &usr_model.UserChanges{ - Changes: result, - LastSequence: lastSequence, - }, nil -} - -func ChangesQuery(userID string, latestSequence, limit uint64, sortAscending bool) *es_models.SearchQuery { - query := es_models.NewSearchQuery(). - AggregateTypeFilter(model.UserAggregate) - if !sortAscending { - query.OrderDesc() - } - - query.LatestSequenceFilter(latestSequence). - AggregateIDFilter(userID). - SetLimit(limit) - return query -} - -func (es *UserEventstore) GetPasswordless(ctx context.Context, userID string) ([]*usr_model.WebAuthNToken, error) { - user, err := es.HumanByID(ctx, userID) - if err != nil { - return nil, err - } - return user.PasswordlessTokens, nil -} diff --git a/internal/user/repository/eventsourcing/model/otp.go b/internal/user/repository/eventsourcing/model/otp.go index 7d4ccf6a02..772857f8ee 100644 --- a/internal/user/repository/eventsourcing/model/otp.go +++ b/internal/user/repository/eventsourcing/model/otp.go @@ -21,22 +21,6 @@ type OTPVerified struct { UserAgentID string `json:"userAgentID,omitempty"` } -func OTPFromModel(otp *model.OTP) *OTP { - return &OTP{ - ObjectRoot: otp.ObjectRoot, - Secret: otp.Secret, - State: int32(otp.State), - } -} - -func OTPToModel(otp *OTP) *model.OTP { - return &model.OTP{ - ObjectRoot: otp.ObjectRoot, - Secret: otp.Secret, - State: model.MFAState(otp.State), - } -} - func (u *Human) appendOTPAddedEvent(event *es_models.Event) error { u.OTP = &OTP{ State: int32(model.MFAStateNotReady), diff --git a/internal/user/repository/eventsourcing/model/user.go b/internal/user/repository/eventsourcing/model/user.go index 655af99da3..bf6ff180f7 100644 --- a/internal/user/repository/eventsourcing/model/user.go +++ b/internal/user/repository/eventsourcing/model/user.go @@ -24,42 +24,6 @@ type User struct { *Machine } -func UserFromModel(user *model.User) *User { - var human *Human - if user.Human != nil { - human = HumanFromModel(user.Human) - } - var machine *Machine - if user.Machine != nil { - machine = MachineFromModel(user.Machine) - } - return &User{ - ObjectRoot: user.ObjectRoot, - State: int32(user.State), - UserName: user.UserName, - Human: human, - Machine: machine, - } -} - -func UserToModel(user *User) *model.User { - var human *model.Human - if user.Human != nil { - human = HumanToModel(user.Human) - } - var machine *model.Machine - if user.Machine != nil { - machine = MachineToModel(user.Machine) - } - return &model.User{ - ObjectRoot: user.ObjectRoot, - State: model.UserState(user.State), - UserName: user.UserName, - Human: human, - Machine: machine, - } -} - func (u *User) AppendEvents(events ...*es_models.Event) error { for _, event := range events { if err := u.AppendEvent(event); err != nil { diff --git a/internal/user/repository/eventsourcing/model/user_human.go b/internal/user/repository/eventsourcing/model/user_human.go index 3e191d65cb..d1438a0688 100644 --- a/internal/user/repository/eventsourcing/model/user_human.go +++ b/internal/user/repository/eventsourcing/model/user_human.go @@ -37,113 +37,6 @@ type InitUserCode struct { Expiry time.Duration `json:"expiry,omitempty"` } -func HumanFromModel(user *model.Human) *Human { - human := new(Human) - if user.Password != nil { - human.Password = PasswordFromModel(user.Password) - } - if user.Profile != nil { - human.Profile = ProfileFromModel(user.Profile) - } - if user.Email != nil { - human.Email = EmailFromModel(user.Email) - } - if user.Phone != nil { - human.Phone = PhoneFromModel(user.Phone) - } - if user.Address != nil { - human.Address = AddressFromModel(user.Address) - } - if user.OTP != nil { - human.OTP = OTPFromModel(user.OTP) - } - if user.ExternalIDPs != nil { - human.ExternalIDPs = ExternalIDPsFromModel(user.ExternalIDPs) - } - if user.U2FTokens != nil { - human.U2FTokens = WebAuthNsFromModel(user.U2FTokens) - } - if user.PasswordlessTokens != nil { - human.PasswordlessTokens = WebAuthNsFromModel(user.PasswordlessTokens) - } - if user.U2FLogins != nil { - human.U2FLogins = WebAuthNLoginsFromModel(user.U2FLogins) - } - if user.PasswordlessLogins != nil { - human.PasswordlessLogins = WebAuthNLoginsFromModel(user.PasswordlessLogins) - } - return human -} - -func HumanToModel(user *Human) *model.Human { - human := new(model.Human) - if user.Password != nil { - human.Password = PasswordToModel(user.Password) - } - if user.Profile != nil { - human.Profile = ProfileToModel(user.Profile) - } - if user.Email != nil { - human.Email = EmailToModel(user.Email) - } - if user.Phone != nil { - human.Phone = PhoneToModel(user.Phone) - } - if user.Address != nil { - human.Address = AddressToModel(user.Address) - } - if user.ExternalIDPs != nil { - human.ExternalIDPs = ExternalIDPsToModel(user.ExternalIDPs) - } - if user.InitCode != nil { - human.InitCode = InitCodeToModel(user.InitCode) - } - if user.EmailCode != nil { - human.EmailCode = EmailCodeToModel(user.EmailCode) - } - if user.PhoneCode != nil { - human.PhoneCode = PhoneCodeToModel(user.PhoneCode) - } - if user.PasswordCode != nil { - human.PasswordCode = PasswordCodeToModel(user.PasswordCode) - } - if user.OTP != nil { - human.OTP = OTPToModel(user.OTP) - } - if user.U2FTokens != nil { - human.U2FTokens = WebAuthNsToModel(user.U2FTokens) - } - if user.PasswordlessTokens != nil { - human.PasswordlessTokens = WebAuthNsToModel(user.PasswordlessTokens) - } - if user.U2FLogins != nil { - human.U2FLogins = WebAuthNLoginsToModel(user.U2FLogins) - } - if user.PasswordlessLogins != nil { - human.PasswordlessLogins = WebAuthNLoginsToModel(user.PasswordlessLogins) - } - return human -} - -func InitCodeFromModel(code *model.InitUserCode) *InitUserCode { - if code == nil { - return nil - } - return &InitUserCode{ - ObjectRoot: code.ObjectRoot, - Expiry: code.Expiry, - Code: code.Code, - } -} - -func InitCodeToModel(code *InitUserCode) *model.InitUserCode { - return &model.InitUserCode{ - ObjectRoot: code.ObjectRoot, - Expiry: code.Expiry, - Code: code.Code, - } -} - func (p *Human) AppendEvents(events ...*es_models.Event) error { for _, event := range events { if err := p.AppendEvent(event); err != nil { diff --git a/internal/user/repository/eventsourcing/model/user_human_test.go b/internal/user/repository/eventsourcing/model/user_human_test.go deleted file mode 100644 index 61f0dbb9d7..0000000000 --- a/internal/user/repository/eventsourcing/model/user_human_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package model - -import ( - "encoding/json" - "testing" - "time" - - es_models "github.com/caos/zitadel/internal/eventstore/models" -) - -func TestAppendInitUserCodeEvent(t *testing.T) { - type args struct { - user *Human - code *InitUserCode - event *es_models.Event - } - tests := []struct { - name string - args args - result *Human - }{ - { - name: "append init user code event", - args: args{ - user: &Human{}, - code: &InitUserCode{Expiry: time.Hour * 30}, - event: &es_models.Event{}, - }, - result: &Human{InitCode: &InitUserCode{Expiry: time.Hour * 30}}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if tt.args.code != nil { - data, _ := json.Marshal(tt.args.code) - tt.args.event.Data = data - } - tt.args.user.appendInitUsercodeCreatedEvent(tt.args.event) - if tt.args.user.InitCode.Expiry != tt.result.InitCode.Expiry { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) - } - }) - } -} diff --git a/internal/user/repository/eventsourcing/model/user_machine.go b/internal/user/repository/eventsourcing/model/user_machine.go index a82fad1c1b..5346e3e65a 100644 --- a/internal/user/repository/eventsourcing/model/user_machine.go +++ b/internal/user/repository/eventsourcing/model/user_machine.go @@ -5,12 +5,9 @@ import ( "time" "github.com/caos/logging" - "github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" - key_model "github.com/caos/zitadel/internal/key/model" - "github.com/caos/zitadel/internal/user/model" ) type Machine struct { @@ -46,28 +43,6 @@ func (sa *Machine) setData(event *models.Event) error { return nil } -func (sa *Machine) Changes(updatedAccount *Machine) map[string]interface{} { - changes := make(map[string]interface{}) - if updatedAccount.Description != "" && updatedAccount.Description != sa.Description { - changes["description"] = updatedAccount.Description - } - return changes -} - -func MachineFromModel(machine *model.Machine) *Machine { - return &Machine{ - Description: machine.Description, - Name: machine.Name, - } -} - -func MachineToModel(machine *Machine) *model.Machine { - return &model.Machine{ - Description: machine.Description, - Name: machine.Name, - } -} - type MachineKey struct { es_models.ObjectRoot `json:"-"` KeyID string `json:"keyId,omitempty"` @@ -100,35 +75,3 @@ func (key *MachineKey) AppendEvent(event *es_models.Event) (err error) { } return err } - -func MachineKeyFromModel(machine *model.MachineKey) *MachineKey { - return &MachineKey{ - ObjectRoot: machine.ObjectRoot, - ExpirationDate: machine.ExpirationDate, - KeyID: machine.KeyID, - Type: int32(machine.Type), - } -} - -func MachineKeyToModel(machine *MachineKey) *model.MachineKey { - return &model.MachineKey{ - ObjectRoot: machine.ObjectRoot, - ExpirationDate: machine.ExpirationDate, - KeyID: machine.KeyID, - PrivateKey: machine.privateKey, - Type: key_model.AuthNKeyType(machine.Type), - } -} - -func (key *MachineKey) GenerateMachineKeyPair(keySize int, alg crypto.EncryptionAlgorithm) error { - privateKey, publicKey, err := crypto.GenerateKeyPair(keySize) - if err != nil { - return err - } - key.PublicKey, err = crypto.PublicKeyToBytes(publicKey) - if err != nil { - return err - } - key.privateKey = crypto.PrivateKeyToBytes(privateKey) - return nil -} diff --git a/internal/user/repository/eventsourcing/model/user_test.go b/internal/user/repository/eventsourcing/model/user_test.go deleted file mode 100644 index a828d3e952..0000000000 --- a/internal/user/repository/eventsourcing/model/user_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package model - -import ( - "testing" - - "github.com/caos/zitadel/internal/user/model" -) - -func TestAppendDeactivatedEvent(t *testing.T) { - type args struct { - user *User - } - tests := []struct { - name string - args args - result *User - }{ - { - name: "append deactivate event", - args: args{ - user: &User{}, - }, - result: &User{State: int32(model.UserStateInactive)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.user.appendDeactivatedEvent() - if tt.args.user.State != tt.result.State { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) - } - }) - } -} - -func TestAppendReactivatedEvent(t *testing.T) { - type args struct { - user *User - } - tests := []struct { - name string - args args - result *User - }{ - { - name: "append reactivate event", - args: args{ - user: &User{}, - }, - result: &User{State: int32(model.UserStateActive)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.user.appendReactivatedEvent() - if tt.args.user.State != tt.result.State { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) - } - }) - } -} - -func TestAppendLockEvent(t *testing.T) { - type args struct { - user *User - } - tests := []struct { - name string - args args - result *User - }{ - { - name: "append lock event", - args: args{ - user: &User{}, - }, - result: &User{State: int32(model.UserStateLocked)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.user.appendLockedEvent() - if tt.args.user.State != tt.result.State { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) - } - }) - } -} - -func TestAppendUnlockEvent(t *testing.T) { - type args struct { - user *User - } - tests := []struct { - name string - args args - result *User - }{ - { - name: "append unlock event", - args: args{ - user: &User{}, - }, - result: &User{State: int32(model.UserStateActive)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.user.appendUnlockedEvent() - if tt.args.user.State != tt.result.State { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) - } - }) - } -} diff --git a/internal/user/repository/eventsourcing/model/web_auth_n.go b/internal/user/repository/eventsourcing/model/web_auth_n.go index 226ac77a71..8a5e5e5411 100644 --- a/internal/user/repository/eventsourcing/model/web_auth_n.go +++ b/internal/user/repository/eventsourcing/model/web_auth_n.go @@ -62,97 +62,6 @@ func GetWebauthn(webauthnTokens []*WebAuthNToken, id string) (int, *WebAuthNToke return -1, nil } -func WebAuthNsToModel(u2fs []*WebAuthNToken) []*model.WebAuthNToken { - convertedIDPs := make([]*model.WebAuthNToken, len(u2fs)) - for i, m := range u2fs { - convertedIDPs[i] = WebAuthNToModel(m) - } - return convertedIDPs -} - -func WebAuthNsFromModel(u2fs []*model.WebAuthNToken) []*WebAuthNToken { - convertedIDPs := make([]*WebAuthNToken, len(u2fs)) - for i, m := range u2fs { - convertedIDPs[i] = WebAuthNFromModel(m) - } - return convertedIDPs -} - -func WebAuthNFromModel(webAuthN *model.WebAuthNToken) *WebAuthNToken { - return &WebAuthNToken{ - ObjectRoot: webAuthN.ObjectRoot, - WebauthNTokenID: webAuthN.WebAuthNTokenID, - Challenge: webAuthN.Challenge, - State: int32(webAuthN.State), - KeyID: webAuthN.KeyID, - PublicKey: webAuthN.PublicKey, - AAGUID: webAuthN.AAGUID, - SignCount: webAuthN.SignCount, - AttestationType: webAuthN.AttestationType, - WebAuthNTokenName: webAuthN.WebAuthNTokenName, - } -} - -func WebAuthNToModel(webAuthN *WebAuthNToken) *model.WebAuthNToken { - return &model.WebAuthNToken{ - ObjectRoot: webAuthN.ObjectRoot, - WebAuthNTokenID: webAuthN.WebauthNTokenID, - Challenge: webAuthN.Challenge, - State: model.MFAState(webAuthN.State), - KeyID: webAuthN.KeyID, - PublicKey: webAuthN.PublicKey, - AAGUID: webAuthN.AAGUID, - SignCount: webAuthN.SignCount, - AttestationType: webAuthN.AttestationType, - WebAuthNTokenName: webAuthN.WebAuthNTokenName, - } -} - -func WebAuthNVerifyFromModel(webAuthN *model.WebAuthNToken, userAgentID string) *WebAuthNVerify { - return &WebAuthNVerify{ - WebAuthNTokenID: webAuthN.WebAuthNTokenID, - KeyID: webAuthN.KeyID, - PublicKey: webAuthN.PublicKey, - AAGUID: webAuthN.AAGUID, - SignCount: webAuthN.SignCount, - AttestationType: webAuthN.AttestationType, - WebAuthNTokenName: webAuthN.WebAuthNTokenName, - UserAgentID: userAgentID, - } -} - -func WebAuthNLoginsToModel(u2fs []*WebAuthNLogin) []*model.WebAuthNLogin { - convertedIDPs := make([]*model.WebAuthNLogin, len(u2fs)) - for i, m := range u2fs { - convertedIDPs[i] = WebAuthNLoginToModel(m) - } - return convertedIDPs -} - -func WebAuthNLoginsFromModel(u2fs []*model.WebAuthNLogin) []*WebAuthNLogin { - convertedIDPs := make([]*WebAuthNLogin, len(u2fs)) - for i, m := range u2fs { - convertedIDPs[i] = WebAuthNLoginFromModel(m) - } - return convertedIDPs -} - -func WebAuthNLoginFromModel(webAuthN *model.WebAuthNLogin) *WebAuthNLogin { - return &WebAuthNLogin{ - ObjectRoot: webAuthN.ObjectRoot, - Challenge: webAuthN.Challenge, - AuthRequest: AuthRequestFromModel(webAuthN.AuthRequest), - } -} - -func WebAuthNLoginToModel(webAuthN *WebAuthNLogin) *model.WebAuthNLogin { - return &model.WebAuthNLogin{ - ObjectRoot: webAuthN.ObjectRoot, - Challenge: webAuthN.Challenge, - AuthRequest: AuthRequestToModel(webAuthN.AuthRequest), - } -} - func (w *WebAuthNVerify) SetData(event *es_models.Event) error { if err := json.Unmarshal(event.Data, w); err != nil { logging.Log("EVEN-G342rf").WithError(err).Error("could not unmarshal event data") diff --git a/internal/user/repository/eventsourcing/user.go b/internal/user/repository/view/query.go similarity index 63% rename from internal/user/repository/eventsourcing/user.go rename to internal/user/repository/view/query.go index 063f0f934d..6f59186834 100644 --- a/internal/user/repository/eventsourcing/user.go +++ b/internal/user/repository/view/query.go @@ -1,7 +1,6 @@ -package eventsourcing +package view import ( - "context" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" @@ -21,9 +20,15 @@ func UserQuery(latestSequence uint64) *es_models.SearchQuery { LatestSequenceFilter(latestSequence) } -func UserAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User) (*es_models.Aggregate, error) { - if user == nil { - return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dis83", "Errors.Internal") +func ChangesQuery(userID string, latestSequence, limit uint64, sortAscending bool) *es_models.SearchQuery { + query := es_models.NewSearchQuery(). + AggregateTypeFilter(model.UserAggregate) + if !sortAscending { + query.OrderDesc() } - return aggCreator.NewAggregate(ctx, user.AggregateID, model.UserAggregate, model.UserVersion, user.Sequence) + + query.LatestSequenceFilter(latestSequence). + AggregateIDFilter(userID). + SetLimit(limit) + return query } diff --git a/internal/v2/repository/usergrant/user_grant.go b/internal/v2/repository/usergrant/user_grant.go index 1f006fbd0c..3ef3558e45 100644 --- a/internal/v2/repository/usergrant/user_grant.go +++ b/internal/v2/repository/usergrant/user_grant.go @@ -32,7 +32,7 @@ func NewAddUserGrantUniqueConstraint(resourceOwner, userID, projectID, projectGr func NewRemoveUserGrantUniqueConstraint(resourceOwner, userID, projectID, projectGrantID string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( UniqueUserGrant, - fmt.Sprintf("%s:%s:%s:%S", resourceOwner, userID, projectID, projectGrantID)) + fmt.Sprintf("%s:%s:%s:%s", resourceOwner, userID, projectID, projectGrantID)) } type UserGrantAddedEvent struct {