diff --git a/internal/command/org_policy_label.go b/internal/command/org_policy_label.go index 751c52835b..fea680b44c 100644 --- a/internal/command/org_policy_label.go +++ b/internal/command/org_policy_label.go @@ -3,6 +3,7 @@ package command import ( "context" + "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/domain" caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/repository/org" @@ -24,6 +25,10 @@ func (c *Commands) AddLabelPolicy(ctx context.Context, resourceOwner string, pol return nil, caos_errs.ThrowAlreadyExists(nil, "Org-2B0ps", "Errors.Org.LabelPolicy.AlreadyExists") } + err = c.checkLabelPolicyAllowed(ctx, resourceOwner, policy) + if err != nil { + return nil, err + } orgAgg := OrgAggregateFromWriteModel(&addedPolicy.LabelPolicyWriteModel.WriteModel) pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyAddedEvent( ctx, @@ -65,6 +70,11 @@ func (c *Commands) ChangeLabelPolicy(ctx context.Context, resourceOwner string, return nil, caos_errs.ThrowNotFound(nil, "Org-0K9dq", "Errors.Org.LabelPolicy.NotFound") } + err = c.checkLabelPolicyAllowed(ctx, resourceOwner, policy) + if err != nil { + return nil, err + } + orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel) changedEvent, hasChanged := existingPolicy.NewChangedEvent( ctx, @@ -95,6 +105,28 @@ func (c *Commands) ChangeLabelPolicy(ctx context.Context, resourceOwner string, return writeModelToLabelPolicy(&existingPolicy.LabelPolicyWriteModel), nil } +func (c *Commands) checkLabelPolicyAllowed(ctx context.Context, resourceOwner string, policy *domain.LabelPolicy) error { + defaultPolicy, err := c.getDefaultLabelPolicy(ctx) + if err != nil { + return err + } + requiredFeatures := make([]string, 0) + if defaultPolicy.PrimaryColor != policy.PrimaryColor || defaultPolicy.PrimaryColorDark != policy.PrimaryColorDark || + defaultPolicy.FontColor != policy.FontColor || defaultPolicy.FontColorDark != policy.FontColorDark || + defaultPolicy.BackgroundColor != policy.BackgroundColor || defaultPolicy.BackgroundColorDark != policy.BackgroundColorDark || + defaultPolicy.WarnColor != defaultPolicy.WarnColor || defaultPolicy.WarnColorDark != defaultPolicy.WarnColorDark || + defaultPolicy.LogoURL != policy.LogoURL || defaultPolicy.LogoDarkURL != policy.LogoDarkURL || + defaultPolicy.IconURL != policy.IconURL || defaultPolicy.IconDarkURL != policy.IconDarkURL || + defaultPolicy.Font != policy.Font || + defaultPolicy.HideLoginNameSuffix != policy.HideLoginNameSuffix { + requiredFeatures = append(requiredFeatures, domain.FeatureLabelPolicyPrivateLabel) + } + if defaultPolicy.DisableWatermark != policy.DisableWatermark { + requiredFeatures = append(requiredFeatures, domain.FeatureLabelPolicyWatermark) + } + return authz.CheckOrgFeatures(ctx, c.tokenVerifier, resourceOwner, requiredFeatures...) +} + func (c *Commands) ActivateLabelPolicy(ctx context.Context, orgID string) (*domain.ObjectDetails, error) { if orgID == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "Org-KKd4X", "Errors.ResourceOwnerMissing") diff --git a/internal/command/org_policy_label_test.go b/internal/command/org_policy_label_test.go index 085704795c..befa74a816 100644 --- a/internal/command/org_policy_label_test.go +++ b/internal/command/org_policy_label_test.go @@ -7,11 +7,13 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/domain" caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore/repository" "github.com/caos/zitadel/internal/eventstore/v1/models" + "github.com/caos/zitadel/internal/repository/iam" "github.com/caos/zitadel/internal/repository/org" "github.com/caos/zitadel/internal/repository/policy" "github.com/caos/zitadel/internal/static" @@ -20,7 +22,8 @@ import ( func TestCommandSide_AddLabelPolicy(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore *eventstore.Eventstore + tokenVerifier *authz.TokenVerifier } type args struct { ctx context.Context @@ -101,12 +104,78 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) { err: caos_errs.IsErrorAlreadyExists, }, }, + { + name: "add policy, permission denied", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter(), + expectFilter( + eventFromEventPusher( + iam.NewLabelPolicyAddedEvent(context.Background(), + &iam.NewAggregate().Aggregate, + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + true, + true, + false, + ), + ), + ), + ), + tokenVerifier: GetMockVerifier(t), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + policy: &domain.LabelPolicy{ + PrimaryColor: "#ffffff", + BackgroundColor: "#ffffff", + WarnColor: "#ffffff", + FontColor: "#ffffff", + PrimaryColorDark: "#ffffff", + BackgroundColorDark: "#ffffff", + WarnColorDark: "#ffffff", + FontColorDark: "#ffffff", + HideLoginNameSuffix: true, + ErrorMsgPopup: true, + DisableWatermark: true, + }, + }, + res: res{ + err: caos_errs.IsPermissionDenied, + }, + }, { name: "add policy,ok", fields: fields{ eventstore: eventstoreExpect( t, expectFilter(), + expectFilter( + eventFromEventPusher( + iam.NewLabelPolicyAddedEvent(context.Background(), + &iam.NewAggregate().Aggregate, + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + true, + true, + false, + ), + ), + ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -128,6 +197,7 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) { }, ), ), + tokenVerifier: GetMockVerifier(t, domain.FeatureLabelPolicyPrivateLabel, domain.FeatureLabelPolicyWatermark), }, args: args{ ctx: context.Background(), @@ -170,7 +240,8 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore, + tokenVerifier: tt.fields.tokenVerifier, } got, err := r.AddLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.policy) if tt.res.err == nil { @@ -188,7 +259,8 @@ func TestCommandSide_AddLabelPolicy(t *testing.T) { func TestCommandSide_ChangeLabelPolicy(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore *eventstore.Eventstore + tokenVerifier *authz.TokenVerifier } type args struct { ctx context.Context @@ -244,6 +316,71 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { err: caos_errs.IsNotFound, }, }, + { + name: "permission denied error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + org.NewLabelPolicyAddedEvent(context.Background(), + &org.NewAggregate("org1", "org1").Aggregate, + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + true, + true, + true, + ), + ), + ), + expectFilter( + eventFromEventPusher( + iam.NewLabelPolicyAddedEvent(context.Background(), + &iam.NewAggregate().Aggregate, + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + true, + true, + false, + ), + ), + ), + ), + tokenVerifier: GetMockVerifier(t), + }, + args: args{ + ctx: context.Background(), + orgID: "org1", + policy: &domain.LabelPolicy{ + PrimaryColor: "#000000", + BackgroundColor: "#000000", + WarnColor: "#000000", + FontColor: "#000000", + PrimaryColorDark: "#000000", + BackgroundColorDark: "#000000", + WarnColorDark: "#000000", + FontColorDark: "#000000", + HideLoginNameSuffix: true, + ErrorMsgPopup: true, + DisableWatermark: true, + }, + }, + res: res{ + err: caos_errs.IsPermissionDenied, + }, + }, { name: "no changes, precondition error", fields: fields{ @@ -267,7 +404,26 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { ), ), ), + expectFilter( + eventFromEventPusher( + iam.NewLabelPolicyAddedEvent(context.Background(), + &iam.NewAggregate().Aggregate, + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + true, + true, + false, + ), + ), + ), ), + tokenVerifier: GetMockVerifier(t, domain.FeatureLabelPolicyPrivateLabel, domain.FeatureLabelPolicyWatermark), }, args: args{ ctx: context.Background(), @@ -313,6 +469,24 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { ), ), ), + expectFilter( + eventFromEventPusher( + iam.NewLabelPolicyAddedEvent(context.Background(), + &iam.NewAggregate().Aggregate, + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + "#ffffff", + true, + true, + false, + ), + ), + ), expectPush( []*repository.Event{ eventFromEventPusher( @@ -334,6 +508,7 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { }, ), ), + tokenVerifier: GetMockVerifier(t, domain.FeatureLabelPolicyPrivateLabel, domain.FeatureLabelPolicyWatermark), }, args: args{ ctx: context.Background(), @@ -376,7 +551,8 @@ func TestCommandSide_ChangeLabelPolicy(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore, + tokenVerifier: tt.fields.tokenVerifier, } got, err := r.ChangeLabelPolicy(tt.args.ctx, tt.args.orgID, tt.args.policy) if tt.res.err == nil {