fix: unify commands (and remove todos for checking existence) (#3696)

This commit is contained in:
Livio Amstutz
2022-05-24 11:28:17 +02:00
committed by GitHub
parent cf6f4d6894
commit e1ee89982a
28 changed files with 820 additions and 954 deletions

View File

@@ -88,7 +88,7 @@ func (s *Server) ListLoginPolicySecondFactors(ctx context.Context, req *admin_pb
} }
func (s *Server) AddSecondFactorToLoginPolicy(ctx context.Context, req *admin_pb.AddSecondFactorToLoginPolicyRequest) (*admin_pb.AddSecondFactorToLoginPolicyResponse, error) { func (s *Server) AddSecondFactorToLoginPolicy(ctx context.Context, req *admin_pb.AddSecondFactorToLoginPolicyRequest) (*admin_pb.AddSecondFactorToLoginPolicyResponse, error) {
_, objectDetails, err := s.command.AddSecondFactorToDefaultLoginPolicy(ctx, policy_grpc.SecondFactorTypeToDomain(req.Type)) objectDetails, err := s.command.AddSecondFactorToDefaultLoginPolicy(ctx, policy_grpc.SecondFactorTypeToDomain(req.Type))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -119,7 +119,7 @@ func (s *Server) ListLoginPolicyMultiFactors(ctx context.Context, req *admin_pb.
} }
func (s *Server) AddMultiFactorToLoginPolicy(ctx context.Context, req *admin_pb.AddMultiFactorToLoginPolicyRequest) (*admin_pb.AddMultiFactorToLoginPolicyResponse, error) { func (s *Server) AddMultiFactorToLoginPolicy(ctx context.Context, req *admin_pb.AddMultiFactorToLoginPolicyRequest) (*admin_pb.AddMultiFactorToLoginPolicyResponse, error) {
_, objectDetails, err := s.command.AddMultiFactorToDefaultLoginPolicy(ctx, policy_grpc.MultiFactorTypeToDomain(req.Type)) objectDetails, err := s.command.AddMultiFactorToDefaultLoginPolicy(ctx, policy_grpc.MultiFactorTypeToDomain(req.Type))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -12,3 +12,11 @@ func writeModelToObjectDetails(writeModel *eventstore.WriteModel) *domain.Object
EventDate: writeModel.ChangeDate, EventDate: writeModel.ChangeDate,
} }
} }
func pushedEventsToObjectDetails(events []eventstore.Event) *domain.ObjectDetails {
return &domain.ObjectDetails{
Sequence: events[len(events)-1].Sequence(),
EventDate: events[len(events)-1].CreationDate(),
ResourceOwner: events[len(events)-1].Aggregate().ResourceOwner,
}
}

View File

@@ -174,16 +174,16 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
projectAgg := project.NewAggregate(setup.zitadel.projectID, orgID) projectAgg := project.NewAggregate(setup.zitadel.projectID, orgID)
validations := []preparation.Validation{ validations := []preparation.Validation{
addInstance(instanceAgg, setup.InstanceName, setup.DefaultLanguage), prepareAddInstance(instanceAgg, setup.InstanceName, setup.DefaultLanguage),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeAppSecret, setup.SecretGenerators.ClientSecret), prepareAddSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeAppSecret, setup.SecretGenerators.ClientSecret),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeInitCode, setup.SecretGenerators.InitializeUserCode), prepareAddSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeInitCode, setup.SecretGenerators.InitializeUserCode),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeVerifyEmailCode, setup.SecretGenerators.EmailVerificationCode), prepareAddSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeVerifyEmailCode, setup.SecretGenerators.EmailVerificationCode),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeVerifyPhoneCode, setup.SecretGenerators.PhoneVerificationCode), prepareAddSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeVerifyPhoneCode, setup.SecretGenerators.PhoneVerificationCode),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypePasswordResetCode, setup.SecretGenerators.PasswordVerificationCode), prepareAddSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypePasswordResetCode, setup.SecretGenerators.PasswordVerificationCode),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypePasswordlessInitCode, setup.SecretGenerators.PasswordlessInitCode), prepareAddSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypePasswordlessInitCode, setup.SecretGenerators.PasswordlessInitCode),
addSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeVerifyDomain, setup.SecretGenerators.DomainVerification), prepareAddSecretGeneratorConfig(instanceAgg, domain.SecretGeneratorTypeVerifyDomain, setup.SecretGenerators.DomainVerification),
AddPasswordComplexityPolicy( prepareAddDefaultPasswordComplexityPolicy(
instanceAgg, instanceAgg,
setup.PasswordComplexityPolicy.MinLength, setup.PasswordComplexityPolicy.MinLength,
setup.PasswordComplexityPolicy.HasLowercase, setup.PasswordComplexityPolicy.HasLowercase,
@@ -191,18 +191,18 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
setup.PasswordComplexityPolicy.HasNumber, setup.PasswordComplexityPolicy.HasNumber,
setup.PasswordComplexityPolicy.HasSymbol, setup.PasswordComplexityPolicy.HasSymbol,
), ),
AddPasswordAgePolicy( prepareAddDefaultPasswordAgePolicy(
instanceAgg, instanceAgg,
setup.PasswordAgePolicy.ExpireWarnDays, setup.PasswordAgePolicy.ExpireWarnDays,
setup.PasswordAgePolicy.MaxAgeDays, setup.PasswordAgePolicy.MaxAgeDays,
), ),
AddDefaultDomainPolicy( prepareAddDefaultDomainPolicy(
instanceAgg, instanceAgg,
setup.DomainPolicy.UserLoginMustBeDomain, setup.DomainPolicy.UserLoginMustBeDomain,
setup.DomainPolicy.ValidateOrgDomains, setup.DomainPolicy.ValidateOrgDomains,
setup.DomainPolicy.SMTPSenderAddressMatchesInstanceDomain, setup.DomainPolicy.SMTPSenderAddressMatchesInstanceDomain,
), ),
AddDefaultLoginPolicy( prepareAddDefaultLoginPolicy(
instanceAgg, instanceAgg,
setup.LoginPolicy.AllowUsernamePassword, setup.LoginPolicy.AllowUsernamePassword,
setup.LoginPolicy.AllowRegister, setup.LoginPolicy.AllowRegister,
@@ -218,14 +218,14 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
setup.LoginPolicy.SecondFactorCheckLifetime, setup.LoginPolicy.SecondFactorCheckLifetime,
setup.LoginPolicy.MultiFactorCheckLifetime, setup.LoginPolicy.MultiFactorCheckLifetime,
), ),
AddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeOTP), prepareAddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeOTP),
AddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeU2F), prepareAddSecondFactorToDefaultLoginPolicy(instanceAgg, domain.SecondFactorTypeU2F),
AddMultiFactorToDefaultLoginPolicy(instanceAgg, domain.MultiFactorTypeU2FWithPIN), prepareAddMultiFactorToDefaultLoginPolicy(instanceAgg, domain.MultiFactorTypeU2FWithPIN),
AddPrivacyPolicy(instanceAgg, setup.PrivacyPolicy.TOSLink, setup.PrivacyPolicy.PrivacyLink, setup.PrivacyPolicy.HelpLink), prepareAddDefaultPrivacyPolicy(instanceAgg, setup.PrivacyPolicy.TOSLink, setup.PrivacyPolicy.PrivacyLink, setup.PrivacyPolicy.HelpLink),
AddDefaultLockoutPolicy(instanceAgg, setup.LockoutPolicy.MaxAttempts, setup.LockoutPolicy.ShouldShowLockoutFailure), prepareAddDefaultLockoutPolicy(instanceAgg, setup.LockoutPolicy.MaxAttempts, setup.LockoutPolicy.ShouldShowLockoutFailure),
AddDefaultLabelPolicy( prepareAddDefaultLabelPolicy(
instanceAgg, instanceAgg,
setup.LabelPolicy.PrimaryColor, setup.LabelPolicy.PrimaryColor,
setup.LabelPolicy.BackgroundColor, setup.LabelPolicy.BackgroundColor,
@@ -239,13 +239,13 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
setup.LabelPolicy.ErrorMsgPopup, setup.LabelPolicy.ErrorMsgPopup,
setup.LabelPolicy.DisableWatermark, setup.LabelPolicy.DisableWatermark,
), ),
ActivateDefaultLabelPolicy(instanceAgg), prepareActivateDefaultLabelPolicy(instanceAgg),
AddEmailTemplate(instanceAgg, setup.EmailTemplate), prepareAddDefaultEmailTemplate(instanceAgg, setup.EmailTemplate),
} }
for _, msg := range setup.MessageTexts { for _, msg := range setup.MessageTexts {
validations = append(validations, SetInstanceCustomTexts(instanceAgg, msg)) validations = append(validations, prepareSetInstanceCustomMessageTexts(instanceAgg, msg))
} }
console := &addOIDCApp{ console := &addOIDCApp{
@@ -377,7 +377,7 @@ func (c *Commands) SetDefaultLanguage(ctx context.Context, defaultLanguage langu
}, nil }, nil
} }
func addInstance(a *instance.Aggregate, instanceName string, defaultLanguage language.Tag) preparation.Validation { func prepareAddInstance(a *instance.Aggregate, instanceName string, defaultLanguage language.Tag) preparation.Validation {
return func() (preparation.CreateCommands, error) { return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
return []eventstore.Command{ return []eventstore.Command{

View File

@@ -3,11 +3,13 @@ package command
import ( import (
"context" "context"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/instance"
"golang.org/x/text/language"
) )
func (c *Commands) SetDefaultMessageText(ctx context.Context, instanceID string, messageText *domain.CustomMessageText) (*domain.ObjectDetails, error) { func (c *Commands) SetDefaultMessageText(ctx context.Context, instanceID string, messageText *domain.CustomMessageText) (*domain.ObjectDetails, error) {
@@ -121,3 +123,83 @@ func (c *Commands) defaultCustomMessageTextWriteModelByID(ctx context.Context, m
} }
return writeModel, nil return writeModel, nil
} }
func prepareSetInstanceCustomMessageTexts(
a *instance.Aggregate,
msg *domain.CustomMessageText,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if !msg.IsValid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-kd9fs", "Errors.CustomMessageText.Invalid")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
existing, err := existingInstanceCustomMessageText(ctx, filter, msg.MessageTextType, msg.Language)
if err != nil {
return nil, err
}
cmds := make([]eventstore.Command, 0, 7)
if existing.Greeting != msg.Greeting {
if msg.Greeting != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageGreeting, msg.Greeting, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageGreeting, msg.Language))
}
}
if existing.Subject != msg.Subject {
if msg.Subject != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageSubject, msg.Subject, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageSubject, msg.Language))
}
}
if existing.Title != msg.Title {
if msg.Title != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageTitle, msg.Title, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageTitle, msg.Language))
}
}
if existing.PreHeader != msg.PreHeader {
if msg.PreHeader != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessagePreHeader, msg.PreHeader, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessagePreHeader, msg.Language))
}
}
if existing.Text != msg.Text {
if msg.Text != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageText, msg.Text, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageText, msg.Language))
}
}
if existing.ButtonText != msg.ButtonText {
if msg.ButtonText != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageButtonText, msg.ButtonText, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageButtonText, msg.Language))
}
}
if existing.FooterText != msg.FooterText {
if msg.FooterText != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageFooterText, msg.FooterText, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageFooterText, msg.Language))
}
}
return cmds, nil
}, nil
}
}
func existingInstanceCustomMessageText(ctx context.Context, filter preparation.FilterToQueryReducer, textType string, lang language.Tag) (*InstanceCustomMessageTextWriteModel, error) {
writeModel := NewInstanceCustomMessageTextWriteModel(ctx, textType, lang)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
writeModel.Reduce()
return writeModel, nil
}

View File

@@ -1,29 +0,0 @@
package command
import (
"context"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance"
)
func AddDefaultDomainPolicy(
a *instance.Aggregate,
userLoginMustBeDomain,
validateOrgDomains,
smtpSenderAddressMatchesInstanceDomain bool,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewDomainPolicyAddedEvent(ctx, &a.Aggregate,
userLoginMustBeDomain,
validateOrgDomains,
smtpSenderAddressMatchesInstanceDomain,
),
}, nil
}, nil
}
}

View File

@@ -1,106 +0,0 @@
package command
import (
"context"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance"
)
func AddEmailTemplate(
a *instance.Aggregate,
tempalte []byte,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewMailTemplateAddedEvent(ctx, &a.Aggregate,
tempalte,
),
}, nil
}, nil
}
}
func SetInstanceCustomTexts(
a *instance.Aggregate,
msg *domain.CustomMessageText,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
existing, err := existingInstanceCustomMessageText(ctx, filter, msg.MessageTextType, msg.Language)
if err != nil {
return nil, err
}
cmds := make([]eventstore.Command, 0, 7)
if existing.Greeting != msg.Greeting {
if msg.Greeting != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageGreeting, msg.Greeting, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageGreeting, msg.Language))
}
}
if existing.Subject != msg.Subject {
if msg.Subject != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageSubject, msg.Subject, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageSubject, msg.Language))
}
}
if existing.Title != msg.Title {
if msg.Title != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageTitle, msg.Title, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageTitle, msg.Language))
}
}
if existing.PreHeader != msg.PreHeader {
if msg.PreHeader != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessagePreHeader, msg.PreHeader, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessagePreHeader, msg.Language))
}
}
if existing.Text != msg.Text {
if msg.Text != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageText, msg.Text, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageText, msg.Language))
}
}
if existing.ButtonText != msg.ButtonText {
if msg.ButtonText != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageButtonText, msg.ButtonText, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageButtonText, msg.Language))
}
}
if existing.FooterText != msg.FooterText {
if msg.FooterText != "" {
cmds = append(cmds, instance.NewCustomTextSetEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageFooterText, msg.FooterText, msg.Language))
} else {
cmds = append(cmds, instance.NewCustomTextRemovedEvent(ctx, &a.Aggregate, msg.MessageTextType, domain.MessageFooterText, msg.Language))
}
}
// TODO: what if no text changed? len(events) == 0
return cmds, nil
}, nil
}
}
func existingInstanceCustomMessageText(ctx context.Context, filter preparation.FilterToQueryReducer, textType string, lang language.Tag) (*InstanceCustomMessageTextWriteModel, error) {
writeModel := NewInstanceCustomMessageTextWriteModel(ctx, textType, lang)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
writeModel.Reduce()
return writeModel, nil
}

View File

@@ -1,58 +0,0 @@
package command
import (
"context"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance"
)
func AddDefaultLabelPolicy(
a *instance.Aggregate,
primaryColor,
backgroundColor,
warnColor,
fontColor,
primaryColorDark,
backgroundColorDark,
warnColorDark,
fontColorDark string,
hideLoginNameSuffix,
errorMsgPopup,
disableWatermark bool,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewLabelPolicyAddedEvent(ctx, &a.Aggregate,
primaryColor,
backgroundColor,
warnColor,
fontColor,
primaryColorDark,
backgroundColorDark,
warnColorDark,
fontColorDark,
hideLoginNameSuffix,
errorMsgPopup,
disableWatermark,
),
}, nil
}, nil
}
}
func ActivateDefaultLabelPolicy(
a *instance.Aggregate,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewLabelPolicyActivatedEvent(ctx, &a.Aggregate),
}, nil
}, nil
}
}

View File

@@ -1,24 +0,0 @@
package command
import (
"context"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance"
)
func AddDefaultLockoutPolicy(
a *instance.Aggregate,
maxAttempts uint64,
showLockoutFailure bool,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewLockoutPolicyAddedEvent(ctx, &a.Aggregate, maxAttempts, showLockoutFailure),
}, nil
}, nil
}
}

View File

@@ -1,73 +0,0 @@
package command
import (
"context"
"time"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance"
)
func AddDefaultLoginPolicy(
a *instance.Aggregate,
allowUsernamePassword bool,
allowRegister bool,
allowExternalIDP bool,
forceMFA bool,
hidePasswordReset bool,
ignoreUnknownUsernames bool,
passwordlessType domain.PasswordlessType,
defaultRedirectURI string,
passwordCheckLifetime time.Duration,
externalLoginCheckLifetime time.Duration,
mfaInitSkipLifetime time.Duration,
secondFactorCheckLifetime time.Duration,
multiFactorCheckLifetime time.Duration,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewLoginPolicyAddedEvent(ctx, &a.Aggregate,
allowUsernamePassword,
allowRegister,
allowExternalIDP,
forceMFA,
hidePasswordReset,
ignoreUnknownUsernames,
passwordlessType,
defaultRedirectURI,
passwordCheckLifetime,
externalLoginCheckLifetime,
mfaInitSkipLifetime,
secondFactorCheckLifetime,
multiFactorCheckLifetime,
),
}, nil
}, nil
}
}
func AddSecondFactorToDefaultLoginPolicy(a *instance.Aggregate, factor domain.SecondFactorType) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewLoginPolicySecondFactorAddedEvent(ctx, &a.Aggregate, factor),
}, nil
}, nil
}
}
func AddMultiFactorToDefaultLoginPolicy(a *instance.Aggregate, factor domain.MultiFactorType) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewLoginPolicyMultiFactorAddedEvent(ctx, &a.Aggregate, factor),
}, nil
}, nil
}
}

View File

@@ -1,27 +0,0 @@
package command
import (
"context"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance"
)
func AddPasswordAgePolicy(
a *instance.Aggregate,
expireWarnDays,
maxAgeDays uint64,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewPasswordAgePolicyAddedEvent(ctx, &a.Aggregate,
expireWarnDays,
maxAgeDays,
),
}, nil
}, nil
}
}

View File

@@ -1,33 +0,0 @@
package command
import (
"context"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance"
)
func AddPasswordComplexityPolicy(
a *instance.Aggregate,
minLength uint64,
hasLowercase,
hasUppercase,
hasNumber,
hasSymbol bool,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewPasswordComplexityPolicyAddedEvent(ctx, &a.Aggregate,
minLength,
hasLowercase,
hasUppercase,
hasNumber,
hasSymbol,
),
}, nil
}, nil
}
}

View File

@@ -3,41 +3,26 @@ package command
import ( import (
"context" "context"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
iam_repo "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/telemetry/tracing"
) )
func (c *Commands) AddDefaultDomainPolicy(ctx context.Context, policy *domain.DomainPolicy) (*domain.DomainPolicy, error) { func (c *Commands) AddDefaultDomainPolicy(ctx context.Context, userLoginMustBeDomain, validateOrgDomains, smtpSenderAddressMatchesInstanceDomain bool) (*domain.ObjectDetails, error) {
addedPolicy := NewInstanceDomainPolicyWriteModel(ctx) instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
instanceAgg := InstanceAggregateFromWriteModel(&addedPolicy.WriteModel) cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddDefaultDomainPolicy(instanceAgg, userLoginMustBeDomain, validateOrgDomains, smtpSenderAddressMatchesInstanceDomain))
event, err := c.addDefaultDomainPolicy(ctx, instanceAgg, addedPolicy, policy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
pushedEvents, err := c.eventstore.Push(ctx, event)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = AppendAndReduce(addedPolicy, pushedEvents...) return pushedEventsToObjectDetails(pushedEvents), nil
if err != nil {
return nil, err
}
return writeModelToDomainPolicy(addedPolicy), nil
}
func (c *Commands) addDefaultDomainPolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, addedPolicy *InstanceDomainPolicyWriteModel, policy *domain.DomainPolicy) (eventstore.Command, error) {
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-Lk0dS", "Errors.IAM.DomainPolicy.AlreadyExists")
}
return iam_repo.NewDomainPolicyAddedEvent(ctx, instanceAgg, policy.UserLoginMustBeDomain, policy.ValidateOrgDomains, policy.SMTPSenderAddressMatchesInstanceDomain), nil
} }
func (c *Commands) ChangeDefaultDomainPolicy(ctx context.Context, policy *domain.DomainPolicy) (*domain.DomainPolicy, error) { func (c *Commands) ChangeDefaultDomainPolicy(ctx context.Context, policy *domain.DomainPolicy) (*domain.DomainPolicy, error) {
@@ -90,3 +75,34 @@ func (c *Commands) defaultDomainPolicyWriteModelByID(ctx context.Context) (polic
} }
return writeModel, nil return writeModel, nil
} }
func prepareAddDefaultDomainPolicy(
a *instance.Aggregate,
userLoginMustBeDomain,
validateOrgDomains,
smtpSenderAddressMatchesInstanceDomain bool,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstanceDomainPolicyWriteModel(ctx)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-Lk0dS", "Errors.Instance.DomainPolicy.AlreadyExists")
}
return []eventstore.Command{
instance.NewDomainPolicyAddedEvent(ctx, &a.Aggregate,
userLoginMustBeDomain,
validateOrgDomains,
smtpSenderAddressMatchesInstanceDomain,
),
}, nil
}, nil
}
}

View File

@@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
@@ -21,10 +22,12 @@ func TestCommandSide_AddDefaultDomainPolicy(t *testing.T) {
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
policy *domain.DomainPolicy userLoginMustBeDomain bool
validateOrgDomains bool
smtpSenderAddressMatchesInstanceDomain bool
} }
type res struct { type res struct {
want *domain.DomainPolicy want *domain.ObjectDetails
err func(error) bool err func(error) bool
} }
tests := []struct { tests := []struct {
@@ -52,11 +55,9 @@ func TestCommandSide_AddDefaultDomainPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
policy: &domain.DomainPolicy{ userLoginMustBeDomain: true,
UserLoginMustBeDomain: true, validateOrgDomains: true,
ValidateOrgDomains: true, smtpSenderAddressMatchesInstanceDomain: true,
SMTPSenderAddressMatchesInstanceDomain: true,
},
}, },
res: res{ res: res{
err: caos_errs.IsErrorAlreadyExists, err: caos_errs.IsErrorAlreadyExists,
@@ -85,23 +86,14 @@ func TestCommandSide_AddDefaultDomainPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
policy: &domain.DomainPolicy{ userLoginMustBeDomain: true,
UserLoginMustBeDomain: true, validateOrgDomains: true,
ValidateOrgDomains: true, smtpSenderAddressMatchesInstanceDomain: true,
SMTPSenderAddressMatchesInstanceDomain: true,
},
}, },
res: res{ res: res{
want: &domain.DomainPolicy{ want: &domain.ObjectDetails{
ObjectRoot: models.ObjectRoot{
InstanceID: "INSTANCE",
AggregateID: "INSTANCE",
ResourceOwner: "INSTANCE", ResourceOwner: "INSTANCE",
}, },
UserLoginMustBeDomain: true,
ValidateOrgDomains: true,
SMTPSenderAddressMatchesInstanceDomain: true,
},
}, },
}, },
} }
@@ -110,7 +102,7 @@ func TestCommandSide_AddDefaultDomainPolicy(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore,
} }
got, err := r.AddDefaultDomainPolicy(tt.args.ctx, tt.args.policy) got, err := r.AddDefaultDomainPolicy(tt.args.ctx, tt.args.userLoginMustBeDomain, tt.args.validateOrgDomains, tt.args.smtpSenderAddressMatchesInstanceDomain)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
@@ -11,52 +12,35 @@ import (
"github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/telemetry/tracing"
) )
func (c *Commands) AddDefaultLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) { func (c *Commands) AddDefaultLabelPolicy(
addedPolicy := NewInstanceLabelPolicyWriteModel(ctx) ctx context.Context,
instanceAgg := InstanceAggregateFromWriteModel(&addedPolicy.LabelPolicyWriteModel.WriteModel) primaryColor, backgroundColor, warnColor, fontColor, primaryColorDark, backgroundColorDark, warnColorDark, fontColorDark string,
event, err := c.addDefaultLabelPolicy(ctx, instanceAgg, addedPolicy, policy) hideLoginNameSuffix, errorMsgPopup, disableWatermark bool,
if err != nil { ) (*domain.ObjectDetails, error) {
return nil, err instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
} cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter,
prepareAddDefaultLabelPolicy(
pushedEvents, err := c.eventstore.Push(ctx, event)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(&addedPolicy.LabelPolicyWriteModel), nil
}
func (c *Commands) addDefaultLabelPolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, addedPolicy *InstanceLabelPolicyWriteModel, policy *domain.LabelPolicy) (eventstore.Command, error) {
if err := policy.IsValid(); err != nil {
return nil, err
}
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-2B0ps", "Errors.IAM.LabelPolicy.AlreadyExists")
}
return instance.NewLabelPolicyAddedEvent(
ctx,
instanceAgg, instanceAgg,
policy.PrimaryColor, primaryColor,
policy.BackgroundColor, backgroundColor,
policy.WarnColor, warnColor,
policy.FontColor, fontColor,
policy.PrimaryColorDark, primaryColorDark,
policy.BackgroundColorDark, backgroundColorDark,
policy.WarnColorDark, warnColorDark,
policy.FontColorDark, fontColorDark,
policy.HideLoginNameSuffix, hideLoginNameSuffix,
policy.ErrorMsgPopup, errorMsgPopup,
policy.DisableWatermark), nil disableWatermark,
))
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if err != nil {
return nil, err
}
return pushedEventsToObjectDetails(pushedEvents), nil
} }
func (c *Commands) ChangeDefaultLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) { func (c *Commands) ChangeDefaultLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) {
@@ -102,26 +86,16 @@ func (c *Commands) ChangeDefaultLabelPolicy(ctx context.Context, policy *domain.
} }
func (c *Commands) ActivateDefaultLabelPolicy(ctx context.Context) (*domain.ObjectDetails, error) { func (c *Commands) ActivateDefaultLabelPolicy(ctx context.Context) (*domain.ObjectDetails, error) {
existingPolicy, err := c.defaultLabelPolicyWriteModelByID(ctx) instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareActivateDefaultLabelPolicy(instanceAgg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-6M23e", "Errors.IAM.LabelPolicy.NotFound")
}
instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
pushedEvents, err := c.eventstore.Push(ctx, instance.NewLabelPolicyActivatedEvent(ctx, instanceAgg))
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = AppendAndReduce(existingPolicy, pushedEvents...) return pushedEventsToObjectDetails(pushedEvents), nil
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&existingPolicy.LabelPolicyWriteModel.WriteModel), nil
} }
func (c *Commands) AddLogoDefaultLabelPolicy(ctx context.Context, upload *AssetUpload) (*domain.ObjectDetails, error) { func (c *Commands) AddLogoDefaultLabelPolicy(ctx context.Context, upload *AssetUpload) (*domain.ObjectDetails, error) {
@@ -396,3 +370,74 @@ func (c *Commands) getDefaultLabelPolicy(ctx context.Context) (*domain.LabelPoli
policy.Default = true policy.Default = true
return policy, nil return policy, nil
} }
func prepareAddDefaultLabelPolicy(
a *instance.Aggregate,
primaryColor,
backgroundColor,
warnColor,
fontColor,
primaryColorDark,
backgroundColorDark,
warnColorDark,
fontColorDark string,
hideLoginNameSuffix,
errorMsgPopup,
disableWatermark bool,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstanceLabelPolicyWriteModel(ctx)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-2B0ps", "Errors.Instance.LabelPolicy.AlreadyExists")
}
return []eventstore.Command{
instance.NewLabelPolicyAddedEvent(ctx, &a.Aggregate,
primaryColor,
backgroundColor,
warnColor,
fontColor,
primaryColorDark,
backgroundColorDark,
warnColorDark,
fontColorDark,
hideLoginNameSuffix,
errorMsgPopup,
disableWatermark,
),
}, nil
}, nil
}
}
func prepareActivateDefaultLabelPolicy(
a *instance.Aggregate,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstanceLabelPolicyWriteModel(ctx)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if !writeModel.State.Exists() {
return nil, caos_errs.ThrowNotFound(nil, "INSTANCE-6M23e", "Errors.Instance.LabelPolicy.NotFound")
}
return []eventstore.Command{
instance.NewLabelPolicyActivatedEvent(ctx, &a.Aggregate),
}, nil
}, nil
}
}

View File

@@ -26,10 +26,20 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
policy *domain.LabelPolicy primaryColor string
backgroundColor string
warnColor string
fontColor string
primaryColorDark string
backgroundColorDark string
warnColorDark string
fontColorDark string
hideLoginNameSuffix bool
errorMsgPopup bool
disableWatermark bool
} }
type res struct { type res struct {
want *domain.LabelPolicy want *domain.ObjectDetails
err func(error) bool err func(error) bool
} }
tests := []struct { tests := []struct {
@@ -65,19 +75,17 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
policy: &domain.LabelPolicy{ primaryColor: "#ffffff",
PrimaryColor: "#ffffff", backgroundColor: "#ffffff",
BackgroundColor: "#ffffff", warnColor: "#ffffff",
WarnColor: "#ffffff", fontColor: "#ffffff",
FontColor: "#ffffff", primaryColorDark: "#ffffff",
PrimaryColorDark: "#ffffff", backgroundColorDark: "#ffffff",
BackgroundColorDark: "#ffffff", warnColorDark: "#ffffff",
WarnColorDark: "#ffffff", fontColorDark: "#ffffff",
FontColorDark: "#ffffff", hideLoginNameSuffix: true,
HideLoginNameSuffix: true, errorMsgPopup: true,
ErrorMsgPopup: true, disableWatermark: true,
DisableWatermark: true,
},
}, },
res: res{ res: res{
err: caos_errs.IsErrorAlreadyExists, err: caos_errs.IsErrorAlreadyExists,
@@ -114,39 +122,22 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
policy: &domain.LabelPolicy{ primaryColor: "#ffffff",
PrimaryColor: "#ffffff", backgroundColor: "#ffffff",
BackgroundColor: "#ffffff", warnColor: "#ffffff",
WarnColor: "#ffffff", fontColor: "#ffffff",
FontColor: "#ffffff", primaryColorDark: "#ffffff",
PrimaryColorDark: "#ffffff", backgroundColorDark: "#ffffff",
BackgroundColorDark: "#ffffff", warnColorDark: "#ffffff",
WarnColorDark: "#ffffff", fontColorDark: "#ffffff",
FontColorDark: "#ffffff", hideLoginNameSuffix: true,
HideLoginNameSuffix: true, errorMsgPopup: true,
ErrorMsgPopup: true, disableWatermark: true,
DisableWatermark: true,
},
}, },
res: res{ res: res{
want: &domain.LabelPolicy{ want: &domain.ObjectDetails{
ObjectRoot: models.ObjectRoot{
InstanceID: "INSTANCE",
AggregateID: "INSTANCE",
ResourceOwner: "INSTANCE", ResourceOwner: "INSTANCE",
}, },
PrimaryColor: "#ffffff",
BackgroundColor: "#ffffff",
WarnColor: "#ffffff",
FontColor: "#ffffff",
PrimaryColorDark: "#ffffff",
BackgroundColorDark: "#ffffff",
WarnColorDark: "#ffffff",
FontColorDark: "#ffffff",
HideLoginNameSuffix: true,
ErrorMsgPopup: true,
DisableWatermark: true,
},
}, },
}, },
} }
@@ -155,7 +146,20 @@ func TestCommandSide_AddDefaultLabelPolicy(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore,
} }
got, err := r.AddDefaultLabelPolicy(tt.args.ctx, tt.args.policy) got, err := r.AddDefaultLabelPolicy(
tt.args.ctx,
tt.args.primaryColor,
tt.args.backgroundColor,
tt.args.warnColor,
tt.args.fontColor,
tt.args.primaryColorDark,
tt.args.backgroundColorDark,
tt.args.warnColorDark,
tt.args.fontColorDark,
tt.args.hideLoginNameSuffix,
tt.args.errorMsgPopup,
tt.args.disableWatermark,
)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }
@@ -378,7 +382,7 @@ func TestCommandSide_ActivateDefaultLabelPolicy(t *testing.T) {
), ),
}, },
args: args{ args: args{
ctx: context.Background(), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
}, },
res: res{ res: res{
err: caos_errs.IsNotFound, err: caos_errs.IsNotFound,
@@ -409,7 +413,8 @@ func TestCommandSide_ActivateDefaultLabelPolicy(t *testing.T) {
), ),
expectPush( expectPush(
[]*repository.Event{ []*repository.Event{
eventFromEventPusher( eventFromEventPusherWithInstanceID(
"INSTANCE",
instance.NewLabelPolicyActivatedEvent(context.Background(), instance.NewLabelPolicyActivatedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate, &instance.NewAggregate("INSTANCE").Aggregate,
), ),
@@ -419,7 +424,7 @@ func TestCommandSide_ActivateDefaultLabelPolicy(t *testing.T) {
), ),
}, },
args: args{ args: args{
ctx: context.Background(), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
}, },
res: res{ res: res{
want: &domain.ObjectDetails{ want: &domain.ObjectDetails{

View File

@@ -2,9 +2,12 @@ package command
import ( import (
"context" "context"
"time"
"github.com/zitadel/logging" "github.com/zitadel/logging"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
@@ -12,59 +15,35 @@ import (
"github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/telemetry/tracing"
) )
func (c *Commands) getDefaultLoginPolicy(ctx context.Context) (*domain.LoginPolicy, error) { func (c *Commands) AddDefaultLoginPolicy(
policyWriteModel := NewInstanceLoginPolicyWriteModel(ctx) ctx context.Context,
err := c.eventstore.FilterToQueryReducer(ctx, policyWriteModel) allowUsernamePassword, allowRegister, allowExternalIDP, forceMFA, hidePasswordReset, ignoreUnknownUsernames bool,
passwordlessType domain.PasswordlessType,
defaultRedirectURI string,
passwordCheckLifetime, externalLoginCheckLifetime, mfaInitSkipLifetime, secondFactorCheckLifetime, multiFactorCheckLifetime time.Duration,
) (*domain.ObjectDetails, error) {
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddDefaultLoginPolicy(instanceAgg, allowUsernamePassword,
allowRegister,
allowExternalIDP,
forceMFA,
hidePasswordReset,
ignoreUnknownUsernames,
passwordlessType,
defaultRedirectURI,
passwordCheckLifetime,
externalLoginCheckLifetime,
mfaInitSkipLifetime,
secondFactorCheckLifetime,
multiFactorCheckLifetime))
if err != nil { if err != nil {
return nil, err return nil, err
} }
policy := writeModelToLoginPolicy(&policyWriteModel.LoginPolicyWriteModel) pushedEvents, err := c.eventstore.Push(ctx, cmds...)
policy.Default = true
return policy, nil
}
func (c *Commands) AddDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
addedPolicy := NewInstanceLoginPolicyWriteModel(ctx)
instanceAgg := InstanceAggregateFromWriteModel(&addedPolicy.WriteModel)
event, err := c.addDefaultLoginPolicy(ctx, instanceAgg, addedPolicy, policy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pushedEvents, err := c.eventstore.Push(ctx, event) return pushedEventsToObjectDetails(pushedEvents), nil
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(&addedPolicy.LoginPolicyWriteModel), nil
}
func (c *Commands) addDefaultLoginPolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, addedPolicy *InstanceLoginPolicyWriteModel, policy *domain.LoginPolicy) (eventstore.Command, error) {
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-2B0ps", "Errors.IAM.LoginPolicy.AlreadyExists")
}
return instance.NewLoginPolicyAddedEvent(ctx,
instanceAgg,
policy.AllowUsernamePassword,
policy.AllowRegister,
policy.AllowExternalIDP,
policy.ForceMFA,
policy.HidePasswordReset,
policy.IgnoreUnknownUsernames,
policy.PasswordlessType,
policy.DefaultRedirectURI,
policy.PasswordCheckLifetime,
policy.ExternalLoginCheckLifetime,
policy.MFAInitSkipLifetime,
policy.SecondFactorCheckLifetime,
policy.MultiFactorCheckLifetime), nil
} }
func (c *Commands) ChangeDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) { func (c *Commands) ChangeDefaultLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
@@ -210,38 +189,17 @@ func (c *Commands) removeIDPProviderFromDefaultLoginPolicy(ctx context.Context,
return events return events
} }
func (c *Commands) AddSecondFactorToDefaultLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType) (domain.SecondFactorType, *domain.ObjectDetails, error) { func (c *Commands) AddSecondFactorToDefaultLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType) (*domain.ObjectDetails, error) {
if !secondFactor.Valid() { instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
return domain.SecondFactorTypeUnspecified, nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-5m9fs", "Errors.IAM.LoginPolicy.MFA.Unspecified") cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddSecondFactorToDefaultLoginPolicy(instanceAgg, secondFactor))
}
secondFactorModel := NewInstanceSecondFactorWriteModel(ctx, secondFactor)
instanceAgg := InstanceAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
event, err := c.addSecondFactorToDefaultLoginPolicy(ctx, instanceAgg, secondFactorModel, secondFactor)
if err != nil {
return domain.SecondFactorTypeUnspecified, nil, err
}
pushedEvents, err := c.eventstore.Push(ctx, event)
if err != nil {
return domain.SecondFactorTypeUnspecified, nil, err
}
err = AppendAndReduce(secondFactorModel, pushedEvents...)
if err != nil {
return domain.SecondFactorTypeUnspecified, nil, err
}
return secondFactorModel.MFAType, writeModelToObjectDetails(&secondFactorModel.WriteModel), nil
}
func (c *Commands) addSecondFactorToDefaultLoginPolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, secondFactorModel *InstanceSecondFactorWriteModel, secondFactor domain.SecondFactorType) (eventstore.Command, error) {
err := c.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if secondFactorModel.State == domain.FactorStateActive { if err != nil {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-2B0ps", "Errors.IAM.LoginPolicy.MFA.AlreadyExists") return nil, err
} }
return instance.NewLoginPolicySecondFactorAddedEvent(ctx, instanceAgg, secondFactor), nil return pushedEventsToObjectDetails(pushedEvents), nil
} }
func (c *Commands) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType) (*domain.ObjectDetails, error) { func (c *Commands) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType) (*domain.ObjectDetails, error) {
@@ -268,38 +226,17 @@ func (c *Commands) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Context,
return writeModelToObjectDetails(&secondFactorModel.WriteModel), nil return writeModelToObjectDetails(&secondFactorModel.WriteModel), nil
} }
func (c *Commands) AddMultiFactorToDefaultLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType) (domain.MultiFactorType, *domain.ObjectDetails, error) { func (c *Commands) AddMultiFactorToDefaultLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType) (*domain.ObjectDetails, error) {
if !multiFactor.Valid() { instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
return domain.MultiFactorTypeUnspecified, nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-5m9fs", "Errors.IAM.LoginPolicy.MFA.Unspecified") cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddMultiFactorToDefaultLoginPolicy(instanceAgg, multiFactor))
}
multiFactorModel := NewInstanceMultiFactorWriteModel(ctx, multiFactor)
instanceAgg := InstanceAggregateFromWriteModel(&multiFactorModel.MultiFactorWriteModel.WriteModel)
event, err := c.addMultiFactorToDefaultLoginPolicy(ctx, instanceAgg, multiFactorModel, multiFactor)
if err != nil {
return domain.MultiFactorTypeUnspecified, nil, err
}
pushedEvents, err := c.eventstore.Push(ctx, event)
if err != nil {
return domain.MultiFactorTypeUnspecified, nil, err
}
err = AppendAndReduce(multiFactorModel, pushedEvents...)
if err != nil {
return domain.MultiFactorTypeUnspecified, nil, err
}
return multiFactorModel.MultiFactorWriteModel.MFAType, writeModelToObjectDetails(&multiFactorModel.WriteModel), nil
}
func (c *Commands) addMultiFactorToDefaultLoginPolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, multiFactorModel *InstanceMultiFactorWriteModel, multiFactor domain.MultiFactorType) (eventstore.Command, error) {
err := c.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if multiFactorModel.State == domain.FactorStateActive { pushedEvents, err := c.eventstore.Push(ctx, cmds...)
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-3M9od", "Errors.IAM.LoginPolicy.MFA.AlreadyExists") if err != nil {
return nil, err
} }
return pushedEventsToObjectDetails(pushedEvents), nil
return instance.NewLoginPolicyMultiFactorAddedEvent(ctx, instanceAgg, multiFactor), nil
} }
func (c *Commands) RemoveMultiFactorFromDefaultLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType) (*domain.ObjectDetails, error) { func (c *Commands) RemoveMultiFactorFromDefaultLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType) (*domain.ObjectDetails, error) {
@@ -336,3 +273,115 @@ func (c *Commands) defaultLoginPolicyWriteModelByID(ctx context.Context, writeMo
} }
return nil return nil
} }
func (c *Commands) getDefaultLoginPolicy(ctx context.Context) (*domain.LoginPolicy, error) {
policyWriteModel := NewInstanceLoginPolicyWriteModel(ctx)
err := c.eventstore.FilterToQueryReducer(ctx, policyWriteModel)
if err != nil {
return nil, err
}
policy := writeModelToLoginPolicy(&policyWriteModel.LoginPolicyWriteModel)
policy.Default = true
return policy, nil
}
func prepareAddDefaultLoginPolicy(
a *instance.Aggregate,
allowUsernamePassword bool,
allowRegister bool,
allowExternalIDP bool,
forceMFA bool,
hidePasswordReset bool,
ignoreUnknownUsernames bool,
passwordlessType domain.PasswordlessType,
defaultRedirectURI string,
passwordCheckLifetime time.Duration,
externalLoginCheckLifetime time.Duration,
mfaInitSkipLifetime time.Duration,
secondFactorCheckLifetime time.Duration,
multiFactorCheckLifetime time.Duration,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstanceLoginPolicyWriteModel(ctx)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-2B0ps", "Errors.Instance.LoginPolicy.AlreadyExists")
}
return []eventstore.Command{
instance.NewLoginPolicyAddedEvent(ctx, &a.Aggregate,
allowUsernamePassword,
allowRegister,
allowExternalIDP,
forceMFA,
hidePasswordReset,
ignoreUnknownUsernames,
passwordlessType,
defaultRedirectURI,
passwordCheckLifetime,
externalLoginCheckLifetime,
mfaInitSkipLifetime,
secondFactorCheckLifetime,
multiFactorCheckLifetime,
),
}, nil
}, nil
}
}
func prepareAddSecondFactorToDefaultLoginPolicy(a *instance.Aggregate, factor domain.SecondFactorType) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if !factor.Valid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-5m9fs", "Errors.Instance.LoginPolicy.MFA.Unspecified")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstanceSecondFactorWriteModel(ctx, factor)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.FactorStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-2B0ps", "Errors.Instance.MFA.AlreadyExists")
}
return []eventstore.Command{
instance.NewLoginPolicySecondFactorAddedEvent(ctx, &a.Aggregate, factor),
}, nil
}, nil
}
}
func prepareAddMultiFactorToDefaultLoginPolicy(a *instance.Aggregate, factor domain.MultiFactorType) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if !factor.Valid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-5m9fs", "Errors.Instance.LoginPolicy.MFA.Unspecified")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstanceMultiFactorWriteModel(ctx, factor)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.FactorStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-3M9od", "Errors.Instance.MFA.AlreadyExists")
}
return []eventstore.Command{
instance.NewLoginPolicyMultiFactorAddedEvent(ctx, &a.Aggregate, factor),
}, nil
}, nil
}
}

View File

@@ -24,10 +24,22 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
policy *domain.LoginPolicy allowUsernamePassword bool
allowRegister bool
allowExternalIDP bool
forceMFA bool
hidePasswordReset bool
ignoreUnknownUsernames bool
passwordlessType domain.PasswordlessType
defaultRedirectURI string
passwordCheckLifetime time.Duration
externalLoginCheckLifetime time.Duration
mfaInitSkipLifetime time.Duration
secondFactorCheckLifetime time.Duration
multiFactorCheckLifetime time.Duration
} }
type res struct { type res struct {
want *domain.LoginPolicy want *domain.ObjectDetails
err func(error) bool err func(error) bool
} }
tests := []struct { tests := []struct {
@@ -65,11 +77,9 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
policy: &domain.LoginPolicy{ allowRegister: true,
AllowRegister: true, allowUsernamePassword: true,
AllowUsernamePassword: true, passwordlessType: domain.PasswordlessTypeAllowed,
PasswordlessType: domain.PasswordlessTypeAllowed,
},
}, },
res: res{ res: res{
err: caos_errs.IsErrorAlreadyExists, err: caos_errs.IsErrorAlreadyExists,
@@ -108,43 +118,24 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
policy: &domain.LoginPolicy{ allowRegister: true,
AllowRegister: true, allowUsernamePassword: true,
AllowUsernamePassword: true, allowExternalIDP: true,
AllowExternalIDP: true, forceMFA: true,
ForceMFA: true, hidePasswordReset: true,
HidePasswordReset: true, ignoreUnknownUsernames: true,
IgnoreUnknownUsernames: true, passwordlessType: domain.PasswordlessTypeAllowed,
PasswordlessType: domain.PasswordlessTypeAllowed, defaultRedirectURI: "https://example.com/redirect",
DefaultRedirectURI: "https://example.com/redirect", passwordCheckLifetime: time.Hour * 1,
PasswordCheckLifetime: time.Hour * 1, externalLoginCheckLifetime: time.Hour * 2,
ExternalLoginCheckLifetime: time.Hour * 2, mfaInitSkipLifetime: time.Hour * 3,
MFAInitSkipLifetime: time.Hour * 3, secondFactorCheckLifetime: time.Hour * 4,
SecondFactorCheckLifetime: time.Hour * 4, multiFactorCheckLifetime: time.Hour * 5,
MultiFactorCheckLifetime: time.Hour * 5,
},
}, },
res: res{ res: res{
want: &domain.LoginPolicy{ want: &domain.ObjectDetails{
ObjectRoot: models.ObjectRoot{
InstanceID: "INSTANCE",
AggregateID: "INSTANCE",
ResourceOwner: "INSTANCE", ResourceOwner: "INSTANCE",
}, },
AllowRegister: true,
AllowUsernamePassword: true,
AllowExternalIDP: true,
ForceMFA: true,
HidePasswordReset: true,
IgnoreUnknownUsernames: true,
PasswordlessType: domain.PasswordlessTypeAllowed,
DefaultRedirectURI: "https://example.com/redirect",
PasswordCheckLifetime: time.Hour * 1,
ExternalLoginCheckLifetime: time.Hour * 2,
MFAInitSkipLifetime: time.Hour * 3,
SecondFactorCheckLifetime: time.Hour * 4,
MultiFactorCheckLifetime: time.Hour * 5,
},
}, },
}, },
} }
@@ -153,7 +144,22 @@ func TestCommandSide_AddDefaultLoginPolicy(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore,
} }
got, err := r.AddDefaultLoginPolicy(tt.args.ctx, tt.args.policy) got, err := r.AddDefaultLoginPolicy(
tt.args.ctx,
tt.args.allowUsernamePassword,
tt.args.allowRegister,
tt.args.allowExternalIDP,
tt.args.forceMFA,
tt.args.hidePasswordReset,
tt.args.ignoreUnknownUsernames,
tt.args.passwordlessType,
tt.args.defaultRedirectURI,
tt.args.passwordCheckLifetime,
tt.args.externalLoginCheckLifetime,
tt.args.mfaInitSkipLifetime,
tt.args.secondFactorCheckLifetime,
tt.args.multiFactorCheckLifetime,
)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }
@@ -1046,7 +1052,7 @@ func TestCommandSide_AddSecondFactorDefaultLoginPolicy(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore,
} }
_, got, err := r.AddSecondFactorToDefaultLoginPolicy(tt.args.ctx, tt.args.factor) got, err := r.AddSecondFactorToDefaultLoginPolicy(tt.args.ctx, tt.args.factor)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }
@@ -1282,7 +1288,7 @@ func TestCommandSide_AddMultiFactorDefaultLoginPolicy(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore,
} }
_, got, err := r.AddMultiFactorToDefaultLoginPolicy(tt.args.ctx, tt.args.factor) got, err := r.AddMultiFactorToDefaultLoginPolicy(tt.args.ctx, tt.args.factor)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@@ -3,6 +3,7 @@ package command
import ( import (
"context" "context"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
@@ -93,3 +94,33 @@ func (c *Commands) defaultMailTemplateWriteModelByID(ctx context.Context) (polic
} }
return writeModel, nil return writeModel, nil
} }
func prepareAddDefaultEmailTemplate(
a *instance.Aggregate,
template []byte,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if template == nil {
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-fm9sd", "Errors.Instance.MailTemplate.Invalid")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstanceMailTemplateWriteModel(ctx)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-5n8fs", "Errors.Instance.MailTemplate.AlreadyExists")
}
return []eventstore.Command{
instance.NewMailTemplateAddedEvent(ctx, &a.Aggregate,
template,
),
}, nil
}, nil
}
}

View File

@@ -3,6 +3,8 @@ package command
import ( import (
"context" "context"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
@@ -10,36 +12,17 @@ import (
"github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/telemetry/tracing"
) )
func (c *Commands) AddDefaultPasswordAgePolicy(ctx context.Context, policy *domain.PasswordAgePolicy) (*domain.PasswordAgePolicy, error) { func (c *Commands) AddDefaultPasswordAgePolicy(ctx context.Context, expireWarnDays, maxAgeDays uint64) (*domain.ObjectDetails, error) {
addedPolicy := NewInstancePasswordAgePolicyWriteModel(ctx) instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
instanceAgg := InstanceAggregateFromWriteModel(&addedPolicy.WriteModel) cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddDefaultPasswordAgePolicy(instanceAgg, expireWarnDays, maxAgeDays))
event, err := c.addDefaultPasswordAgePolicy(ctx, instanceAgg, addedPolicy, policy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
pushedEvents, err := c.eventstore.Push(ctx, event)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = AppendAndReduce(addedPolicy, pushedEvents...) return pushedEventsToObjectDetails(pushedEvents), nil
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(&addedPolicy.PasswordAgePolicyWriteModel), nil
}
func (c *Commands) addDefaultPasswordAgePolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, addedPolicy *InstancePasswordAgePolicyWriteModel, policy *domain.PasswordAgePolicy) (eventstore.Command, error) {
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-Lk0dS", "Errors.IAM.PasswordAgePolicy.AlreadyExists")
}
return instance.NewPasswordAgePolicyAddedEvent(ctx, instanceAgg, policy.ExpireWarnDays, policy.MaxAgeDays), nil
} }
func (c *Commands) ChangeDefaultPasswordAgePolicy(ctx context.Context, policy *domain.PasswordAgePolicy) (*domain.PasswordAgePolicy, error) { func (c *Commands) ChangeDefaultPasswordAgePolicy(ctx context.Context, policy *domain.PasswordAgePolicy) (*domain.PasswordAgePolicy, error) {
@@ -80,3 +63,32 @@ func (c *Commands) defaultPasswordAgePolicyWriteModelByID(ctx context.Context) (
} }
return writeModel, nil return writeModel, nil
} }
func prepareAddDefaultPasswordAgePolicy(
a *instance.Aggregate,
expireWarnDays,
maxAgeDays uint64,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstancePasswordAgePolicyWriteModel(ctx)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-Lk0dS", "Errors.Instance.PasswordAgePolicy.AlreadyExists")
}
return []eventstore.Command{
instance.NewPasswordAgePolicyAddedEvent(ctx, &a.Aggregate,
expireWarnDays,
maxAgeDays,
),
}, nil
}, nil
}
}

View File

@@ -22,10 +22,11 @@ func TestCommandSide_AddDefaultPasswordAgePolicy(t *testing.T) {
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
policy *domain.PasswordAgePolicy maxAgeDays uint64
expireWarnDays uint64
} }
type res struct { type res struct {
want *domain.PasswordAgePolicy want *domain.ObjectDetails
err func(error) bool err func(error) bool
} }
tests := []struct { tests := []struct {
@@ -52,10 +53,8 @@ func TestCommandSide_AddDefaultPasswordAgePolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
policy: &domain.PasswordAgePolicy{ maxAgeDays: 365,
MaxAgeDays: 365, expireWarnDays: 10,
ExpireWarnDays: 10,
},
}, },
res: res{ res: res{
err: caos_errs.IsErrorAlreadyExists, err: caos_errs.IsErrorAlreadyExists,
@@ -83,21 +82,13 @@ func TestCommandSide_AddDefaultPasswordAgePolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
policy: &domain.PasswordAgePolicy{ expireWarnDays: 365,
ExpireWarnDays: 365, maxAgeDays: 10,
MaxAgeDays: 10,
},
}, },
res: res{ res: res{
want: &domain.PasswordAgePolicy{ want: &domain.ObjectDetails{
ObjectRoot: models.ObjectRoot{
InstanceID: "INSTANCE",
AggregateID: "INSTANCE",
ResourceOwner: "INSTANCE", ResourceOwner: "INSTANCE",
}, },
ExpireWarnDays: 365,
MaxAgeDays: 10,
},
}, },
}, },
} }
@@ -106,7 +97,7 @@ func TestCommandSide_AddDefaultPasswordAgePolicy(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore,
} }
got, err := r.AddDefaultPasswordAgePolicy(tt.args.ctx, tt.args.policy) got, err := r.AddDefaultPasswordAgePolicy(tt.args.ctx, tt.args.expireWarnDays, tt.args.maxAgeDays)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@@ -3,6 +3,8 @@ package command
import ( import (
"context" "context"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
@@ -10,53 +12,17 @@ import (
"github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/telemetry/tracing"
) )
func (c *Commands) getDefaultPasswordComplexityPolicy(ctx context.Context) (*domain.PasswordComplexityPolicy, error) { func (c *Commands) AddDefaultPasswordComplexityPolicy(ctx context.Context, minLength uint64, hasLowercase, hasUppercase, hasNumber, hasSymbol bool) (*domain.ObjectDetails, error) {
policyWriteModel := NewInstancePasswordComplexityPolicyWriteModel(ctx) instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
err := c.eventstore.FilterToQueryReducer(ctx, policyWriteModel) cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddDefaultPasswordComplexityPolicy(instanceAgg, minLength, hasLowercase, hasUppercase, hasNumber, hasSymbol))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !policyWriteModel.State.Exists() { pushedEvents, err := c.eventstore.Push(ctx, cmds...)
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-M0gsf", "Errors.IAM.PasswordComplexityPolicy.NotFound")
}
policy := writeModelToPasswordComplexityPolicy(&policyWriteModel.PasswordComplexityPolicyWriteModel)
policy.Default = true
return policy, nil
}
func (c *Commands) AddDefaultPasswordComplexityPolicy(ctx context.Context, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) {
addedPolicy := NewInstancePasswordComplexityPolicyWriteModel(ctx)
instanceAgg := InstanceAggregateFromWriteModel(&addedPolicy.WriteModel)
events, err := c.addDefaultPasswordComplexityPolicy(ctx, instanceAgg, addedPolicy, policy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return pushedEventsToObjectDetails(pushedEvents), nil
pushedEvents, err := c.eventstore.Push(ctx, events)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(&addedPolicy.PasswordComplexityPolicyWriteModel), nil
}
func (c *Commands) addDefaultPasswordComplexityPolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, addedPolicy *InstancePasswordComplexityPolicyWriteModel, policy *domain.PasswordComplexityPolicy) (eventstore.Command, error) {
if err := policy.IsValid(); err != nil {
return nil, err
}
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-Lk0dS", "Errors.IAM.PasswordComplexityPolicy.AlreadyExists")
}
return instance.NewPasswordComplexityPolicyAddedEvent(ctx, instanceAgg, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol), nil
} }
func (c *Commands) ChangeDefaultPasswordComplexityPolicy(ctx context.Context, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) { func (c *Commands) ChangeDefaultPasswordComplexityPolicy(ctx context.Context, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) {
@@ -88,6 +54,58 @@ func (c *Commands) ChangeDefaultPasswordComplexityPolicy(ctx context.Context, po
return writeModelToPasswordComplexityPolicy(&existingPolicy.PasswordComplexityPolicyWriteModel), nil return writeModelToPasswordComplexityPolicy(&existingPolicy.PasswordComplexityPolicyWriteModel), nil
} }
func prepareAddDefaultPasswordComplexityPolicy(
a *instance.Aggregate,
minLength uint64,
hasLowercase,
hasUppercase,
hasNumber,
hasSymbol bool,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
if minLength == 0 || minLength > 72 {
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-Lsp0e", "Errors.Instance.PasswordComplexityPolicy.MinLengthNotAllowed")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstancePasswordComplexityPolicyWriteModel(ctx)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-Lk0dS", "Errors.Instance.PasswordComplexityPolicy.AlreadyExists")
}
return []eventstore.Command{
instance.NewPasswordComplexityPolicyAddedEvent(ctx, &a.Aggregate,
minLength,
hasLowercase,
hasUppercase,
hasNumber,
hasSymbol,
),
}, nil
}, nil
}
}
func (c *Commands) getDefaultPasswordComplexityPolicy(ctx context.Context) (*domain.PasswordComplexityPolicy, error) {
policyWriteModel := NewInstancePasswordComplexityPolicyWriteModel(ctx)
err := c.eventstore.FilterToQueryReducer(ctx, policyWriteModel)
if err != nil {
return nil, err
}
if !policyWriteModel.State.Exists() {
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-M0gsf", "Errors.IAM.PasswordComplexityPolicy.NotFound")
}
policy := writeModelToPasswordComplexityPolicy(&policyWriteModel.PasswordComplexityPolicyWriteModel)
policy.Default = true
return policy, nil
}
func (c *Commands) defaultPasswordComplexityPolicyWriteModelByID(ctx context.Context) (policy *InstancePasswordComplexityPolicyWriteModel, err error) { func (c *Commands) defaultPasswordComplexityPolicyWriteModelByID(ctx context.Context) (policy *InstancePasswordComplexityPolicyWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()

View File

@@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
@@ -21,10 +22,14 @@ func TestCommandSide_AddDefaultPasswordComplexityPolicy(t *testing.T) {
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
policy *domain.PasswordComplexityPolicy minLength uint64
hasLowercase bool
hasUppercase bool
hasNumber bool
hasSymbol bool
} }
type res struct { type res struct {
want *domain.PasswordComplexityPolicy want *domain.ObjectDetails
err func(error) bool err func(error) bool
} }
tests := []struct { tests := []struct {
@@ -42,13 +47,11 @@ func TestCommandSide_AddDefaultPasswordComplexityPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
policy: &domain.PasswordComplexityPolicy{ minLength: 0,
MinLength: 0, hasUppercase: true,
HasUppercase: true, hasLowercase: true,
HasLowercase: true, hasNumber: true,
HasNumber: true, hasSymbol: true,
HasSymbol: true,
},
}, },
res: res{ res: res{
err: caos_errs.IsErrorInvalidArgument, err: caos_errs.IsErrorInvalidArgument,
@@ -72,13 +75,11 @@ func TestCommandSide_AddDefaultPasswordComplexityPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
policy: &domain.PasswordComplexityPolicy{ minLength: 8,
MinLength: 8, hasUppercase: true,
HasUppercase: true, hasLowercase: true,
HasLowercase: true, hasNumber: true,
HasNumber: true, hasSymbol: true,
HasSymbol: true,
},
}, },
res: res{ res: res{
err: caos_errs.IsErrorAlreadyExists, err: caos_errs.IsErrorAlreadyExists,
@@ -106,27 +107,16 @@ func TestCommandSide_AddDefaultPasswordComplexityPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
policy: &domain.PasswordComplexityPolicy{ minLength: 8,
MinLength: 8, hasUppercase: true,
HasUppercase: true, hasLowercase: true,
HasLowercase: true, hasNumber: true,
HasNumber: true, hasSymbol: true,
HasSymbol: true,
},
}, },
res: res{ res: res{
want: &domain.PasswordComplexityPolicy{ want: &domain.ObjectDetails{
ObjectRoot: models.ObjectRoot{
InstanceID: "INSTANCE",
AggregateID: "INSTANCE",
ResourceOwner: "INSTANCE", ResourceOwner: "INSTANCE",
}, },
MinLength: 8,
HasUppercase: true,
HasLowercase: true,
HasNumber: true,
HasSymbol: true,
},
}, },
}, },
} }
@@ -135,7 +125,7 @@ func TestCommandSide_AddDefaultPasswordComplexityPolicy(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore,
} }
got, err := r.AddDefaultPasswordComplexityPolicy(tt.args.ctx, tt.args.policy) got, err := r.AddDefaultPasswordComplexityPolicy(tt.args.ctx, tt.args.minLength, tt.args.hasLowercase, tt.args.hasUppercase, tt.args.hasNumber, tt.args.hasSymbol)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@@ -3,6 +3,8 @@ package command
import ( import (
"context" "context"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
@@ -10,35 +12,17 @@ import (
"github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/telemetry/tracing"
) )
func (c *Commands) AddDefaultLockoutPolicy(ctx context.Context, policy *domain.LockoutPolicy) (*domain.LockoutPolicy, error) { func (c *Commands) AddDefaultLockoutPolicy(ctx context.Context, maxAttempts uint64, showLockoutFailure bool) (*domain.ObjectDetails, error) {
addedPolicy := NewInstanceLockoutPolicyWriteModel(ctx) instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
instanceAgg := InstanceAggregateFromWriteModel(&addedPolicy.WriteModel) cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddDefaultLockoutPolicy(instanceAgg, maxAttempts, showLockoutFailure))
event, err := c.addDefaultLockoutPolicy(ctx, instanceAgg, addedPolicy, policy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pushedEvents, err := c.eventstore.Push(ctx, event) pushedEvents, err := c.eventstore.Push(ctx, cmds...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = AppendAndReduce(addedPolicy, pushedEvents...) return pushedEventsToObjectDetails(pushedEvents), nil
if err != nil {
return nil, err
}
return writeModelToLockoutPolicy(&addedPolicy.LockoutPolicyWriteModel), nil
}
func (c *Commands) addDefaultLockoutPolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, addedPolicy *InstanceLockoutPolicyWriteModel, policy *domain.LockoutPolicy) (eventstore.Command, error) {
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-0olDf", "Errors.IAM.LockoutPolicy.AlreadyExists")
}
return instance.NewLockoutPolicyAddedEvent(ctx, instanceAgg, policy.MaxPasswordAttempts, policy.ShowLockOutFailures), nil
} }
func (c *Commands) ChangeDefaultLockoutPolicy(ctx context.Context, policy *domain.LockoutPolicy) (*domain.LockoutPolicy, error) { func (c *Commands) ChangeDefaultLockoutPolicy(ctx context.Context, policy *domain.LockoutPolicy) (*domain.LockoutPolicy, error) {
@@ -78,3 +62,29 @@ func (c *Commands) defaultLockoutPolicyWriteModelByID(ctx context.Context) (poli
} }
return writeModel, nil return writeModel, nil
} }
func prepareAddDefaultLockoutPolicy(
a *instance.Aggregate,
maxAttempts uint64,
showLockoutFailure bool,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstanceLockoutPolicyWriteModel(ctx)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-0olDf", "Errors.Instance.LockoutPolicy.AlreadyExists")
}
return []eventstore.Command{
instance.NewLockoutPolicyAddedEvent(ctx, &a.Aggregate, maxAttempts, showLockoutFailure),
}, nil
}, nil
}
}

View File

@@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
@@ -21,10 +22,11 @@ func TestCommandSide_AddDefaultLockoutPolicy(t *testing.T) {
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
policy *domain.LockoutPolicy maxPasswordAttempts uint64
showLockOutFailures bool
} }
type res struct { type res struct {
want *domain.LockoutPolicy want *domain.ObjectDetails
err func(error) bool err func(error) bool
} }
tests := []struct { tests := []struct {
@@ -51,10 +53,8 @@ func TestCommandSide_AddDefaultLockoutPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
policy: &domain.LockoutPolicy{ maxPasswordAttempts: 10,
MaxPasswordAttempts: 10, showLockOutFailures: true,
ShowLockOutFailures: true,
},
}, },
res: res{ res: res{
err: caos_errs.IsErrorAlreadyExists, err: caos_errs.IsErrorAlreadyExists,
@@ -82,21 +82,13 @@ func TestCommandSide_AddDefaultLockoutPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
policy: &domain.LockoutPolicy{ maxPasswordAttempts: 10,
MaxPasswordAttempts: 10, showLockOutFailures: true,
ShowLockOutFailures: true,
},
}, },
res: res{ res: res{
want: &domain.LockoutPolicy{ want: &domain.ObjectDetails{
ObjectRoot: models.ObjectRoot{
InstanceID: "INSTANCE",
AggregateID: "INSTANCE",
ResourceOwner: "INSTANCE", ResourceOwner: "INSTANCE",
}, },
MaxPasswordAttempts: 10,
ShowLockOutFailures: true,
},
}, },
}, },
} }
@@ -105,7 +97,7 @@ func TestCommandSide_AddDefaultLockoutPolicy(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore,
} }
got, err := r.AddDefaultLockoutPolicy(tt.args.ctx, tt.args.policy) got, err := r.AddDefaultLockoutPolicy(tt.args.ctx, tt.args.maxPasswordAttempts, tt.args.showLockOutFailures)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@@ -3,6 +3,8 @@ package command
import ( import (
"context" "context"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore"
@@ -10,49 +12,17 @@ import (
"github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/telemetry/tracing"
) )
func (c *Commands) getDefaultPrivacyPolicy(ctx context.Context) (*domain.PrivacyPolicy, error) { func (c *Commands) AddDefaultPrivacyPolicy(ctx context.Context, tosLink, privacyLink, helpLink string) (*domain.ObjectDetails, error) {
policyWriteModel := NewInstancePrivacyPolicyWriteModel(ctx) instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
err := c.eventstore.FilterToQueryReducer(ctx, policyWriteModel) cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddDefaultPrivacyPolicy(instanceAgg, tosLink, privacyLink, helpLink))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !policyWriteModel.State.Exists() { pushedEvents, err := c.eventstore.Push(ctx, cmds...)
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-559os", "Errors.IAM.PrivacyPolicy.NotFound")
}
policy := writeModelToPrivacyPolicy(&policyWriteModel.PrivacyPolicyWriteModel)
policy.Default = true
return policy, nil
}
func (c *Commands) AddDefaultPrivacyPolicy(ctx context.Context, policy *domain.PrivacyPolicy) (*domain.PrivacyPolicy, error) {
addedPolicy := NewInstancePrivacyPolicyWriteModel(ctx)
instanceAgg := InstanceAggregateFromWriteModel(&addedPolicy.WriteModel)
events, err := c.addDefaultPrivacyPolicy(ctx, instanceAgg, addedPolicy, policy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return pushedEventsToObjectDetails(pushedEvents), nil
pushedEvents, err := c.eventstore.Push(ctx, events)
if err != nil {
return nil, err
}
err = AppendAndReduce(addedPolicy, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToPrivacyPolicy(&addedPolicy.PrivacyPolicyWriteModel), nil
}
func (c *Commands) addDefaultPrivacyPolicy(ctx context.Context, instanceAgg *eventstore.Aggregate, addedPolicy *InstancePrivacyPolicyWriteModel, policy *domain.PrivacyPolicy) (eventstore.Command, error) {
err := c.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-M00rJ", "Errors.IAM.PrivacyPolicy.AlreadyExists")
}
return instance.NewPrivacyPolicyAddedEvent(ctx, instanceAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink), nil
} }
func (c *Commands) ChangeDefaultPrivacyPolicy(ctx context.Context, policy *domain.PrivacyPolicy) (*domain.PrivacyPolicy, error) { func (c *Commands) ChangeDefaultPrivacyPolicy(ctx context.Context, policy *domain.PrivacyPolicy) (*domain.PrivacyPolicy, error) {
@@ -91,3 +61,44 @@ func (c *Commands) defaultPrivacyPolicyWriteModelByID(ctx context.Context) (poli
} }
return writeModel, nil return writeModel, nil
} }
func (c *Commands) getDefaultPrivacyPolicy(ctx context.Context) (*domain.PrivacyPolicy, error) {
policyWriteModel := NewInstancePrivacyPolicyWriteModel(ctx)
err := c.eventstore.FilterToQueryReducer(ctx, policyWriteModel)
if err != nil {
return nil, err
}
if !policyWriteModel.State.Exists() {
return nil, caos_errs.ThrowInvalidArgument(nil, "INSTANCE-559os", "Errors.IAM.PrivacyPolicy.NotFound")
}
policy := writeModelToPrivacyPolicy(&policyWriteModel.PrivacyPolicyWriteModel)
policy.Default = true
return policy, nil
}
func prepareAddDefaultPrivacyPolicy(
a *instance.Aggregate,
tosLink,
privacyLink,
helpLink string,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel := NewInstancePrivacyPolicyWriteModel(ctx)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return nil, err
}
writeModel.AppendEvents(events...)
if err = writeModel.Reduce(); err != nil {
return nil, err
}
if writeModel.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "INSTANCE-M00rJ", "Errors.Instance.PrivacyPolicy.AlreadyExists")
}
return []eventstore.Command{
instance.NewPrivacyPolicyAddedEvent(ctx, &a.Aggregate, tosLink, privacyLink, helpLink),
}, nil
}, nil
}
}

View File

@@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
@@ -22,10 +23,12 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
policy *domain.PrivacyPolicy tosLink string
privacyLink string
helpLink string
} }
type res struct { type res struct {
want *domain.PrivacyPolicy want *domain.ObjectDetails
err func(error) bool err func(error) bool
} }
tests := []struct { tests := []struct {
@@ -53,11 +56,9 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
policy: &domain.PrivacyPolicy{ tosLink: "TOSLink",
TOSLink: "TOSLink", privacyLink: "PrivacyLink",
PrivacyLink: "PrivacyLink", helpLink: "HelpLink",
HelpLink: "HelpLink",
},
}, },
res: res{ res: res{
err: caos_errs.IsErrorAlreadyExists, err: caos_errs.IsErrorAlreadyExists,
@@ -86,23 +87,14 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
policy: &domain.PrivacyPolicy{ tosLink: "TOSLink",
TOSLink: "TOSLink", privacyLink: "PrivacyLink",
PrivacyLink: "PrivacyLink", helpLink: "HelpLink",
HelpLink: "HelpLink",
},
}, },
res: res{ res: res{
want: &domain.PrivacyPolicy{ want: &domain.ObjectDetails{
ObjectRoot: models.ObjectRoot{
InstanceID: "INSTANCE",
AggregateID: "INSTANCE",
ResourceOwner: "INSTANCE", ResourceOwner: "INSTANCE",
}, },
TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
},
}, },
}, },
{ {
@@ -128,23 +120,14 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
}, },
args: args{ args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
policy: &domain.PrivacyPolicy{ tosLink: "",
TOSLink: "", privacyLink: "",
PrivacyLink: "", helpLink: "",
HelpLink: "",
},
}, },
res: res{ res: res{
want: &domain.PrivacyPolicy{ want: &domain.ObjectDetails{
ObjectRoot: models.ObjectRoot{
InstanceID: "INSTANCE",
AggregateID: "INSTANCE",
ResourceOwner: "INSTANCE", ResourceOwner: "INSTANCE",
}, },
TOSLink: "",
PrivacyLink: "",
HelpLink: "",
},
}, },
}, },
} }
@@ -153,7 +136,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore,
} }
got, err := r.AddDefaultPrivacyPolicy(tt.args.ctx, tt.args.policy) got, err := r.AddDefaultPrivacyPolicy(tt.args.ctx, tt.args.tosLink, tt.args.privacyLink, tt.args.helpLink)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@@ -1,25 +0,0 @@
package command
import (
"context"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/instance"
)
func AddPrivacyPolicy(
a *instance.Aggregate,
tosLink,
privacyLink,
helpLink string,
) preparation.Validation {
return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
//TODO: check if already exists
return []eventstore.Command{
instance.NewPrivacyPolicyAddedEvent(ctx, &a.Aggregate, tosLink, privacyLink, helpLink),
}, nil
}, nil
}
}

View File

@@ -15,7 +15,7 @@ import (
func (c *Commands) AddSecretGeneratorConfig(ctx context.Context, typ domain.SecretGeneratorType, config *crypto.GeneratorConfig) (*domain.ObjectDetails, error) { func (c *Commands) AddSecretGeneratorConfig(ctx context.Context, typ domain.SecretGeneratorType, config *crypto.GeneratorConfig) (*domain.ObjectDetails, error) {
agg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID()) agg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, addSecretGeneratorConfig(agg, typ, config)) cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddSecretGeneratorConfig(agg, typ, config))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -31,7 +31,7 @@ func (c *Commands) AddSecretGeneratorConfig(ctx context.Context, typ domain.Secr
}, nil }, nil
} }
func addSecretGeneratorConfig(a *instance.Aggregate, typ domain.SecretGeneratorType, config *crypto.GeneratorConfig) preparation.Validation { func prepareAddSecretGeneratorConfig(a *instance.Aggregate, typ domain.SecretGeneratorType, config *crypto.GeneratorConfig) preparation.Validation {
return func() (preparation.CreateCommands, error) { return func() (preparation.CreateCommands, error) {
if !typ.Valid() { if !typ.Valid() {
return nil, errors.ThrowInvalidArgument(nil, "V2-FGqVj", "Errors.InvalidArgument") return nil, errors.ThrowInvalidArgument(nil, "V2-FGqVj", "Errors.InvalidArgument")