fix(api): correct permission check in organization v2beta service

# Which Problems Are Solved

The organozation v2beta service wrongly checked the permissions on the user's organization instead of the organization the user tried to access.

# How the Problems Are Solved

- Check permissions in business logic based on accessed organization rather than the user's organization.
  - Queries now use permission v2 to ensure this.
  - Also changed the  /  to use the same pattern even if the old was no direct issue.

# Additional Changes

None

# Additional Context

None
This commit is contained in:
Livio Spring
2025-11-05 09:33:06 +01:00
parent 9c5ad4efcc
commit 8dcfff97ed
20 changed files with 1597 additions and 567 deletions

View File

@@ -255,6 +255,17 @@ func newMockProjectPermissionCheckSAMLNotAllowed() domain.ProjectPermissionCheck
}
}
func newMockOrganizationPermissionCheckNotAllowed() OrganizationPermissionCheck {
return func(ctx context.Context, organizationID string) (err error) {
return zerrors.ThrowPermissionDenied(nil, "", "Errors.PermissionDenied")
}
}
func newMockOrganizationPermissionCheckAllowed() OrganizationPermissionCheck {
return func(ctx context.Context, organizationID string) (err error) {
return nil
}
}
func newMockTokenVerifierValid() func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) {
return func(ctx context.Context, sessionToken, sessionID, tokenID string) (err error) {
return nil

View File

@@ -181,7 +181,7 @@ func (c *orgSetupCommands) setupOrgAdminMachine(orgAgg *org.Aggregate, machine *
func (c *orgSetupCommands) addCustomDomain(domain string, userIDs []string) error {
if domain != "" {
c.validations = append(c.validations, c.commands.prepareAddOrgDomain(c.aggregate, domain, userIDs))
c.validations = append(c.validations, c.commands.prepareAddOrgDomain(c.aggregate, domain, userIDs, nil))
}
return nil
}
@@ -263,7 +263,7 @@ func (c *orgSetupCommands) createdMachineAdmin(admin *OrgSetupAdmin) *CreatedOrg
return createdAdmin
}
func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, allowInitialMail bool, userIDs ...string) (*CreatedOrg, error) {
func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, allowInitialMail bool, permissionCheck OrganizationPermissionCheck, userIDs ...string) (*CreatedOrg, error) {
if err := o.Validate(); err != nil {
return nil, err
}
@@ -276,6 +276,12 @@ func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, allowInitialMail b
}
}
if permissionCheck != nil {
if err := permissionCheck(ctx, o.OrgID); err != nil {
return nil, err
}
}
// because users can choose their own ID, we must check that an org with the same ID does not already exist
existingOrg, err := c.getOrgWriteModelByID(ctx, o.OrgID)
if err != nil {
@@ -394,13 +400,17 @@ func (c *Commands) addOrgWithIDAndMember(ctx context.Context, name, userID, reso
return orgWriteModelToOrg(addedOrg), nil
}
func (c *Commands) ChangeOrg(ctx context.Context, orgID, name string) (*domain.ObjectDetails, error) {
func (c *Commands) ChangeOrg(ctx context.Context, organizationID, name string, permissionCheck OrganizationPermissionCheck) (*domain.ObjectDetails, error) {
name = strings.TrimSpace(name)
if orgID == "" || name == "" {
if organizationID == "" || name == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "EVENT-Mf9sd", "Errors.Org.Invalid")
}
orgWriteModel, err := c.getOrgWriteModelByID(ctx, orgID)
if permissionCheck != nil {
if err := permissionCheck(ctx, organizationID); err != nil {
return nil, err
}
}
orgWriteModel, err := c.getOrgWriteModelByID(ctx, organizationID)
if err != nil {
return nil, err
}
@@ -413,7 +423,7 @@ func (c *Commands) ChangeOrg(ctx context.Context, orgID, name string) (*domain.O
orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel)
events := make([]eventstore.Command, 0)
events = append(events, org.NewOrgChangedEvent(ctx, orgAgg, orgWriteModel.Name, name))
changeDomainEvents, err := c.changeDefaultDomain(ctx, orgID, name)
changeDomainEvents, err := c.changeDefaultDomain(ctx, organizationID, name)
if err != nil {
return nil, err
}
@@ -431,8 +441,15 @@ func (c *Commands) ChangeOrg(ctx context.Context, orgID, name string) (*domain.O
return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil
}
func (c *Commands) DeactivateOrg(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
orgWriteModel, err := c.getOrgWriteModelByID(ctx, orgID)
type OrganizationPermissionCheck func(ctx context.Context, organizationID string) error
func (c *Commands) DeactivateOrg(ctx context.Context, organizationID string, permissionCheck OrganizationPermissionCheck) (*domain.ObjectDetails, error) {
if permissionCheck != nil {
if err := permissionCheck(ctx, organizationID); err != nil {
return nil, err
}
}
orgWriteModel, err := c.getOrgWriteModelByID(ctx, organizationID)
if err != nil {
return nil, err
}
@@ -454,8 +471,13 @@ func (c *Commands) DeactivateOrg(ctx context.Context, orgID string) (*domain.Obj
return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil
}
func (c *Commands) ReactivateOrg(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
orgWriteModel, err := c.getOrgWriteModelByID(ctx, orgID)
func (c *Commands) ReactivateOrg(ctx context.Context, organizationID string, permissionCheck OrganizationPermissionCheck) (*domain.ObjectDetails, error) {
if permissionCheck != nil {
if err := permissionCheck(ctx, organizationID); err != nil {
return nil, err
}
}
orgWriteModel, err := c.getOrgWriteModelByID(ctx, organizationID)
if err != nil {
return nil, err
}
@@ -477,13 +499,16 @@ func (c *Commands) ReactivateOrg(ctx context.Context, orgID string) (*domain.Obj
return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil
}
func (c *Commands) RemoveOrg(ctx context.Context, id string) (*domain.ObjectDetails, error) {
func (c *Commands) RemoveOrg(ctx context.Context, id string, permissionCheck OrganizationPermissionCheck, mustExist bool) (*domain.ObjectDetails, error) {
orgAgg := org.NewAggregate(id)
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareRemoveOrg(orgAgg))
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareRemoveOrg(orgAgg, permissionCheck, mustExist))
if err != nil {
return nil, err
}
if len(cmds) == 0 {
return &domain.ObjectDetails{}, nil
}
events, err := c.eventstore.Push(ctx, cmds...)
if err != nil {
@@ -497,9 +522,14 @@ func (c *Commands) RemoveOrg(ctx context.Context, id string) (*domain.ObjectDeta
}, nil
}
func (c *Commands) prepareRemoveOrg(a *org.Aggregate) preparation.Validation {
func (c *Commands) prepareRemoveOrg(a *org.Aggregate, permissionCheck OrganizationPermissionCheck, mustExist bool) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
if permissionCheck != nil {
if err := permissionCheck(ctx, a.ID); err != nil {
return nil, err
}
}
instance := authz.GetInstance(ctx)
if a.ID == instance.DefaultOrganisationID() {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMA-wG9p1", "Errors.Org.DefaultOrgNotDeletable")
@@ -519,7 +549,10 @@ func (c *Commands) prepareRemoveOrg(a *org.Aggregate) preparation.Validation {
return nil, zerrors.ThrowPreconditionFailed(err, "COMMA-wG9p1", "Errors.Org.NotFound")
}
if !isOrgStateExists(writeModel.State) {
return nil, zerrors.ThrowNotFound(nil, "COMMA-aps2n", "Errors.Org.NotFound")
if mustExist {
return nil, zerrors.ThrowNotFound(nil, "COMMA-aps2n", "Errors.Org.NotFound")
}
return nil, nil
}
domainPolicy, err := c.domainPolicyWriteModel(ctx, a.ID)

View File

@@ -20,7 +20,7 @@ import (
"github.com/zitadel/zitadel/internal/zerrors"
)
func (c *Commands) prepareAddOrgDomain(a *org.Aggregate, addDomain string, userIDs []string) preparation.Validation {
func (c *Commands) prepareAddOrgDomain(a *org.Aggregate, addDomain string, userIDs []string, permissionCheck OrganizationPermissionCheck) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if addDomain = strings.TrimSpace(addDomain); addDomain == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-r3h4J", "Errors.Invalid.Argument")
@@ -29,6 +29,15 @@ func (c *Commands) prepareAddOrgDomain(a *org.Aggregate, addDomain string, userI
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
if permissionCheck != nil {
if err := permissionCheck(ctx, a.ID); err != nil {
return nil, err
}
}
if err := c.checkOrgExists(ctx, a.ID); err != nil {
return nil, err
}
existing, err := orgDomain(ctx, filter, a.ID, addDomain)
if err != nil && !errors.Is(err, zerrors.ThrowNotFound(nil, "", "")) {
return nil, err
@@ -123,12 +132,12 @@ func (c *Commands) VerifyOrgDomain(ctx context.Context, orgID, domain string) (_
return pushedEventsToObjectDetails(pushedEvents), nil
}
func (c *Commands) AddOrgDomain(ctx context.Context, orgID, domain string, claimedUserIDs []string) (_ *domain.ObjectDetails, err error) {
func (c *Commands) AddOrgDomain(ctx context.Context, orgID, domain string, claimedUserIDs []string, permissionCheck OrganizationPermissionCheck) (_ *domain.ObjectDetails, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
orgAgg := org.NewAggregate(orgID)
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareAddOrgDomain(orgAgg, domain, claimedUserIDs))
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareAddOrgDomain(orgAgg, domain, claimedUserIDs, permissionCheck))
if err != nil {
return nil, err
}
@@ -139,7 +148,7 @@ func (c *Commands) AddOrgDomain(ctx context.Context, orgID, domain string, claim
return pushedEventsToObjectDetails(pushedEvents), nil
}
func (c *Commands) GenerateOrgDomainValidation(ctx context.Context, orgDomain *domain.OrgDomain) (token, url string, err error) {
func (c *Commands) GenerateOrgDomainValidation(ctx context.Context, orgDomain *domain.OrgDomain, permissionCheck OrganizationPermissionCheck) (token, url string, err error) {
if orgDomain == nil || !orgDomain.IsValid() || orgDomain.AggregateID == "" {
return "", "", zerrors.ThrowInvalidArgument(nil, "ORG-R24hb", "Errors.Org.InvalidDomain")
}
@@ -147,6 +156,11 @@ func (c *Commands) GenerateOrgDomainValidation(ctx context.Context, orgDomain *d
if !ok {
return "", "", zerrors.ThrowInvalidArgument(nil, "ORG-Gsw31", "Errors.Org.DomainVerificationTypeInvalid")
}
if permissionCheck != nil {
if err := permissionCheck(ctx, orgDomain.AggregateID); err != nil {
return "", "", err
}
}
domainWriteModel, err := c.getOrgDomainWriteModel(ctx, orgDomain.AggregateID, orgDomain.Domain)
if err != nil {
return "", "", err
@@ -177,10 +191,15 @@ func (c *Commands) GenerateOrgDomainValidation(ctx context.Context, orgDomain *d
return token, url, nil
}
func (c *Commands) ValidateOrgDomain(ctx context.Context, orgDomain *domain.OrgDomain, claimedUserIDs []string) (*domain.ObjectDetails, error) {
func (c *Commands) ValidateOrgDomain(ctx context.Context, orgDomain *domain.OrgDomain, claimedUserIDs []string, permissionCheck OrganizationPermissionCheck) (*domain.ObjectDetails, error) {
if orgDomain == nil || !orgDomain.IsValid() || orgDomain.AggregateID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-R24hb", "Errors.Org.InvalidDomain")
}
if permissionCheck != nil {
if err := permissionCheck(ctx, orgDomain.AggregateID); err != nil {
return nil, err
}
}
domainWriteModel, err := c.getOrgDomainWriteModel(ctx, orgDomain.AggregateID, orgDomain.Domain)
if err != nil {
return nil, err
@@ -261,10 +280,15 @@ func (c *Commands) SetPrimaryOrgDomain(ctx context.Context, orgDomain *domain.Or
return writeModelToObjectDetails(&domainWriteModel.WriteModel), nil
}
func (c *Commands) RemoveOrgDomain(ctx context.Context, orgDomain *domain.OrgDomain) (*domain.ObjectDetails, error) {
func (c *Commands) RemoveOrgDomain(ctx context.Context, orgDomain *domain.OrgDomain, permissionCheck OrganizationPermissionCheck) (*domain.ObjectDetails, error) {
if orgDomain == nil || !orgDomain.IsValid() || orgDomain.AggregateID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-SJsK3", "Errors.Org.InvalidDomain")
}
if permissionCheck != nil {
if err := permissionCheck(ctx, orgDomain.AggregateID); err != nil {
return nil, err
}
}
domainWriteModel, err := c.getOrgDomainWriteModel(ctx, orgDomain.AggregateID, orgDomain.Domain)
if err != nil {
return nil, err

View File

@@ -23,11 +23,13 @@ import (
func TestAddDomain(t *testing.T) {
type args struct {
a *org.Aggregate
domain string
claimedUserIDs []string
idGenerator id.Generator
filter preparation.FilterToQueryReducer
a *org.Aggregate
domain string
claimedUserIDs []string
idGenerator id.Generator
filter preparation.FilterToQueryReducer
eventstore func(*testing.T) *eventstore.Eventstore
permissionCheck OrganizationPermissionCheck
}
agg := org.NewAggregate("test")
@@ -40,8 +42,9 @@ func TestAddDomain(t *testing.T) {
{
name: "invalid domain",
args: args{
a: agg,
domain: "",
a: agg,
domain: "",
eventstore: expectEventstore(),
},
want: Want{
ValidationErr: zerrors.ThrowInvalidArgument(nil, "ORG-r3h4J", "Errors.Invalid.Argument"),
@@ -58,6 +61,14 @@ func TestAddDomain(t *testing.T) {
org.NewDomainPolicyAddedEvent(ctx, &agg.Aggregate, true, true, true),
}, nil
},
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"org"),
),
),
),
},
want: Want{
Commands: []eventstore.Command{
@@ -99,6 +110,14 @@ func TestAddDomain(t *testing.T) {
return []eventstore.Event{org.NewDomainPolicyAddedEvent(ctx, &agg.Aggregate, true, false, false)}, nil
}
}(),
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"org"),
),
),
),
},
want: Want{
Commands: []eventstore.Command{
@@ -121,18 +140,67 @@ func TestAddDomain(t *testing.T) {
org.NewDomainVerifiedEvent(ctx, &agg.Aggregate, "domain"),
}, nil
},
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"org"),
),
),
),
},
want: Want{
CreateErr: zerrors.ThrowAlreadyExists(nil, "", ""),
},
},
{
name: "no permission",
args: args{
a: agg,
domain: "domain",
claimedUserIDs: []string{"userID1"},
filter: nil,
eventstore: expectEventstore(),
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
want: Want{
CreateErr: zerrors.ThrowPermissionDenied(nil, "", "Errors.PermissionDenied"),
},
},
{
name: "correct with permission check",
args: args{
a: agg,
domain: "domain",
claimedUserIDs: []string{"userID1"},
filter: func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
return []eventstore.Event{
org.NewDomainPolicyAddedEvent(ctx, &agg.Aggregate, true, true, true),
}, nil
},
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"org"),
),
),
),
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
},
want: Want{
Commands: []eventstore.Command{
org.NewDomainAddedEvent(context.Background(), &agg.Aggregate, "domain"),
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
AssertValidation(
t,
http.WithRequestedHost(context.Background(), "domain"),
(&Commands{idGenerator: tt.args.idGenerator}).prepareAddOrgDomain(tt.args.a, tt.args.domain, tt.args.claimedUserIDs),
(&Commands{idGenerator: tt.args.idGenerator, eventstore: tt.args.eventstore(t)}).prepareAddOrgDomain(tt.args.a, tt.args.domain, tt.args.claimedUserIDs, tt.args.permissionCheck),
tt.args.filter,
tt.want,
)
@@ -278,13 +346,14 @@ func TestSetDomainPrimary(t *testing.T) {
func TestCommandSide_AddOrgDomain(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(*testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
orgID string
domain string
claimedUserIDs []string
ctx context.Context
orgID string
domain string
claimedUserIDs []string
permissionCheck OrganizationPermissionCheck
}
type res struct {
want *domain.ObjectDetails
@@ -299,9 +368,7 @@ func TestCommandSide_AddOrgDomain(t *testing.T) {
{
name: "invalid domain, error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -313,8 +380,13 @@ func TestCommandSide_AddOrgDomain(t *testing.T) {
{
name: "domain already exists, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"org"),
),
),
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -343,8 +415,13 @@ func TestCommandSide_AddOrgDomain(t *testing.T) {
{
name: "domain add, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"org"),
),
),
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -382,13 +459,76 @@ func TestCommandSide_AddOrgDomain(t *testing.T) {
},
},
},
{
name: "domain add (with permission check), ok",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
"org"),
),
),
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"name",
),
),
),
expectFilter(
eventFromEventPusher(
org.NewDomainPolicyAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
true,
true,
true,
),
),
),
expectPush(
org.NewDomainAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"domain.ch",
),
),
),
},
args: args{
ctx: context.Background(),
orgID: "org1",
domain: "domain.ch",
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "no permission, error",
fields: fields{
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
orgID: "org1",
domain: "domain.ch",
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
}
got, err := r.AddOrgDomain(tt.args.ctx, tt.args.orgID, tt.args.domain, tt.args.claimedUserIDs)
got, err := r.AddOrgDomain(tt.args.ctx, tt.args.orgID, tt.args.domain, tt.args.claimedUserIDs, tt.args.permissionCheck)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -404,12 +544,13 @@ func TestCommandSide_AddOrgDomain(t *testing.T) {
func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(*testing.T) *eventstore.Eventstore
secretGenerator crypto.Generator
}
type args struct {
ctx context.Context
domain *domain.OrgDomain
ctx context.Context
domain *domain.OrgDomain
permissionCheck OrganizationPermissionCheck
}
type res struct {
wantToken string
@@ -425,9 +566,7 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
{
name: "invalid domain, error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -444,9 +583,7 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
{
name: "missing aggregateid, error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -461,9 +598,7 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
{
name: "invalid validation type, error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -481,8 +616,7 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
{
name: "domain not exists, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -510,8 +644,7 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
{
name: "domain already verified, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -551,8 +684,7 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
{
name: "add dns validation, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -601,8 +733,7 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
{
name: "add http validation, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -648,14 +779,85 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
wantURL: "https://domain.ch/.well-known/zitadel-challenge/a.txt",
},
},
{
name: "add validation (with permission check), ok",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"name",
),
),
eventFromEventPusher(
org.NewDomainAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"domain.ch",
),
),
),
expectPush(
org.NewDomainVerificationAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"domain.ch",
domain.OrgDomainValidationTypeHTTP,
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("a"),
},
),
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
domain: &domain.OrgDomain{
ObjectRoot: models.ObjectRoot{
AggregateID: "org1",
},
Domain: "domain.ch",
ValidationType: domain.OrgDomainValidationTypeHTTP,
},
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
},
res: res{
wantToken: "a",
wantURL: "https://domain.ch/.well-known/zitadel-challenge/a.txt",
},
},
{
name: "add validation (no permission), error",
fields: fields{
eventstore: expectEventstore(),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
domain: &domain.OrgDomain{
ObjectRoot: models.ObjectRoot{
AggregateID: "org1",
},
Domain: "domain.ch",
ValidationType: domain.OrgDomainValidationTypeHTTP,
},
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
domainVerificationGenerator: tt.fields.secretGenerator,
}
token, url, err := r.GenerateOrgDomainValidation(tt.args.ctx, tt.args.domain)
token, url, err := r.GenerateOrgDomainValidation(tt.args.ctx, tt.args.domain, tt.args.permissionCheck)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -679,9 +881,10 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
domainValidationFunc func(domain, token, verifier string, checkType http.CheckType) error
}
type args struct {
ctx context.Context
domain *domain.OrgDomain
claimedUserIDs []string
ctx context.Context
domain *domain.OrgDomain
claimedUserIDs []string
permissionCheck OrganizationPermissionCheck
}
type res struct {
want *domain.ObjectDetails
@@ -1084,6 +1287,86 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
},
},
},
{
name: "domain verification (with permission check), ok",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"name",
),
),
eventFromEventPusher(
org.NewDomainAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"domain.ch",
),
),
eventFromEventPusher(
org.NewDomainVerificationAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"domain.ch",
domain.OrgDomainValidationTypeDNS,
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("a"),
},
),
),
),
expectPush(
org.NewDomainVerifiedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"domain.ch",
),
),
),
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
domainValidationFunc: validDomainVerification,
},
args: args{
ctx: context.Background(),
domain: &domain.OrgDomain{
ObjectRoot: models.ObjectRoot{
AggregateID: "org1",
},
Domain: "domain.ch",
ValidationType: domain.OrgDomainValidationTypeDNS,
},
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "domain verification (no permission), error",
fields: fields{
eventstore: expectEventstore(),
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
domainValidationFunc: validDomainVerification,
},
args: args{
ctx: context.Background(),
domain: &domain.OrgDomain{
ObjectRoot: models.ObjectRoot{
AggregateID: "org1",
},
Domain: "domain.ch",
ValidationType: domain.OrgDomainValidationTypeDNS,
},
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -1094,7 +1377,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
domainVerificationValidator: tt.fields.domainValidationFunc,
idGenerator: tt.fields.idGenerator,
}
got, err := r.ValidateOrgDomain(http.WithRequestedHost(tt.args.ctx, "zitadel.ch"), tt.args.domain, tt.args.claimedUserIDs)
got, err := r.ValidateOrgDomain(http.WithRequestedHost(tt.args.ctx, "zitadel.ch"), tt.args.domain, tt.args.claimedUserIDs, tt.args.permissionCheck)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -1295,11 +1578,12 @@ func TestCommandSide_SetPrimaryDomain(t *testing.T) {
func TestCommandSide_RemoveOrgDomain(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(*testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
domain *domain.OrgDomain
ctx context.Context
domain *domain.OrgDomain
permissionCheck OrganizationPermissionCheck
}
type res struct {
want *domain.ObjectDetails
@@ -1314,9 +1598,7 @@ func TestCommandSide_RemoveOrgDomain(t *testing.T) {
{
name: "invalid domain, error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -1333,9 +1615,7 @@ func TestCommandSide_RemoveOrgDomain(t *testing.T) {
{
name: "missing aggregateid, error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -1350,8 +1630,7 @@ func TestCommandSide_RemoveOrgDomain(t *testing.T) {
{
name: "domain not exists, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -1379,8 +1658,7 @@ func TestCommandSide_RemoveOrgDomain(t *testing.T) {
{
name: "remove verified domain, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -1425,8 +1703,7 @@ func TestCommandSide_RemoveOrgDomain(t *testing.T) {
{
name: "remove domain, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -1467,8 +1744,7 @@ func TestCommandSide_RemoveOrgDomain(t *testing.T) {
{
name: "remove verified domain, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -1512,13 +1788,80 @@ func TestCommandSide_RemoveOrgDomain(t *testing.T) {
},
},
},
{
name: "remove verified domain (with permission check), ok",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"name",
),
),
eventFromEventPusher(
org.NewDomainAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"domain.ch",
),
),
eventFromEventPusher(
org.NewDomainVerifiedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"domain.ch",
),
),
),
expectPush(
org.NewDomainRemovedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"domain.ch", true,
),
),
),
},
args: args{
ctx: context.Background(),
domain: &domain.OrgDomain{
ObjectRoot: models.ObjectRoot{
AggregateID: "org1",
},
Domain: "domain.ch",
},
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "remove verified domain (no permission), error",
fields: fields{
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
domain: &domain.OrgDomain{
ObjectRoot: models.ObjectRoot{
AggregateID: "org1",
},
Domain: "domain.ch",
},
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
}
got, err := r.RemoveOrgDomain(tt.args.ctx, tt.args.domain)
got, err := r.RemoveOrgDomain(tt.args.ctx, tt.args.domain, tt.args.permissionCheck)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -32,10 +32,15 @@ func (c *Commands) SetOrgMetadata(ctx context.Context, orgID string, metadata *d
return writeModelToOrgMetadata(setMetadata), nil
}
func (c *Commands) BulkSetOrgMetadata(ctx context.Context, orgID string, metadatas ...*domain.Metadata) (_ *domain.ObjectDetails, err error) {
func (c *Commands) BulkSetOrgMetadata(ctx context.Context, orgID string, permissionCheck OrganizationPermissionCheck, metadatas ...*domain.Metadata) (_ *domain.ObjectDetails, err error) {
if len(metadatas) == 0 {
return nil, zerrors.ThrowPreconditionFailed(nil, "META-9mm2d", "Errors.Metadata.NoData")
}
if permissionCheck != nil {
if err := permissionCheck(ctx, orgID); err != nil {
return nil, err
}
}
err = c.checkOrgExists(ctx, orgID)
if err != nil {
return nil, err
@@ -108,10 +113,15 @@ func (c *Commands) RemoveOrgMetadata(ctx context.Context, orgID, metadataKey str
return writeModelToObjectDetails(&removeMetadata.WriteModel), nil
}
func (c *Commands) BulkRemoveOrgMetadata(ctx context.Context, orgID string, metadataKeys ...string) (_ *domain.ObjectDetails, err error) {
func (c *Commands) BulkRemoveOrgMetadata(ctx context.Context, orgID string, permissionCheck OrganizationPermissionCheck, metadataKeys ...string) (_ *domain.ObjectDetails, err error) {
if len(metadataKeys) == 0 {
return nil, zerrors.ThrowPreconditionFailed(nil, "META-9mw2d", "Errors.Metadata.NoData")
}
if permissionCheck != nil {
if err := permissionCheck(ctx, orgID); err != nil {
return nil, err
}
}
err = c.checkOrgExists(ctx, orgID)
if err != nil {
return nil, err

View File

@@ -144,13 +144,14 @@ func TestCommandSide_SetOrgMetadata(t *testing.T) {
func TestCommandSide_BulkSetOrgMetadata(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(*testing.T) *eventstore.Eventstore
}
type (
args struct {
ctx context.Context
orgID string
metadataList []*domain.Metadata
ctx context.Context
orgID string
permissionCheck OrganizationPermissionCheck
metadataList []*domain.Metadata
}
)
type res struct {
@@ -166,9 +167,7 @@ func TestCommandSide_BulkSetOrgMetadata(t *testing.T) {
{
name: "empty meta data list, pre condition error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -181,8 +180,7 @@ func TestCommandSide_BulkSetOrgMetadata(t *testing.T) {
{
name: "org not existing, pre condition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(),
),
},
@@ -201,8 +199,7 @@ func TestCommandSide_BulkSetOrgMetadata(t *testing.T) {
{
name: "invalid metadata, pre condition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -228,8 +225,7 @@ func TestCommandSide_BulkSetOrgMetadata(t *testing.T) {
{
name: "add metadata, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -266,13 +262,72 @@ func TestCommandSide_BulkSetOrgMetadata(t *testing.T) {
},
},
},
{
name: "add metadata (with permission check), ok",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"ZITADEL",
),
),
),
expectPush(
org.NewMetadataSetEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"key",
[]byte("value"),
),
org.NewMetadataSetEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"key1",
[]byte("value1"),
),
),
),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
metadataList: []*domain.Metadata{
{Key: "key", Value: []byte("value")},
{Key: "key1", Value: []byte("value1")},
},
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "add metadata (no permission), error",
fields: fields{
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
metadataList: []*domain.Metadata{
{Key: "key", Value: []byte("value")},
{Key: "key1", Value: []byte("value1")},
},
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
}
got, err := r.BulkSetOrgMetadata(tt.args.ctx, tt.args.orgID, tt.args.metadataList...)
got, err := r.BulkSetOrgMetadata(tt.args.ctx, tt.args.orgID, tt.args.permissionCheck, tt.args.metadataList...)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -428,13 +483,14 @@ func TestCommandSide_OrgRemoveMetadata(t *testing.T) {
func TestCommandSide_BulkRemoveOrgMetadata(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(*testing.T) *eventstore.Eventstore
}
type (
args struct {
ctx context.Context
orgID string
metadataList []string
ctx context.Context
orgID string
permissionCheck OrganizationPermissionCheck
metadataList []string
}
)
type res struct {
@@ -450,9 +506,7 @@ func TestCommandSide_BulkRemoveOrgMetadata(t *testing.T) {
{
name: "empty meta data list, pre condition error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -465,8 +519,7 @@ func TestCommandSide_BulkRemoveOrgMetadata(t *testing.T) {
{
name: "org not existing, pre condition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(),
),
},
@@ -482,8 +535,7 @@ func TestCommandSide_BulkRemoveOrgMetadata(t *testing.T) {
{
name: "remove metadata keys not existing, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -515,8 +567,7 @@ func TestCommandSide_BulkRemoveOrgMetadata(t *testing.T) {
{
name: "invalid metadata, pre condition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -555,8 +606,7 @@ func TestCommandSide_BulkRemoveOrgMetadata(t *testing.T) {
{
name: "remove metadata, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
@@ -604,13 +654,80 @@ func TestCommandSide_BulkRemoveOrgMetadata(t *testing.T) {
},
},
},
{
name: "remove metadata (with permission check), ok",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"ZITADEL",
),
),
),
expectFilter(
eventFromEventPusher(
org.NewMetadataSetEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"key",
[]byte("value"),
),
),
eventFromEventPusher(
org.NewMetadataSetEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"key1",
[]byte("value1"),
),
),
),
expectPush(
org.NewMetadataRemovedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"key",
),
org.NewMetadataRemovedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"key1",
),
),
),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
metadataList: []string{"key", "key1"},
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "remove metadata (no permission), ok",
fields: fields{
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
metadataList: []string{"key", "key1"},
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
}
got, err := r.BulkRemoveOrgMetadata(tt.args.ctx, tt.args.orgID, tt.args.metadataList...)
got, err := r.BulkRemoveOrgMetadata(tt.args.ctx, tt.args.orgID, tt.args.permissionCheck, tt.args.metadataList...)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -463,9 +463,10 @@ func TestCommandSide_ChangeOrg(t *testing.T) {
eventstore func(t *testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
orgID string
name string
ctx context.Context
orgID string
name string
permissionCheck OrganizationPermissionCheck
}
type res struct {
err func(error) bool
@@ -727,13 +728,76 @@ func TestCommandSide_ChangeOrg(t *testing.T) {
},
res: res{},
},
{
name: "change org name (with permission check), ok",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"org"),
),
),
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"org"),
),
eventFromEventPusher(
org.NewDomainAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"org.zitadel.ch"),
),
eventFromEventPusher(
org.NewDomainVerifiedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"org.zitadel.ch"),
),
eventFromEventPusher(
org.NewDomainPrimarySetEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"org.zitadel.ch"),
),
),
expectPush(
org.NewOrgChangedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate, "org", "ORG",
),
),
),
},
args: args{
ctx: http_util.WithRequestedHost(context.Background(), "zitadel.ch"),
orgID: "org1",
name: "ORG",
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
},
res: res{},
},
{
name: "change org name (no permission), error",
fields: fields{
eventstore: expectEventstore(),
},
args: args{
ctx: http_util.WithRequestedHost(context.Background(), "zitadel.ch"),
orgID: "org1",
name: "ORG",
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore(t),
}
_, err := r.ChangeOrg(tt.args.ctx, tt.args.orgID, tt.args.name)
_, err := r.ChangeOrg(tt.args.ctx, tt.args.orgID, tt.args.name, tt.args.permissionCheck)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -751,8 +815,9 @@ func TestCommandSide_DeactivateOrg(t *testing.T) {
iamDomain string
}
type args struct {
ctx context.Context
orgID string
ctx context.Context
orgID string
permissionCheck OrganizationPermissionCheck
}
type res struct {
want *domain.Org
@@ -855,6 +920,45 @@ func TestCommandSide_DeactivateOrg(t *testing.T) {
},
res: res{},
},
{
name: "deactivate org (with permission check)",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"org"),
),
),
expectPush(
org.NewOrgDeactivatedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
),
),
),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
},
res: res{},
},
{
name: "deactivate org (no permission)",
fields: fields{
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -862,7 +966,7 @@ func TestCommandSide_DeactivateOrg(t *testing.T) {
eventstore: tt.fields.eventstore(t),
idGenerator: tt.fields.idGenerator,
}
_, err := r.DeactivateOrg(tt.args.ctx, tt.args.orgID)
_, err := r.DeactivateOrg(tt.args.ctx, tt.args.orgID, tt.args.permissionCheck)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -880,8 +984,9 @@ func TestCommandSide_ReactivateOrg(t *testing.T) {
iamDomain string
}
type args struct {
ctx context.Context
orgID string
ctx context.Context
orgID string
permissionCheck OrganizationPermissionCheck
}
type res struct {
want *domain.Org
@@ -989,6 +1094,49 @@ func TestCommandSide_ReactivateOrg(t *testing.T) {
},
res: res{},
},
{
name: "reactivate org (with permission check)",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"org"),
),
eventFromEventPusher(
org.NewOrgDeactivatedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate),
),
),
expectPush(
org.NewOrgReactivatedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
),
),
),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
},
res: res{},
},
{
name: "reactivate org (with permission check)",
fields: fields{
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -996,7 +1144,7 @@ func TestCommandSide_ReactivateOrg(t *testing.T) {
eventstore: tt.fields.eventstore(t),
idGenerator: tt.fields.idGenerator,
}
_, err := r.ReactivateOrg(tt.args.ctx, tt.args.orgID)
_, err := r.ReactivateOrg(tt.args.ctx, tt.args.orgID, tt.args.permissionCheck)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -1013,8 +1161,10 @@ func TestCommandSide_RemoveOrg(t *testing.T) {
idGenerator id.Generator
}
type args struct {
ctx context.Context
orgID string
ctx context.Context
orgID string
permissionCheck OrganizationPermissionCheck
mustExist bool
}
type res struct {
err func(error) bool
@@ -1064,7 +1214,24 @@ func TestCommandSide_RemoveOrg(t *testing.T) {
},
},
{
name: "org not found, error",
name: "org not found, must exist, error",
fields: fields{
eventstore: expectEventstore(
expectFilter(), // zitadel project check
expectFilter(),
),
},
args: args{
ctx: context.Background(),
orgID: "org1",
mustExist: true,
},
res: res{
err: zerrors.IsNotFound,
},
},
{
name: "org not found, ok",
fields: fields{
eventstore: expectEventstore(
expectFilter(), // zitadel project check
@@ -1075,9 +1242,7 @@ func TestCommandSide_RemoveOrg(t *testing.T) {
ctx: context.Background(),
orgID: "org1",
},
res: res{
err: zerrors.IsNotFound,
},
res: res{},
},
{
name: "push failed, error",
@@ -1249,6 +1414,62 @@ func TestCommandSide_RemoveOrg(t *testing.T) {
},
res: res{},
},
{
name: "remove org (with permission check)",
fields: fields{
eventstore: expectEventstore(
expectFilter(), // zitadel project check
expectFilter(
eventFromEventPusher(
org.NewOrgAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
"org"),
),
),
expectFilter(
eventFromEventPusher(
org.NewDomainPolicyAddedEvent(context.Background(),
&org.NewAggregate("org1").Aggregate,
true,
true,
true,
),
),
),
expectFilter(),
expectFilter(),
expectFilter(),
expectFilter(),
expectPush(
org.NewOrgRemovedEvent(
context.Background(), &org.NewAggregate("org1").Aggregate, "org", []string{}, false, []string{}, []*domain.UserIDPLink{}, []string{},
),
),
),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckAllowed(),
},
res: res{},
},
{
name: "remove org (no permission)",
fields: fields{
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
orgID: "org1",
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
res: res{
err: zerrors.IsPermissionDenied,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -1256,7 +1477,7 @@ func TestCommandSide_RemoveOrg(t *testing.T) {
eventstore: tt.fields.eventstore(t),
idGenerator: tt.fields.idGenerator,
}
_, err := r.RemoveOrg(tt.args.ctx, tt.args.orgID)
_, err := r.RemoveOrg(tt.args.ctx, tt.args.orgID, tt.args.permissionCheck, tt.args.mustExist)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -1278,6 +1499,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
ctx context.Context
setupOrg *OrgSetup
allowInitialMail bool
permissionCheck OrganizationPermissionCheck
userIDs []string
}
type res struct {
@@ -1816,6 +2038,41 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
},
},
},
{
name: "no permission, error",
fields: fields{
eventstore: expectEventstore(),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t),
newCode: mockEncryptedCode("userinit", time.Hour),
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
setupOrg: &OrgSetup{
Name: "Org",
Admins: []*OrgSetupAdmin{
{
Machine: &AddMachine{
Machine: &Machine{
Username: "username",
Name: "name",
Description: "description",
AccessTokenType: domain.OIDCTokenTypeBearer,
},
Pat: &AddPat{
ExpirationDate: testNow.Add(time.Hour),
Scopes: []string{openid.ScopeOpenID},
},
},
},
},
},
permissionCheck: newMockOrganizationPermissionCheckNotAllowed(),
},
res: res{
err: zerrors.ThrowPermissionDenied(nil, "", "Errors.PermissionDenied"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -1830,7 +2087,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
},
},
}
got, err := r.SetUpOrg(tt.args.ctx, tt.args.setupOrg, tt.args.allowInitialMail, tt.args.userIDs...)
got, err := r.SetUpOrg(tt.args.ctx, tt.args.setupOrg, tt.args.allowInitialMail, tt.args.permissionCheck, tt.args.userIDs...)
assert.ErrorIs(t, err, tt.res.err)
assert.Equal(t, tt.res.createdOrg, got)
})

View File

@@ -159,3 +159,15 @@ func (c *Commands) NewPermissionCheckUserGrantWrite(ctx context.Context) UserGra
func (c *Commands) NewPermissionCheckUserGrantDelete(ctx context.Context) UserGrantPermissionCheck {
return c.newUserGrantPermissionCheck(ctx, domain.PermissionUserGrantDelete)
}
func (c *Commands) CheckPermissionOrganizationCreate(ctx context.Context, organizationID string) error {
return c.newPermissionCheck(ctx, domain.PermissionOrganizationWrite, org.AggregateType)(organizationID, organizationID)
}
func (c *Commands) CheckPermissionOrganizationWrite(ctx context.Context, organizationID string) error {
return c.newPermissionCheck(ctx, domain.PermissionOrganizationWrite, org.AggregateType)(organizationID, organizationID)
}
func (c *Commands) CheckPermissionOrganizationDelete(ctx context.Context, organizationID string) error {
return c.newPermissionCheck(ctx, domain.PermissionOrganizationDelete, org.AggregateType)(organizationID, organizationID)
}