fix: Project checks (#141)

* project validations

* unique project on resourceowner
This commit is contained in:
Fabi 2020-05-28 06:53:12 +02:00 committed by GitHub
parent d447f68d78
commit 2758bf30b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 191 additions and 14 deletions

View File

@ -126,7 +126,7 @@ func prepareWhere(searchQuery *es_models.SearchQuery) (clause string, values []i
for i, filter := range searchQuery.Filters {
value := filter.GetValue()
switch value.(type) {
case []bool, []float64, []int64, []string, []models.AggregateType, *[]bool, *[]float64, *[]int64, *[]string, *[]models.AggregateType:
case []bool, []float64, []int64, []string, []models.AggregateType, []models.EventType, *[]bool, *[]float64, *[]int64, *[]string, *[]models.AggregateType, *[]models.EventType:
value = pq.Array(value)
}
@ -165,6 +165,8 @@ func getField(field es_models.Field) string {
return "editor_service"
case es_models.Field_EditorUser:
return "editor_user"
case es_models.Field_EventType:
return "event_type"
}
return ""
}

View File

@ -9,4 +9,5 @@ const (
Field_ResourceOwner
Field_EditorService
Field_EditorUser
Field_EventType
)

View File

@ -43,6 +43,10 @@ func (q *SearchQuery) AggregateTypeFilter(types ...AggregateType) *SearchQuery {
return q.setFilter(NewFilter(Field_AggregateType, types, Operation_In))
}
func (q *SearchQuery) EventTypesFilter(types ...EventType) *SearchQuery {
return q.setFilter(NewFilter(Field_EventType, types, Operation_In))
}
func (q *SearchQuery) LatestSequenceFilter(sequence uint64) *SearchQuery {
sortOrder := Operation_Greater
if q.Desc {

View File

@ -113,8 +113,10 @@ func (es *ProjectEventstore) DeactivateProject(ctx context.Context, id string) (
repoExisting := model.ProjectFromModel(existing)
aggregate := ProjectDeactivateAggregate(es.AggregateCreator(), repoExisting)
es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoExisting)
return model.ProjectToModel(repoExisting), nil
}
@ -130,8 +132,10 @@ func (es *ProjectEventstore) ReactivateProject(ctx context.Context, id string) (
repoExisting := model.ProjectFromModel(existing)
aggregate := ProjectReactivateAggregate(es.AggregateCreator(), repoExisting)
es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoExisting)
return model.ProjectToModel(repoExisting), nil
}
@ -194,6 +198,9 @@ func (es *ProjectEventstore) ChangeProjectMember(ctx context.Context, member *pr
projectAggregate := ProjectMemberChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, m := model.GetProjectMember(repoProject.Members, member.UserID); m != nil {
@ -218,6 +225,9 @@ func (es *ProjectEventstore) RemoveProjectMember(ctx context.Context, member *pr
projectAggregate := ProjectMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return err
}
es.projectCache.cacheProject(repoProject)
return err
}
@ -347,6 +357,9 @@ func (es *ProjectEventstore) AddApplication(ctx context.Context, app *proj_model
addAggregate := ApplicationAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, addAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
converted := model.AppToModel(a)
@ -372,6 +385,9 @@ func (es *ProjectEventstore) ChangeApplication(ctx context.Context, app *proj_mo
projectAggregate := ApplicationChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
return model.AppToModel(a), nil
@ -418,6 +434,9 @@ func (es *ProjectEventstore) DeactivateApplication(ctx context.Context, projectI
projectAggregate := ApplicationDeactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
return model.AppToModel(a), nil
@ -442,6 +461,9 @@ func (es *ProjectEventstore) ReactivateApplication(ctx context.Context, projectI
projectAggregate := ApplicationReactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
return model.AppToModel(a), nil
@ -469,6 +491,9 @@ func (es *ProjectEventstore) ChangeOIDCConfig(ctx context.Context, config *proj_
projectAggregate := OIDCConfigChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoConfig)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
return model.OIDCConfigToModel(a.OIDCConfig), nil
@ -500,6 +525,9 @@ func (es *ProjectEventstore) ChangeOIDCConfigSecret(ctx context.Context, project
projectAggregate := OIDCConfigSecretChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, appID, crypto)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
@ -550,7 +578,9 @@ func (es *ProjectEventstore) AddProjectGrant(ctx context.Context, grant *proj_mo
addAggregate := ProjectGrantAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, addAggregate)
if err != nil {
return nil, err
}
if _, g := model.GetProjectGrant(repoProject.Grants, grant.GrantID); g != nil {
return model.GrantToModel(g), nil
}
@ -576,6 +606,9 @@ func (es *ProjectEventstore) ChangeProjectGrant(ctx context.Context, grant *proj
projectAggregate := ProjectGrantChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, g := model.GetProjectGrant(repoProject.Grants, grant.GrantID); g != nil {
@ -623,6 +656,9 @@ func (es *ProjectEventstore) DeactivateProjectGrant(ctx context.Context, project
projectAggregate := ProjectGrantDeactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, g := model.GetProjectGrant(repoProject.Grants, grant.GrantID); g != nil {
return model.GrantToModel(g), nil
@ -647,6 +683,9 @@ func (es *ProjectEventstore) ReactivateProjectGrant(ctx context.Context, project
projectAggregate := ProjectGrantReactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, g := model.GetProjectGrant(repoProject.Grants, grant.GrantID); g != nil {
@ -687,6 +726,9 @@ func (es *ProjectEventstore) AddProjectGrantMember(ctx context.Context, member *
addAggregate := ProjectGrantMemberAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, addAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, g := model.GetProjectGrant(repoProject.Grants, member.GrantID); g != nil {
if _, m := model.GetProjectGrantMember(g.Members, member.UserID); m != nil {
@ -712,6 +754,9 @@ func (es *ProjectEventstore) ChangeProjectGrantMember(ctx context.Context, membe
projectAggregate := ProjectGrantMemberChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, g := model.GetProjectGrant(repoProject.Grants, member.GrantID); g != nil {
if _, m := model.GetProjectGrantMember(g.Members, member.UserID); m != nil {
@ -737,6 +782,9 @@ func (es *ProjectEventstore) RemoveProjectGrantMember(ctx context.Context, membe
projectAggregate := ProjectGrantMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return err
}
es.projectCache.cacheProject(repoProject)
return err
}

View File

@ -21,6 +21,15 @@ type Project struct {
Grants []*ProjectGrant `json:"-"`
}
func GetProject(projects []*Project, id string) (int, *Project) {
for i, p := range projects {
if p.AggregateID == id {
return i, p
}
}
return -1, nil
}
func (p *Project) Changes(changed *Project) map[string]interface{} {
changes := make(map[string]interface{}, 1)
if changed.Name != "" && p.Name != changed.Name {

View File

@ -6,7 +6,9 @@ import (
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
"github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
func ProjectByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
@ -40,8 +42,12 @@ func ProjectCreateAggregate(aggCreator *es_models.AggregateCreator, project *mod
if err != nil {
return nil, err
}
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(model.ProjectAggregate).
EventTypesFilter(model.ProjectAdded, model.ProjectChanged, model.ProjectRemoved)
return agg.AppendEvent(model.ProjectAdded, project)
validation := addProjectValidation(project.Name)
return agg.SetPrecondition(validationQuery, validation).AppendEvent(model.ProjectAdded, project)
}
}
@ -55,6 +61,17 @@ func ProjectUpdateAggregate(aggCreator *es_models.AggregateCreator, existing *mo
return nil, err
}
changes := existing.Changes(new)
if len(changes) == 0 {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-9soPE", "no changes found")
}
if existing.Name != new.Name {
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(model.ProjectAggregate).
EventTypesFilter(model.ProjectAdded, model.ProjectChanged, model.ProjectRemoved)
validation := addProjectValidation(new.Name)
agg.SetPrecondition(validationQuery, validation)
}
return agg.AppendEvent(model.ProjectChanged, changes)
}
}
@ -86,7 +103,12 @@ func ProjectMemberAddedAggregate(aggCreator *es_models.AggregateCreator, existin
if err != nil {
return nil, err
}
return agg.AppendEvent(model.ProjectMemberAdded, member)
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(usr_model.UserAggregate).
AggregateIDFilter(member.UserID)
validation := addProjectMemberValidation()
return agg.SetPrecondition(validationQuery, validation).AppendEvent(model.ProjectMemberAdded, member)
}
}
@ -287,7 +309,12 @@ func ProjectGrantAddedAggregate(aggCreator *es_models.AggregateCreator, existing
if err != nil {
return nil, err
}
agg.AppendEvent(model.ProjectGrantAdded, grant)
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(org_model.OrgAggregate).
AggregateIDFilter(grant.GrantedOrgID)
validation := addProjectGrantValidation()
agg.SetPrecondition(validationQuery, validation).AppendEvent(model.ProjectGrantAdded, grant)
return agg, nil
}
}
@ -352,9 +379,7 @@ func ProjectGrantReactivatedAggregate(aggCreator *es_models.AggregateCreator, ex
if err != nil {
return nil, err
}
agg.AppendEvent(model.ProjectGrantReactivated, &model.ProjectGrantID{GrantID: grant.GrantID})
return agg, nil
return agg.AppendEvent(model.ProjectGrantReactivated, &model.ProjectGrantID{GrantID: grant.GrantID})
}
}
@ -367,8 +392,12 @@ func ProjectGrantMemberAddedAggregate(aggCreator *es_models.AggregateCreator, ex
if err != nil {
return nil, err
}
agg.AppendEvent(model.ProjectGrantMemberAdded, member)
return agg, nil
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(usr_model.UserAggregate).
AggregateIDFilter(member.UserID)
validation := addProjectGrantMemberValidation()
return agg.SetPrecondition(validationQuery, validation).AppendEvent(model.ProjectGrantMemberAdded, member)
}
}
@ -403,3 +432,86 @@ func ProjectGrantMemberRemovedAggregate(aggCreator *es_models.AggregateCreator,
return agg.AppendEvent(model.ProjectGrantMemberRemoved, member)
}
}
func addProjectValidation(projectName string) func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
projects := make([]*model.Project, 0)
for _, event := range events {
switch event.Type {
case model.ProjectAdded:
project := &model.Project{ObjectRoot: es_models.ObjectRoot{AggregateID: event.AggregateID}}
project.AppendAddProjectEvent(event)
projects = append(projects, project)
case model.ProjectChanged:
_, project := model.GetProject(projects, event.AggregateID)
project.AppendAddProjectEvent(event)
case model.ProjectRoleRemoved:
for i, project := range projects {
if project.AggregateID == event.AggregateID {
projects[i] = projects[len(projects)-1]
projects[len(projects)-1] = nil
projects = projects[:len(projects)-1]
}
}
}
}
for _, p := range projects {
if p.Name == projectName {
return errors.ThrowPreconditionFailed(nil, "EVENT-s9oPw", "conditions not met")
}
}
return nil
}
}
func addProjectMemberValidation() func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
return checkExistsUser(events...)
}
}
func addProjectGrantValidation() func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
existsOrg := false
for _, event := range events {
switch event.AggregateType {
case org_model.OrgAggregate:
switch event.Type {
case org_model.OrgAdded:
existsOrg = true
case org_model.OrgRemoved:
existsOrg = false
}
}
}
if existsOrg {
return nil
}
return errors.ThrowPreconditionFailed(nil, "EVENT-3OfIm", "conditions not met")
}
}
func addProjectGrantMemberValidation() func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
return checkExistsUser(events...)
}
}
func checkExistsUser(events ...*es_models.Event) error {
existsUser := false
for _, event := range events {
switch event.AggregateType {
case usr_model.UserAggregate:
switch event.Type {
case usr_model.UserAdded, usr_model.UserRegistered:
existsUser = true
case usr_model.UserRemoved:
existsUser = false
}
}
}
if existsUser {
return nil
}
return errors.ThrowPreconditionFailed(nil, "EVENT-3OfIm", "conditions not met")
}

View File

@ -11,6 +11,7 @@ const (
UserRegistered models.EventType = "user.selfregistered"
InitializedUserCodeAdded models.EventType = "user.initialization.code.added"
InitializedUserCodeSent models.EventType = "user.initialization.code.sent"
UserRemoved models.EventType = "user.removed"
UserUserNameReserved models.EventType = "user.username.reserved"
UserUserNameReleased models.EventType = "user.username.released"