feat: org and policies commands (#1167)

* add setup steps

* refactoring

* omitempty

* cleanup

* begin org

* create org

* setup org

* setup org

* merge

* fixes

* fixes

* fixes

* add project

* add oidc application

* fix app creation

* add resourceOwner to writemodels

* resource owner

* cleanup

* global org, iam project and iam member in setup

* logs

* logs

* logs

* cleanup

* Update internal/v2/command/project.go

Co-authored-by: Fabi <[email protected]>

* check project state

* add org domain commands

* add org status changes and member commands

* fixes

* policies

* login policy

* fix iam project event

* mapper

* label policy

* change to command

* fix

* fix

* handle change event differently and lot of fixes

* fixes

* changedEvent handling

Co-authored-by: Fabi <[email protected]>
This commit is contained in:
Livio Amstutz
2021-01-18 11:24:15 +01:00
committed by GitHub
co-authored by Fabi
parent 959530ddad
commit 3eb909c4b4
88 changed files with 2586 additions and 518 deletions
+25 -13
View File
@@ -2,16 +2,18 @@ package command
import (
"context"
global_model "github.com/caos/zitadel/internal/model"
webauthn_helper "github.com/caos/zitadel/internal/webauthn"
"github.com/caos/zitadel/internal/api/http"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/id"
global_model "github.com/caos/zitadel/internal/model"
"github.com/caos/zitadel/internal/telemetry/tracing"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/org"
usr_repo "github.com/caos/zitadel/internal/v2/repository/user"
webauthn_helper "github.com/caos/zitadel/internal/webauthn"
)
type CommandSide struct {
@@ -21,18 +23,20 @@ type CommandSide struct {
idpConfigSecretCrypto crypto.Crypto
userPasswordAlg crypto.HashAlgorithm
initializeUserCode crypto.Generator
emailVerificationCode crypto.Generator
phoneVerificationCode crypto.Generator
passwordVerificationCode crypto.Generator
machineKeyAlg crypto.EncryptionAlgorithm
machineKeySize int
userPasswordAlg crypto.HashAlgorithm
initializeUserCode crypto.Generator
emailVerificationCode crypto.Generator
phoneVerificationCode crypto.Generator
passwordVerificationCode crypto.Generator
machineKeyAlg crypto.EncryptionAlgorithm
machineKeySize int
applicationSecretGenerator crypto.Generator
domainVerificationAlg *crypto.AESCrypto
domainVerificationGenerator crypto.Generator
domainVerificationValidator func(domain, token, verifier string, checkType http.CheckType) error
//TODO: remove global model, or move to domain
multifactors global_model.Multifactors
applicationSecretGenerator crypto.Generator
webauthn *webauthn_helper.WebAuthN
multifactors global_model.Multifactors
webauthn *webauthn_helper.WebAuthN
}
type Config struct {
@@ -47,6 +51,7 @@ func StartCommandSide(config *Config) (repo *CommandSide, err error) {
iamDomain: config.SystemDefaults.Domain,
}
iam_repo.RegisterEventMappers(repo.eventstore)
org.RegisterEventMappers(repo.eventstore)
usr_repo.RegisterEventMappers(repo.eventstore)
//TODO: simplify!!!!
@@ -78,6 +83,13 @@ func StartCommandSide(config *Config) (repo *CommandSide, err error) {
}
passwordAlg := crypto.NewBCrypt(config.SystemDefaults.SecretGenerators.PasswordSaltCost)
repo.applicationSecretGenerator = crypto.NewHashGenerator(config.SystemDefaults.SecretGenerators.ClientSecretGenerator, passwordAlg)
repo.domainVerificationAlg, err = crypto.NewAESCrypto(config.SystemDefaults.DomainVerification.VerificationKey)
if err != nil {
return nil, err
}
repo.domainVerificationGenerator = crypto.NewEncryptionGenerator(config.SystemDefaults.DomainVerification.VerificationGenerator, repo.domainVerificationAlg)
repo.domainVerificationValidator = http.ValidateDomain
web, err := webauthn_helper.StartServer(config.SystemDefaults.WebAuthN)
if err != nil {
return nil, err
+13 -13
View File
@@ -33,9 +33,9 @@ func memberWriteModelToMember(writeModel *MemberWriteModel) *domain.Member {
}
}
func writeModelToLoginPolicy(wm *IAMLoginPolicyWriteModel) *domain.LoginPolicy {
func writeModelToLoginPolicy(wm *LoginPolicyWriteModel) *domain.LoginPolicy {
return &domain.LoginPolicy{
ObjectRoot: writeModelToObjectRoot(wm.LoginPolicyWriteModel.WriteModel),
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
AllowUsernamePassword: wm.AllowUserNamePassword,
AllowRegister: wm.AllowRegister,
AllowExternalIdp: wm.AllowExternalIDP,
@@ -44,9 +44,9 @@ func writeModelToLoginPolicy(wm *IAMLoginPolicyWriteModel) *domain.LoginPolicy {
}
}
func writeModelToLabelPolicy(wm *IAMLabelPolicyWriteModel) *domain.LabelPolicy {
func writeModelToLabelPolicy(wm *LabelPolicyWriteModel) *domain.LabelPolicy {
return &domain.LabelPolicy{
ObjectRoot: writeModelToObjectRoot(wm.LabelPolicyWriteModel.WriteModel),
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
PrimaryColor: wm.PrimaryColor,
SecondaryColor: wm.SecondaryColor,
}
@@ -59,28 +59,28 @@ func writeModelToOrgIAMPolicy(wm *IAMOrgIAMPolicyWriteModel) *domain.OrgIAMPolic
}
}
func writeModelToPasswordAgePolicy(wm *IAMPasswordAgePolicyWriteModel) *domain.PasswordAgePolicy {
func writeModelToPasswordAgePolicy(wm *PasswordAgePolicyWriteModel) *domain.PasswordAgePolicy {
return &domain.PasswordAgePolicy{
ObjectRoot: writeModelToObjectRoot(wm.PasswordAgePolicyWriteModel.WriteModel),
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
MaxAgeDays: wm.MaxAgeDays,
ExpireWarnDays: wm.ExpireWarnDays,
}
}
func writeModelToPasswordComplexityPolicy(wm *IAMPasswordComplexityPolicyWriteModel) *domain.PasswordComplexityPolicy {
func writeModelToPasswordComplexityPolicy(wm *PasswordComplexityPolicyWriteModel) *domain.PasswordComplexityPolicy {
return &domain.PasswordComplexityPolicy{
ObjectRoot: writeModelToObjectRoot(wm.PasswordComplexityPolicyWriteModel.WriteModel),
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
MinLength: wm.MinLength,
HasLowercase: wm.HasLowercase,
HasUppercase: wm.HasUpperCase,
HasUppercase: wm.HasUppercase,
HasNumber: wm.HasNumber,
HasSymbol: wm.HasSymbol,
}
}
func writeModelToPasswordLockoutPolicy(wm *IAMPasswordLockoutPolicyWriteModel) *domain.PasswordLockoutPolicy {
func writeModelToPasswordLockoutPolicy(wm *PasswordLockoutPolicyWriteModel) *domain.PasswordLockoutPolicy {
return &domain.PasswordLockoutPolicy{
ObjectRoot: writeModelToObjectRoot(wm.PasswordLockoutPolicyWriteModel.WriteModel),
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
MaxAttempts: wm.MaxAttempts,
ShowLockOutFailures: wm.ShowLockOutFailures,
}
@@ -109,9 +109,9 @@ func writeModelToIDPOIDCConfig(wm *OIDCConfigWriteModel) *domain.OIDCIDPConfig {
}
}
func writeModelToIDPProvider(wm *IAMIdentityProviderWriteModel) *domain.IDPProvider {
func writeModelToIDPProvider(wm *IdentityProviderWriteModel) *domain.IDPProvider {
return &domain.IDPProvider{
ObjectRoot: writeModelToObjectRoot(wm.IdentityProviderWriteModel.WriteModel),
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
IDPConfigID: wm.IDPConfigID,
Type: wm.IDPProviderType,
}
+4 -7
View File
@@ -2,6 +2,7 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
@@ -117,16 +118,12 @@ func (r *CommandSide) ReactivateDefaultIDPConfig(ctx context.Context, idpID stri
return writeModelToIDPConfig(existingIDP), nil
}
func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, idpID string) (*domain.IDPConfig, error) {
writeModel, err := r.pushDefaultIDPWriteModel(ctx, idpID, func(a *iam.Aggregate, _ *IAMIDPConfigWriteModel) *iam.Aggregate {
func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, idpID string) error {
_, err := r.pushDefaultIDPWriteModel(ctx, idpID, func(a *iam.Aggregate, _ *IAMIDPConfigWriteModel) *iam.Aggregate {
a.Aggregate = *a.PushEvents(iam_repo.NewIDPConfigRemovedEvent(ctx, idpID))
return a
})
if err != nil {
return nil, err
}
return writeModelToIDPConfig(writeModel), nil
return err
}
func (r *CommandSide) pushDefaultIDPWriteModel(ctx context.Context, idpID string, eventSetter func(*iam.Aggregate, *IAMIDPConfigWriteModel) *iam.Aggregate) (*IAMIDPConfigWriteModel, error) {
+2 -2
View File
@@ -21,7 +21,7 @@ func (r *CommandSide) AddDefaultLabelPolicy(ctx context.Context, policy *domain.
return nil, err
}
return writeModelToLabelPolicy(addedPolicy), nil
return writeModelToLabelPolicy(&addedPolicy.LabelPolicyWriteModel), nil
}
func (r *CommandSide) addDefaultLabelPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMLabelPolicyWriteModel, policy *domain.LabelPolicy) error {
@@ -61,7 +61,7 @@ func (r *CommandSide) ChangeDefaultLabelPolicy(ctx context.Context, policy *doma
return nil, err
}
return writeModelToLabelPolicy(existingPolicy), nil
return writeModelToLabelPolicy(&existingPolicy.LabelPolicyWriteModel), nil
}
func (r *CommandSide) defaultLabelPolicyWriteModelByID(ctx context.Context) (policy *IAMLabelPolicyWriteModel, err error) {
+12 -7
View File
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMLabelPolicyWriteModel struct {
@@ -49,15 +50,19 @@ func (wm *IAMLabelPolicyWriteModel) NewChangedEvent(
primaryColor,
secondaryColor string,
) (*iam.LabelPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewLabelPolicyChangedEvent(ctx)
changes := make([]policy.LabelPolicyChanges, 0)
if wm.PrimaryColor != primaryColor {
hasChanged = true
changedEvent.PrimaryColor = &primaryColor
changes = append(changes, policy.ChangePrimaryColor(primaryColor))
}
if wm.SecondaryColor != secondaryColor {
hasChanged = true
changedEvent.SecondaryColor = &secondaryColor
changes = append(changes, policy.ChangeSecondaryColor(secondaryColor))
}
return changedEvent, hasChanged
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewLabelPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
+19 -20
View File
@@ -4,19 +4,18 @@ import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *CommandSide) GetDefaultLoginPolicy(ctx context.Context) (*domain.LoginPolicy, error) {
func (r *CommandSide) getDefaultLoginPolicy(ctx context.Context) (*domain.LoginPolicy, error) {
policyWriteModel := NewIAMLoginPolicyWriteModel()
err := r.eventstore.FilterToQueryReducer(ctx, policyWriteModel)
if err != nil {
return nil, err
}
policy := writeModelToLoginPolicy(policyWriteModel)
policy := writeModelToLoginPolicy(&policyWriteModel.LoginPolicyWriteModel)
policy.Default = true
return policy, nil
}
@@ -33,7 +32,7 @@ func (r *CommandSide) AddDefaultLoginPolicy(ctx context.Context, policy *domain.
return nil, err
}
return writeModelToLoginPolicy(addedPolicy), nil
return writeModelToLoginPolicy(&addedPolicy.LoginPolicyWriteModel), nil
}
func (r *CommandSide) addDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMLoginPolicyWriteModel, policy *domain.LoginPolicy) error {
@@ -62,7 +61,7 @@ func (r *CommandSide) ChangeDefaultLoginPolicy(ctx context.Context, policy *doma
return nil, err
}
return writeModelToLoginPolicy(existingPolicy), nil
return writeModelToLoginPolicy(&existingPolicy.LoginPolicyWriteModel), nil
}
func (r *CommandSide) changeDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, existingPolicy *IAMLoginPolicyWriteModel, policy *domain.LoginPolicy) error {
@@ -73,7 +72,7 @@ func (r *CommandSide) changeDefaultLoginPolicy(ctx context.Context, iamAgg *iam_
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return caos_errs.ThrowNotFound(nil, "IAM-M0sif", "Errors.IAM.LoginPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIdp, policy.ForceMFA, domain.PasswordlessType(policy.PasswordlessType))
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIdp, policy.ForceMFA, policy.PasswordlessType)
if !hasChanged {
return caos_errs.ThrowPreconditionFailed(nil, "IAM-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
}
@@ -99,10 +98,10 @@ func (r *CommandSide) AddIDPProviderToDefaultLoginPolicy(ctx context.Context, id
return nil, err
}
return writeModelToIDPProvider(idpModel), nil
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
}
func (r *CommandSide) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context, idpProvider *iam_model.IDPProvider) error {
func (r *CommandSide) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider) error {
idpModel := NewIAMIdentityProviderWriteModel(idpProvider.IDPConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, idpModel)
if err != nil {
@@ -117,22 +116,22 @@ func (r *CommandSide) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Contex
return r.eventstore.PushAggregate(ctx, idpModel, iamAgg)
}
func (r *CommandSide) AddSecondFactorToDefaultLoginPolicy(ctx context.Context, secondFactor iam_model.SecondFactorType) (iam_model.SecondFactorType, error) {
func (r *CommandSide) AddSecondFactorToDefaultLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType) (domain.SecondFactorType, error) {
secondFactorModel := NewIAMSecondFactorWriteModel()
iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
err := r.addSecondFactorToDefaultLoginPolicy(ctx, nil, secondFactorModel, secondFactor)
if err != nil {
return iam_model.SecondFactorTypeUnspecified, err
return domain.SecondFactorTypeUnspecified, err
}
if err = r.eventstore.PushAggregate(ctx, secondFactorModel, iamAgg); err != nil {
return iam_model.SecondFactorTypeUnspecified, err
return domain.SecondFactorTypeUnspecified, err
}
return iam_model.SecondFactorType(secondFactorModel.MFAType), nil
return domain.SecondFactorType(secondFactorModel.MFAType), nil
}
func (r *CommandSide) addSecondFactorToDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, secondFactorModel *IAMSecondFactorWriteModel, secondFactor iam_model.SecondFactorType) error {
func (r *CommandSide) addSecondFactorToDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, secondFactorModel *IAMSecondFactorWriteModel, secondFactor domain.SecondFactorType) error {
err := r.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
if err != nil {
return err
@@ -147,7 +146,7 @@ func (r *CommandSide) addSecondFactorToDefaultLoginPolicy(ctx context.Context, i
return nil
}
func (r *CommandSide) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Context, secondFactor iam_model.SecondFactorType) error {
func (r *CommandSide) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType) error {
secondFactorModel := NewIAMSecondFactorWriteModel()
err := r.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
if err != nil {
@@ -162,22 +161,22 @@ func (r *CommandSide) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Conte
return r.eventstore.PushAggregate(ctx, secondFactorModel, iamAgg)
}
func (r *CommandSide) AddMultiFactorToDefaultLoginPolicy(ctx context.Context, multiFactor iam_model.MultiFactorType) (iam_model.MultiFactorType, error) {
func (r *CommandSide) AddMultiFactorToDefaultLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType) (domain.MultiFactorType, error) {
multiFactorModel := NewIAMMultiFactorWriteModel()
iamAgg := IAMAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel)
err := r.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, multiFactor)
if err != nil {
return iam_model.MultiFactorTypeUnspecified, err
return domain.MultiFactorTypeUnspecified, err
}
if err = r.eventstore.PushAggregate(ctx, multiFactorModel, iamAgg); err != nil {
return iam_model.MultiFactorTypeUnspecified, err
return domain.MultiFactorTypeUnspecified, err
}
return iam_model.MultiFactorType(multiFactorModel.MultiFactoryWriteModel.MFAType), nil
return domain.MultiFactorType(multiFactorModel.MultiFactoryWriteModel.MFAType), nil
}
func (r *CommandSide) addMultiFactorToDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, multiFactorModel *IAMMultiFactorWriteModel, multiFactor iam_model.MultiFactorType) error {
func (r *CommandSide) addMultiFactorToDefaultLoginPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, multiFactorModel *IAMMultiFactorWriteModel, multiFactor domain.MultiFactorType) error {
err := r.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
if err != nil {
return err
@@ -191,7 +190,7 @@ func (r *CommandSide) addMultiFactorToDefaultLoginPolicy(ctx context.Context, ia
return nil
}
func (r *CommandSide) RemoveMultiFactorFromDefaultLoginPolicy(ctx context.Context, multiFactor iam_model.MultiFactorType) error {
func (r *CommandSide) RemoveMultiFactorFromDefaultLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType) error {
multiFactorModel := NewIAMMultiFactorWriteModel()
err := r.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
if err != nil {
@@ -26,6 +26,8 @@ func (wm *IAMSecondFactorWriteModel) AppendEvents(events ...eventstore.EventRead
switch e := event.(type) {
case *iam.LoginPolicySecondFactorAddedEvent:
wm.WriteModel.AppendEvents(&e.SecondFactorAddedEvent)
case *iam.LoginPolicySecondFactorRemovedEvent:
wm.WriteModel.AppendEvents(&e.SecondFactorRemovedEvent)
}
}
}
@@ -60,6 +62,8 @@ func (wm *IAMMultiFactorWriteModel) AppendEvents(events ...eventstore.EventReade
switch e := event.(type) {
case *iam.LoginPolicyMultiFactorAddedEvent:
wm.WriteModel.AppendEvents(&e.MultiFactorAddedEvent)
case *iam.LoginPolicyMultiFactorRemovedEvent:
wm.WriteModel.AppendEvents(&e.MultiFactorRemovedEvent)
}
}
}
@@ -30,6 +30,11 @@ func (wm *IAMIdentityProviderWriteModel) AppendEvents(events ...eventstore.Event
continue
}
wm.IdentityProviderWriteModel.AppendEvents(&e.IdentityProviderAddedEvent)
case *iam.IdentityProviderRemovedEvent:
if e.IDPConfigID != wm.IDPConfigID {
continue
}
wm.IdentityProviderWriteModel.AppendEvents(&e.IdentityProviderRemovedEvent)
}
}
}
+18 -16
View File
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMLoginPolicyWriteModel struct {
@@ -57,27 +58,28 @@ func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
passwordlessType domain.PasswordlessType,
) (*iam.LoginPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewLoginPolicyChangedEvent(ctx)
if wm.AllowUserNamePassword == allowUsernamePassword {
hasChanged = true
changedEvent.AllowUserNamePassword = &allowUsernamePassword
changes := make([]policy.LoginPolicyChanges, 0)
if wm.AllowUserNamePassword != allowUsernamePassword {
changes = append(changes, policy.ChangeAllowUserNamePassword(allowUsernamePassword))
}
if wm.AllowRegister == allowRegister {
hasChanged = true
changedEvent.AllowRegister = &allowRegister
if wm.AllowRegister != allowRegister {
changes = append(changes, policy.ChangeAllowRegister(allowRegister))
}
if wm.AllowExternalIDP == allowExternalIDP {
hasChanged = true
changedEvent.AllowExternalIDP = &allowExternalIDP
if wm.AllowExternalIDP != allowExternalIDP {
changes = append(changes, policy.ChangeAllowExternalIDP(allowExternalIDP))
}
if wm.ForceMFA != forceMFA {
hasChanged = true
changedEvent.ForceMFA = &forceMFA
changes = append(changes, policy.ChangeForceMFA(forceMFA))
}
if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType {
hasChanged = true
changedEvent.PasswordlessType = &passwordlessType
changes = append(changes, policy.ChangePasswordlessType(passwordlessType))
}
return changedEvent, hasChanged
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewLoginPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMOrgIAMPolicyWriteModel struct {
@@ -45,11 +46,16 @@ func (wm *IAMOrgIAMPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
}
func (wm *IAMOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLoginMustBeDomain bool) (*iam.OrgIAMPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewOrgIAMPolicyChangedEvent(ctx)
changes := make([]policy.OrgIAMPolicyChanges, 0)
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
hasChanged = true
changedEvent.UserLoginMustBeDomain = &userLoginMustBeDomain
changes = append(changes, policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain))
}
return changedEvent, hasChanged
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewOrgIAMPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
@@ -21,7 +21,7 @@ func (r *CommandSide) AddDefaultPasswordAgePolicy(ctx context.Context, policy *d
return nil, err
}
return writeModelToPasswordAgePolicy(addedPolicy), nil
return writeModelToPasswordAgePolicy(&addedPolicy.PasswordAgePolicyWriteModel), nil
}
func (r *CommandSide) addDefaultPasswordAgePolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMPasswordAgePolicyWriteModel, policy *domain.PasswordAgePolicy) error {
@@ -60,7 +60,7 @@ func (r *CommandSide) ChangeDefaultPasswordAgePolicy(ctx context.Context, policy
return nil, err
}
return writeModelToPasswordAgePolicy(existingPolicy), nil
return writeModelToPasswordAgePolicy(&existingPolicy.PasswordAgePolicyWriteModel), nil
}
func (r *CommandSide) defaultPasswordAgePolicyWriteModelByID(ctx context.Context) (policy *IAMPasswordAgePolicyWriteModel, err error) {
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMPasswordAgePolicyWriteModel struct {
@@ -45,15 +46,19 @@ func (wm *IAMPasswordAgePolicyWriteModel) Query() *eventstore.SearchQueryBuilder
}
func (wm *IAMPasswordAgePolicyWriteModel) NewChangedEvent(ctx context.Context, expireWarnDays, maxAgeDays uint64) (*iam.PasswordAgePolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewPasswordAgePolicyChangedEvent(ctx)
changes := make([]policy.PasswordAgePolicyChanges, 0)
if wm.ExpireWarnDays != expireWarnDays {
hasChanged = true
changedEvent.ExpireWarnDays = &expireWarnDays
changes = append(changes, policy.ChangeExpireWarnDays(expireWarnDays))
}
if wm.MaxAgeDays != maxAgeDays {
hasChanged = true
changedEvent.MaxAgeDays = &maxAgeDays
changes = append(changes, policy.ChangeMaxAgeDays(maxAgeDays))
}
return changedEvent, hasChanged
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewPasswordAgePolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
@@ -8,13 +8,13 @@ import (
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *CommandSide) GetDefaultPasswordComplexityPolicy(ctx context.Context) (*domain.PasswordComplexityPolicy, error) {
func (r *CommandSide) getDefaultPasswordComplexityPolicy(ctx context.Context) (*domain.PasswordComplexityPolicy, error) {
policyWriteModel := NewIAMPasswordComplexityPolicyWriteModel()
err := r.eventstore.FilterToQueryReducer(ctx, policyWriteModel)
if err != nil {
return nil, err
}
policy := writeModelToPasswordComplexityPolicy(policyWriteModel)
policy := writeModelToPasswordComplexityPolicy(&policyWriteModel.PasswordComplexityPolicyWriteModel)
policy.Default = true
return policy, nil
}
@@ -32,7 +32,7 @@ func (r *CommandSide) AddDefaultPasswordComplexityPolicy(ctx context.Context, po
return nil, err
}
return writeModelToPasswordComplexityPolicy(addedPolicy), nil
return writeModelToPasswordComplexityPolicy(&addedPolicy.PasswordComplexityPolicyWriteModel), nil
}
func (r *CommandSide) addDefaultPasswordComplexityPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMPasswordComplexityPolicyWriteModel, policy *domain.PasswordComplexityPolicy) error {
@@ -78,7 +78,7 @@ func (r *CommandSide) ChangeDefaultPasswordComplexityPolicy(ctx context.Context,
return nil, err
}
return writeModelToPasswordComplexityPolicy(existingPolicy), nil
return writeModelToPasswordComplexityPolicy(&existingPolicy.PasswordComplexityPolicyWriteModel), nil
}
func (r *CommandSide) defaultPasswordComplexityPolicyWriteModelByID(ctx context.Context) (policy *IAMPasswordComplexityPolicyWriteModel, err error) {
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMPasswordComplexityPolicyWriteModel struct {
@@ -53,27 +54,28 @@ func (wm *IAMPasswordComplexityPolicyWriteModel) NewChangedEvent(
hasSymbol bool,
) (*iam.PasswordComplexityPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewPasswordComplexityPolicyChangedEvent(ctx)
changes := make([]policy.PasswordComplexityPolicyChanges, 0)
if wm.MinLength != minLength {
hasChanged = true
changedEvent.MinLength = &minLength
changes = append(changes, policy.ChangeMinLength(minLength))
}
if wm.HasLowercase != hasLowercase {
hasChanged = true
changedEvent.HasLowercase = &hasLowercase
changes = append(changes, policy.ChangeHasLowercase(hasLowercase))
}
if wm.HasUpperCase != hasUppercase {
hasChanged = true
changedEvent.HasUpperCase = &hasUppercase
if wm.HasUppercase != hasUppercase {
changes = append(changes, policy.ChangeHasUppercase(hasUppercase))
}
if wm.HasNumber != hasNumber {
hasChanged = true
changedEvent.HasNumber = &hasNumber
changes = append(changes, policy.ChangeHasNumber(hasNumber))
}
if wm.HasSymbol != hasSymbol {
hasChanged = true
changedEvent.HasSymbol = &hasSymbol
changes = append(changes, policy.ChangeHasSymbol(hasSymbol))
}
return changedEvent, hasChanged
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewPasswordComplexityPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
@@ -21,7 +21,7 @@ func (r *CommandSide) AddDefaultPasswordLockoutPolicy(ctx context.Context, polic
return nil, err
}
return writeModelToPasswordLockoutPolicy(addedPolicy), nil
return writeModelToPasswordLockoutPolicy(&addedPolicy.PasswordLockoutPolicyWriteModel), nil
}
func (r *CommandSide) addDefaultPasswordLockoutPolicy(ctx context.Context, iamAgg *iam_repo.Aggregate, addedPolicy *IAMPasswordLockoutPolicyWriteModel, policy *domain.PasswordLockoutPolicy) error {
@@ -60,7 +60,7 @@ func (r *CommandSide) ChangeDefaultPasswordLockoutPolicy(ctx context.Context, po
return nil, err
}
return writeModelToPasswordLockoutPolicy(existingPolicy), nil
return writeModelToPasswordLockoutPolicy(&existingPolicy.PasswordLockoutPolicyWriteModel), nil
}
func (r *CommandSide) defaultPasswordLockoutPolicyWriteModelByID(ctx context.Context) (policy *IAMPasswordLockoutPolicyWriteModel, err error) {
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMPasswordLockoutPolicyWriteModel struct {
@@ -45,15 +46,19 @@ func (wm *IAMPasswordLockoutPolicyWriteModel) Query() *eventstore.SearchQueryBui
}
func (wm *IAMPasswordLockoutPolicyWriteModel) NewChangedEvent(ctx context.Context, maxAttempts uint64, showLockoutFailure bool) (*iam.PasswordLockoutPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewPasswordLockoutPolicyChangedEvent(ctx)
changes := make([]policy.PasswordLockoutPolicyChanges, 0)
if wm.MaxAttempts != maxAttempts {
hasChanged = true
changedEvent.MaxAttempts = &maxAttempts
changes = append(changes, policy.ChangeMaxAttempts(maxAttempts))
}
if wm.ShowLockOutFailures != showLockoutFailure {
hasChanged = true
changedEvent.ShowLockOutFailures = &showLockoutFailure
changes = append(changes, policy.ChangeShowLockOutFailures(showLockoutFailure))
}
return changedEvent, hasChanged
if len(changes) == 0 {
return nil, false
}
changedEvent, err := iam.NewPasswordLockoutPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
+59
View File
@@ -30,6 +30,65 @@ func (r *CommandSide) SetUpOrg(ctx context.Context, organisation *domain.Org, ad
return err
}
func (r *CommandSide) AddOrg(ctx context.Context, name, userID, resourceOwner string) (*domain.Org, error) {
orgAgg, addedOrg, err := r.addOrg(ctx, &domain.Org{Name: name})
if err != nil {
return nil, err
}
active, err := r.checkUserExists(ctx, userID, resourceOwner)
if err != nil {
return nil, err
}
if !active {
return nil, caos_errs.ThrowPreconditionFailed(err, "ORG-HBR2z", "Errors.User.NotFound")
}
addedMember := NewOrgMemberWriteModel(orgAgg.ID(), userID)
err = r.addOrgMember(ctx, orgAgg, addedMember, domain.NewMember(orgAgg.ID(), userID, domain.RoleOrgOwner))
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedOrg, orgAgg)
if err != nil {
return nil, err
}
return orgWriteModelToOrg(addedOrg), nil
}
func (r *CommandSide) DeactivateOrg(ctx context.Context, orgID string) error {
orgWriteModel, err := r.getOrgWriteModelByID(ctx, orgID)
if err != nil {
return err
}
if orgWriteModel.State == domain.OrgStateUnspecified || orgWriteModel.State == domain.OrgStateRemoved {
return caos_errs.ThrowNotFound(nil, "ORG-oL9nT", "Errors.Org.NotFound")
}
if orgWriteModel.State == domain.OrgStateInactive {
return caos_errs.ThrowInvalidArgument(nil, "EVENT-Dbs2g", "Errors.Org.AlreadyDeactivated")
}
orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel)
orgAgg.PushEvents(org.NewOrgDeactivatedEvent(ctx))
return r.eventstore.PushAggregate(ctx, orgWriteModel, orgAgg)
}
func (r *CommandSide) ReactivateOrg(ctx context.Context, orgID string) error {
orgWriteModel, err := r.getOrgWriteModelByID(ctx, orgID)
if err != nil {
return err
}
if orgWriteModel.State == domain.OrgStateUnspecified || orgWriteModel.State == domain.OrgStateRemoved {
return caos_errs.ThrowNotFound(nil, "ORG-Dgf3g", "Errors.Org.NotFound")
}
if orgWriteModel.State == domain.OrgStateActive {
return caos_errs.ThrowInvalidArgument(nil, "EVENT-bfnrh", "Errors.Org.AlreadyActive")
}
orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel)
orgAgg.PushEvents(org.NewOrgReactivatedEvent(ctx))
return r.eventstore.PushAggregate(ctx, orgWriteModel, orgAgg)
}
func (r *CommandSide) setUpOrg(ctx context.Context, organisation *domain.Org, admin *domain.Human) (*org.Aggregate, *user.Aggregate, *org.Aggregate, error) {
orgAgg, _, err := r.addOrg(ctx, organisation)
if err != nil {
+1 -1
View File
@@ -25,7 +25,7 @@ func orgWriteModelToPasswordComplexityPolicy(wm *OrgPasswordComplexityPolicyWrit
ObjectRoot: writeModelToObjectRoot(wm.PasswordComplexityPolicyWriteModel.WriteModel),
MinLength: wm.MinLength,
HasLowercase: wm.HasLowercase,
HasUppercase: wm.HasUpperCase,
HasUppercase: wm.HasUppercase,
HasNumber: wm.HasNumber,
HasSymbol: wm.HasSymbol,
}
+123
View File
@@ -3,6 +3,10 @@ package command
import (
"context"
"github.com/caos/logging"
http_utils "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/crypto"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
@@ -22,6 +26,116 @@ func (r *CommandSide) AddOrgDomain(ctx context.Context, orgDomain *domain.OrgDom
return orgDomainWriteModelToOrgDomain(domainWriteModel), nil
}
func (r *CommandSide) GenerateOrgDomainValidation(ctx context.Context, orgDomain *domain.OrgDomain) (token, url string, err error) {
if orgDomain == nil || !orgDomain.IsValid() {
return "", "", caos_errs.ThrowPreconditionFailed(nil, "ORG-R24hb", "Errors.Org.InvalidDomain")
}
checkType, ok := orgDomain.ValidationType.CheckType()
if !ok {
return "", "", caos_errs.ThrowPreconditionFailed(nil, "ORG-Gsw31", "Errors.Org.DomainVerificationTypeInvalid")
}
domainWriteModel, err := r.getOrgDomainWriteModel(ctx, orgDomain.AggregateID, orgDomain.Domain)
if err != nil {
return "", "", err
}
if domainWriteModel.State != domain.OrgDomainStateActive {
return "", "", caos_errs.ThrowPreconditionFailed(nil, "ORG-AGD31", "Errors.Org.DomainNotOnOrg")
}
if domainWriteModel.Verified {
return "", "", caos_errs.ThrowPreconditionFailed(nil, "ORG-HGw21", "Errors.Org.DomainAlreadyVerified")
}
token, err = orgDomain.GenerateVerificationCode(r.domainVerificationGenerator)
if err != nil {
return "", "", err
}
url, err = http_utils.TokenUrl(orgDomain.Domain, token, checkType)
if err != nil {
return "", "", caos_errs.ThrowPreconditionFailed(err, "ORG-Bae21", "Errors.Org.DomainVerificationTypeInvalid")
}
orgAgg := OrgAggregateFromWriteModel(&domainWriteModel.WriteModel)
orgAgg.PushEvents(org.NewDomainVerificationAddedEvent(ctx, orgDomain.Domain, orgDomain.ValidationType, orgDomain.ValidationCode))
err = r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
if err != nil {
return "", "", err
}
return token, url, nil
}
func (r *CommandSide) ValidateOrgDomain(ctx context.Context, orgDomain *domain.OrgDomain) error {
if orgDomain == nil || !orgDomain.IsValid() {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-R24hb", "Errors.Org.InvalidDomain")
}
domainWriteModel, err := r.getOrgDomainWriteModel(ctx, orgDomain.AggregateID, orgDomain.Domain)
if err != nil {
return err
}
if domainWriteModel.State != domain.OrgDomainStateActive {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-Sjdi3", "Errors.Org.DomainNotOnOrg")
}
if domainWriteModel.Verified {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-HGw21", "Errors.Org.DomainAlreadyVerified")
}
if domainWriteModel.ValidationCode == nil || domainWriteModel.ValidationType == domain.OrgDomainValidationTypeUnspecified {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-SFBB3", "Errors.Org.DomainVerificationMissing")
}
validationCode, err := crypto.DecryptString(domainWriteModel.ValidationCode, r.domainVerificationAlg)
if err != nil {
return err
}
checkType, _ := domainWriteModel.ValidationType.CheckType()
err = r.domainVerificationValidator(domainWriteModel.Domain, validationCode, validationCode, checkType)
orgAgg := OrgAggregateFromWriteModel(&domainWriteModel.WriteModel)
if err == nil {
orgAgg.PushEvents(org.NewDomainVerifiedEvent(ctx, orgDomain.Domain))
return r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
}
orgAgg.PushEvents(org.NewDomainVerificationFailedEvent(ctx, orgDomain.Domain))
err = r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
logging.LogWithFields("ORG-dhTE", "orgID", orgAgg.ID(), "domain", orgDomain.Domain).OnError(err).Error("NewDomainVerificationFailedEvent push failed")
return caos_errs.ThrowInvalidArgument(err, "ORG-GH3s", "Errors.Org.DomainVerificationFailed")
}
func (r *CommandSide) SetPrimaryOrgDomain(ctx context.Context, orgDomain *domain.OrgDomain) error {
if orgDomain == nil || !orgDomain.IsValid() {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-SsDG2", "Errors.Org.InvalidDomain")
}
domainWriteModel, err := r.getOrgDomainWriteModel(ctx, orgDomain.AggregateID, orgDomain.Domain)
if err != nil {
return err
}
if domainWriteModel.State != domain.OrgDomainStateActive {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-GDfA3", "Errors.Org.DomainNotOnOrg")
}
if !domainWriteModel.Verified {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-Ggd32", "Errors.Org.DomainNotVerified")
}
orgAgg := OrgAggregateFromWriteModel(&domainWriteModel.WriteModel)
orgAgg.PushEvents(org.NewDomainPrimarySetEvent(ctx, orgDomain.Domain))
return r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
}
func (r *CommandSide) RemoveOrgDomain(ctx context.Context, orgDomain *domain.OrgDomain) error {
if orgDomain == nil || !orgDomain.IsValid() {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-SJsK3", "Errors.Org.InvalidDomain")
}
domainWriteModel, err := r.getOrgDomainWriteModel(ctx, orgDomain.AggregateID, orgDomain.Domain)
if err != nil {
return err
}
if domainWriteModel.State != domain.OrgDomainStateActive {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-GDfA3", "Errors.Org.DomainNotOnOrg")
}
if domainWriteModel.Primary {
return caos_errs.ThrowPreconditionFailed(nil, "ORG-Sjdi3", "Errors.Org.PrimaryDomainNotDeletable")
}
orgAgg := OrgAggregateFromWriteModel(&domainWriteModel.WriteModel)
orgAgg.PushEvents(org.NewDomainRemovedEvent(ctx, orgDomain.Domain))
return r.eventstore.PushAggregate(ctx, domainWriteModel, orgAgg)
}
func (r *CommandSide) addOrgDomain(ctx context.Context, orgAgg *org.Aggregate, addedDomain *OrgDomainWriteModel, orgDomain *domain.OrgDomain) error {
err := r.eventstore.FilterToQueryReducer(ctx, addedDomain)
if err != nil {
@@ -41,3 +155,12 @@ func (r *CommandSide) addOrgDomain(ctx context.Context, orgAgg *org.Aggregate, a
}
return nil
}
func (r *CommandSide) getOrgDomainWriteModel(ctx context.Context, orgID, domain string) (*OrgDomainWriteModel, error) {
domainWriteModel := NewOrgDomainWriteModel(orgID, domain)
err := r.eventstore.FilterToQueryReducer(ctx, domainWriteModel)
if err != nil {
return nil, err
}
return domainWriteModel, nil
}
+71
View File
@@ -0,0 +1,71 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
)
func (r *CommandSide) AddLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) {
addedPolicy := NewOrgLabelPolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "Org-2B0ps", "Errors.Org.LabelPolicy.AlreadyExists")
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.LabelPolicyWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLabelPolicyAddedEvent(ctx, policy.PrimaryColor, policy.SecondaryColor))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(&addedPolicy.LabelPolicyWriteModel), nil
}
func (r *CommandSide) ChangeLabelPolicy(ctx context.Context, policy *domain.LabelPolicy) (*domain.LabelPolicy, error) {
existingPolicy := NewOrgLabelPolicyWriteModel(policy.AggregateID)
err := r.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-0K9dq", "Errors.Org.LabelPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.PrimaryColor, policy.SecondaryColor)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4M9vs", "Errors.Org.LabelPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(&existingPolicy.LabelPolicyWriteModel), nil
}
func (r *CommandSide) RemoveLabelPolicy(ctx context.Context, orgID string) error {
existingPolicy := NewOrgLabelPolicyWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, existingPolicy)
if err != nil {
return err
}
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LabelPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewLabelPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
}
@@ -0,0 +1,67 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/org"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type OrgLabelPolicyWriteModel struct {
LabelPolicyWriteModel
}
func NewOrgLabelPolicyWriteModel(orgID string) *OrgLabelPolicyWriteModel {
return &OrgLabelPolicyWriteModel{
LabelPolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
ResourceOwner: orgID,
},
},
}
}
func (wm *OrgLabelPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.LabelPolicyAddedEvent:
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyAddedEvent)
case *org.LabelPolicyChangedEvent:
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyChangedEvent)
}
}
}
func (wm *OrgLabelPolicyWriteModel) Reduce() error {
return wm.LabelPolicyWriteModel.Reduce()
}
func (wm *OrgLabelPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.LabelPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
}
func (wm *OrgLabelPolicyWriteModel) NewChangedEvent(
ctx context.Context,
primaryColor,
secondaryColor string,
) (*org.LabelPolicyChangedEvent, bool) {
changes := make([]policy.LabelPolicyChanges, 0)
if wm.PrimaryColor != primaryColor {
changes = append(changes, policy.ChangePrimaryColor(primaryColor))
}
if wm.SecondaryColor != secondaryColor {
changes = append(changes, policy.ChangeSecondaryColor(secondaryColor))
}
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewLabelPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
+176
View File
@@ -0,0 +1,176 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
)
func (r *CommandSide) AddLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
addedPolicy := NewOrgLoginPolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "Org-Dgfb2", "Errors.Org.LoginPolicy.AlreadyExists")
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicyAddedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIdp, policy.ForceMFA, policy.PasswordlessType))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(&addedPolicy.LoginPolicyWriteModel), nil
}
func (r *CommandSide) ChangeLoginPolicy(ctx context.Context, policy *domain.LoginPolicy) (*domain.LoginPolicy, error) {
existingPolicy := NewOrgLoginPolicyWriteModel(policy.AggregateID)
err := r.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-M0sif", "Errors.Org.LoginPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIdp, policy.ForceMFA, domain.PasswordlessType(policy.PasswordlessType))
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-5M9vdd", "Errors.Org.LoginPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(&existingPolicy.LoginPolicyWriteModel), nil
}
func (r *CommandSide) RemoveLoginPolicy(ctx context.Context, orgID string) error {
existingPolicy := NewOrgLoginPolicyWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, existingPolicy)
if err != nil {
return err
}
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return caos_errs.ThrowNotFound(nil, "Org-GHB37", "Errors.Org.LoginPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
}
func (r *CommandSide) AddIDPProviderToLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider) (*domain.IDPProvider, error) {
idpModel := NewOrgIdentityProviderWriteModel(idpProvider.AggregateID, idpProvider.IDPConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, idpModel)
if err != nil {
return nil, err
}
if idpModel.State == domain.IdentityProviderStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "Org-2B0ps", "Errors.Org.LoginPolicy.IDP.AlreadyExists")
}
orgAgg := OrgAggregateFromWriteModel(&idpModel.WriteModel)
orgAgg.PushEvents(org.NewIdentityProviderAddedEvent(ctx, idpProvider.IDPConfigID, idpProvider.Type))
if err = r.eventstore.PushAggregate(ctx, idpModel, orgAgg); err != nil {
return nil, err
}
return writeModelToIDPProvider(&idpModel.IdentityProviderWriteModel), nil
}
func (r *CommandSide) RemoveIDPProviderFromLoginPolicy(ctx context.Context, idpProvider *domain.IDPProvider) error {
idpModel := NewOrgIdentityProviderWriteModel(idpProvider.AggregateID, idpProvider.IDPConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, idpModel)
if err != nil {
return err
}
if idpModel.State == domain.IdentityProviderStateUnspecified || idpModel.State == domain.IdentityProviderStateRemoved {
return caos_errs.ThrowNotFound(nil, "Org-39fjs", "Errors.Org.LoginPolicy.IDP.NotExisting")
}
orgAgg := OrgAggregateFromWriteModel(&idpModel.IdentityProviderWriteModel.WriteModel)
orgAgg.PushEvents(org.NewIdentityProviderRemovedEvent(ctx, idpProvider.IDPConfigID))
return r.eventstore.PushAggregate(ctx, idpModel, orgAgg)
}
func (r *CommandSide) AddSecondFactorToLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType, orgID string) (domain.SecondFactorType, error) {
secondFactorModel := NewOrgSecondFactorWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
if err != nil {
return domain.SecondFactorTypeUnspecified, err
}
if secondFactorModel.State == domain.FactorStateActive {
return domain.SecondFactorTypeUnspecified, caos_errs.ThrowAlreadyExists(nil, "Org-2B0ps", "Errors.Org.LoginPolicy.MFA.AlreadyExists")
}
orgAgg := OrgAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicySecondFactorAddedEvent(ctx, secondFactor))
if err = r.eventstore.PushAggregate(ctx, secondFactorModel, orgAgg); err != nil {
return domain.SecondFactorTypeUnspecified, err
}
return secondFactorModel.MFAType, nil
}
func (r *CommandSide) RemoveSecondFactorFromLoginPolicy(ctx context.Context, secondFactor domain.SecondFactorType, orgID string) error {
secondFactorModel := NewOrgSecondFactorWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
if err != nil {
return err
}
if secondFactorModel.State == domain.FactorStateUnspecified || secondFactorModel.State == domain.FactorStateRemoved {
return caos_errs.ThrowNotFound(nil, "Org-3M9od", "Errors.Org.LoginPolicy.MFA.NotExisting")
}
orgAgg := OrgAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicySecondFactorRemovedEvent(ctx, domain.SecondFactorType(secondFactor)))
return r.eventstore.PushAggregate(ctx, secondFactorModel, orgAgg)
}
func (r *CommandSide) AddMultiFactorToLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType, orgID string) (domain.MultiFactorType, error) {
multiFactorModel := NewOrgMultiFactorWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
if err != nil {
return domain.MultiFactorTypeUnspecified, err
}
if multiFactorModel.State == domain.FactorStateActive {
return domain.MultiFactorTypeUnspecified, caos_errs.ThrowAlreadyExists(nil, "Org-3M9od", "Errors.Org.LoginPolicy.MFA.AlreadyExists")
}
orgAgg := OrgAggregateFromWriteModel(&multiFactorModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicyMultiFactorAddedEvent(ctx, multiFactor))
if err = r.eventstore.PushAggregate(ctx, multiFactorModel, orgAgg); err != nil {
return domain.MultiFactorTypeUnspecified, err
}
return multiFactorModel.MFAType, nil
}
func (r *CommandSide) RemoveMultiFactorFromLoginPolicy(ctx context.Context, multiFactor domain.MultiFactorType, orgID string) error {
multiFactorModel := NewOrgMultiFactorWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
if err != nil {
return err
}
if multiFactorModel.State == domain.FactorStateUnspecified || multiFactorModel.State == domain.FactorStateRemoved {
return caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LoginPolicy.MFA.NotExisting")
}
orgAgg := OrgAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel)
orgAgg.PushEvents(org.NewLoginPolicyMultiFactorRemovedEvent(ctx, domain.MultiFactorType(multiFactor)))
return r.eventstore.PushAggregate(ctx, multiFactorModel, orgAgg)
}
@@ -0,0 +1,74 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type OrgSecondFactorWriteModel struct {
SecondFactorWriteModel
}
func NewOrgSecondFactorWriteModel(orgID string) *OrgSecondFactorWriteModel {
return &OrgSecondFactorWriteModel{
SecondFactorWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
ResourceOwner: orgID,
},
},
}
}
func (wm *OrgSecondFactorWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LoginPolicySecondFactorAddedEvent:
wm.WriteModel.AppendEvents(&e.SecondFactorAddedEvent)
}
}
}
func (wm *OrgSecondFactorWriteModel) Reduce() error {
return wm.WriteModel.Reduce()
}
func (wm *OrgSecondFactorWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.WriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
}
type OrgMultiFactorWriteModel struct {
MultiFactoryWriteModel
}
func NewOrgMultiFactorWriteModel(orgID string) *OrgMultiFactorWriteModel {
return &OrgMultiFactorWriteModel{
MultiFactoryWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
ResourceOwner: orgID,
},
},
}
}
func (wm *OrgMultiFactorWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LoginPolicyMultiFactorAddedEvent:
wm.WriteModel.AppendEvents(&e.MultiFactorAddedEvent)
}
}
}
func (wm *OrgMultiFactorWriteModel) Reduce() error {
return wm.WriteModel.Reduce()
}
func (wm *OrgMultiFactorWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.WriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
}
@@ -0,0 +1,44 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type OrgIdentityProviderWriteModel struct {
IdentityProviderWriteModel
}
func NewOrgIdentityProviderWriteModel(orgID, idpConfigID string) *OrgIdentityProviderWriteModel {
return &OrgIdentityProviderWriteModel{
IdentityProviderWriteModel: IdentityProviderWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
ResourceOwner: orgID,
},
IDPConfigID: idpConfigID,
},
}
}
func (wm *OrgIdentityProviderWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.IdentityProviderAddedEvent:
if e.IDPConfigID != wm.IDPConfigID {
continue
}
wm.IdentityProviderWriteModel.AppendEvents(&e.IdentityProviderAddedEvent)
}
}
}
func (wm *OrgIdentityProviderWriteModel) Reduce() error {
return wm.IdentityProviderWriteModel.Reduce()
}
func (wm *OrgIdentityProviderWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.AggregateID).
ResourceOwner(wm.ResourceOwner)
}
@@ -0,0 +1,87 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type OrgLoginPolicyWriteModel struct {
LoginPolicyWriteModel
}
func NewOrgLoginPolicyWriteModel(orgID string) *OrgLoginPolicyWriteModel {
return &OrgLoginPolicyWriteModel{
LoginPolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
ResourceOwner: orgID,
},
},
}
}
func (wm *OrgLoginPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.LoginPolicyAddedEvent:
wm.LoginPolicyWriteModel.AppendEvents(&e.LoginPolicyAddedEvent)
case *org.LoginPolicyChangedEvent:
wm.LoginPolicyWriteModel.AppendEvents(&e.LoginPolicyChangedEvent)
case *org.LoginPolicyRemovedEvent:
wm.LoginPolicyWriteModel.AppendEvents(&e.LoginPolicyRemovedEvent)
}
}
}
func (wm *OrgLoginPolicyWriteModel) IsValid() bool {
return wm.AggregateID != ""
}
func (wm *OrgLoginPolicyWriteModel) Reduce() error {
return wm.LoginPolicyWriteModel.Reduce()
}
func (wm *OrgLoginPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.LoginPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
}
func (wm *OrgLoginPolicyWriteModel) NewChangedEvent(
ctx context.Context,
allowUsernamePassword,
allowRegister,
allowExternalIDP,
forceMFA bool,
passwordlessType domain.PasswordlessType,
) (*org.LoginPolicyChangedEvent, bool) {
changes := make([]policy.LoginPolicyChanges, 0)
if wm.AllowUserNamePassword != allowUsernamePassword {
changes = append(changes, policy.ChangeAllowUserNamePassword(allowUsernamePassword))
}
if wm.AllowRegister != allowRegister {
changes = append(changes, policy.ChangeAllowRegister(allowRegister))
}
if wm.AllowExternalIDP != allowExternalIDP {
changes = append(changes, policy.ChangeAllowExternalIDP(allowExternalIDP))
}
if wm.ForceMFA != forceMFA {
changes = append(changes, policy.ChangeForceMFA(forceMFA))
}
if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType {
changes = append(changes, policy.ChangePasswordlessType(passwordlessType))
}
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewLoginPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
+15
View File
@@ -65,6 +65,21 @@ func (r *CommandSide) ChangeOrgIAMPolicy(ctx context.Context, policy *domain.Org
return orgWriteModelToOrgIAMPolicy(existingPolicy), nil
}
func (r *CommandSide) RemoveOrgIAMPolicy(ctx context.Context, orgID string) error {
existingPolicy, err := r.orgIAMPolicyWriteModelByID(ctx, orgID)
if err != nil {
return err
}
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return caos_errs.ThrowNotFound(nil, "ORG-Dvsh3", "Errors.Org.OrgIAMPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)
orgAgg.PushEvents(org.NewOrgIAMPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
}
func (r *CommandSide) getOrgIAMPolicy(ctx context.Context, orgID string) (*domain.OrgIAMPolicy, error) {
policy, err := r.orgIAMPolicyWriteModelByID(ctx, orgID)
if err != nil {
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/org"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type ORGOrgIAMPolicyWriteModel struct {
@@ -44,11 +45,16 @@ func (wm *ORGOrgIAMPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
}
func (wm *ORGOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLoginMustBeDomain bool) (*org.OrgIAMPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := org.NewOrgIAMPolicyChangedEvent(ctx)
changes := make([]policy.OrgIAMPolicyChanges, 0)
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
hasChanged = true
changedEvent.UserLoginMustBeDomain = &userLoginMustBeDomain
changes = append(changes, policy.ChangeUserLoginMustBeDomain(userLoginMustBeDomain))
}
return changedEvent, hasChanged
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewOrgIAMPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
@@ -0,0 +1,70 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
)
func (r *CommandSide) AddPasswordAgePolicy(ctx context.Context, policy *domain.PasswordAgePolicy) (*domain.PasswordAgePolicy, error) {
addedPolicy := NewOrgPasswordAgePolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "ORG-Lk0dS", "Errors.Org.PasswordAgePolicy.AlreadyExists")
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordAgePolicyAddedEvent(ctx, policy.ExpireWarnDays, policy.MaxAgeDays))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(&addedPolicy.PasswordAgePolicyWriteModel), nil
}
func (r *CommandSide) ChangePasswordAgePolicy(ctx context.Context, policy *domain.PasswordAgePolicy) (*domain.PasswordAgePolicy, error) {
existingPolicy := NewOrgPasswordAgePolicyWriteModel(policy.AggregateID)
err := r.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-0oPew", "Errors.Org.PasswordAgePolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.ExpireWarnDays, policy.MaxAgeDays)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-dsgjR", "Errors.ORg.LabelPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PasswordAgePolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(&existingPolicy.PasswordAgePolicyWriteModel), nil
}
func (r *CommandSide) RemovePasswordAgePolicy(ctx context.Context, orgID string) error {
existingPolicy := NewOrgPasswordAgePolicyWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, existingPolicy)
if err != nil {
return err
}
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return caos_errs.ThrowNotFound(nil, "ORG-Dgs1g", "Errors.Org.PasswordAgePolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordAgePolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
}
@@ -0,0 +1,65 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/org"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type OrgPasswordAgePolicyWriteModel struct {
PasswordAgePolicyWriteModel
}
func NewOrgPasswordAgePolicyWriteModel(orgID string) *OrgPasswordAgePolicyWriteModel {
return &OrgPasswordAgePolicyWriteModel{
PasswordAgePolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
ResourceOwner: orgID,
},
},
}
}
func (wm *OrgPasswordAgePolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.PasswordAgePolicyAddedEvent:
wm.PasswordAgePolicyWriteModel.AppendEvents(&e.PasswordAgePolicyAddedEvent)
case *org.PasswordAgePolicyChangedEvent:
wm.PasswordAgePolicyWriteModel.AppendEvents(&e.PasswordAgePolicyChangedEvent)
case *org.PasswordAgePolicyRemovedEvent:
wm.PasswordAgePolicyWriteModel.AppendEvents(&e.PasswordAgePolicyRemovedEvent)
}
}
}
func (wm *OrgPasswordAgePolicyWriteModel) Reduce() error {
return wm.PasswordAgePolicyWriteModel.Reduce()
}
func (wm *OrgPasswordAgePolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.PasswordAgePolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
}
func (wm *OrgPasswordAgePolicyWriteModel) NewChangedEvent(ctx context.Context, expireWarnDays, maxAgeDays uint64) (*org.PasswordAgePolicyChangedEvent, bool) {
changes := make([]policy.PasswordAgePolicyChanges, 0)
if wm.ExpireWarnDays != expireWarnDays {
changes = append(changes, policy.ChangeExpireWarnDays(expireWarnDays))
}
if wm.MaxAgeDays != maxAgeDays {
changes = append(changes, policy.ChangeMaxAgeDays(maxAgeDays))
}
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewPasswordAgePolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
@@ -2,10 +2,13 @@ package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
)
func (r *CommandSide) GetOrgPasswordComplexityPolicy(ctx context.Context, orgID string) (*domain.PasswordComplexityPolicy, error) {
func (r *CommandSide) getOrgPasswordComplexityPolicy(ctx context.Context, orgID string) (*domain.PasswordComplexityPolicy, error) {
policy := NewOrgPasswordComplexityPolicyWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, policy)
if err != nil {
@@ -14,5 +17,72 @@ func (r *CommandSide) GetOrgPasswordComplexityPolicy(ctx context.Context, orgID
if policy.State == domain.PolicyStateActive {
return orgWriteModelToPasswordComplexityPolicy(policy), nil
}
return r.GetDefaultPasswordComplexityPolicy(ctx)
return r.getDefaultPasswordComplexityPolicy(ctx)
}
func (r *CommandSide) AddPasswordComplexityPolicy(ctx context.Context, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) {
if err := policy.IsValid(); err != nil {
return nil, err
}
addedPolicy := NewOrgPasswordComplexityPolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "Org-LdhbS", "Errors.Org.PasswordComplexityPolicy.AlreadyExists")
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordComplexityPolicyAddedEvent(ctx, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(&addedPolicy.PasswordComplexityPolicyWriteModel), nil
}
func (r *CommandSide) ChangePasswordComplexityPolicy(ctx context.Context, policy *domain.PasswordComplexityPolicy) (*domain.PasswordComplexityPolicy, error) {
if err := policy.IsValid(); err != nil {
return nil, err
}
existingPolicy := NewOrgPasswordComplexityPolicyWriteModel(policy.AggregateID)
err := r.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-Dgs3g", "Errors.Org.PasswordComplexityPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-DAs21", "Errors.Org.PasswordComplexityPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PasswordComplexityPolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(&existingPolicy.PasswordComplexityPolicyWriteModel), nil
}
func (r *CommandSide) RemovePasswordComplexityPolicy(ctx context.Context, orgID string) error {
existingPolicy := NewOrgPasswordComplexityPolicyWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, existingPolicy)
if err != nil {
return err
}
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return caos_errs.ThrowNotFound(nil, "ORG-ADgs2", "Errors.Org.PasswordComplexityPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordComplexityPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
}
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/org"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type OrgPasswordComplexityPolicyWriteModel struct {
@@ -29,6 +30,8 @@ func (wm *OrgPasswordComplexityPolicyWriteModel) AppendEvents(events ...eventsto
wm.PasswordComplexityPolicyWriteModel.AppendEvents(&e.PasswordComplexityPolicyAddedEvent)
case *org.PasswordComplexityPolicyChangedEvent:
wm.PasswordComplexityPolicyWriteModel.AppendEvents(&e.PasswordComplexityPolicyChangedEvent)
case *org.PasswordComplexityPolicyRemovedEvent:
wm.PasswordComplexityPolicyWriteModel.AppendEvents(&e.PasswordComplexityPolicyRemovedEvent)
}
}
}
@@ -52,27 +55,28 @@ func (wm *OrgPasswordComplexityPolicyWriteModel) NewChangedEvent(
hasSymbol bool,
) (*org.PasswordComplexityPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := org.NewPasswordComplexityPolicyChangedEvent(ctx)
changes := make([]policy.PasswordComplexityPolicyChanges, 0)
if wm.MinLength != minLength {
hasChanged = true
changedEvent.MinLength = &minLength
changes = append(changes, policy.ChangeMinLength(minLength))
}
if wm.HasLowercase != hasLowercase {
hasChanged = true
changedEvent.HasLowercase = &hasLowercase
changes = append(changes, policy.ChangeHasLowercase(hasLowercase))
}
if wm.HasUpperCase != hasUppercase {
hasChanged = true
changedEvent.HasUpperCase = &hasUppercase
if wm.HasUppercase != hasUppercase {
changes = append(changes, policy.ChangeHasUppercase(hasUppercase))
}
if wm.HasNumber != hasNumber {
hasChanged = true
changedEvent.HasNumber = &hasNumber
changes = append(changes, policy.ChangeHasNumber(hasNumber))
}
if wm.HasSymbol != hasSymbol {
hasChanged = true
changedEvent.HasSymbol = &hasSymbol
changes = append(changes, policy.ChangeHasSymbol(hasSymbol))
}
return changedEvent, hasChanged
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewPasswordComplexityPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
@@ -0,0 +1,70 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/org"
)
func (r *CommandSide) AddPasswordLockoutPolicy(ctx context.Context, policy *domain.PasswordLockoutPolicy) (*domain.PasswordLockoutPolicy, error) {
addedPolicy := NewOrgPasswordLockoutPolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.State == domain.PolicyStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "ORG-0olDf", "Errors.ORG.PasswordLockoutPolicy.AlreadyExists")
}
orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordLockoutPolicyAddedEvent(ctx, policy.MaxAttempts, policy.ShowLockOutFailures))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordLockoutPolicy(&addedPolicy.PasswordLockoutPolicyWriteModel), nil
}
func (r *CommandSide) ChangePasswordLockoutPolicy(ctx context.Context, policy *domain.PasswordLockoutPolicy) (*domain.PasswordLockoutPolicy, error) {
existingPolicy := NewOrgPasswordLockoutPolicyWriteModel(policy.AggregateID)
err := r.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-ADfs1", "Errors.Org.PasswordLockoutPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.MaxAttempts, policy.ShowLockOutFailures)
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "ORG-4M9vs", "Errors.Org.PasswordLockoutPolicy.NotChanged")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PasswordLockoutPolicyWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordLockoutPolicy(&existingPolicy.PasswordLockoutPolicyWriteModel), nil
}
func (r *CommandSide) RemovePasswordLockoutPolicy(ctx context.Context, orgID string) error {
existingPolicy := NewOrgPasswordLockoutPolicyWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, existingPolicy)
if err != nil {
return err
}
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return caos_errs.ThrowNotFound(nil, "ORG-D4zuz", "Errors.Org.PasswordLockoutPolicy.NotFound")
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.WriteModel)
orgAgg.PushEvents(org.NewPasswordLockoutPolicyRemovedEvent(ctx))
return r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
}
@@ -0,0 +1,65 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/org"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type OrgPasswordLockoutPolicyWriteModel struct {
PasswordLockoutPolicyWriteModel
}
func NewOrgPasswordLockoutPolicyWriteModel(orgID string) *OrgPasswordLockoutPolicyWriteModel {
return &OrgPasswordLockoutPolicyWriteModel{
PasswordLockoutPolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
ResourceOwner: orgID,
},
},
}
}
func (wm *OrgPasswordLockoutPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.PasswordLockoutPolicyAddedEvent:
wm.PasswordLockoutPolicyWriteModel.AppendEvents(&e.PasswordLockoutPolicyAddedEvent)
case *org.PasswordLockoutPolicyChangedEvent:
wm.PasswordLockoutPolicyWriteModel.AppendEvents(&e.PasswordLockoutPolicyChangedEvent)
case *org.PasswordComplexityPolicyRemovedEvent:
wm.PasswordLockoutPolicyWriteModel.AppendEvents(&e.PasswordComplexityPolicyRemovedEvent)
}
}
}
func (wm *OrgPasswordLockoutPolicyWriteModel) Reduce() error {
return wm.PasswordLockoutPolicyWriteModel.Reduce()
}
func (wm *OrgPasswordLockoutPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.PasswordLockoutPolicyWriteModel.AggregateID).
ResourceOwner(wm.ResourceOwner)
}
func (wm *OrgPasswordLockoutPolicyWriteModel) NewChangedEvent(ctx context.Context, maxAttempts uint64, showLockoutFailure bool) (*org.PasswordLockoutPolicyChangedEvent, bool) {
changes := make([]policy.PasswordLockoutPolicyChanges, 0)
if wm.MaxAttempts != maxAttempts {
changes = append(changes, policy.ChangeMaxAttempts(maxAttempts))
}
if wm.ShowLockOutFailures != showLockoutFailure {
changes = append(changes, policy.ChangeShowLockOutFailures(showLockoutFailure))
}
if len(changes) == 0 {
return nil, false
}
changedEvent, err := org.NewPasswordLockoutPolicyChangedEvent(ctx, changes)
if err != nil {
return nil, false
}
return changedEvent, true
}
@@ -25,8 +25,8 @@ func (wm *PasswordAgePolicyWriteModel) Reduce() error {
if e.ExpireWarnDays != nil {
wm.ExpireWarnDays = *e.ExpireWarnDays
}
if e.ExpireWarnDays != nil {
wm.ExpireWarnDays = *e.ExpireWarnDays
if e.MaxAgeDays != nil {
wm.MaxAgeDays = *e.MaxAgeDays
}
case *policy.PasswordAgePolicyRemovedEvent:
wm.State = domain.PolicyStateRemoved
@@ -11,7 +11,7 @@ type PasswordComplexityPolicyWriteModel struct {
MinLength uint64
HasLowercase bool
HasUpperCase bool
HasUppercase bool
HasNumber bool
HasSymbol bool
State domain.PolicyState
@@ -23,7 +23,7 @@ func (wm *PasswordComplexityPolicyWriteModel) Reduce() error {
case *policy.PasswordComplexityPolicyAddedEvent:
wm.MinLength = e.MinLength
wm.HasLowercase = e.HasLowercase
wm.HasUpperCase = e.HasUpperCase
wm.HasUppercase = e.HasUppercase
wm.HasNumber = e.HasNumber
wm.HasSymbol = e.HasSymbol
wm.State = domain.PolicyStateActive
@@ -34,8 +34,8 @@ func (wm *PasswordComplexityPolicyWriteModel) Reduce() error {
if e.HasLowercase != nil {
wm.HasLowercase = *e.HasLowercase
}
if e.HasUpperCase != nil {
wm.HasUpperCase = *e.HasUpperCase
if e.HasUppercase != nil {
wm.HasUppercase = *e.HasUppercase
}
if e.HasNumber != nil {
wm.HasNumber = *e.HasNumber
+1 -2
View File
@@ -5,7 +5,6 @@ import (
"github.com/caos/logging"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
@@ -29,7 +28,7 @@ func (r *CommandSide) SetupStep7(ctx context.Context, step *Step7) error {
if !step.OTP {
return iamAgg, nil
}
err := r.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, iam_model.SecondFactorTypeOTP)
err := r.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, domain.SecondFactorTypeOTP)
if err != nil {
return nil, err
}
+1 -2
View File
@@ -5,7 +5,6 @@ import (
"github.com/caos/logging"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
@@ -29,7 +28,7 @@ func (r *CommandSide) SetupStep8(ctx context.Context, step *Step8) error {
if !step.U2F {
return iamAgg, nil
}
err := r.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, iam_model.SecondFactorTypeU2F)
err := r.addSecondFactorToDefaultLoginPolicy(ctx, iamAgg, secondFactorModel, domain.SecondFactorTypeU2F)
if err != nil {
return nil, err
}
+2 -3
View File
@@ -5,7 +5,6 @@ import (
"github.com/caos/logging"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/domain"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
@@ -34,7 +33,7 @@ func (r *CommandSide) SetupStep9(ctx context.Context, step *Step9) error {
return nil, err
}
logging.Log("SETUP-AEG2t").Info("allowed passwordless in login policy")
err = r.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, iam_model.MultiFactorTypeU2FWithPIN)
err = r.addMultiFactorToDefaultLoginPolicy(ctx, iamAgg, multiFactorModel, domain.MultiFactorTypeU2FWithPIN)
if err != nil {
return nil, err
}
@@ -45,7 +44,7 @@ func (r *CommandSide) SetupStep9(ctx context.Context, step *Step9) error {
}
func setPasswordlessAllowedInPolicy(ctx context.Context, c *CommandSide, iamAgg *iam_repo.Aggregate) error {
policy, err := c.GetDefaultLoginPolicy(ctx)
policy, err := c.getDefaultLoginPolicy(ctx)
if err != nil {
return err
}
+8
View File
@@ -138,6 +138,14 @@ func (r *CommandSide) RemoveUser(ctx context.Context, userID, resourceOwner stri
return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
}
func (r *CommandSide) checkUserExists(ctx context.Context, userID, resourceOwner string) (bool, error) {
userWriteModel, err := r.userWriteModelByID(ctx, userID, resourceOwner)
if err != nil {
return false, err
}
return userWriteModel.UserState != domain.UserStateUnspecified && userWriteModel.UserState != domain.UserStateDeleted, nil
}
func (r *CommandSide) userWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *UserWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
+1 -1
View File
@@ -70,7 +70,7 @@ func (r *CommandSide) createHuman(ctx context.Context, orgID string, human *doma
if err != nil {
return nil, nil, err
}
pwPolicy, err := r.GetOrgPasswordComplexityPolicy(ctx, orgID)
pwPolicy, err := r.getOrgPasswordComplexityPolicy(ctx, orgID)
if err != nil {
return nil, nil, err
}
+1 -1
View File
@@ -62,7 +62,7 @@ func (r *CommandSide) changePassword(ctx context.Context, orgID, userID, userAge
if existingPassword.UserState == domain.UserStateInitial {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-M9dse", "Errors.User.NotInitialised")
}
pwPolicy, err := r.GetOrgPasswordComplexityPolicy(ctx, orgID)
pwPolicy, err := r.getOrgPasswordComplexityPolicy(ctx, orgID)
if err != nil {
return err
}