mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:37:32 +00:00
fix: multiple setup steps (#773)
* fix: multiple setup steps * fix: test set up started * fix: possible nil pointers in setup * fix: validate executed step
This commit is contained in:
@@ -4,12 +4,22 @@ import (
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
type Step int
|
||||
|
||||
const (
|
||||
Step1 Step = iota + 1
|
||||
//TODO: label policy
|
||||
// Step2
|
||||
//StepCount marks the the length of possible steps (StepCount-1 == last possible step)
|
||||
StepCount
|
||||
)
|
||||
|
||||
type IAM struct {
|
||||
es_models.ObjectRoot
|
||||
GlobalOrgID string
|
||||
IAMProjectID string
|
||||
SetUpDone bool
|
||||
SetUpStarted bool
|
||||
SetUpDone Step
|
||||
SetUpStarted Step
|
||||
Members []*IAMMember
|
||||
IDPs []*IDPConfig
|
||||
DefaultLoginPolicy *LoginPolicy
|
||||
|
@@ -60,32 +60,37 @@ func (es *IAMEventstore) IAMByID(ctx context.Context, id string) (*iam_model.IAM
|
||||
return model.IAMToModel(iam), nil
|
||||
}
|
||||
|
||||
func (es *IAMEventstore) StartSetup(ctx context.Context, iamID string) (*iam_model.IAM, error) {
|
||||
func (es *IAMEventstore) StartSetup(ctx context.Context, iamID string, step iam_model.Step) (*iam_model.IAM, error) {
|
||||
iam, err := es.IAMByID(ctx, iamID)
|
||||
if err != nil && !caos_errs.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if iam != nil && iam.SetUpStarted {
|
||||
if iam != nil && (iam.SetUpStarted >= step || iam.SetUpStarted != iam.SetUpDone) {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9so34", "Setup already started")
|
||||
}
|
||||
|
||||
repoIam := &model.IAM{ObjectRoot: models.ObjectRoot{AggregateID: iamID}}
|
||||
createAggregate := IAMSetupStartedAggregate(es.AggregateCreator(), repoIam)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, createAggregate)
|
||||
repoIAM := &model.IAM{ObjectRoot: models.ObjectRoot{AggregateID: iamID}, SetUpStarted: model.Step(step)}
|
||||
if iam != nil {
|
||||
repoIAM.ObjectRoot = iam.ObjectRoot
|
||||
}
|
||||
createAggregate := IAMSetupStartedAggregate(es.AggregateCreator(), repoIAM)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoIAM.AppendEvents, createAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
es.iamCache.cacheIAM(repoIam)
|
||||
return model.IAMToModel(repoIam), nil
|
||||
es.iamCache.cacheIAM(repoIAM)
|
||||
return model.IAMToModel(repoIAM), nil
|
||||
}
|
||||
|
||||
func (es *IAMEventstore) SetupDone(ctx context.Context, iamID string) (*iam_model.IAM, error) {
|
||||
func (es *IAMEventstore) SetupDone(ctx context.Context, iamID string, step iam_model.Step) (*iam_model.IAM, error) {
|
||||
iam, err := es.IAMByID(ctx, iamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iam.SetUpDone = step
|
||||
|
||||
repoIam := model.IAMFromModel(iam)
|
||||
createAggregate := IAMSetupDoneAggregate(es.AggregateCreator(), repoIam)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoIam.AppendEvents, createAggregate)
|
||||
|
@@ -79,9 +79,10 @@ func TestSetUpStarted(t *testing.T) {
|
||||
es *IAMEventstore
|
||||
ctx context.Context
|
||||
iamID string
|
||||
step iam_model.Step
|
||||
}
|
||||
type res struct {
|
||||
iam *model.IAM
|
||||
iam *iam_model.IAM
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
@@ -95,9 +96,10 @@ func TestSetUpStarted(t *testing.T) {
|
||||
es: GetMockManipulateIamNotExisting(ctrl),
|
||||
ctx: authz.NewMockContext("orgID", "userID"),
|
||||
iamID: "iamID",
|
||||
step: iam_model.Step1,
|
||||
},
|
||||
res: res{
|
||||
iam: &model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: true},
|
||||
iam: &iam_model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: iam_model.Step1},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -106,6 +108,7 @@ func TestSetUpStarted(t *testing.T) {
|
||||
es: GetMockManipulateIam(ctrl),
|
||||
ctx: authz.NewMockContext("orgID", "userID"),
|
||||
iamID: "iamID",
|
||||
step: iam_model.Step1,
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
@@ -114,8 +117,9 @@ func TestSetUpStarted(t *testing.T) {
|
||||
{
|
||||
name: "setup iam no id",
|
||||
args: args{
|
||||
es: GetMockManipulateIam(ctrl),
|
||||
ctx: authz.NewMockContext("orgID", "userID"),
|
||||
es: GetMockManipulateIam(ctrl),
|
||||
ctx: authz.NewMockContext("orgID", "userID"),
|
||||
step: iam_model.Step1,
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
@@ -124,7 +128,7 @@ func TestSetUpStarted(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := tt.args.es.StartSetup(tt.args.ctx, tt.args.iamID)
|
||||
result, err := tt.args.es.StartSetup(tt.args.ctx, tt.args.iamID, tt.args.step)
|
||||
|
||||
if tt.res.errFunc == nil && result.AggregateID == "" {
|
||||
t.Errorf("result has no id")
|
||||
@@ -145,9 +149,10 @@ func TestSetUpDone(t *testing.T) {
|
||||
es *IAMEventstore
|
||||
ctx context.Context
|
||||
iamID string
|
||||
step iam_model.Step
|
||||
}
|
||||
type res struct {
|
||||
iam *model.IAM
|
||||
iam *iam_model.IAM
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
@@ -161,16 +166,18 @@ func TestSetUpDone(t *testing.T) {
|
||||
es: GetMockManipulateIam(ctrl),
|
||||
ctx: authz.NewMockContext("orgID", "userID"),
|
||||
iamID: "iamID",
|
||||
step: iam_model.Step1,
|
||||
},
|
||||
res: res{
|
||||
iam: &model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: true, SetUpDone: true},
|
||||
iam: &iam_model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: iam_model.Step1, SetUpDone: iam_model.Step1},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "setup iam no id",
|
||||
args: args{
|
||||
es: GetMockManipulateIam(ctrl),
|
||||
ctx: authz.NewMockContext("orgID", "userID"),
|
||||
es: GetMockManipulateIam(ctrl),
|
||||
ctx: authz.NewMockContext("orgID", "userID"),
|
||||
step: iam_model.Step1,
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
@@ -182,6 +189,7 @@ func TestSetUpDone(t *testing.T) {
|
||||
es: GetMockManipulateIamNotExisting(ctrl),
|
||||
ctx: authz.NewMockContext("orgID", "userID"),
|
||||
iamID: "iamID",
|
||||
step: iam_model.Step1,
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsNotFound,
|
||||
@@ -190,7 +198,7 @@ func TestSetUpDone(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := tt.args.es.SetupDone(tt.args.ctx, tt.args.iamID)
|
||||
result, err := tt.args.es.SetupDone(tt.args.ctx, tt.args.iamID, tt.args.step)
|
||||
|
||||
if tt.res.errFunc == nil && result.AggregateID == "" {
|
||||
t.Errorf("result has no id")
|
||||
@@ -231,7 +239,7 @@ func TestSetGlobalOrg(t *testing.T) {
|
||||
globalOrg: "globalOrg",
|
||||
},
|
||||
res: res{
|
||||
iam: &model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: true, GlobalOrgID: "globalOrg"},
|
||||
iam: &model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: model.Step1, GlobalOrgID: "globalOrg"},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -312,7 +320,7 @@ func TestSetIamProjectID(t *testing.T) {
|
||||
iamProjectID: "iamProjectID",
|
||||
},
|
||||
res: res{
|
||||
iam: &model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: true, IAMProjectID: "iamProjectID"},
|
||||
iam: &model.IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "iamID", Sequence: 1}, SetUpStarted: model.Step1, IAMProjectID: "iamProjectID"},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@@ -43,7 +43,7 @@ func IAMSetupStartedAggregate(aggCreator *es_models.AggregateCreator, iam *model
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.IAMSetupStarted, nil)
|
||||
return agg.AppendEvent(model.IAMSetupStarted, &struct{ Step model.Step }{Step: iam.SetUpStarted})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ func IAMSetupDoneAggregate(aggCreator *es_models.AggregateCreator, iam *model.IA
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return agg.AppendEvent(model.IAMSetupDone, nil)
|
||||
return agg.AppendEvent(model.IAMSetupDone, &struct{ Step model.Step }{Step: iam.SetUpDone})
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/caos/logging"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
@@ -12,10 +13,19 @@ const (
|
||||
IAMVersion = "v1"
|
||||
)
|
||||
|
||||
type Step int
|
||||
|
||||
const (
|
||||
Step1 = Step(model.Step1)
|
||||
//TODO: label policy
|
||||
// Step2 = Step(model.Step2)
|
||||
StepCount = Step(model.StepCount)
|
||||
)
|
||||
|
||||
type IAM struct {
|
||||
es_models.ObjectRoot
|
||||
SetUpStarted bool `json:"-"`
|
||||
SetUpDone bool `json:"-"`
|
||||
SetUpStarted Step `json:"-"`
|
||||
SetUpDone Step `json:"-"`
|
||||
GlobalOrgID string `json:"globalOrgId,omitempty"`
|
||||
IAMProjectID string `json:"iamProjectId,omitempty"`
|
||||
Members []*IAMMember `json:"-"`
|
||||
@@ -28,8 +38,8 @@ func IAMFromModel(iam *model.IAM) *IAM {
|
||||
idps := IDPConfigsFromModel(iam.IDPs)
|
||||
converted := &IAM{
|
||||
ObjectRoot: iam.ObjectRoot,
|
||||
SetUpStarted: iam.SetUpStarted,
|
||||
SetUpDone: iam.SetUpDone,
|
||||
SetUpStarted: Step(iam.SetUpStarted),
|
||||
SetUpDone: Step(iam.SetUpDone),
|
||||
GlobalOrgID: iam.GlobalOrgID,
|
||||
IAMProjectID: iam.IAMProjectID,
|
||||
Members: members,
|
||||
@@ -46,8 +56,8 @@ func IAMToModel(iam *IAM) *model.IAM {
|
||||
idps := IDPConfigsToModel(iam.IDPs)
|
||||
converted := &model.IAM{
|
||||
ObjectRoot: iam.ObjectRoot,
|
||||
SetUpStarted: iam.SetUpStarted,
|
||||
SetUpDone: iam.SetUpDone,
|
||||
SetUpStarted: model.Step(iam.SetUpStarted),
|
||||
SetUpDone: model.Step(iam.SetUpDone),
|
||||
GlobalOrgID: iam.GlobalOrgID,
|
||||
IAMProjectID: iam.IAMProjectID,
|
||||
Members: members,
|
||||
@@ -72,9 +82,27 @@ func (i *IAM) AppendEvent(event *es_models.Event) (err error) {
|
||||
i.ObjectRoot.AppendEvent(event)
|
||||
switch event.Type {
|
||||
case IAMSetupStarted:
|
||||
i.SetUpStarted = true
|
||||
if len(event.Data) == 0 {
|
||||
i.SetUpStarted = Step(model.Step1)
|
||||
return
|
||||
}
|
||||
step := new(struct{ Step Step })
|
||||
err = json.Unmarshal(event.Data, step)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.SetUpStarted = step.Step
|
||||
case IAMSetupDone:
|
||||
i.SetUpDone = true
|
||||
if len(event.Data) == 0 {
|
||||
i.SetUpDone = Step(model.Step1)
|
||||
return
|
||||
}
|
||||
step := new(struct{ Step Step })
|
||||
err = json.Unmarshal(event.Data, step)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.SetUpDone = step.Step
|
||||
case IAMProjectSet,
|
||||
GlobalOrgSet:
|
||||
err = i.SetData(event)
|
||||
|
@@ -2,8 +2,9 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"testing"
|
||||
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
func mockIamData(iam *IAM) []byte {
|
||||
@@ -27,31 +28,31 @@ func TestProjectRoleAppendEvent(t *testing.T) {
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: IAMSetupStarted, ResourceOwner: "OrgID"},
|
||||
iam: &IAM{},
|
||||
},
|
||||
result: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true},
|
||||
result: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: Step1},
|
||||
},
|
||||
{
|
||||
name: "append set up done event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: IAMSetupDone, ResourceOwner: "OrgID"},
|
||||
iam: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true},
|
||||
iam: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: Step1},
|
||||
},
|
||||
result: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true, SetUpDone: true},
|
||||
result: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: Step1, SetUpDone: Step1},
|
||||
},
|
||||
{
|
||||
name: "append globalorg event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: GlobalOrgSet, ResourceOwner: "OrgID", Data: mockIamData(&IAM{GlobalOrgID: "GlobalOrg"})},
|
||||
iam: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true},
|
||||
iam: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: Step1},
|
||||
},
|
||||
result: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true, GlobalOrgID: "GlobalOrg"},
|
||||
result: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: Step1, GlobalOrgID: "GlobalOrg"},
|
||||
},
|
||||
{
|
||||
name: "append iamproject event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: IAMProjectSet, ResourceOwner: "OrgID", Data: mockIamData(&IAM{IAMProjectID: "IamProject"})},
|
||||
iam: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true},
|
||||
iam: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: Step1},
|
||||
},
|
||||
result: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: true, IAMProjectID: "IamProject"},
|
||||
result: &IAM{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, SetUpStarted: Step1, IAMProjectID: "IamProject"},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
Reference in New Issue
Block a user