mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 20:27:32 +00:00
fix: add resourceowner to check for project in project grant (#8785)
Some checks failed
ZITADEL CI/CD / core (push) Waiting to run
ZITADEL CI/CD / console (push) Waiting to run
ZITADEL CI/CD / version (push) Waiting to run
ZITADEL CI/CD / compile (push) Blocked by required conditions
ZITADEL CI/CD / core-unit-test (push) Blocked by required conditions
ZITADEL CI/CD / core-integration-test (push) Blocked by required conditions
ZITADEL CI/CD / lint (push) Blocked by required conditions
ZITADEL CI/CD / container (push) Blocked by required conditions
ZITADEL CI/CD / e2e (push) Blocked by required conditions
ZITADEL CI/CD / release (push) Blocked by required conditions
Code Scanning / CodeQL-Build (javascript) (push) Failing after 7m42s
Code Scanning / CodeQL-Build (go) (push) Failing after 15m0s
Some checks failed
ZITADEL CI/CD / core (push) Waiting to run
ZITADEL CI/CD / console (push) Waiting to run
ZITADEL CI/CD / version (push) Waiting to run
ZITADEL CI/CD / compile (push) Blocked by required conditions
ZITADEL CI/CD / core-unit-test (push) Blocked by required conditions
ZITADEL CI/CD / core-integration-test (push) Blocked by required conditions
ZITADEL CI/CD / lint (push) Blocked by required conditions
ZITADEL CI/CD / container (push) Blocked by required conditions
ZITADEL CI/CD / e2e (push) Blocked by required conditions
ZITADEL CI/CD / release (push) Blocked by required conditions
Code Scanning / CodeQL-Build (javascript) (push) Failing after 7m42s
Code Scanning / CodeQL-Build (go) (push) Failing after 15m0s
# Which Problems Are Solved Resource owner can be different than expected if the provided x-zitadel-orgid header is provided. # How the Problems Are Solved Check that the project is only checked with the correct resource owner to avoid unexpected situations. # Additional Changes None # Additional Context Closes #8685 --------- Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
@@ -27,7 +27,7 @@ func (c *Commands) AddProjectGrant(ctx context.Context, grant *domain.ProjectGra
|
|||||||
if !grant.IsValid() {
|
if !grant.IsValid() {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-3b8fs", "Errors.Project.Grant.Invalid")
|
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-3b8fs", "Errors.Project.Grant.Invalid")
|
||||||
}
|
}
|
||||||
err = c.checkProjectGrantPreCondition(ctx, grant)
|
err = c.checkProjectGrantPreCondition(ctx, grant, resourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ func (c *Commands) ChangeProjectGrant(ctx context.Context, grant *domain.Project
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
grant.GrantedOrgID = existingGrant.GrantedOrgID
|
grant.GrantedOrgID = existingGrant.GrantedOrgID
|
||||||
err = c.checkProjectGrantPreCondition(ctx, grant)
|
err = c.checkProjectGrantPreCondition(ctx, grant, resourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -255,11 +255,11 @@ func (c *Commands) projectGrantWriteModelByID(ctx context.Context, grantID, proj
|
|||||||
return writeModel, nil
|
return writeModel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) checkProjectGrantPreCondition(ctx context.Context, projectGrant *domain.ProjectGrant) error {
|
func (c *Commands) checkProjectGrantPreCondition(ctx context.Context, projectGrant *domain.ProjectGrant, resourceOwner string) error {
|
||||||
if !authz.GetFeatures(ctx).ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeProjectGrant) {
|
if !authz.GetFeatures(ctx).ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeProjectGrant) {
|
||||||
return c.checkProjectGrantPreConditionOld(ctx, projectGrant)
|
return c.checkProjectGrantPreConditionOld(ctx, projectGrant, resourceOwner)
|
||||||
}
|
}
|
||||||
existingRoleKeys, err := c.searchProjectGrantState(ctx, projectGrant.AggregateID, projectGrant.GrantedOrgID)
|
existingRoleKeys, err := c.searchProjectGrantState(ctx, projectGrant.AggregateID, projectGrant.GrantedOrgID, resourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -270,11 +270,12 @@ func (c *Commands) checkProjectGrantPreCondition(ctx context.Context, projectGra
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grantedOrgID string) (existingRoleKeys []string, err error) {
|
func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grantedOrgID, resourceOwner string) (existingRoleKeys []string, err error) {
|
||||||
results, err := c.eventstore.Search(
|
results, err := c.eventstore.Search(
|
||||||
ctx,
|
ctx,
|
||||||
// project state query
|
// project state query
|
||||||
map[eventstore.FieldType]any{
|
map[eventstore.FieldType]any{
|
||||||
|
eventstore.FieldTypeResourceOwner: resourceOwner,
|
||||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||||
eventstore.FieldTypeAggregateID: projectID,
|
eventstore.FieldTypeAggregateID: projectID,
|
||||||
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
||||||
@@ -289,6 +290,7 @@ func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grant
|
|||||||
},
|
},
|
||||||
// role query
|
// role query
|
||||||
map[eventstore.FieldType]any{
|
map[eventstore.FieldType]any{
|
||||||
|
eventstore.FieldTypeResourceOwner: resourceOwner,
|
||||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||||
eventstore.FieldTypeAggregateID: projectID,
|
eventstore.FieldTypeAggregateID: projectID,
|
||||||
eventstore.FieldTypeFieldName: project.ProjectRoleKeySearchField,
|
eventstore.FieldTypeFieldName: project.ProjectRoleKeySearchField,
|
||||||
|
@@ -121,8 +121,9 @@ type ProjectGrantPreConditionReadModel struct {
|
|||||||
ExistingRoleKeys []string
|
ExistingRoleKeys []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProjectGrantPreConditionReadModel(projectID, grantedOrgID string) *ProjectGrantPreConditionReadModel {
|
func NewProjectGrantPreConditionReadModel(projectID, grantedOrgID, resourceOwner string) *ProjectGrantPreConditionReadModel {
|
||||||
return &ProjectGrantPreConditionReadModel{
|
return &ProjectGrantPreConditionReadModel{
|
||||||
|
WriteModel: eventstore.WriteModel{ResourceOwner: resourceOwner},
|
||||||
ProjectID: projectID,
|
ProjectID: projectID,
|
||||||
GrantedOrgID: grantedOrgID,
|
GrantedOrgID: grantedOrgID,
|
||||||
}
|
}
|
||||||
@@ -132,12 +133,24 @@ func (wm *ProjectGrantPreConditionReadModel) Reduce() error {
|
|||||||
for _, event := range wm.Events {
|
for _, event := range wm.Events {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *project.ProjectAddedEvent:
|
case *project.ProjectAddedEvent:
|
||||||
|
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||||
|
continue
|
||||||
|
}
|
||||||
wm.ProjectExists = true
|
wm.ProjectExists = true
|
||||||
case *project.ProjectRemovedEvent:
|
case *project.ProjectRemovedEvent:
|
||||||
|
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||||
|
continue
|
||||||
|
}
|
||||||
wm.ProjectExists = false
|
wm.ProjectExists = false
|
||||||
case *project.RoleAddedEvent:
|
case *project.RoleAddedEvent:
|
||||||
|
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||||
|
continue
|
||||||
|
}
|
||||||
wm.ExistingRoleKeys = append(wm.ExistingRoleKeys, e.Key)
|
wm.ExistingRoleKeys = append(wm.ExistingRoleKeys, e.Key)
|
||||||
case *project.RoleRemovedEvent:
|
case *project.RoleRemovedEvent:
|
||||||
|
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||||
|
continue
|
||||||
|
}
|
||||||
for i, key := range wm.ExistingRoleKeys {
|
for i, key := range wm.ExistingRoleKeys {
|
||||||
if key == e.Key {
|
if key == e.Key {
|
||||||
copy(wm.ExistingRoleKeys[i:], wm.ExistingRoleKeys[i+1:])
|
copy(wm.ExistingRoleKeys[i:], wm.ExistingRoleKeys[i+1:])
|
||||||
|
@@ -79,6 +79,50 @@ func TestCommandSide_AddProjectGrant(t *testing.T) {
|
|||||||
err: zerrors.IsPreconditionFailed,
|
err: zerrors.IsPreconditionFailed,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "project not existing in org, precondition error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewProjectAddedEvent(context.Background(),
|
||||||
|
&project.NewAggregate("project1", "otherorg").Aggregate,
|
||||||
|
"projectname1", true, true, true,
|
||||||
|
domain.PrivateLabelingSettingUnspecified,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewOrgAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("grantedorg1").Aggregate,
|
||||||
|
"granted org",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewRoleAddedEvent(context.Background(),
|
||||||
|
&project.NewAggregate("project1", "otherorg").Aggregate,
|
||||||
|
"key1",
|
||||||
|
"key",
|
||||||
|
"",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
projectGrant: &domain.ProjectGrant{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
AggregateID: "project1",
|
||||||
|
},
|
||||||
|
GrantedOrgID: "grantedorg1",
|
||||||
|
},
|
||||||
|
resourceOwner: "org1",
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: zerrors.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "granted org not existing, precondition error",
|
name: "granted org not existing, precondition error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
@@ -325,6 +369,52 @@ func TestCommandSide_ChangeProjectGrant(t *testing.T) {
|
|||||||
err: zerrors.IsPreconditionFailed,
|
err: zerrors.IsPreconditionFailed,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "project not existing in org, precondition error",
|
||||||
|
fields: fields{
|
||||||
|
eventstore: eventstoreExpect(
|
||||||
|
t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(project.NewGrantAddedEvent(context.Background(),
|
||||||
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
|
"projectgrant1",
|
||||||
|
"grantedorg1",
|
||||||
|
[]string{"key1"},
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewProjectAddedEvent(context.Background(),
|
||||||
|
&project.NewAggregate("project1", "otherorg").Aggregate,
|
||||||
|
"projectname1", true, true, true,
|
||||||
|
domain.PrivateLabelingSettingUnspecified,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
org.NewOrgAddedEvent(context.Background(),
|
||||||
|
&org.NewAggregate("grantedorg1").Aggregate,
|
||||||
|
"granted org",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
projectGrant: &domain.ProjectGrant{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
AggregateID: "project1",
|
||||||
|
},
|
||||||
|
GrantID: "projectgrant1",
|
||||||
|
GrantedOrgID: "grantedorg1",
|
||||||
|
RoleKeys: []string{"key1"},
|
||||||
|
},
|
||||||
|
resourceOwner: "org1",
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
err: zerrors.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "granted org not existing, precondition error",
|
name: "granted org not existing, precondition error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
|
@@ -161,8 +161,8 @@ func (c *Commands) removeProjectOld(ctx context.Context, projectID, resourceOwne
|
|||||||
return writeModelToObjectDetails(&existingProject.WriteModel), nil
|
return writeModelToObjectDetails(&existingProject.WriteModel), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) checkProjectGrantPreConditionOld(ctx context.Context, projectGrant *domain.ProjectGrant) error {
|
func (c *Commands) checkProjectGrantPreConditionOld(ctx context.Context, projectGrant *domain.ProjectGrant, resourceOwner string) error {
|
||||||
preConditions := NewProjectGrantPreConditionReadModel(projectGrant.AggregateID, projectGrant.GrantedOrgID)
|
preConditions := NewProjectGrantPreConditionReadModel(projectGrant.AggregateID, projectGrant.GrantedOrgID, resourceOwner)
|
||||||
err := c.eventstore.FilterToQueryReducer(ctx, preConditions)
|
err := c.eventstore.FilterToQueryReducer(ctx, preConditions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
Reference in New Issue
Block a user