mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-13 03:24:26 +00:00
fix: handle org features downgrades (#1578)
* features * features * features * fix json tags * add features handler to auth * mocks for tests * add setup step * fixes * add featurelist to auth api * fx proto merge * remove policies * factors * handle auth factors * test org features * cleanup
This commit is contained in:
parent
0e1e7bb382
commit
75d4b33281
@ -2,12 +2,17 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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/repository/org"
|
||||
)
|
||||
|
||||
func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, features *domain.Features) (*domain.ObjectDetails, error) {
|
||||
if resourceOwner == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Features-G5tg", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingFeatures := NewOrgFeaturesWriteModel(resourceOwner)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingFeatures)
|
||||
if err != nil {
|
||||
@ -33,7 +38,13 @@ func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, fea
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged")
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, setEvent)
|
||||
events, err := c.ensureOrgSettingsToFeatures(ctx, resourceOwner, features)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events = append(events, setEvent)
|
||||
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, events...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -45,6 +56,9 @@ func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, fea
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveOrgFeatures(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Features-G5tg", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingFeatures := NewOrgFeaturesWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingFeatures)
|
||||
if err != nil {
|
||||
@ -53,9 +67,19 @@ func (c *Commands) RemoveOrgFeatures(ctx context.Context, orgID string) (*domain
|
||||
if existingFeatures.State == domain.FeaturesStateUnspecified || existingFeatures.State == domain.FeaturesStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Features-Bg32G", "Errors.Features.NotFound")
|
||||
}
|
||||
removedEvent := org.NewFeaturesRemovedEvent(ctx, OrgAggregateFromWriteModel(&existingFeatures.FeaturesWriteModel.WriteModel))
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingFeatures.FeaturesWriteModel.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewFeaturesRemovedEvent(ctx, orgAgg))
|
||||
features, err := c.getDefaultFeatures(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events, err := c.ensureOrgSettingsToFeatures(ctx, orgID, features)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
events = append(events, removedEvent)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, events...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -65,3 +89,130 @@ func (c *Commands) RemoveOrgFeatures(ctx context.Context, orgID string) (*domain
|
||||
}
|
||||
return writeModelToObjectDetails(&existingFeatures.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) ensureOrgSettingsToFeatures(ctx context.Context, orgID string, features *domain.Features) ([]eventstore.EventPusher, error) {
|
||||
events, err := c.setAllowedLoginPolicy(ctx, orgID, features)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !features.PasswordComplexityPolicy {
|
||||
removePasswordComplexityEvent, err := c.removePasswordComplexityPolicyIfExists(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if removePasswordComplexityEvent != nil {
|
||||
events = append(events, removePasswordComplexityEvent)
|
||||
}
|
||||
}
|
||||
if !features.LabelPolicy {
|
||||
removeLabelPolicyEvent, err := c.removeLabelPolicyIfExists(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if removeLabelPolicyEvent != nil {
|
||||
events = append(events, removeLabelPolicyEvent)
|
||||
}
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) setAllowedLoginPolicy(ctx context.Context, orgID string, features *domain.Features) ([]eventstore.EventPusher, error) {
|
||||
events := make([]eventstore.EventPusher, 0)
|
||||
existingPolicy, err := c.orgLoginPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, nil
|
||||
}
|
||||
defaultPolicy, err := c.getDefaultLoginPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy := *existingPolicy
|
||||
if !features.LoginPolicyFactors {
|
||||
if defaultPolicy.ForceMFA != existingPolicy.ForceMFA {
|
||||
policy.ForceMFA = defaultPolicy.ForceMFA
|
||||
}
|
||||
authFactorsEvents, err := c.setDefaultAuthFactorsInCustomLoginPolicy(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events = append(events, authFactorsEvents...)
|
||||
}
|
||||
if !features.LoginPolicyIDP {
|
||||
if defaultPolicy.AllowExternalIDP != existingPolicy.AllowExternalIDP {
|
||||
policy.AllowExternalIDP = defaultPolicy.AllowExternalIDP
|
||||
}
|
||||
//TODO: handle idps
|
||||
}
|
||||
if !features.LoginPolicyRegistration && defaultPolicy.AllowRegister != existingPolicy.AllowRegister {
|
||||
policy.AllowRegister = defaultPolicy.AllowRegister
|
||||
}
|
||||
if !features.LoginPolicyPasswordless && defaultPolicy.PasswordlessType != existingPolicy.PasswordlessType {
|
||||
policy.PasswordlessType = defaultPolicy.PasswordlessType
|
||||
}
|
||||
if !features.LoginPolicyUsernameLogin && defaultPolicy.AllowUsernamePassword != existingPolicy.AllowUserNamePassword {
|
||||
policy.AllowUserNamePassword = defaultPolicy.AllowUsernamePassword
|
||||
}
|
||||
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel), policy.AllowUserNamePassword, policy.AllowRegister, policy.AllowExternalIDP, policy.ForceMFA, policy.PasswordlessType)
|
||||
if hasChanged {
|
||||
events = append(events, changedEvent)
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) setDefaultAuthFactorsInCustomLoginPolicy(ctx context.Context, orgID string) ([]eventstore.EventPusher, error) {
|
||||
orgAuthFactors, err := c.orgLoginPolicyAuthFactorsWriteModel(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events := make([]eventstore.EventPusher, 0)
|
||||
for factor, state := range orgAuthFactors.SecondFactors {
|
||||
if state.IAM == state.Org {
|
||||
continue
|
||||
}
|
||||
secondFactorWriteModel := orgAuthFactors.ToSecondFactorWriteModel(factor)
|
||||
if state.IAM == domain.FactorStateActive {
|
||||
event, err := c.addSecondFactorToLoginPolicy(ctx, secondFactorWriteModel, factor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event != nil {
|
||||
events = append(events, event)
|
||||
}
|
||||
continue
|
||||
}
|
||||
event, err := c.removeSecondFactorFromLoginPolicy(ctx, secondFactorWriteModel, factor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event != nil {
|
||||
events = append(events, event)
|
||||
}
|
||||
}
|
||||
for factor, state := range orgAuthFactors.MultiFactors {
|
||||
if state.IAM == state.Org {
|
||||
continue
|
||||
}
|
||||
multiFactorWriteModel := orgAuthFactors.ToMultiFactorWriteModel(factor)
|
||||
if state.IAM == domain.FactorStateActive {
|
||||
event, err := c.addMultiFactorToLoginPolicy(ctx, multiFactorWriteModel, factor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event != nil {
|
||||
events = append(events, event)
|
||||
}
|
||||
continue
|
||||
}
|
||||
event, err := c.removeMultiFactorFromLoginPolicy(ctx, multiFactorWriteModel, factor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event != nil {
|
||||
events = append(events, event)
|
||||
}
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
514
internal/command/org_features_test.go
Normal file
514
internal/command/org_features_test.go
Normal file
@ -0,0 +1,514 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"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/repository/features"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
features *domain.Features
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "resourceowner missing, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
features: &domain.Features{
|
||||
TierName: "Test",
|
||||
State: domain.FeaturesStateActive,
|
||||
AuditLogRetention: time.Hour,
|
||||
LoginPolicyFactors: false,
|
||||
LoginPolicyIDP: false,
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no change, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
features: &domain.Features{
|
||||
TierName: "Test",
|
||||
State: domain.FeaturesStateActive,
|
||||
AuditLogRetention: time.Hour,
|
||||
LoginPolicyFactors: false,
|
||||
LoginPolicyIDP: false,
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "set with default policies, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLoginPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewPasswordComplexityPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
8,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLabelPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
features: &domain.Features{
|
||||
TierName: "Test",
|
||||
State: domain.FeaturesStateActive,
|
||||
AuditLogRetention: time.Hour,
|
||||
LoginPolicyFactors: false,
|
||||
LoginPolicyIDP: false,
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "set with custom policies, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
//NewOrgFeaturesWriteModel
|
||||
expectFilter(),
|
||||
//begin ensureOrgSettingsToFeatures
|
||||
//begin setAllowedLoginPolicy
|
||||
//orgLoginPolicyWriteModelByID
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLoginPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewLoginPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeNotAllowed,
|
||||
),
|
||||
),
|
||||
),
|
||||
//getDefaultLoginPolicy
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLoginPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
),
|
||||
//begin setDefaultAuthFactorsInCustomLoginPolicy
|
||||
//orgLoginPolicyAuthFactorsWriteModel
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLoginPolicySecondFactorAddedEvent(context.Background(), &iam.NewAggregate().Aggregate, domain.SecondFactorTypeU2F),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
iam.NewLoginPolicyMultiFactorAddedEvent(context.Background(), &iam.NewAggregate().Aggregate, domain.MultiFactorTypeU2FWithPIN),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewLoginPolicySecondFactorAddedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.SecondFactorTypeOTP),
|
||||
),
|
||||
),
|
||||
//addSecondFactorToLoginPolicy
|
||||
expectFilter(),
|
||||
//removeSecondFactorFromLoginPolicy
|
||||
expectFilter(),
|
||||
//addMultiFactorToLoginPolicy
|
||||
expectFilter(),
|
||||
//end setDefaultAuthFactorsInCustomLoginPolicy
|
||||
//orgPasswordComplexityPolicyWriteModelByID
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewPasswordComplexityPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
8,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewPasswordComplexityPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
7,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
//orgLabelPolicyWriteModelByID
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLabelPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
false,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewLabelPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"custom",
|
||||
"secondary",
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
org.NewLoginPolicySecondFactorAddedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.SecondFactorTypeU2F),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewLoginPolicySecondFactorRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.SecondFactorTypeOTP),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewLoginPolicyMultiFactorAddedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate, domain.MultiFactorTypeU2FWithPIN),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
newLoginPolicyChangedEvent(context.Background(), "org1", true, true, true, true, domain.PasswordlessTypeAllowed),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewPasswordComplexityPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewLabelPolicyRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
features: &domain.Features{
|
||||
TierName: "Test",
|
||||
State: domain.FeaturesStateActive,
|
||||
AuditLogRetention: time.Hour,
|
||||
LoginPolicyFactors: false,
|
||||
LoginPolicyIDP: false,
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicy: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
got, err := r.SetOrgFeatures(tt.args.ctx, tt.args.resourceOwner, tt.args.features)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_RemoveOrgFeatures(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "resourceowner missing, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no features set, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove with default policies, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
newIAMFeaturesSetEvent(context.Background(), "Default", domain.FeaturesStateActive, time.Hour)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLoginPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewPasswordComplexityPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
8,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLabelPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
org.NewFeaturesRemovedEvent(context.Background(), &org.NewAggregate("org1", "org1").Aggregate),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
}
|
||||
got, err := r.RemoveOrgFeatures(tt.args.ctx, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newIAMFeaturesSetEvent(ctx context.Context, tierName string, state domain.FeaturesState, auditLog time.Duration) *iam.FeaturesSetEvent {
|
||||
event, _ := iam.NewFeaturesSetEvent(
|
||||
ctx,
|
||||
&iam.NewAggregate().Aggregate,
|
||||
[]features.FeaturesChanges{
|
||||
features.ChangeTierName(tierName),
|
||||
features.ChangeState(state),
|
||||
features.ChangeAuditLogRetention(auditLog),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}
|
||||
|
||||
func newFeaturesSetEvent(ctx context.Context, orgID string, tierName string, state domain.FeaturesState, auditLog time.Duration) *org.FeaturesSetEvent {
|
||||
event, _ := org.NewFeaturesSetEvent(
|
||||
ctx,
|
||||
&org.NewAggregate(orgID, orgID).Aggregate,
|
||||
[]features.FeaturesChanges{
|
||||
features.ChangeTierName(tierName),
|
||||
features.ChangeState(state),
|
||||
features.ChangeAuditLogRetention(auditLog),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}
|
@ -142,22 +142,9 @@ func (c *Commands) RemoveIDPConfig(ctx context.Context, idpID, orgID string, cas
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existingIDP.State == domain.IDPConfigStateRemoved || existingIDP.State == domain.IDPConfigStateUnspecified {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-Yx9vd", "Errors.Org.IDPConfig.NotExisting")
|
||||
}
|
||||
if existingIDP.State != domain.IDPConfigStateInactive {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5Mo0d", "Errors.Org.IDPConfig.NotInactive")
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingIDP.WriteModel)
|
||||
events := []eventstore.EventPusher{
|
||||
org_repo.NewIDPConfigRemovedEvent(ctx, orgAgg, idpID, existingIDP.Name),
|
||||
}
|
||||
|
||||
if cascadeRemoveProvider {
|
||||
removeIDPEvents := c.removeIDPProviderFromLoginPolicy(ctx, orgAgg, idpID, true, cascadeExternalIDPs...)
|
||||
events = append(events, removeIDPEvents...)
|
||||
events, err := c.removeIDPConfig(ctx, existingIDP, cascadeRemoveProvider, cascadeExternalIDPs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, events...)
|
||||
if err != nil {
|
||||
@ -170,6 +157,26 @@ func (c *Commands) RemoveIDPConfig(ctx context.Context, idpID, orgID string, cas
|
||||
return writeModelToObjectDetails(&existingIDP.IDPConfigWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeIDPConfig(ctx context.Context, existingIDP *OrgIDPConfigWriteModel, cascadeRemoveProvider bool, cascadeExternalIDPs ...*domain.ExternalIDP) ([]eventstore.EventPusher, error) {
|
||||
if existingIDP.State == domain.IDPConfigStateRemoved || existingIDP.State == domain.IDPConfigStateUnspecified {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-Yx9vd", "Errors.Org.IDPConfig.NotExisting")
|
||||
}
|
||||
if existingIDP.State != domain.IDPConfigStateInactive {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5Mo0d", "Errors.Org.IDPConfig.NotInactive")
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingIDP.WriteModel)
|
||||
events := []eventstore.EventPusher{
|
||||
org_repo.NewIDPConfigRemovedEvent(ctx, orgAgg, existingIDP.AggregateID, existingIDP.Name),
|
||||
}
|
||||
|
||||
if cascadeRemoveProvider {
|
||||
removeIDPEvents := c.removeIDPProviderFromLoginPolicy(ctx, orgAgg, existingIDP.AggregateID, true, cascadeExternalIDPs...)
|
||||
events = append(events, removeIDPEvents...)
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) getOrgIDPConfigByID(ctx context.Context, idpID, orgID string) (*domain.IDPConfig, error) {
|
||||
config, err := c.orgIDPConfigWriteModelByID(ctx, idpID, orgID)
|
||||
if err != nil {
|
||||
|
@ -74,15 +74,11 @@ func (c *Commands) RemoveLabelPolicy(ctx context.Context, orgID string) (*domain
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-Mf9sf", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingPolicy := NewOrgLabelPolicyWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicy)
|
||||
removeEvent, err := c.removeLabelPolicy(ctx, existingPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyRemovedEvent(ctx, orgAgg))
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, removeEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -92,3 +88,36 @@ func (c *Commands) RemoveLabelPolicy(ctx context.Context, orgID string) (*domain
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeLabelPolicy(ctx context.Context, existingPolicy *OrgLabelPolicyWriteModel) (*org.LabelPolicyRemovedEvent, error) {
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LabelPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
return org.NewLabelPolicyRemovedEvent(ctx, orgAgg), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeLabelPolicyIfExists(ctx context.Context, orgID string) (*org.LabelPolicyRemovedEvent, error) {
|
||||
existingPolicy, err := c.orgLabelPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingPolicy.State != domain.PolicyStateActive {
|
||||
return nil, nil
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
return org.NewLabelPolicyRemovedEvent(ctx, orgAgg), nil
|
||||
}
|
||||
|
||||
func (c *Commands) orgLabelPolicyWriteModelByID(ctx context.Context, orgID string) (*OrgLabelPolicyWriteModel, error) {
|
||||
policy := NewOrgLabelPolicyWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return policy, nil
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
)
|
||||
|
||||
func (c *Commands) AddLoginPolicy(ctx context.Context, resourceOwner string, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
|
||||
@ -238,18 +239,12 @@ func (c *Commands) AddSecondFactorToLoginPolicy(ctx context.Context, secondFacto
|
||||
return domain.SecondFactorTypeUnspecified, nil, caos_errs.ThrowInvalidArgument(nil, "Org-5m9fs", "Errors.Org.LoginPolicy.MFA.Unspecified")
|
||||
}
|
||||
secondFactorModel := NewOrgSecondFactorWriteModel(orgID, secondFactor)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
|
||||
addedEvent, err := c.addSecondFactorToLoginPolicy(ctx, secondFactorModel, secondFactor)
|
||||
if err != nil {
|
||||
return domain.SecondFactorTypeUnspecified, nil, err
|
||||
}
|
||||
|
||||
if secondFactorModel.State == domain.FactorStateActive {
|
||||
return domain.SecondFactorTypeUnspecified, nil, caos_errs.ThrowAlreadyExists(nil, "Org-2B0ps", "Errors.Org.LoginPolicy.MFA.AlreadyExists")
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
|
||||
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLoginPolicySecondFactorAddedEvent(ctx, orgAgg, secondFactor))
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, addedEvent)
|
||||
if err != nil {
|
||||
return domain.SecondFactorTypeUnspecified, nil, err
|
||||
}
|
||||
@ -261,6 +256,20 @@ func (c *Commands) AddSecondFactorToLoginPolicy(ctx context.Context, secondFacto
|
||||
return secondFactorModel.MFAType, writeModelToObjectDetails(&secondFactorModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) addSecondFactorToLoginPolicy(ctx context.Context, secondFactorModel *OrgSecondFactorWriteModel, secondFactor domain.SecondFactorType) (*org.LoginPolicySecondFactorAddedEvent, error) {
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if secondFactorModel.State == domain.FactorStateActive {
|
||||
return nil, caos_errs.ThrowAlreadyExists(nil, "Org-2B0ps", "Errors.Org.LoginPolicy.MFA.AlreadyExists")
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
|
||||
return org.NewLoginPolicySecondFactorAddedEvent(ctx, orgAgg, secondFactor), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveSecondFactorFromLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-fM0gs", "Errors.ResourceOwnerMissing")
|
||||
@ -269,16 +278,12 @@ func (c *Commands) RemoveSecondFactorFromLoginPolicy(ctx context.Context, second
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-55n8s", "Errors.Org.LoginPolicy.MFA.Unspecified")
|
||||
}
|
||||
secondFactorModel := NewOrgSecondFactorWriteModel(orgID, secondFactor)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
|
||||
removedEvent, err := c.removeSecondFactorFromLoginPolicy(ctx, secondFactorModel, secondFactor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secondFactorModel.State == domain.FactorStateUnspecified || secondFactorModel.State == domain.FactorStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9od", "Errors.Org.LoginPolicy.MFA.NotExisting")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
|
||||
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLoginPolicySecondFactorRemovedEvent(ctx, orgAgg, secondFactor))
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, removedEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -289,6 +294,18 @@ func (c *Commands) RemoveSecondFactorFromLoginPolicy(ctx context.Context, second
|
||||
return writeModelToObjectDetails(&secondFactorModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeSecondFactorFromLoginPolicy(ctx context.Context, secondFactorModel *OrgSecondFactorWriteModel, secondFactor domain.SecondFactorType) (*org.LoginPolicySecondFactorRemovedEvent, error) {
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secondFactorModel.State == domain.FactorStateUnspecified || secondFactorModel.State == domain.FactorStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9od", "Errors.Org.LoginPolicy.MFA.NotExisting")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
|
||||
return org.NewLoginPolicySecondFactorRemovedEvent(ctx, orgAgg, secondFactor), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddMultiFactorToLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType, orgID string) (domain.MultiFactorType, *domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return domain.MultiFactorTypeUnspecified, nil, caos_errs.ThrowInvalidArgument(nil, "Org-M0fsf", "Errors.ResourceOwnerMissing")
|
||||
@ -297,17 +314,12 @@ func (c *Commands) AddMultiFactorToLoginPolicy(ctx context.Context, multiFactor
|
||||
return domain.MultiFactorTypeUnspecified, nil, caos_errs.ThrowInvalidArgument(nil, "Org-5m9fs", "Errors.Org.LoginPolicy.MFA.Unspecified")
|
||||
}
|
||||
multiFactorModel := NewOrgMultiFactorWriteModel(orgID, multiFactor)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
|
||||
addedEvent, err := c.addMultiFactorToLoginPolicy(ctx, multiFactorModel, multiFactor)
|
||||
if err != nil {
|
||||
return domain.MultiFactorTypeUnspecified, nil, err
|
||||
}
|
||||
if multiFactorModel.State == domain.FactorStateActive {
|
||||
return domain.MultiFactorTypeUnspecified, nil, caos_errs.ThrowAlreadyExists(nil, "Org-3M9od", "Errors.Org.LoginPolicy.MFA.AlreadyExists")
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&multiFactorModel.WriteModel)
|
||||
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLoginPolicyMultiFactorAddedEvent(ctx, orgAgg, multiFactor))
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, addedEvent)
|
||||
if err != nil {
|
||||
return domain.MultiFactorTypeUnspecified, nil, err
|
||||
}
|
||||
@ -318,6 +330,19 @@ func (c *Commands) AddMultiFactorToLoginPolicy(ctx context.Context, multiFactor
|
||||
return multiFactorModel.MultiFactorWriteModel.MFAType, writeModelToObjectDetails(&multiFactorModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) addMultiFactorToLoginPolicy(ctx context.Context, multiFactorModel *OrgMultiFactorWriteModel, multiFactor domain.MultiFactorType) (*org.LoginPolicyMultiFactorAddedEvent, error) {
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if multiFactorModel.State == domain.FactorStateActive {
|
||||
return nil, caos_errs.ThrowAlreadyExists(nil, "Org-3M9od", "Errors.Org.LoginPolicy.MFA.AlreadyExists")
|
||||
}
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&multiFactorModel.WriteModel)
|
||||
return org.NewLoginPolicyMultiFactorAddedEvent(ctx, orgAgg, multiFactor), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveMultiFactorFromLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType, orgID string) (*domain.ObjectDetails, error) {
|
||||
if orgID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-M0fsf", "Errors.ResourceOwnerMissing")
|
||||
@ -326,16 +351,12 @@ func (c *Commands) RemoveMultiFactorFromLoginPolicy(ctx context.Context, multiFa
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-5m9fs", "Errors.Org.LoginPolicy.MFA.Unspecified")
|
||||
}
|
||||
multiFactorModel := NewOrgMultiFactorWriteModel(orgID, multiFactor)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
|
||||
removedEvent, err := c.removeMultiFactorFromLoginPolicy(ctx, multiFactorModel, multiFactor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if multiFactorModel.State == domain.FactorStateUnspecified || multiFactorModel.State == domain.FactorStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LoginPolicy.MFA.NotExisting")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&multiFactorModel.MultiFactorWriteModel.WriteModel)
|
||||
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLoginPolicyMultiFactorRemovedEvent(ctx, orgAgg, multiFactor))
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, removedEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -345,3 +366,28 @@ func (c *Commands) RemoveMultiFactorFromLoginPolicy(ctx context.Context, multiFa
|
||||
}
|
||||
return writeModelToObjectDetails(&multiFactorModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeMultiFactorFromLoginPolicy(ctx context.Context, multiFactorModel *OrgMultiFactorWriteModel, multiFactor domain.MultiFactorType) (*org.LoginPolicyMultiFactorRemovedEvent, error) {
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if multiFactorModel.State == domain.FactorStateUnspecified || multiFactorModel.State == domain.FactorStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LoginPolicy.MFA.NotExisting")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&multiFactorModel.MultiFactorWriteModel.WriteModel)
|
||||
|
||||
return org.NewLoginPolicyMultiFactorRemovedEvent(ctx, orgAgg, multiFactor), nil
|
||||
}
|
||||
|
||||
func (c *Commands) orgLoginPolicyAuthFactorsWriteModel(ctx context.Context, orgID string) (_ *OrgAuthFactorsAllowedWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
writeModel := NewOrgAuthFactorsAllowedWriteModel(orgID)
|
||||
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModel, nil
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package command
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
@ -93,3 +94,99 @@ func (wm *OrgMultiFactorWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
org.LoginPolicyMultiFactorAddedEventType,
|
||||
org.LoginPolicyMultiFactorRemovedEventType)
|
||||
}
|
||||
|
||||
func NewOrgAuthFactorsAllowedWriteModel(orgID string) *OrgAuthFactorsAllowedWriteModel {
|
||||
return &OrgAuthFactorsAllowedWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: orgID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
SecondFactors: map[domain.SecondFactorType]*factorState{},
|
||||
MultiFactors: map[domain.MultiFactorType]*factorState{},
|
||||
}
|
||||
}
|
||||
|
||||
type OrgAuthFactorsAllowedWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
SecondFactors map[domain.SecondFactorType]*factorState
|
||||
MultiFactors map[domain.MultiFactorType]*factorState
|
||||
}
|
||||
|
||||
type factorState struct {
|
||||
IAM domain.FactorState
|
||||
Org domain.FactorState
|
||||
}
|
||||
|
||||
func (wm *OrgAuthFactorsAllowedWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *iam.LoginPolicySecondFactorAddedEvent:
|
||||
wm.ensureSecondFactor(e.MFAType)
|
||||
wm.SecondFactors[e.MFAType].IAM = domain.FactorStateActive
|
||||
case *iam.LoginPolicySecondFactorRemovedEvent:
|
||||
wm.ensureSecondFactor(e.MFAType)
|
||||
wm.SecondFactors[e.MFAType].IAM = domain.FactorStateRemoved
|
||||
case *org.LoginPolicySecondFactorAddedEvent:
|
||||
wm.ensureSecondFactor(e.MFAType)
|
||||
wm.SecondFactors[e.MFAType].Org = domain.FactorStateActive
|
||||
case *org.LoginPolicySecondFactorRemovedEvent:
|
||||
wm.ensureSecondFactor(e.MFAType)
|
||||
wm.SecondFactors[e.MFAType].Org = domain.FactorStateRemoved
|
||||
case *iam.LoginPolicyMultiFactorAddedEvent:
|
||||
wm.ensureMultiFactor(e.MFAType)
|
||||
wm.MultiFactors[e.MFAType].IAM = domain.FactorStateActive
|
||||
case *iam.LoginPolicyMultiFactorRemovedEvent:
|
||||
wm.ensureMultiFactor(e.MFAType)
|
||||
wm.MultiFactors[e.MFAType].IAM = domain.FactorStateRemoved
|
||||
case *org.LoginPolicyMultiFactorAddedEvent:
|
||||
wm.ensureMultiFactor(e.MFAType)
|
||||
wm.MultiFactors[e.MFAType].Org = domain.FactorStateActive
|
||||
case *org.LoginPolicyMultiFactorRemovedEvent:
|
||||
wm.ensureMultiFactor(e.MFAType)
|
||||
wm.MultiFactors[e.MFAType].Org = domain.FactorStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OrgAuthFactorsAllowedWriteModel) ensureSecondFactor(secondFactor domain.SecondFactorType) {
|
||||
_, ok := wm.SecondFactors[secondFactor]
|
||||
if !ok {
|
||||
wm.SecondFactors[secondFactor] = &factorState{}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgAuthFactorsAllowedWriteModel) ensureMultiFactor(multiFactor domain.MultiFactorType) {
|
||||
_, ok := wm.MultiFactors[multiFactor]
|
||||
if !ok {
|
||||
wm.MultiFactors[multiFactor] = &factorState{}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgAuthFactorsAllowedWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType, org.AggregateType).
|
||||
AggregateIDs(domain.IAMID, wm.WriteModel.AggregateID).
|
||||
EventTypes(
|
||||
iam.LoginPolicySecondFactorAddedEventType,
|
||||
iam.LoginPolicySecondFactorRemovedEventType,
|
||||
iam.LoginPolicyMultiFactorAddedEventType,
|
||||
iam.LoginPolicyMultiFactorRemovedEventType,
|
||||
org.LoginPolicySecondFactorAddedEventType,
|
||||
org.LoginPolicySecondFactorRemovedEventType,
|
||||
org.LoginPolicyMultiFactorAddedEventType,
|
||||
org.LoginPolicyMultiFactorRemovedEventType)
|
||||
}
|
||||
|
||||
func (wm *OrgAuthFactorsAllowedWriteModel) ToSecondFactorWriteModel(factor domain.SecondFactorType) *OrgSecondFactorWriteModel {
|
||||
orgSecondFactorWriteModel := NewOrgSecondFactorWriteModel(wm.AggregateID, factor)
|
||||
orgSecondFactorWriteModel.ProcessedSequence = wm.ProcessedSequence
|
||||
orgSecondFactorWriteModel.State = wm.SecondFactors[factor].Org
|
||||
return orgSecondFactorWriteModel
|
||||
}
|
||||
|
||||
func (wm *OrgAuthFactorsAllowedWriteModel) ToMultiFactorWriteModel(factor domain.MultiFactorType) *OrgMultiFactorWriteModel {
|
||||
orgMultiFactorWriteModel := NewOrgMultiFactorWriteModel(wm.AggregateID, factor)
|
||||
orgMultiFactorWriteModel.ProcessedSequence = wm.ProcessedSequence
|
||||
orgMultiFactorWriteModel.State = wm.MultiFactors[factor].Org
|
||||
return orgMultiFactorWriteModel
|
||||
}
|
||||
|
@ -9,8 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func (c *Commands) getOrgPasswordComplexityPolicy(ctx context.Context, orgID string) (*domain.PasswordComplexityPolicy, error) {
|
||||
policy := NewOrgPasswordComplexityPolicyWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, policy)
|
||||
policy, err := c.orgPasswordComplexityPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -20,6 +19,15 @@ func (c *Commands) getOrgPasswordComplexityPolicy(ctx context.Context, orgID str
|
||||
return c.getDefaultPasswordComplexityPolicy(ctx)
|
||||
}
|
||||
|
||||
func (c *Commands) orgPasswordComplexityPolicyWriteModelByID(ctx context.Context, orgID string) (*OrgPasswordComplexityPolicyWriteModel, error) {
|
||||
policy := NewOrgPasswordComplexityPolicyWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddPasswordComplexityPolicy(ctx context.Context, resourceOwner string, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) {
|
||||
if resourceOwner == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-7ufEs", "Errors.ResourceOwnerMissing")
|
||||
@ -96,15 +104,11 @@ func (c *Commands) RemovePasswordComplexityPolicy(ctx context.Context, orgID str
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "Org-J8fsf", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
existingPolicy := NewOrgPasswordComplexityPolicyWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicy)
|
||||
event, err := c.removePasswordComplexityPolicy(ctx, existingPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-ADgs2", "Errors.Org.PasswordComplexityPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewPasswordComplexityPolicyRemovedEvent(ctx, orgAgg))
|
||||
pushedEvents, err := c.eventstore.PushEvents(ctx, event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -114,3 +118,27 @@ func (c *Commands) RemovePasswordComplexityPolicy(ctx context.Context, orgID str
|
||||
}
|
||||
return writeModelToObjectDetails(&existingPolicy.PasswordComplexityPolicyWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removePasswordComplexityPolicy(ctx context.Context, existingPolicy *OrgPasswordComplexityPolicyWriteModel) (*org.PasswordComplexityPolicyRemovedEvent, error) {
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-ADgs2", "Errors.Org.PasswordComplexityPolicy.NotFound")
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
return org.NewPasswordComplexityPolicyRemovedEvent(ctx, orgAgg), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removePasswordComplexityPolicyIfExists(ctx context.Context, orgID string) (*org.PasswordComplexityPolicyRemovedEvent, error) {
|
||||
existingPolicy, err := c.orgPasswordComplexityPolicyWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingPolicy.State != domain.PolicyStateActive {
|
||||
return nil, nil
|
||||
}
|
||||
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
|
||||
return org.NewPasswordComplexityPolicyRemovedEvent(ctx, orgAgg), nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user