new pkg structure (#1150)

* fix: split command query side

* fix: split command query side

* fix: members in correct pkg structure

* fix: label policy in correct pkg structure

* fix: structure

* fix: structure of login policy

* fix: identityprovider structure

* fix: org iam policy structure

* fix: password age policy structure

* fix: password complexity policy structure

* fix: password lockout policy structure

* fix: idp structure

* fix: user events structure

* fix: user write model

* fix: profile email changed command

* fix: address changed command

* fix: user states

* fix: user

* fix: org structure and add human

* begin iam setup command side

* setup

* step2

* step2

* fix: add user

* step2

* isvalid

* fix: folder structure v2 business

Co-authored-by: Fabiennne <fabienne.gerschwiler@gmail.com>
This commit is contained in:
Livio Amstutz
2021-01-04 14:52:13 +01:00
committed by GitHub
parent 762941f0ea
commit 21ffe1b0cb
260 changed files with 7917 additions and 6570 deletions

View File

@@ -1,280 +0,0 @@
package iam
import (
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/repository/iam"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/label"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/login"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/login/idpprovider"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/org_iam"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/password_age"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/password_complexity"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/password_lockout"
"github.com/caos/zitadel/internal/v2/repository/idp/oidc"
"github.com/caos/zitadel/internal/v2/repository/member"
)
func readModelToIAM(readModel *iam_repo.ReadModel) *model.IAM {
return &model.IAM{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel),
GlobalOrgID: readModel.GlobalOrgID,
IAMProjectID: readModel.ProjectID,
SetUpDone: model.Step(readModel.SetUpDone),
SetUpStarted: model.Step(readModel.SetUpStarted),
Members: readModelToMembers(&readModel.Members),
DefaultLabelPolicy: readModelToLabelPolicy(&readModel.DefaultLabelPolicy),
DefaultLoginPolicy: readModelToLoginPolicy(&readModel.DefaultLoginPolicy),
DefaultOrgIAMPolicy: readModelToOrgIAMPolicy(&readModel.DefaultOrgIAMPolicy),
DefaultPasswordAgePolicy: readModelToPasswordAgePolicy(&readModel.DefaultPasswordAgePolicy),
DefaultPasswordComplexityPolicy: readModelToPasswordComplexityPolicy(&readModel.DefaultPasswordComplexityPolicy),
DefaultPasswordLockoutPolicy: readModelToPasswordLockoutPolicy(&readModel.DefaultPasswordLockoutPolicy),
IDPs: readModelToIDPConfigs(&readModel.IDPs),
}
}
func readModelToMembers(readModel *iam_repo.MembersReadModel) []*model.IAMMember {
members := make([]*model.IAMMember, len(readModel.Members))
for i, member := range readModel.Members {
members[i] = &model.IAMMember{
ObjectRoot: readModelToObjectRoot(member.ReadModel),
Roles: member.Roles,
UserID: member.UserID,
}
}
return members
}
func readModelToLabelPolicy(readModel *label.ReadModel) *model.LabelPolicy {
return &model.LabelPolicy{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel.ReadModel),
PrimaryColor: readModel.PrimaryColor,
SecondaryColor: readModel.SecondaryColor,
Default: true,
//TODO: State: int32,
}
}
func readModelToLoginPolicy(readModel *login.ReadModel) *model.LoginPolicy {
return &model.LoginPolicy{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel.ReadModel),
AllowExternalIdp: readModel.AllowExternalIDP,
AllowRegister: readModel.AllowRegister,
AllowUsernamePassword: readModel.AllowUserNamePassword,
Default: true,
//TODO: IDPProviders: []*model.IDPProvider,
//TODO: State: int32,
}
}
func readModelToOrgIAMPolicy(readModel *org_iam.ReadModel) *model.OrgIAMPolicy {
return &model.OrgIAMPolicy{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel.ReadModel),
UserLoginMustBeDomain: readModel.UserLoginMustBeDomain,
Default: true,
//TODO: State: int32,
}
}
func readModelToPasswordAgePolicy(readModel *password_age.ReadModel) *model.PasswordAgePolicy {
return &model.PasswordAgePolicy{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel.ReadModel),
ExpireWarnDays: uint64(readModel.ExpireWarnDays),
MaxAgeDays: uint64(readModel.MaxAgeDays),
//TODO: State: int32,
}
}
func readModelToPasswordComplexityPolicy(readModel *password_complexity.ReadModel) *model.PasswordComplexityPolicy {
return &model.PasswordComplexityPolicy{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel.ReadModel),
HasLowercase: readModel.HasLowercase,
HasNumber: readModel.HasNumber,
HasSymbol: readModel.HasSymbol,
HasUppercase: readModel.HasUpperCase,
MinLength: uint64(readModel.MinLength),
//TODO: State: int32,
}
}
func readModelToPasswordLockoutPolicy(readModel *password_lockout.ReadModel) *model.PasswordLockoutPolicy {
return &model.PasswordLockoutPolicy{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel.ReadModel),
MaxAttempts: uint64(readModel.MaxAttempts),
ShowLockOutFailures: readModel.ShowLockOutFailures,
//TODO: State: int32,
}
}
func readModelToObjectRoot(readModel eventstore.ReadModel) models.ObjectRoot {
return models.ObjectRoot{
AggregateID: readModel.AggregateID,
ChangeDate: readModel.ChangeDate,
CreationDate: readModel.CreationDate,
ResourceOwner: readModel.ResourceOwner,
Sequence: readModel.ProcessedSequence,
}
}
func writeModelToObjectRoot(writeModel eventstore.WriteModel) models.ObjectRoot {
return models.ObjectRoot{
AggregateID: writeModel.AggregateID,
ChangeDate: writeModel.ChangeDate,
ResourceOwner: writeModel.ResourceOwner,
Sequence: writeModel.ProcessedSequence,
}
}
func readModelToMember(readModel *member.ReadModel) *model.IAMMember {
return &model.IAMMember{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel),
Roles: readModel.Roles,
UserID: readModel.UserID,
}
}
func writeModelToMember(writeModel *iam.MemberWriteModel) *model.IAMMember {
return &model.IAMMember{
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel.WriteModel),
Roles: writeModel.Roles,
UserID: writeModel.UserID,
}
}
func writeModelToLoginPolicy(wm *login.WriteModel) *model.LoginPolicy {
return &model.LoginPolicy{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel.WriteModel),
AllowUsernamePassword: wm.AllowUserNamePassword,
AllowRegister: wm.AllowRegister,
AllowExternalIdp: wm.AllowExternalIDP,
ForceMFA: wm.ForceMFA,
PasswordlessType: model.PasswordlessType(wm.PasswordlessType),
}
}
func writeModelToLabelPolicy(wm *label.WriteModel) *model.LabelPolicy {
return &model.LabelPolicy{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel.WriteModel),
PrimaryColor: wm.PrimaryColor,
SecondaryColor: wm.SecondaryColor,
}
}
func writeModelToOrgIAMPolicy(wm *org_iam.WriteModel) *model.OrgIAMPolicy {
return &model.OrgIAMPolicy{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel.WriteModel),
UserLoginMustBeDomain: wm.UserLoginMustBeDomain,
}
}
func writeModelToPasswordAgePolicy(wm *password_age.WriteModel) *model.PasswordAgePolicy {
return &model.PasswordAgePolicy{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel.WriteModel),
MaxAgeDays: wm.MaxAgeDays,
ExpireWarnDays: wm.ExpireWarnDays,
}
}
func writeModelToPasswordComplexityPolicy(wm *password_complexity.WriteModel) *model.PasswordComplexityPolicy {
return &model.PasswordComplexityPolicy{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel.WriteModel),
MinLength: wm.MinLength,
HasLowercase: wm.HasLowercase,
HasUppercase: wm.HasUpperCase,
HasNumber: wm.HasNumber,
HasSymbol: wm.HasSymbol,
}
}
func writeModelToPasswordLockoutPolicy(wm *password_lockout.WriteModel) *model.PasswordLockoutPolicy {
return &model.PasswordLockoutPolicy{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel.WriteModel),
MaxAttempts: wm.MaxAttempts,
ShowLockOutFailures: wm.ShowLockOutFailures,
}
}
func readModelToIDPConfigView(rm *iam.IDPConfigReadModel) *model.IDPConfigView {
return &model.IDPConfigView{
AggregateID: rm.AggregateID,
ChangeDate: rm.ChangeDate,
CreationDate: rm.CreationDate,
IDPConfigID: rm.ConfigID,
IDPProviderType: model.IDPProviderType(rm.ProviderType),
IsOIDC: rm.OIDCConfig != nil,
Name: rm.Name,
OIDCClientID: rm.OIDCConfig.ClientID,
OIDCClientSecret: rm.OIDCConfig.ClientSecret,
OIDCIDPDisplayNameMapping: model.OIDCMappingField(rm.OIDCConfig.IDPDisplayNameMapping),
OIDCIssuer: rm.OIDCConfig.Issuer,
OIDCScopes: rm.OIDCConfig.Scopes,
OIDCUsernameMapping: model.OIDCMappingField(rm.OIDCConfig.UserNameMapping),
Sequence: rm.ProcessedSequence,
State: model.IDPConfigState(rm.State),
StylingType: model.IDPStylingType(rm.StylingType),
}
}
func readModelToIDPConfigs(rm *iam.IDPConfigsReadModel) []*model.IDPConfig {
configs := make([]*model.IDPConfig, len(rm.Configs))
for i, config := range rm.Configs {
configs[i] = readModelToIDPConfig(&iam.IDPConfigReadModel{ConfigReadModel: *config})
}
return configs
}
func readModelToIDPConfig(rm *iam.IDPConfigReadModel) *model.IDPConfig {
return &model.IDPConfig{
ObjectRoot: readModelToObjectRoot(rm.ReadModel),
OIDCConfig: readModelToIDPOIDCConfig(rm.OIDCConfig),
IDPConfigID: rm.ConfigID,
Name: rm.Name,
State: model.IDPConfigState(rm.State),
StylingType: model.IDPStylingType(rm.StylingType),
}
}
func readModelToIDPOIDCConfig(rm *oidc.ConfigReadModel) *model.OIDCIDPConfig {
return &model.OIDCIDPConfig{
ObjectRoot: readModelToObjectRoot(rm.ReadModel),
ClientID: rm.ClientID,
ClientSecret: rm.ClientSecret,
ClientSecretString: string(rm.ClientSecret.Crypted),
IDPConfigID: rm.IDPConfigID,
IDPDisplayNameMapping: model.OIDCMappingField(rm.IDPDisplayNameMapping),
Issuer: rm.Issuer,
Scopes: rm.Scopes,
UsernameMapping: model.OIDCMappingField(rm.UserNameMapping),
}
}
func writeModelToIDPConfig(wm *iam.IDPConfigWriteModel) *model.IDPConfig {
return &model.IDPConfig{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
OIDCConfig: writeModelToIDPOIDCConfig(wm.OIDCConfig),
IDPConfigID: wm.ConfigID,
Name: wm.Name,
State: model.IDPConfigState(wm.State),
StylingType: model.IDPStylingType(wm.StylingType),
}
}
func writeModelToIDPOIDCConfig(wm *oidc.ConfigWriteModel) *model.OIDCIDPConfig {
return &model.OIDCIDPConfig{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
ClientID: wm.ClientID,
IDPConfigID: wm.IDPConfigID,
IDPDisplayNameMapping: model.OIDCMappingField(wm.IDPDisplayNameMapping),
Issuer: wm.Issuer,
Scopes: wm.Scopes,
UsernameMapping: model.OIDCMappingField(wm.UserNameMapping),
}
}
func writeModelToIDPProvider(wm *idpprovider.WriteModel) *model.IDPProvider {
return &model.IDPProvider{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel.WriteModel),
IDPConfigID: wm.IDPConfigID,
Type: model.IDPProviderType(wm.IDPProviderType),
}
}

View File

@@ -1,130 +0,0 @@
package iam
import (
"context"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/idp"
"github.com/caos/zitadel/internal/v2/repository/idp/oidc"
)
func (r *Repository) IDPConfigByID(ctx context.Context, iamID, idpConfigID string) (*iam_model.IDPConfigView, error) {
idpConfig := iam.NewIDPConfigReadModel(iamID, idpConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, idpConfig)
if err != nil {
return nil, err
}
return readModelToIDPConfigView(idpConfig), nil
}
func (r *Repository) AddIDPConfig(ctx context.Context, config *iam_model.IDPConfig) (*iam_model.IDPConfig, error) {
if config.OIDCConfig == nil {
return nil, errors.ThrowInvalidArgument(nil, "IAM-eUpQU", "Errors.idp.config.notset")
}
idpConfigID, err := r.idGenerator.Next()
if err != nil {
return nil, err
}
//TODO: check name unique on aggregate
clientSecret, err := crypto.Crypt([]byte(config.OIDCConfig.ClientSecretString), r.secretCrypto)
if err != nil {
return nil, err
}
writeModel, err := r.pushIDPWriteModel(ctx, config.AggregateID, idpConfigID, func(a *iam.Aggregate, _ *iam.IDPConfigWriteModel) *iam.Aggregate {
return a.
PushIDPConfigAdded(
ctx,
idpConfigID,
config.Name,
idp.ConfigType(config.Type),
idp.StylingType(config.StylingType)).
PushIDPOIDCConfigAdded(
ctx,
config.OIDCConfig.ClientID,
idpConfigID,
config.OIDCConfig.Issuer,
clientSecret,
oidc.MappingField(config.OIDCConfig.IDPDisplayNameMapping),
oidc.MappingField(config.OIDCConfig.UsernameMapping),
config.OIDCConfig.Scopes...)
})
if err != nil {
return nil, err
}
return writeModelToIDPConfig(writeModel), nil
}
func (r *Repository) ChangeIDPConfig(ctx context.Context, config *iam_model.IDPConfig) (*iam_model.IDPConfig, error) {
writeModel, err := r.pushIDPWriteModel(ctx, config.AggregateID, config.IDPConfigID, func(a *iam.Aggregate, writeModel *iam.IDPConfigWriteModel) *iam.Aggregate {
return a.PushIDPConfigChanged(
ctx,
writeModel,
config.IDPConfigID,
config.Name,
idp.ConfigType(config.Type),
idp.StylingType(config.StylingType))
})
if err != nil {
return nil, err
}
return writeModelToIDPConfig(writeModel), nil
}
func (r *Repository) DeactivateIDPConfig(ctx context.Context, iamID, idpID string) (*iam_model.IDPConfig, error) {
writeModel, err := r.pushIDPWriteModel(ctx, iamID, idpID, func(a *iam.Aggregate, _ *iam.IDPConfigWriteModel) *iam.Aggregate {
return a.PushIDPConfigDeactivated(ctx, idpID)
})
if err != nil {
return nil, err
}
return writeModelToIDPConfig(writeModel), nil
}
func (r *Repository) ReactivateIDPConfig(ctx context.Context, iamID, idpID string) (*iam_model.IDPConfig, error) {
writeModel, err := r.pushIDPWriteModel(ctx, iamID, idpID, func(a *iam.Aggregate, _ *iam.IDPConfigWriteModel) *iam.Aggregate {
return a.PushIDPConfigReactivated(ctx, idpID)
})
if err != nil {
return nil, err
}
return writeModelToIDPConfig(writeModel), nil
}
func (r *Repository) RemoveIDPConfig(ctx context.Context, iamID, idpID string) (*iam_model.IDPConfig, error) {
writeModel, err := r.pushIDPWriteModel(ctx, iamID, idpID, func(a *iam.Aggregate, _ *iam.IDPConfigWriteModel) *iam.Aggregate {
return a.PushIDPConfigRemoved(ctx, idpID)
})
if err != nil {
return nil, err
}
return writeModelToIDPConfig(writeModel), nil
}
func (r *Repository) pushIDPWriteModel(ctx context.Context, iamID, idpID string, eventSetter func(*iam.Aggregate, *iam.IDPConfigWriteModel) *iam.Aggregate) (*iam.IDPConfigWriteModel, error) {
writeModel := iam.NewIDPConfigWriteModel(iamID, idpID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
aggregate := eventSetter(iam.AggregateFromWriteModel(&writeModel.WriteModel), writeModel)
err = r.eventstore.PushAggregate(ctx, writeModel, aggregate)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -1,44 +0,0 @@
package iam
import (
"context"
"github.com/caos/zitadel/internal/crypto"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/idp/oidc"
)
func (r *Repository) ChangeIDPOIDCConfig(ctx context.Context, config *iam_model.OIDCIDPConfig) (*iam_model.OIDCIDPConfig, error) {
writeModel := iam.NewIDPOIDCConfigWriteModel(config.AggregateID, config.IDPConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
var clientSecret *crypto.CryptoValue
if config.ClientSecretString != "" {
clientSecret, err = crypto.Crypt([]byte(config.ClientSecretString), r.secretCrypto)
if err != nil {
return nil, err
}
}
aggregate := iam.AggregateFromWriteModel(&writeModel.WriteModel).
PushIDPOIDCConfigChanged(
ctx,
writeModel,
config.ClientID,
config.Issuer,
clientSecret,
oidc.MappingField(config.IDPDisplayNameMapping),
oidc.MappingField(config.UsernameMapping),
config.Scopes...)
err = r.eventstore.PushAggregate(ctx, writeModel, aggregate)
if err != nil {
return nil, err
}
return writeModelToIDPOIDCConfig(&writeModel.ConfigWriteModel), nil
}

View File

@@ -1,60 +0,0 @@
package iam
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/org_iam"
)
func (r *Repository) AddOrgIAMPolicy(ctx context.Context, policy *iam_model.OrgIAMPolicy) (*iam_model.OrgIAMPolicy, error) {
addedPolicy := org_iam.NewWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy != nil {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.OrgIAMPolicy.AlreadyExists")
}
iamAgg := iam_repo.AggregateFromWriteModel(&addedPolicy.WriteModel.WriteModel).
PushOrgIAMPolicyAddedEvent(ctx, policy.UserLoginMustBeDomain)
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToOrgIAMPolicy(addedPolicy), nil
}
func (r *Repository) ChangeOrgIAMPolicy(ctx context.Context, policy *iam_model.OrgIAMPolicy) (*iam_model.OrgIAMPolicy, error) {
existingPolicy, err := r.orgIAMPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
iamAgg := iam_repo.AggregateFromWriteModel(&existingPolicy.WriteModel.WriteModel).
PushOrgIAMPolicyChangedFromExisting(ctx, existingPolicy, policy.UserLoginMustBeDomain)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToOrgIAMPolicy(existingPolicy), nil
}
func (r *Repository) orgIAMPolicyWriteModelByID(ctx context.Context, iamID string) (policy *org_iam.WriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := org_iam.NewWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -1,69 +0,0 @@
package iam
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/label"
iam_model "github.com/caos/zitadel/internal/iam/model"
)
func (r *Repository) AddLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error) {
if !policy.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-5Mv0s", "Errors.IAM.LabelPolicyInvalid")
}
addedPolicy := label.NewWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy != nil {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LabelPolicy.AlreadyExists")
}
iamAgg := iam_repo.AggregateFromWriteModel(&addedPolicy.WriteModel.WriteModel).
PushLabelPolicyAddedEvent(ctx, policy.PrimaryColor, policy.SecondaryColor)
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(addedPolicy), nil
}
func (r *Repository) ChangeLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error) {
if !policy.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-6M0od", "Errors.IAM.LabelPolicyInvalid")
}
existingPolicy, err := r.labelPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
iamAgg := iam_repo.AggregateFromWriteModel(&existingPolicy.WriteModel.WriteModel).
PushLabelPolicyChangedFromExisting(ctx, existingPolicy, policy.PrimaryColor, policy.SecondaryColor)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(existingPolicy), nil
}
func (r *Repository) labelPolicyWriteModelByID(ctx context.Context, iamID string) (policy *label.WriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := label.NewWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -1,160 +0,0 @@
package iam
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
iam_login "github.com/caos/zitadel/internal/v2/repository/iam/policy/login"
iam_factor "github.com/caos/zitadel/internal/v2/repository/iam/policy/login/factors"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/login/idpprovider"
"github.com/caos/zitadel/internal/v2/repository/policy/login"
"github.com/caos/zitadel/internal/v2/repository/policy/login/factors"
idpprovider2 "github.com/caos/zitadel/internal/v2/repository/policy/login/idpprovider"
)
func (r *Repository) AddLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
if !policy.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-5Mv0s", "Errors.IAM.LoginPolicyInvalid")
}
addedPolicy := iam_login.NewWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy != nil {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.AlreadyExists")
}
iamAgg := iam_repo.AggregateFromWriteModel(&addedPolicy.WriteModel.WriteModel).
PushLoginPolicyAddedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIdp, policy.ForceMFA, login.PasswordlessType(policy.PasswordlessType))
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(addedPolicy), nil
}
func (r *Repository) ChangeLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
if !policy.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-6M0od", "Errors.IAM.LoginPolicyInvalid")
}
existingPolicy, err := r.loginPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
iamAgg := iam_repo.AggregateFromWriteModel(&existingPolicy.WriteModel.WriteModel).
PushLoginPolicyChangedFromExisting(ctx, existingPolicy, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIdp, policy.ForceMFA, login.PasswordlessType(policy.PasswordlessType))
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(existingPolicy), nil
}
func (r *Repository) AddIDPProviderToLoginPolicy(ctx context.Context, idpProvider *iam_model.IDPProvider) (*iam_model.IDPProvider, error) {
writeModel := idpprovider.NewWriteModel(idpProvider.AggregateID, idpProvider.IDPConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
aggregate := iam_repo.AggregateFromWriteModel(&writeModel.WriteModel.WriteModel).
PushLoginPolicyIDPProviderAddedEvent(ctx, idpProvider.IDPConfigID, idpprovider2.Type(idpProvider.Type))
if err = r.eventstore.PushAggregate(ctx, writeModel, aggregate); err != nil {
return nil, err
}
return writeModelToIDPProvider(writeModel), nil
}
func (r *Repository) RemoveIDPProviderFromLoginPolicy(ctx context.Context, idpProvider *iam_model.IDPProvider) error {
writeModel := idpprovider.NewWriteModel(idpProvider.AggregateID, idpProvider.IDPConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return err
}
aggregate := iam_repo.AggregateFromWriteModel(&writeModel.WriteModel.WriteModel).
PushLoginPolicyIDPProviderAddedEvent(ctx, idpProvider.IDPConfigID, idpprovider2.Type(idpProvider.Type))
return r.eventstore.PushAggregate(ctx, writeModel, aggregate)
}
func (r *Repository) AddSecondFactorToLoginPolicy(ctx context.Context, iamID string, secondFactor iam_model.SecondFactorType) (iam_model.SecondFactorType, error) {
writeModel := iam_factor.NewSecondFactorWriteModel(iamID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return iam_model.SecondFactorTypeUnspecified, err
}
aggregate := iam_repo.AggregateFromWriteModel(&writeModel.SecondFactorWriteModel.WriteModel).
PushLoginPolicySecondFactorAdded(ctx, factors.SecondFactorType(secondFactor))
if err = r.eventstore.PushAggregate(ctx, writeModel, aggregate); err != nil {
return iam_model.SecondFactorTypeUnspecified, err
}
return iam_model.SecondFactorType(writeModel.MFAType), nil
}
func (r *Repository) RemoveSecondFactorFromLoginPolicy(ctx context.Context, iamID string, secondFactor iam_model.SecondFactorType) error {
writeModel := iam_factor.NewSecondFactorWriteModel(iamID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return err
}
aggregate := iam_repo.AggregateFromWriteModel(&writeModel.SecondFactorWriteModel.WriteModel).
PushLoginPolicySecondFactorRemoved(ctx, factors.SecondFactorType(secondFactor))
return r.eventstore.PushAggregate(ctx, writeModel, aggregate)
}
func (r *Repository) AddMultiFactorToLoginPolicy(ctx context.Context, iamID string, secondFactor iam_model.MultiFactorType) (iam_model.MultiFactorType, error) {
writeModel := iam_factor.NewMultiFactorWriteModel(iamID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return iam_model.MultiFactorTypeUnspecified, err
}
aggregate := iam_repo.AggregateFromWriteModel(&writeModel.MultiFactoryWriteModel.WriteModel).
PushLoginPolicyMultiFactorAdded(ctx, factors.MultiFactorType(secondFactor))
if err = r.eventstore.PushAggregate(ctx, writeModel, aggregate); err != nil {
return iam_model.MultiFactorTypeUnspecified, err
}
return iam_model.MultiFactorType(writeModel.MultiFactoryWriteModel.MFAType), nil
}
func (r *Repository) RemoveMultiFactorFromLoginPolicy(ctx context.Context, iamID string, secondFactor iam_model.MultiFactorType) error {
writeModel := iam_factor.NewMultiFactorWriteModel(iamID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return err
}
aggregate := iam_repo.AggregateFromWriteModel(&writeModel.MultiFactoryWriteModel.WriteModel).
PushLoginPolicyMultiFactorRemoved(ctx, factors.MultiFactorType(secondFactor))
return r.eventstore.PushAggregate(ctx, writeModel, aggregate)
}
func (r *Repository) loginPolicyWriteModelByID(ctx context.Context, iamID string) (policy *iam_login.WriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := iam_login.NewWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -1,60 +0,0 @@
package iam
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/password_age"
)
func (r *Repository) AddPasswordAgePolicy(ctx context.Context, policy *iam_model.PasswordAgePolicy) (*iam_model.PasswordAgePolicy, error) {
addedPolicy := password_age.NewWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy != nil {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-6L0pd", "Errors.IAM.PasswordAgePolicy.AlreadyExists")
}
iamAgg := iam_repo.AggregateFromWriteModel(&addedPolicy.WriteModel.WriteModel).
PushPasswordAgePolicyAddedEvent(ctx, policy.ExpireWarnDays, policy.MaxAgeDays)
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(addedPolicy), nil
}
func (r *Repository) ChangePasswordAgePolicy(ctx context.Context, policy *iam_model.PasswordAgePolicy) (*iam_model.PasswordAgePolicy, error) {
existingPolicy, err := r.passwordAgePolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
iamAgg := iam_repo.AggregateFromWriteModel(&existingPolicy.WriteModel.WriteModel).
PushPasswordAgePolicyChangedFromExisting(ctx, existingPolicy, policy.ExpireWarnDays, policy.MaxAgeDays)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(existingPolicy), nil
}
func (r *Repository) passwordAgePolicyWriteModelByID(ctx context.Context, iamID string) (policy *password_age.WriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := password_age.NewWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -1,68 +0,0 @@
package iam
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/password_complexity"
)
func (r *Repository) AddPasswordComplexityPolicy(ctx context.Context, policy *iam_model.PasswordComplexityPolicy) (*iam_model.PasswordComplexityPolicy, error) {
if err := policy.IsValid(); err != nil {
return nil, err
}
addedPolicy := password_complexity.NewWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy != nil {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.PasswordComplexityPolicy.AlreadyExists")
}
iamAgg := iam_repo.AggregateFromWriteModel(&addedPolicy.WriteModel.WriteModel).
PushPasswordComplexityPolicyAddedEvent(ctx, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol)
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(addedPolicy), nil
}
func (r *Repository) ChangePasswordComplexityPolicy(ctx context.Context, policy *iam_model.PasswordComplexityPolicy) (*iam_model.PasswordComplexityPolicy, error) {
if err := policy.IsValid(); err != nil {
return nil, err
}
existingPolicy, err := r.passwordComplexityPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
iamAgg := iam_repo.AggregateFromWriteModel(&existingPolicy.WriteModel.WriteModel).
PushPasswordComplexityPolicyChangedFromExisting(ctx, existingPolicy, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(existingPolicy), nil
}
func (r *Repository) passwordComplexityPolicyWriteModelByID(ctx context.Context, iamID string) (policy *password_complexity.WriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := password_complexity.NewWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -1,60 +0,0 @@
package iam
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/iam/policy/password_lockout"
)
func (r *Repository) AddPasswordLockoutPolicy(ctx context.Context, policy *iam_model.PasswordLockoutPolicy) (*iam_model.PasswordLockoutPolicy, error) {
addedPolicy := password_lockout.NewWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy != nil {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-0olDf", "Errors.IAM.PasswordLockoutPolicy.AlreadyExists")
}
iamAgg := iam_repo.AggregateFromWriteModel(&addedPolicy.WriteModel.WriteModel).
PushPasswordLockoutPolicyAddedEvent(ctx, policy.MaxAttempts, policy.ShowLockOutFailures)
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordLockoutPolicy(addedPolicy), nil
}
func (r *Repository) ChangePasswordLockoutPolicy(ctx context.Context, policy *iam_model.PasswordLockoutPolicy) (*iam_model.PasswordLockoutPolicy, error) {
existingPolicy, err := r.passwordLockoutPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
iamAgg := iam_repo.AggregateFromWriteModel(&existingPolicy.WriteModel.WriteModel).
PushPasswordLockoutPolicyChangedFromExisting(ctx, existingPolicy, policy.MaxAttempts, policy.ShowLockOutFailures)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordLockoutPolicy(existingPolicy), nil
}
func (r *Repository) passwordLockoutPolicyWriteModelByID(ctx context.Context, iamID string) (policy *password_lockout.WriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := password_lockout.NewWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -1,50 +0,0 @@
package iam
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v2"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *Repository) StartSetup(ctx context.Context, iamID string, step iam_model.Step) (*iam_model.IAM, error) {
iam, err := r.setup(ctx, iamID, iam_repo.Step(step), iam_repo.NewSetupStepStartedEvent(ctx, iam_repo.Step(step)))
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-zx03n", "Setup start failed")
}
return iam, nil
}
func (r *Repository) SetupDone(ctx context.Context, iamID string, step iam_model.Step) (*iam_model.IAM, error) {
iam, err := r.setup(ctx, iamID, iam_repo.Step(step), iam_repo.NewSetupStepDoneEvent(ctx, iam_repo.Step(step)))
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-zx03n", "Setup start failed")
}
return iam, nil
}
func (r *Repository) setup(ctx context.Context, iamID string, step iam_repo.Step, event eventstore.EventPusher) (*iam_model.IAM, error) {
iam, err := r.iamByID(ctx, iamID)
if err != nil && !caos_errs.IsNotFound(err) {
return nil, err
}
if iam != nil && (iam.SetUpStarted >= iam_repo.Step(step) || iam.SetUpStarted != iam.SetUpDone) {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9so34", "setup error")
}
aggregate := iam_repo.AggregateFromReadModel(iam).
PushEvents(event)
events, err := r.eventstore.PushAggregates(ctx, aggregate)
if err != nil {
return nil, err
}
if err = iam.AppendAndReduce(events...); err != nil {
return nil, err
}
return readModelToIAM(iam), nil
}

View File

@@ -1,99 +0,0 @@
package org
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
iam_model "github.com/caos/zitadel/internal/iam/model"
)
type Repository struct {
eventstore *eventstore.Eventstore
}
type Config struct {
Eventstore *eventstore.Eventstore
}
func StartRepository(config *Config) *Repository {
return &Repository{
eventstore: config.Eventstore,
}
}
func (r *Repository) GetMyOrgIamPolicy(ctx context.Context) (*iam_model.OrgIAMPolicyView, error) {
return nil, nil
}
func (r *Repository) GetLoginPolicy(ctx context.Context) (*iam_model.LoginPolicyView, error) {
return nil, nil
}
func (r *Repository) GetDefaultLoginPolicy(ctx context.Context) (*iam_model.LoginPolicyView, error) {
return nil, nil
}
func (r *Repository) AddLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
return nil, nil
}
func (r *Repository) ChangeLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
return nil, nil
}
func (r *Repository) RemoveLoginPolicy(ctx context.Context) error {
return nil
}
func (r *Repository) SearchIDPProviders(ctx context.Context, request *iam_model.IDPProviderSearchRequest) (*iam_model.IDPProviderSearchResponse, error) {
return nil, nil
}
func (r *Repository) AddIDPProviderToLoginPolicy(ctx context.Context, provider *iam_model.IDPProvider) (*iam_model.IDPProvider, error) {
return nil, nil
}
func (r *Repository) RemoveIDPProviderFromLoginPolicy(ctx context.Context, provider *iam_model.IDPProvider) error {
return nil
}
func (r *Repository) GetPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error) {
return nil, nil
}
func (r *Repository) GetDefaultPasswordComplexityPolicy(ctx context.Context) (*iam_model.PasswordComplexityPolicyView, error) {
return nil, nil
}
func (r *Repository) AddPasswordComplexityPolicy(ctx context.Context, policy *iam_model.PasswordComplexityPolicy) (*iam_model.PasswordComplexityPolicy, error) {
return nil, nil
}
func (r *Repository) ChangePasswordComplexityPolicy(ctx context.Context, policy *iam_model.PasswordComplexityPolicy) (*iam_model.PasswordComplexityPolicy, error) {
return nil, nil
}
func (r *Repository) RemovePasswordComplexityPolicy(ctx context.Context) error {
return nil
}
func (r *Repository) GetPasswordAgePolicy(ctx context.Context) (*iam_model.PasswordAgePolicyView, error) {
return nil, nil
}
func (r *Repository) GetDefaultPasswordAgePolicy(ctx context.Context) (*iam_model.PasswordAgePolicyView, error) {
return nil, nil
}
func (r *Repository) AddPasswordAgePolicy(ctx context.Context, policy *iam_model.PasswordAgePolicy) (*iam_model.PasswordAgePolicy, error) {
return nil, nil
}
func (r *Repository) ChangePasswordAgePolicy(ctx context.Context, policy *iam_model.PasswordAgePolicy) (*iam_model.PasswordAgePolicy, error) {
return nil, nil
}
func (r *Repository) RemovePasswordAgePolicy(ctx context.Context) error {
return nil
}
func (r *Repository) GetPasswordLockoutPolicy(ctx context.Context) (*iam_model.PasswordLockoutPolicyView, error) {
return nil, nil
}
func (r *Repository) GetDefaultPasswordLockoutPolicy(ctx context.Context) (*iam_model.PasswordLockoutPolicyView, error) {
return nil, nil
}
func (r *Repository) AddPasswordLockoutPolicy(ctx context.Context, policy *iam_model.PasswordLockoutPolicy) (*iam_model.PasswordLockoutPolicy, error) {
return nil, nil
}
func (r *Repository) ChangePasswordLockoutPolicy(ctx context.Context, policy *iam_model.PasswordLockoutPolicy) (*iam_model.PasswordLockoutPolicy, error) {
return nil, nil
}
func (r *Repository) RemovePasswordLockoutPolicy(ctx context.Context) error {
return nil
}

View File

@@ -0,0 +1,72 @@
package command
import (
"context"
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"
"github.com/caos/zitadel/internal/telemetry/tracing"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
type CommandSide struct {
eventstore *eventstore.Eventstore
idGenerator id.Generator
iamID string
idpConfigSecretCrypto crypto.Crypto
userPasswordAlg crypto.HashAlgorithm
initializeUserCode crypto.Generator
emailVerificationCode crypto.Generator
phoneVerificationCode crypto.Generator
passwordVerificationCode crypto.Generator
machineKeyAlg crypto.EncryptionAlgorithm
machineKeySize int
}
type Config struct {
Eventstore *eventstore.Eventstore
SystemDefaults sd.SystemDefaults
}
func StartCommandSide(config *Config) (repo *CommandSide, err error) {
repo = &CommandSide{
eventstore: config.Eventstore,
idGenerator: id.SonyFlakeGenerator,
iamID: config.SystemDefaults.IamID,
}
iam_repo.RegisterEventMappers(repo.eventstore)
repo.idpConfigSecretCrypto, err = crypto.NewAESCrypto(config.SystemDefaults.IDPConfigVerificationKey)
if err != nil {
return nil, err
}
aesCrypto, err := crypto.NewAESCrypto(config.SystemDefaults.UserVerificationKey)
if err != nil {
return nil, err
}
repo.initializeUserCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.InitializeUserCode, aesCrypto)
repo.emailVerificationCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.EmailVerificationCode, aesCrypto)
repo.phoneVerificationCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.PhoneVerificationCode, aesCrypto)
repo.passwordVerificationCode = crypto.NewEncryptionGenerator(config.SystemDefaults.SecretGenerators.PasswordVerificationCode, aesCrypto)
repo.userPasswordAlg = crypto.NewBCrypt(config.SystemDefaults.SecretGenerators.PasswordSaltCost)
repo.machineKeyAlg = aesCrypto
repo.machineKeySize = int(config.SystemDefaults.SecretGenerators.MachineKeySize)
return repo, nil
}
func (r *CommandSide) iamByID(ctx context.Context, id string) (_ *IAMWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMriteModel(id)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,118 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/iam/model"
)
func writeModelToObjectRoot(writeModel eventstore.WriteModel) models.ObjectRoot {
return models.ObjectRoot{
AggregateID: writeModel.AggregateID,
ChangeDate: writeModel.ChangeDate,
ResourceOwner: writeModel.ResourceOwner,
Sequence: writeModel.ProcessedSequence,
}
}
func writeModelToIAM(wm *IAMWriteModel) *model.IAM {
return &model.IAM{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
SetUpStarted: wm.SetUpStarted,
SetUpDone: wm.SetUpDone,
GlobalOrgID: wm.GlobalOrgID,
IAMProjectID: wm.ProjectID,
}
}
func writeModelToMember(writeModel *IAMMemberWriteModel) *model.IAMMember {
return &model.IAMMember{
ObjectRoot: writeModelToObjectRoot(writeModel.MemberWriteModel.WriteModel),
Roles: writeModel.Roles,
UserID: writeModel.UserID,
}
}
func writeModelToLoginPolicy(wm *IAMLoginPolicyWriteModel) *model.LoginPolicy {
return &model.LoginPolicy{
ObjectRoot: writeModelToObjectRoot(wm.LoginPolicyWriteModel.WriteModel),
AllowUsernamePassword: wm.AllowUserNamePassword,
AllowRegister: wm.AllowRegister,
AllowExternalIdp: wm.AllowExternalIDP,
ForceMFA: wm.ForceMFA,
PasswordlessType: model.PasswordlessType(wm.PasswordlessType),
}
}
func writeModelToLabelPolicy(wm *IAMLabelPolicyWriteModel) *model.LabelPolicy {
return &model.LabelPolicy{
ObjectRoot: writeModelToObjectRoot(wm.LabelPolicyWriteModel.WriteModel),
PrimaryColor: wm.PrimaryColor,
SecondaryColor: wm.SecondaryColor,
}
}
func writeModelToOrgIAMPolicy(wm *IAMOrgIAMPolicyWriteModel) *model.OrgIAMPolicy {
return &model.OrgIAMPolicy{
ObjectRoot: writeModelToObjectRoot(wm.PolicyOrgIAMWriteModel.WriteModel),
UserLoginMustBeDomain: wm.UserLoginMustBeDomain,
}
}
func writeModelToPasswordAgePolicy(wm *IAMPasswordAgePolicyWriteModel) *model.PasswordAgePolicy {
return &model.PasswordAgePolicy{
ObjectRoot: writeModelToObjectRoot(wm.PasswordAgePolicyWriteModel.WriteModel),
MaxAgeDays: wm.MaxAgeDays,
ExpireWarnDays: wm.ExpireWarnDays,
}
}
func writeModelToPasswordComplexityPolicy(wm *IAMPasswordComplexityPolicyWriteModel) *model.PasswordComplexityPolicy {
return &model.PasswordComplexityPolicy{
ObjectRoot: writeModelToObjectRoot(wm.PasswordComplexityPolicyWriteModel.WriteModel),
MinLength: wm.MinLength,
HasLowercase: wm.HasLowercase,
HasUppercase: wm.HasUpperCase,
HasNumber: wm.HasNumber,
HasSymbol: wm.HasSymbol,
}
}
func writeModelToPasswordLockoutPolicy(wm *IAMPasswordLockoutPolicyWriteModel) *model.PasswordLockoutPolicy {
return &model.PasswordLockoutPolicy{
ObjectRoot: writeModelToObjectRoot(wm.PasswordLockoutPolicyWriteModel.WriteModel),
MaxAttempts: wm.MaxAttempts,
ShowLockOutFailures: wm.ShowLockOutFailures,
}
}
func writeModelToIDPConfig(wm *IAMIDPConfigWriteModel) *model.IDPConfig {
return &model.IDPConfig{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
OIDCConfig: writeModelToIDPOIDCConfig(wm.OIDCConfig),
IDPConfigID: wm.ConfigID,
Name: wm.Name,
State: model.IDPConfigState(wm.State),
StylingType: model.IDPStylingType(wm.StylingType),
}
}
func writeModelToIDPOIDCConfig(wm *OIDCConfigWriteModel) *model.OIDCIDPConfig {
return &model.OIDCIDPConfig{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
ClientID: wm.ClientID,
IDPConfigID: wm.IDPConfigID,
IDPDisplayNameMapping: model.OIDCMappingField(wm.IDPDisplayNameMapping),
Issuer: wm.Issuer,
Scopes: wm.Scopes,
UsernameMapping: model.OIDCMappingField(wm.UserNameMapping),
}
}
func writeModelToIDPProvider(wm *IAMIdentityProviderWriteModel) *model.IDPProvider {
return &model.IDPProvider{
ObjectRoot: writeModelToObjectRoot(wm.IdentityProviderWriteModel.WriteModel),
IDPConfigID: wm.IDPConfigID,
Type: model.IDPProviderType(wm.IDPProviderType),
}
}

View File

@@ -0,0 +1,159 @@
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"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/v2/repository/iam"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *CommandSide) AddDefaultIDPConfig(ctx context.Context, config *iam_model.IDPConfig) (*iam_model.IDPConfig, error) {
if config.OIDCConfig == nil {
return nil, errors.ThrowInvalidArgument(nil, "IAM-eUpQU", "Errors.idp.config.notset")
}
idpConfigID, err := r.idGenerator.Next()
if err != nil {
return nil, err
}
//TODO: check name unique on aggregate
addedConfig := NewIAMIDPConfigWriteModel(config.AggregateID, idpConfigID)
clientSecret, err := crypto.Crypt([]byte(config.OIDCConfig.ClientSecretString), r.idpConfigSecretCrypto)
if err != nil {
return nil, err
}
iamAgg := IAMAggregateFromWriteModel(&addedConfig.WriteModel)
iamAgg.PushEvents(
iam_repo.NewIDPConfigAddedEvent(
ctx,
idpConfigID,
config.Name,
domain.IDPConfigType(config.Type),
domain.IDPConfigStylingType(config.StylingType),
),
)
iamAgg.PushEvents(
iam_repo.NewIDPOIDCConfigAddedEvent(
ctx, config.OIDCConfig.ClientID,
idpConfigID,
config.OIDCConfig.Issuer,
clientSecret,
domain.OIDCMappingField(config.OIDCConfig.IDPDisplayNameMapping),
domain.OIDCMappingField(config.OIDCConfig.UsernameMapping),
config.OIDCConfig.Scopes...,
),
)
err = r.eventstore.PushAggregate(ctx, addedConfig, iamAgg)
if err != nil {
return nil, err
}
return writeModelToIDPConfig(addedConfig), nil
}
func (r *CommandSide) ChangeDefaultIDPConfig(ctx context.Context, config *iam_model.IDPConfig) (*iam_model.IDPConfig, error) {
existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, config.AggregateID, config.IDPConfigID)
if err != nil {
return nil, err
}
if existingIDP.State == domain.IDPConfigStateRemoved || existingIDP.State == domain.IDPConfigStateUnspecified {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-4M9so", "Errors.IAM.IDPConfig.NotExisting")
}
changedEvent, hasChanged := existingIDP.NewChangedEvent(ctx, config.IDPConfigID, config.Name, domain.IDPConfigStylingType(config.StylingType))
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingIDP.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingIDP, iamAgg)
if err != nil {
return nil, err
}
return writeModelToIDPConfig(existingIDP), nil
}
func (r *CommandSide) DeactivateDefaultIDPConfig(ctx context.Context, iamID, idpID string) (*iam_model.IDPConfig, error) {
existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, iamID, idpID)
if err != nil {
return nil, err
}
if existingIDP.State != domain.IDPConfigStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-4M9so", "Errors.IAM.IDPConfig.NotActive")
}
iamAgg := IAMAggregateFromWriteModel(&existingIDP.WriteModel)
iamAgg.PushEvents(iam_repo.NewIDPConfigDeactivatedEvent(ctx, idpID))
err = r.eventstore.PushAggregate(ctx, existingIDP, iamAgg)
if err != nil {
return nil, err
}
return writeModelToIDPConfig(existingIDP), nil
}
func (r *CommandSide) ReactivateDefaultIDPConfig(ctx context.Context, iamID, idpID string) (*iam_model.IDPConfig, error) {
existingIDP, err := r.iamIDPConfigWriteModelByID(ctx, iamID, idpID)
if err != nil {
return nil, err
}
if existingIDP.State != domain.IDPConfigStateInactive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-5Mo0d", "Errors.IAM.IDPConfig.NotInactive")
}
iamAgg := IAMAggregateFromWriteModel(&existingIDP.WriteModel)
iamAgg.PushEvents(iam_repo.NewIDPConfigReactivatedEvent(ctx, idpID))
err = r.eventstore.PushAggregate(ctx, existingIDP, iamAgg)
if err != nil {
return nil, err
}
return writeModelToIDPConfig(existingIDP), nil
}
func (r *CommandSide) RemoveDefaultIDPConfig(ctx context.Context, iamID, idpID string) (*iam_model.IDPConfig, error) {
writeModel, err := r.pushDefaultIDPWriteModel(ctx, iamID, 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
}
func (r *CommandSide) pushDefaultIDPWriteModel(ctx context.Context, iamID, idpID string, eventSetter func(*iam.Aggregate, *IAMIDPConfigWriteModel) *iam.Aggregate) (*IAMIDPConfigWriteModel, error) {
writeModel := NewIAMIDPConfigWriteModel(iamID, idpID)
err := r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
aggregate := eventSetter(IAMAggregateFromWriteModel(&writeModel.WriteModel), writeModel)
err = r.eventstore.PushAggregate(ctx, writeModel, aggregate)
if err != nil {
return nil, err
}
return writeModel, nil
}
func (r *CommandSide) iamIDPConfigWriteModelByID(ctx context.Context, iamID, idpID string) (policy *IAMIDPConfigWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMIDPConfigWriteModel(iamID, idpID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,100 @@
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/iam"
)
type IAMIDPConfigWriteModel struct {
IDPConfigWriteModel
}
func NewIAMIDPConfigWriteModel(iamID, configID string) *IAMIDPConfigWriteModel {
return &IAMIDPConfigWriteModel{
IDPConfigWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
ConfigID: configID,
},
}
}
func (wm *IAMIDPConfigWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.AggregateID)
}
func (wm *IAMIDPConfigWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.IDPConfigAddedEvent:
if wm.ConfigID != e.ConfigID {
continue
}
wm.IDPConfigWriteModel.AppendEvents(&e.IDPConfigAddedEvent)
case *iam.IDPConfigChangedEvent:
if wm.ConfigID != e.ConfigID {
continue
}
wm.IDPConfigWriteModel.AppendEvents(&e.IDPConfigChangedEvent)
case *iam.IDPConfigDeactivatedEvent:
if wm.ConfigID != e.ConfigID {
continue
}
wm.IDPConfigWriteModel.AppendEvents(&e.IDPConfigDeactivatedEvent)
case *iam.IDPConfigReactivatedEvent:
if wm.ConfigID != e.ConfigID {
continue
}
wm.IDPConfigWriteModel.AppendEvents(&e.IDPConfigReactivatedEvent)
case *iam.IDPConfigRemovedEvent:
if wm.ConfigID != e.ConfigID {
continue
}
wm.IDPConfigWriteModel.AppendEvents(&e.IDPConfigRemovedEvent)
case *iam.IDPOIDCConfigAddedEvent:
if wm.ConfigID != e.IDPConfigID {
continue
}
wm.IDPConfigWriteModel.AppendEvents(&e.OIDCConfigAddedEvent)
case *iam.IDPOIDCConfigChangedEvent:
if wm.ConfigID != e.IDPConfigID {
continue
}
wm.IDPConfigWriteModel.AppendEvents(&e.OIDCConfigChangedEvent)
}
}
}
func (wm *IAMIDPConfigWriteModel) Reduce() error {
return wm.IDPConfigWriteModel.Reduce()
}
func (wm *IAMIDPConfigWriteModel) AppendAndReduce(events ...eventstore.EventReader) error {
wm.AppendEvents(events...)
return wm.Reduce()
}
func (wm *IAMIDPConfigWriteModel) NewChangedEvent(
ctx context.Context,
configID,
name string,
stylingType domain.IDPConfigStylingType,
) (*iam.IDPConfigChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewIDPConfigChangedEvent(ctx)
changedEvent.ConfigID = configID
if wm.Name != name {
hasChanged = true
changedEvent.Name = name
}
if stylingType.Valid() && wm.StylingType != stylingType {
hasChanged = true
changedEvent.StylingType = stylingType
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,47 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/v2/domain"
iam_model "github.com/caos/zitadel/internal/iam/model"
)
func (r *CommandSide) ChangeDefaultIDPOIDCConfig(ctx context.Context, config *iam_model.OIDCIDPConfig) (*iam_model.OIDCIDPConfig, error) {
existingConfig := NewIDPOIDCConfigWriteModel(config.AggregateID, config.IDPConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, existingConfig)
if err != nil {
return nil, err
}
if existingConfig.State == domain.IDPConfigStateRemoved || existingConfig.State == domain.IDPConfigStateUnspecified {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-67J9d", "Errors.IAM.IDPConfig.AlreadyExists")
}
changedEvent, hasChanged, err := existingConfig.NewChangedEvent(
ctx,
config.ClientID,
config.Issuer,
config.ClientSecretString,
r.idpConfigSecretCrypto,
domain.OIDCMappingField(config.IDPDisplayNameMapping),
domain.OIDCMappingField(config.UsernameMapping),
config.Scopes...)
if err != nil {
return nil, err
}
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingConfig.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingConfig, iamAgg)
if err != nil {
return nil, err
}
return writeModelToIDPOIDCConfig(&existingConfig.OIDCConfigWriteModel), nil
}

View File

@@ -0,0 +1,115 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/iam"
"reflect"
)
type IDPOIDCConfigWriteModel struct {
OIDCConfigWriteModel
}
func NewIDPOIDCConfigWriteModel(iamID, idpConfigID string) *IDPOIDCConfigWriteModel {
return &IDPOIDCConfigWriteModel{
OIDCConfigWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
IDPConfigID: idpConfigID,
},
}
}
func (wm *IDPOIDCConfigWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.IDPOIDCConfigAddedEvent:
if wm.IDPConfigID != e.IDPConfigID {
continue
}
wm.OIDCConfigWriteModel.AppendEvents(&e.OIDCConfigAddedEvent)
case *iam.IDPOIDCConfigChangedEvent:
if wm.IDPConfigID != e.IDPConfigID {
continue
}
wm.OIDCConfigWriteModel.AppendEvents(&e.OIDCConfigChangedEvent)
case *iam.IDPConfigReactivatedEvent:
if wm.IDPConfigID != e.ConfigID {
continue
}
wm.OIDCConfigWriteModel.AppendEvents(&e.IDPConfigReactivatedEvent)
case *iam.IDPConfigDeactivatedEvent:
if wm.IDPConfigID != e.ConfigID {
continue
}
wm.OIDCConfigWriteModel.AppendEvents(&e.IDPConfigDeactivatedEvent)
case *iam.IDPConfigRemovedEvent:
if wm.IDPConfigID != e.ConfigID {
continue
}
wm.OIDCConfigWriteModel.AppendEvents(&e.IDPConfigRemovedEvent)
default:
wm.OIDCConfigWriteModel.AppendEvents(e)
}
}
}
func (wm *IDPOIDCConfigWriteModel) Reduce() error {
if err := wm.OIDCConfigWriteModel.Reduce(); err != nil {
return err
}
return wm.WriteModel.Reduce()
}
func (wm *IDPOIDCConfigWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.AggregateID)
}
func (wm *IDPOIDCConfigWriteModel) NewChangedEvent(
ctx context.Context,
clientID,
issuer,
clientSecretString string,
secretCrypto crypto.Crypto,
idpDisplayNameMapping,
userNameMapping domain.OIDCMappingField,
scopes ...string,
) (*iam.IDPOIDCConfigChangedEvent, bool, error) {
hasChanged := false
changedEvent := iam.NewIDPOIDCConfigChangedEvent(ctx)
var clientSecret *crypto.CryptoValue
var err error
if clientSecretString != "" {
clientSecret, err = crypto.Crypt([]byte(clientSecretString), secretCrypto)
if err != nil {
return nil, false, err
}
changedEvent.ClientSecret = clientSecret
}
if wm.ClientID != clientID {
hasChanged = true
changedEvent.ClientID = clientID
}
if wm.Issuer != issuer {
hasChanged = true
changedEvent.Issuer = issuer
}
if idpDisplayNameMapping.Valid() && wm.IDPDisplayNameMapping != idpDisplayNameMapping {
hasChanged = true
changedEvent.IDPDisplayNameMapping = idpDisplayNameMapping
}
if userNameMapping.Valid() && wm.UserNameMapping != userNameMapping {
hasChanged = true
changedEvent.UserNameMapping = userNameMapping
}
if reflect.DeepEqual(wm.Scopes, scopes) {
hasChanged = true
changedEvent.Scopes = scopes
}
return changedEvent, hasChanged, nil
}

View File

@@ -1,7 +1,8 @@
package iam
package command
import (
"context"
"reflect"
"github.com/caos/zitadel/internal/errors"
caos_errs "github.com/caos/zitadel/internal/errors"
@@ -10,14 +11,14 @@ import (
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *Repository) AddMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) {
func (r *CommandSide) AddIAMMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) {
//TODO: check if roles valid
if !member.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-W8m4l", "Errors.IAM.MemberInvalid")
}
addedMember := iam_repo.NewMemberWriteModel(member.AggregateID, member.UserID)
addedMember := NewIAMMemberWriteModel(member.AggregateID, member.UserID)
err := r.eventstore.FilterToQueryReducer(ctx, addedMember)
if err != nil {
return nil, err
@@ -26,8 +27,8 @@ func (r *Repository) AddMember(ctx context.Context, member *iam_model.IAMMember)
return nil, errors.ThrowAlreadyExists(nil, "IAM-PtXi1", "Errors.IAM.Member.AlreadyExists")
}
iamAgg := iam_repo.AggregateFromWriteModel(&addedMember.WriteModel.WriteModel).
PushMemberAdded(ctx, member.UserID, member.Roles...)
iamAgg := IAMAggregateFromWriteModel(&addedMember.MemberWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewMemberAddedEvent(ctx, member.UserID, member.Roles...))
err = r.eventstore.PushAggregate(ctx, addedMember, iamAgg)
if err != nil {
@@ -37,23 +38,26 @@ func (r *Repository) AddMember(ctx context.Context, member *iam_model.IAMMember)
return writeModelToMember(addedMember), nil
}
//ChangeMember updates an existing member
func (r *Repository) ChangeMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) {
//ChangeIAMMember updates an existing member
func (r *CommandSide) ChangeIAMMember(ctx context.Context, member *iam_model.IAMMember) (*iam_model.IAMMember, error) {
//TODO: check if roles valid
if !member.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-LiaZi", "Errors.IAM.MemberInvalid")
}
existingMember, err := r.memberWriteModelByID(ctx, member.AggregateID, member.UserID)
existingMember, err := r.iamMemberWriteModelByID(ctx, member.AggregateID, member.UserID)
if err != nil {
return nil, err
}
iam := iam_repo.AggregateFromWriteModel(&existingMember.WriteModel.WriteModel).
PushMemberChangedFromExisting(ctx, existingMember, member.Roles...)
if reflect.DeepEqual(existingMember.Roles, member.Roles) {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-LiaZi", "Errors.IAM.Member.RolesNotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingMember.MemberWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewMemberChangedEvent(ctx, member.UserID, member.Roles...))
events, err := r.eventstore.PushAggregates(ctx, iam)
events, err := r.eventstore.PushAggregates(ctx, iamAgg)
if err != nil {
return nil, err
}
@@ -66,8 +70,8 @@ func (r *Repository) ChangeMember(ctx context.Context, member *iam_model.IAMMemb
return writeModelToMember(existingMember), nil
}
func (r *Repository) RemoveMember(ctx context.Context, member *iam_model.IAMMember) error {
m, err := r.memberWriteModelByID(ctx, member.AggregateID, member.UserID)
func (r *CommandSide) RemoveIAMMember(ctx context.Context, member *iam_model.IAMMember) error {
m, err := r.iamMemberWriteModelByID(ctx, member.AggregateID, member.UserID)
if err != nil && !errors.IsNotFound(err) {
return err
}
@@ -75,30 +79,17 @@ func (r *Repository) RemoveMember(ctx context.Context, member *iam_model.IAMMemb
return nil
}
iamAgg := iam_repo.AggregateFromWriteModel(&m.WriteModel.WriteModel).
PushEvents(iam_repo.NewMemberRemovedEvent(ctx, member.UserID))
iamAgg := IAMAggregateFromWriteModel(&m.MemberWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewMemberRemovedEvent(ctx, member.UserID))
return r.eventstore.PushAggregate(ctx, m, iamAgg)
}
func (r *Repository) MemberByID(ctx context.Context, iamID, userID string) (member *iam_repo.MemberReadModel, err error) {
func (r *CommandSide) iamMemberWriteModelByID(ctx context.Context, iamID, userID string) (member *IAMMemberWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
member = iam_repo.NewMemberReadModel(iamID, userID)
err = r.eventstore.FilterToQueryReducer(ctx, member)
if err != nil {
return nil, err
}
return member, nil
}
func (r *Repository) memberWriteModelByID(ctx context.Context, iamID, userID string) (member *iam_repo.MemberWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := iam_repo.NewMemberWriteModel(iamID, userID)
writeModel := NewIAMMemberWriteModel(iamID, userID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err

View File

@@ -0,0 +1,52 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMMemberWriteModel struct {
MemberWriteModel
}
func NewIAMMemberWriteModel(iamID, userID string) *IAMMemberWriteModel {
return &IAMMemberWriteModel{
MemberWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
UserID: userID,
},
}
}
func (wm *IAMMemberWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.MemberAddedEvent:
if e.UserID != wm.MemberWriteModel.UserID {
continue
}
wm.MemberWriteModel.AppendEvents(&e.MemberAddedEvent)
case *iam.MemberChangedEvent:
if e.UserID != wm.MemberWriteModel.UserID {
continue
}
wm.MemberWriteModel.AppendEvents(&e.MemberChangedEvent)
case *iam.MemberRemovedEvent:
if e.UserID != wm.MemberWriteModel.UserID {
continue
}
wm.MemberWriteModel.AppendEvents(&e.MemberRemovedEvent)
}
}
}
func (wm *IAMMemberWriteModel) Reduce() error {
return wm.MemberWriteModel.Reduce()
}
func (wm *IAMMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.MemberWriteModel.AggregateID)
}

View File

@@ -0,0 +1,77 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMWriteModel struct {
eventstore.WriteModel
SetUpStarted domain.Step
SetUpDone domain.Step
GlobalOrgID string
ProjectID string
}
func NewIAMriteModel(iamID string) *IAMWriteModel {
return &IAMWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
}
}
func (wm *IAMWriteModel) AppendEvents(events ...eventstore.EventReader) {
wm.WriteModel.AppendEvents(events...)
//for _, event := range events {
// switch e := event.(type) {
// case *iam.LabelPolicyAddedEvent:
// wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyAddedEvent)
// case *iam.LabelPolicyChangedEvent:
// wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyChangedEvent)
// }
//}
}
func (wm *IAMWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *iam.ProjectSetEvent:
wm.ProjectID = e.ProjectID
case *iam.GlobalOrgSetEvent:
wm.GlobalOrgID = e.OrgID
case *iam.SetupStepEvent:
if e.Done {
wm.SetUpDone = e.Step
} else {
wm.SetUpStarted = e.Step
}
}
}
return nil
}
func (wm *IAMWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.AggregateID)
}
//
//func (wm *IAMLabelPolicyWriteModel) HasChanged(primaryColor, secondaryColor string) bool {
// if primaryColor != "" && wm.PrimaryColor != primaryColor {
// return true
// }
// if secondaryColor != "" && wm.SecondaryColor != secondaryColor {
// return true
// }
// return false
//}
func IAMAggregateFromWriteModel(wm *eventstore.WriteModel) *iam.Aggregate {
return &iam.Aggregate{
Aggregate: *eventstore.AggregateFromWriteModel(wm, iam.AggregateType, iam.AggregateVersion),
}
}

View File

@@ -0,0 +1,76 @@
package command
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *CommandSide) AddDefaultLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error) {
if !policy.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-5Mv0s", "Errors.IAM.LabelPolicyInvalid")
}
addedPolicy := NewIAMLabelPolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LabelPolicy.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.LabelPolicyWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewLabelPolicyAddedEvent(ctx, policy.PrimaryColor, policy.SecondaryColor))
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(addedPolicy), nil
}
func (r *CommandSide) ChangeDefaultLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error) {
if !policy.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-6M0od", "Errors.IAM.LabelPolicyInvalid")
}
existingPolicy, err := r.defaultLabelPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
if !existingPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-0K9dq", "Errors.IAM.LabelPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.PrimaryColor, policy.SecondaryColor)
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToLabelPolicy(existingPolicy), nil
}
func (r *CommandSide) defaultLabelPolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMLabelPolicyWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMLabelPolicyWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,60 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMLabelPolicyWriteModel struct {
LabelPolicyWriteModel
}
func NewIAMLabelPolicyWriteModel(iamID string) *IAMLabelPolicyWriteModel {
return &IAMLabelPolicyWriteModel{
LabelPolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
},
}
}
func (wm *IAMLabelPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LabelPolicyAddedEvent:
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyAddedEvent)
case *iam.LabelPolicyChangedEvent:
wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyChangedEvent)
}
}
}
func (wm *IAMLabelPolicyWriteModel) Reduce() error {
return wm.LabelPolicyWriteModel.Reduce()
}
func (wm *IAMLabelPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.LabelPolicyWriteModel.AggregateID)
}
func (wm *IAMLabelPolicyWriteModel) NewChangedEvent(
ctx context.Context,
primaryColor,
secondaryColor string,
) (*iam.LabelPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewLabelPolicyChangedEvent(ctx)
if wm.PrimaryColor != primaryColor {
hasChanged = true
changedEvent.PrimaryColor = primaryColor
}
if wm.SecondaryColor != secondaryColor {
hasChanged = true
changedEvent.SecondaryColor = secondaryColor
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,183 @@
package command
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) AddDefaultLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
addedPolicy := NewIAMLoginPolicyWriteModel(policy.AggregateID)
iamAgg, err := r.addDefaultLoginPolicy(ctx, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(addedPolicy), nil
}
func (r *CommandSide) addDefaultLoginPolicy(ctx context.Context, addedPolicy *IAMLoginPolicyWriteModel, policy *iam_model.LoginPolicy) (*iam_repo.Aggregate, error) {
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.LoginPolicyWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewLoginPolicyAddedEvent(ctx, policy.AllowUsernamePassword, policy.AllowRegister, policy.AllowExternalIdp, policy.ForceMFA, domain.PasswordlessType(policy.PasswordlessType)))
return iamAgg, nil
}
func (r *CommandSide) ChangeDefaultLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
if !policy.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-6M0od", "Errors.IAM.LoginPolicyInvalid")
}
existingPolicy, err := r.defaultLoginPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
if !existingPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-M0sif", "Errors.IAM.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.ThrowAlreadyExists(nil, "IAM-5M9vdd", "Errors.IAM.LoginPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.LoginPolicyWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToLoginPolicy(existingPolicy), nil
}
func (r *CommandSide) AddIDPProviderToDefaultLoginPolicy(ctx context.Context, idpProvider *iam_model.IDPProvider) (*iam_model.IDPProvider, error) {
idpModel := NewIAMIdentityProviderWriteModel(idpProvider.AggregateID, idpProvider.IDPConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, idpModel)
if err != nil {
return nil, err
}
if idpModel.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.IDP.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&idpModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewIdentityProviderAddedEvent(ctx, idpProvider.IDPConfigID, domain.IdentityProviderType(idpProvider.Type)))
if err = r.eventstore.PushAggregate(ctx, idpModel, iamAgg); err != nil {
return nil, err
}
return writeModelToIDPProvider(idpModel), nil
}
func (r *CommandSide) RemoveIDPProviderFromDefaultLoginPolicy(ctx context.Context, idpProvider *iam_model.IDPProvider) error {
idpModel := NewIAMIdentityProviderWriteModel(idpProvider.AggregateID, idpProvider.IDPConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, idpModel)
if err != nil {
return err
}
if !idpModel.IsActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-39fjs", "Errors.IAM.LoginPolicy.IDP.NotExisting")
}
iamAgg := IAMAggregateFromWriteModel(&idpModel.IdentityProviderWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewIdentityProviderRemovedEvent(ctx, idpProvider.IDPConfigID))
return r.eventstore.PushAggregate(ctx, idpModel, iamAgg)
}
func (r *CommandSide) AddSecondFactorToDefaultLoginPolicy(ctx context.Context, iamID string, secondFactor iam_model.SecondFactorType) (iam_model.SecondFactorType, error) {
secondFactorModel := NewIAMSecondFactorWriteModel(iamID)
err := r.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
if err != nil {
return iam_model.SecondFactorTypeUnspecified, err
}
if secondFactorModel.IsActive {
return iam_model.SecondFactorTypeUnspecified, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewLoginPolicySecondFactorAddedEvent(ctx, domain.SecondFactorType(secondFactor)))
if err = r.eventstore.PushAggregate(ctx, secondFactorModel, iamAgg); err != nil {
return iam_model.SecondFactorTypeUnspecified, err
}
return iam_model.SecondFactorType(secondFactorModel.MFAType), nil
}
func (r *CommandSide) RemoveSecondFactorFromDefaultLoginPolicy(ctx context.Context, iamID string, secondFactor iam_model.SecondFactorType) error {
secondFactorModel := NewIAMSecondFactorWriteModel(iamID)
err := r.eventstore.FilterToQueryReducer(ctx, secondFactorModel)
if err != nil {
return err
}
if !secondFactorModel.IsActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-3M9od", "Errors.IAM.LoginPolicy.MFA.NotExisting")
}
iamAgg := IAMAggregateFromWriteModel(&secondFactorModel.SecondFactorWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewLoginPolicySecondFactorRemovedEvent(ctx, domain.SecondFactorType(secondFactor)))
return r.eventstore.PushAggregate(ctx, secondFactorModel, iamAgg)
}
func (r *CommandSide) AddMultiFactorToDefaultLoginPolicy(ctx context.Context, iamID string, multiFactor iam_model.MultiFactorType) (iam_model.MultiFactorType, error) {
multiFactorModel := NewIAMMultiFactorWriteModel(iamID)
err := r.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
if err != nil {
return iam_model.MultiFactorTypeUnspecified, err
}
if multiFactorModel.IsActive {
return iam_model.MultiFactorTypeUnspecified, caos_errs.ThrowAlreadyExists(nil, "IAM-3M9od", "Errors.IAM.LoginPolicy.MFA.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewLoginPolicyMultiFactorAddedEvent(ctx, domain.MultiFactorType(multiFactor)))
if err = r.eventstore.PushAggregate(ctx, multiFactorModel, iamAgg); err != nil {
return iam_model.MultiFactorTypeUnspecified, err
}
return iam_model.MultiFactorType(multiFactorModel.MultiFactoryWriteModel.MFAType), nil
}
func (r *CommandSide) RemoveMultiFactorFromDefaultLoginPolicy(ctx context.Context, iamID string, multiFactor iam_model.MultiFactorType) error {
multiFactorModel := NewIAMMultiFactorWriteModel(iamID)
err := r.eventstore.FilterToQueryReducer(ctx, multiFactorModel)
if err != nil {
return err
}
if multiFactorModel.IsActive {
return caos_errs.ThrowAlreadyExists(nil, "IAM-3M9df", "Errors.IAM.LoginPolicy.MFA.NotExisting")
}
iamAgg := IAMAggregateFromWriteModel(&multiFactorModel.MultiFactoryWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewLoginPolicyMultiFactorRemovedEvent(ctx, domain.MultiFactorType(multiFactor)))
return r.eventstore.PushAggregate(ctx, multiFactorModel, iamAgg)
}
func (r *CommandSide) defaultLoginPolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMLoginPolicyWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMLoginPolicyWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,70 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMSecondFactorWriteModel struct {
SecondFactorWriteModel
}
func NewIAMSecondFactorWriteModel(iamID string) *IAMSecondFactorWriteModel {
return &IAMSecondFactorWriteModel{
SecondFactorWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
},
}
}
func (wm *IAMSecondFactorWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LoginPolicySecondFactorAddedEvent:
wm.WriteModel.AppendEvents(&e.SecondFactorAddedEvent)
}
}
}
func (wm *IAMSecondFactorWriteModel) Reduce() error {
return wm.WriteModel.Reduce()
}
func (wm *IAMSecondFactorWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.WriteModel.AggregateID)
}
type IAMMultiFactorWriteModel struct {
MultiFactoryWriteModel
}
func NewIAMMultiFactorWriteModel(iamID string) *IAMMultiFactorWriteModel {
return &IAMMultiFactorWriteModel{
MultiFactoryWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
},
}
}
func (wm *IAMMultiFactorWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LoginPolicyMultiFactorAddedEvent:
wm.WriteModel.AppendEvents(&e.MultiFactorAddedEvent)
}
}
}
func (wm *IAMMultiFactorWriteModel) Reduce() error {
return wm.WriteModel.Reduce()
}
func (wm *IAMMultiFactorWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.WriteModel.AggregateID)
}

View File

@@ -0,0 +1,42 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMIdentityProviderWriteModel struct {
IdentityProviderWriteModel
}
func NewIAMIdentityProviderWriteModel(iamID, idpConfigID string) *IAMIdentityProviderWriteModel {
return &IAMIdentityProviderWriteModel{
IdentityProviderWriteModel: IdentityProviderWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
IDPConfigID: idpConfigID,
},
}
}
func (wm *IAMIdentityProviderWriteModel) 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 *IAMIdentityProviderWriteModel) Reduce() error {
return wm.IdentityProviderWriteModel.Reduce()
}
func (wm *IAMIdentityProviderWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.AggregateID)
}

View File

@@ -0,0 +1,80 @@
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/iam"
)
type IAMLoginPolicyWriteModel struct {
LoginPolicyWriteModel
}
func NewIAMLoginPolicyWriteModel(iamID string) *IAMLoginPolicyWriteModel {
return &IAMLoginPolicyWriteModel{
LoginPolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
},
}
}
func (wm *IAMLoginPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LoginPolicyAddedEvent:
wm.LoginPolicyWriteModel.AppendEvents(&e.LoginPolicyAddedEvent)
case *iam.LoginPolicyChangedEvent:
wm.LoginPolicyWriteModel.AppendEvents(&e.LoginPolicyChangedEvent)
}
}
}
func (wm *IAMLoginPolicyWriteModel) IsValid() bool {
return wm.AggregateID != ""
}
func (wm *IAMLoginPolicyWriteModel) Reduce() error {
return wm.LoginPolicyWriteModel.Reduce()
}
func (wm *IAMLoginPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.LoginPolicyWriteModel.AggregateID)
}
func (wm *IAMLoginPolicyWriteModel) NewChangedEvent(
ctx context.Context,
allowUsernamePassword,
allowRegister,
allowExternalIDP,
forceMFA bool,
passwordlessType domain.PasswordlessType,
) (*iam.LoginPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewLoginPolicyChangedEvent(ctx)
if wm.AllowUserNamePassword == allowUsernamePassword {
hasChanged = true
changedEvent.AllowUserNamePassword = allowUsernamePassword
}
if wm.AllowRegister == allowRegister {
hasChanged = true
changedEvent.AllowRegister = allowRegister
}
if wm.AllowExternalIDP == allowExternalIDP {
hasChanged = true
changedEvent.AllowExternalIDP = allowExternalIDP
}
if wm.ForceMFA != forceMFA {
hasChanged = true
changedEvent.ForceMFA = forceMFA
}
if passwordlessType.Valid() && wm.PasswordlessType != passwordlessType {
hasChanged = true
changedEvent.PasswordlessType = passwordlessType
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,77 @@
package command
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *CommandSide) GetDefaultOrgIAMPolicy(ctx context.Context, aggregateID string) (*iam_model.OrgIAMPolicy, error) {
policyWriteModel := NewIAMOrgIAMPolicyWriteModel(aggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, policyWriteModel)
if err != nil {
return nil, err
}
policy := writeModelToOrgIAMPolicy(policyWriteModel)
policy.Default = true
return policy, nil
}
func (r *CommandSide) AddDefaultOrgIAMPolicy(ctx context.Context, policy *iam_model.OrgIAMPolicy) (*iam_model.OrgIAMPolicy, error) {
addedPolicy := NewIAMOrgIAMPolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.OrgIAMPolicy.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.PolicyOrgIAMWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewOrgIAMPolicyAddedEvent(ctx, policy.UserLoginMustBeDomain))
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToOrgIAMPolicy(addedPolicy), nil
}
func (r *CommandSide) ChangeDefaultOrgIAMPolicy(ctx context.Context, policy *iam_model.OrgIAMPolicy) (*iam_model.OrgIAMPolicy, error) {
existingPolicy, err := r.defaultOrgIAMPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
if !existingPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-0Pl0d", "Errors.IAM.OrgIAMPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.UserLoginMustBeDomain)
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToOrgIAMPolicy(existingPolicy), nil
}
func (r *CommandSide) defaultOrgIAMPolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMOrgIAMPolicyWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMOrgIAMPolicyWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,51 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMOrgIAMPolicyWriteModel struct {
PolicyOrgIAMWriteModel
}
func NewIAMOrgIAMPolicyWriteModel(iamID string) *IAMOrgIAMPolicyWriteModel {
return &IAMOrgIAMPolicyWriteModel{
PolicyOrgIAMWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
},
}
}
func (wm *IAMOrgIAMPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.OrgIAMPolicyAddedEvent:
wm.PolicyOrgIAMWriteModel.AppendEvents(&e.OrgIAMPolicyAddedEvent)
case *iam.OrgIAMPolicyChangedEvent:
wm.PolicyOrgIAMWriteModel.AppendEvents(&e.OrgIAMPolicyChangedEvent)
}
}
}
func (wm *IAMOrgIAMPolicyWriteModel) Reduce() error {
return wm.PolicyOrgIAMWriteModel.Reduce()
}
func (wm *IAMOrgIAMPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.PolicyOrgIAMWriteModel.AggregateID)
}
func (wm *IAMOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLoginMustBeDomain bool) (*iam.OrgIAMPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewOrgIAMPolicyChangedEvent(ctx)
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
hasChanged = true
changedEvent.UserLoginMustBeDomain = userLoginMustBeDomain
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,67 @@
package command
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *CommandSide) AddDefaultPasswordAgePolicy(ctx context.Context, policy *iam_model.PasswordAgePolicy) (*iam_model.PasswordAgePolicy, error) {
addedPolicy := NewIAMPasswordAgePolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-2B0ps", "Errors.IAM.PasswordAgePolicy.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.PasswordAgePolicyWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewPasswordAgePolicyAddedEvent(ctx, policy.ExpireWarnDays, policy.MaxAgeDays))
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(addedPolicy), nil
}
func (r *CommandSide) ChangeDefaultPasswordAgePolicy(ctx context.Context, policy *iam_model.PasswordAgePolicy) (*iam_model.PasswordAgePolicy, error) {
existingPolicy, err := r.defaultPasswordAgePolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
if !existingPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-0oPew", "Errors.IAM.PasswordAgePolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.ExpireWarnDays, policy.MaxAgeDays)
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PasswordAgePolicyWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordAgePolicy(existingPolicy), nil
}
func (r *CommandSide) defaultPasswordAgePolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMPasswordAgePolicyWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMPasswordAgePolicyWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,55 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMPasswordAgePolicyWriteModel struct {
PasswordAgePolicyWriteModel
}
func NewIAMPasswordAgePolicyWriteModel(iamID string) *IAMPasswordAgePolicyWriteModel {
return &IAMPasswordAgePolicyWriteModel{
PasswordAgePolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
},
}
}
func (wm *IAMPasswordAgePolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.PasswordAgePolicyAddedEvent:
wm.PasswordAgePolicyWriteModel.AppendEvents(&e.PasswordAgePolicyAddedEvent)
case *iam.PasswordAgePolicyChangedEvent:
wm.PasswordAgePolicyWriteModel.AppendEvents(&e.PasswordAgePolicyChangedEvent)
}
}
}
func (wm *IAMPasswordAgePolicyWriteModel) Reduce() error {
return wm.PasswordAgePolicyWriteModel.Reduce()
}
func (wm *IAMPasswordAgePolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.PasswordAgePolicyWriteModel.AggregateID)
}
func (wm *IAMPasswordAgePolicyWriteModel) NewChangedEvent(ctx context.Context, expireWarnDays, maxAgeDays uint64) (*iam.PasswordAgePolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewPasswordAgePolicyChangedEvent(ctx)
if wm.ExpireWarnDays != expireWarnDays {
hasChanged = true
changedEvent.ExpireWarnDays = expireWarnDays
}
if wm.MaxAgeDays != maxAgeDays {
hasChanged = true
changedEvent.MaxAgeDays = maxAgeDays
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,94 @@
package command
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *CommandSide) GetDefaultPasswordComplexityPolicy(ctx context.Context, aggregateID string) (*iam_model.PasswordComplexityPolicy, error) {
policyWriteModel := NewIAMPasswordComplexityPolicyWriteModel(aggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, policyWriteModel)
if err != nil {
return nil, err
}
policy := writeModelToPasswordComplexityPolicy(policyWriteModel)
policy.Default = true
return policy, nil
}
func (r *CommandSide) AddDefaultPasswordComplexityPolicy(ctx context.Context, policy *iam_model.PasswordComplexityPolicy) (*iam_model.PasswordComplexityPolicy, error) {
addedPolicy := NewIAMPasswordComplexityPolicyWriteModel(policy.AggregateID)
iamAgg, err := r.addDefaultPasswordComplexityPolicy(ctx, addedPolicy, policy)
if err != nil {
return nil, err
}
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(addedPolicy), nil
}
func (r *CommandSide) addDefaultPasswordComplexityPolicy(ctx context.Context, addedPolicy *IAMPasswordComplexityPolicyWriteModel, policy *iam_model.PasswordComplexityPolicy) (*iam_repo.Aggregate, error) {
if err := policy.IsValid(); err != nil {
return nil, err
}
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-Lk0dS", "Errors.IAM.PasswordComplexityPolicy.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.PasswordComplexityPolicyWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewPasswordComplexityPolicyAddedEvent(ctx, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol))
return iamAgg, nil
}
func (r *CommandSide) ChangeDefaultPasswordComplexityPolicy(ctx context.Context, policy *iam_model.PasswordComplexityPolicy) (*iam_model.PasswordComplexityPolicy, error) {
if err := policy.IsValid(); err != nil {
return nil, err
}
existingPolicy, err := r.defaultPasswordComplexityPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
if !existingPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-0oPew", "Errors.IAM.PasswordAgePolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.MinLength, policy.HasLowercase, policy.HasUppercase, policy.HasNumber, policy.HasSymbol)
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PasswordComplexityPolicyWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordComplexityPolicy(existingPolicy), nil
}
func (r *CommandSide) defaultPasswordComplexityPolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMPasswordComplexityPolicyWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMPasswordComplexityPolicyWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,75 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMPasswordComplexityPolicyWriteModel struct {
PasswordComplexityPolicyWriteModel
}
func NewIAMPasswordComplexityPolicyWriteModel(iamID string) *IAMPasswordComplexityPolicyWriteModel {
return &IAMPasswordComplexityPolicyWriteModel{
PasswordComplexityPolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
},
}
}
func (wm *IAMPasswordComplexityPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.PasswordComplexityPolicyAddedEvent:
wm.PasswordComplexityPolicyWriteModel.AppendEvents(&e.PasswordComplexityPolicyAddedEvent)
case *iam.PasswordComplexityPolicyChangedEvent:
wm.PasswordComplexityPolicyWriteModel.AppendEvents(&e.PasswordComplexityPolicyChangedEvent)
}
}
}
func (wm *IAMPasswordComplexityPolicyWriteModel) Reduce() error {
return wm.PasswordComplexityPolicyWriteModel.Reduce()
}
func (wm *IAMPasswordComplexityPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.PasswordComplexityPolicyWriteModel.AggregateID)
}
func (wm *IAMPasswordComplexityPolicyWriteModel) NewChangedEvent(
ctx context.Context,
minLength uint64,
hasLowercase,
hasUppercase,
hasNumber,
hasSymbol bool,
) (*iam.PasswordComplexityPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewPasswordComplexityPolicyChangedEvent(ctx)
if wm.MinLength != minLength {
hasChanged = true
changedEvent.MinLength = minLength
}
if wm.HasLowercase != hasLowercase {
hasChanged = true
changedEvent.HasLowercase = hasLowercase
}
if wm.HasUpperCase != hasUppercase {
hasChanged = true
changedEvent.HasUpperCase = hasUppercase
}
if wm.HasNumber != hasNumber {
hasChanged = true
changedEvent.HasNumber = hasNumber
}
if wm.HasSymbol != hasSymbol {
hasChanged = true
changedEvent.HasSymbol = hasSymbol
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,67 @@
package command
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *CommandSide) AddDefaultPasswordLockoutPolicy(ctx context.Context, policy *iam_model.PasswordLockoutPolicy) (*iam_model.PasswordLockoutPolicy, error) {
addedPolicy := NewIAMPasswordLockoutPolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-0olDf", "Errors.IAM.PasswordLockoutPolicy.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&addedPolicy.PasswordLockoutPolicyWriteModel.WriteModel)
iamAgg.PushEvents(iam_repo.NewPasswordLockoutPolicyAddedEvent(ctx, policy.MaxAttempts, policy.ShowLockOutFailures))
err = r.eventstore.PushAggregate(ctx, addedPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordLockoutPolicy(addedPolicy), nil
}
func (r *CommandSide) ChangeDefaultPasswordLockoutPolicy(ctx context.Context, policy *iam_model.PasswordLockoutPolicy) (*iam_model.PasswordLockoutPolicy, error) {
existingPolicy, err := r.defaultPasswordLockoutPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
if !existingPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-0oPew", "Errors.IAM.PasswordLockoutPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.MaxAttempts, policy.ShowLockOutFailures)
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-4M9vs", "Errors.IAM.PasswordLockoutPolicy.NotChanged")
}
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PasswordLockoutPolicyWriteModel.WriteModel)
iamAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, iamAgg)
if err != nil {
return nil, err
}
return writeModelToPasswordLockoutPolicy(existingPolicy), nil
}
func (r *CommandSide) defaultPasswordLockoutPolicyWriteModelByID(ctx context.Context, iamID string) (policy *IAMPasswordLockoutPolicyWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMPasswordLockoutPolicyWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,55 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMPasswordLockoutPolicyWriteModel struct {
PasswordLockoutPolicyWriteModel
}
func NewIAMPasswordLockoutPolicyWriteModel(iamID string) *IAMPasswordLockoutPolicyWriteModel {
return &IAMPasswordLockoutPolicyWriteModel{
PasswordLockoutPolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
},
}
}
func (wm *IAMPasswordLockoutPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.PasswordLockoutPolicyAddedEvent:
wm.PasswordLockoutPolicyWriteModel.AppendEvents(&e.PasswordLockoutPolicyAddedEvent)
case *iam.PasswordLockoutPolicyChangedEvent:
wm.PasswordLockoutPolicyWriteModel.AppendEvents(&e.PasswordLockoutPolicyChangedEvent)
}
}
}
func (wm *IAMPasswordLockoutPolicyWriteModel) Reduce() error {
return wm.PasswordLockoutPolicyWriteModel.Reduce()
}
func (wm *IAMPasswordLockoutPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(wm.PasswordLockoutPolicyWriteModel.AggregateID)
}
func (wm *IAMPasswordLockoutPolicyWriteModel) NewChangedEvent(ctx context.Context, maxAttempts uint64, showLockoutFailure bool) (*iam.PasswordLockoutPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := iam.NewPasswordLockoutPolicyChangedEvent(ctx)
if wm.MaxAttempts != maxAttempts {
hasChanged = true
changedEvent.MaxAttempts = maxAttempts
}
if wm.ShowLockOutFailures != showLockoutFailure {
hasChanged = true
changedEvent.ShowLockOutFailures = showLockoutFailure
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,29 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IdentityProviderWriteModel struct {
eventstore.WriteModel
IDPConfigID string
IDPProviderType domain.IdentityProviderType
IsActive bool
}
func (wm *IdentityProviderWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *policy.IdentityProviderAddedEvent:
wm.IDPConfigID = e.IDPConfigID
wm.IDPProviderType = e.IDPProviderType
wm.IsActive = true
case *policy.IdentityProviderRemovedEvent:
wm.IsActive = false
}
}
return wm.WriteModel.Reduce()
}

View File

@@ -0,0 +1,75 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/idpconfig"
)
type IDPConfigWriteModel struct {
eventstore.WriteModel
State domain.IDPConfigState
ConfigID string
Name string
StylingType domain.IDPConfigStylingType
OIDCConfig *OIDCConfigWriteModel
}
func (rm *IDPConfigWriteModel) AppendEvents(events ...eventstore.EventReader) {
rm.WriteModel.AppendEvents(events...)
for _, event := range events {
switch event.(type) {
case *idpconfig.OIDCConfigAddedEvent:
rm.OIDCConfig = new(OIDCConfigWriteModel)
rm.OIDCConfig.AppendEvents(event)
case *idpconfig.OIDCConfigChangedEvent:
rm.OIDCConfig.AppendEvents(event)
}
}
}
func (rm *IDPConfigWriteModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *idpconfig.IDPConfigAddedEvent:
rm.reduceConfigAddedEvent(e)
case *idpconfig.IDPConfigChangedEvent:
rm.reduceConfigChangedEvent(e)
case *idpconfig.IDPConfigDeactivatedEvent:
rm.reduceConfigStateChanged(e.ConfigID, domain.IDPConfigStateInactive)
case *idpconfig.IDPConfigReactivatedEvent:
rm.reduceConfigStateChanged(e.ConfigID, domain.IDPConfigStateActive)
case *idpconfig.IDPConfigRemovedEvent:
rm.reduceConfigStateChanged(e.ConfigID, domain.IDPConfigStateRemoved)
}
}
if rm.OIDCConfig != nil {
if err := rm.OIDCConfig.Reduce(); err != nil {
return err
}
}
return rm.WriteModel.Reduce()
}
func (rm *IDPConfigWriteModel) reduceConfigAddedEvent(e *idpconfig.IDPConfigAddedEvent) {
rm.ConfigID = e.ConfigID
rm.Name = e.Name
rm.StylingType = e.StylingType
rm.State = domain.IDPConfigStateActive
}
func (rm *IDPConfigWriteModel) reduceConfigChangedEvent(e *idpconfig.IDPConfigChangedEvent) {
if e.Name != "" {
rm.Name = e.Name
}
if e.StylingType.Valid() {
rm.StylingType = e.StylingType
}
}
func (rm *IDPConfigWriteModel) reduceConfigStateChanged(configID string, state domain.IDPConfigState) {
rm.State = state
}

View File

@@ -0,0 +1,37 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/member"
)
type MemberWriteModel struct {
eventstore.WriteModel
UserID string
Roles []string
IsActive bool
}
func NewMemberWriteModel(userID string) *MemberWriteModel {
return &MemberWriteModel{
UserID: userID,
}
}
func (wm *MemberWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *member.MemberAddedEvent:
wm.UserID = e.UserID
wm.Roles = e.Roles
wm.IsActive = true
case *member.MemberChangedEvent:
wm.Roles = e.Roles
case *member.MemberRemovedEvent:
wm.Roles = nil
wm.IsActive = false
}
}
return wm.WriteModel.Reduce()
}

View File

@@ -1,11 +1,13 @@
package oidc
package command
import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/idpconfig"
)
type ConfigWriteModel struct {
type OIDCConfigWriteModel struct {
eventstore.WriteModel
IDPConfigID string
@@ -14,24 +16,31 @@ type ConfigWriteModel struct {
Issuer string
Scopes []string
IDPDisplayNameMapping MappingField
UserNameMapping MappingField
IDPDisplayNameMapping domain.OIDCMappingField
UserNameMapping domain.OIDCMappingField
State domain.IDPConfigState
}
func (wm *ConfigWriteModel) Reduce() error {
func (wm *OIDCConfigWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *ConfigAddedEvent:
case *idpconfig.OIDCConfigAddedEvent:
wm.reduceConfigAddedEvent(e)
case *ConfigChangedEvent:
case *idpconfig.OIDCConfigChangedEvent:
wm.reduceConfigChangedEvent(e)
case *idpconfig.IDPConfigDeactivatedEvent:
wm.State = domain.IDPConfigStateInactive
case *idpconfig.IDPConfigReactivatedEvent:
wm.State = domain.IDPConfigStateActive
case *idpconfig.IDPConfigRemovedEvent:
wm.State = domain.IDPConfigStateRemoved
}
}
return wm.WriteModel.Reduce()
}
func (wm *ConfigWriteModel) reduceConfigAddedEvent(e *ConfigAddedEvent) {
func (wm *OIDCConfigWriteModel) reduceConfigAddedEvent(e *idpconfig.OIDCConfigAddedEvent) {
wm.IDPConfigID = e.IDPConfigID
wm.ClientID = e.ClientID
wm.ClientSecret = e.ClientSecret
@@ -39,9 +48,10 @@ func (wm *ConfigWriteModel) reduceConfigAddedEvent(e *ConfigAddedEvent) {
wm.Scopes = e.Scopes
wm.IDPDisplayNameMapping = e.IDPDisplayNameMapping
wm.UserNameMapping = e.UserNameMapping
wm.State = domain.IDPConfigStateActive
}
func (wm *ConfigWriteModel) reduceConfigChangedEvent(e *ConfigChangedEvent) {
func (wm *OIDCConfigWriteModel) reduceConfigChangedEvent(e *idpconfig.OIDCConfigChangedEvent) {
if e.ClientID != "" {
wm.ClientID = e.ClientID
}

View File

@@ -0,0 +1,23 @@
package command
import (
"github.com/caos/zitadel/internal/iam/model"
)
func orgWriteModelToOrgIAMPolicy(wm *ORGOrgIAMPolicyWriteModel) *model.OrgIAMPolicy {
return &model.OrgIAMPolicy{
ObjectRoot: writeModelToObjectRoot(wm.PolicyOrgIAMWriteModel.WriteModel),
UserLoginMustBeDomain: wm.UserLoginMustBeDomain,
}
}
func orgWriteModelToPasswordComplexityPolicy(wm *OrgPasswordComplexityPolicyWriteModel) *model.PasswordComplexityPolicy {
return &model.PasswordComplexityPolicy{
ObjectRoot: writeModelToObjectRoot(wm.PasswordComplexityPolicyWriteModel.WriteModel),
MinLength: wm.MinLength,
HasLowercase: wm.HasLowercase,
HasUppercase: wm.HasUpperCase,
HasNumber: wm.HasNumber,
HasSymbol: wm.HasSymbol,
}
}

View File

@@ -0,0 +1,5 @@
package command
type OrgMemberWriteModel struct {
MemberWriteModel
}

View File

@@ -0,0 +1,12 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/org"
)
func ORGAggregateFromWriteModel(wm *eventstore.WriteModel) *org.Aggregate {
return &org.Aggregate{
Aggregate: *eventstore.AggregateFromWriteModel(wm, org.AggregateType, org.AggregateVersion),
}
}

View File

@@ -0,0 +1,78 @@
package command
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"
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
)
func (r *CommandSide) GetOrgIAMPolicy(ctx context.Context, orgID string) (*iam_model.OrgIAMPolicy, error) {
policy := NewORGOrgIAMPolicyWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, policy)
if err != nil {
return nil, err
}
if policy.IsActive {
return orgWriteModelToOrgIAMPolicy(policy), nil
}
return r.GetDefaultOrgIAMPolicy(ctx, r.iamID)
}
func (r *CommandSide) AddOrgIAMPolicy(ctx context.Context, policy *iam_model.OrgIAMPolicy) (*iam_model.OrgIAMPolicy, error) {
addedPolicy := NewORGOrgIAMPolicyWriteModel(policy.AggregateID)
err := r.eventstore.FilterToQueryReducer(ctx, addedPolicy)
if err != nil {
return nil, err
}
if addedPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "ORG-5M0ds", "Errors.Org.OrgIAMPolicy.AlreadyExists")
}
orgAgg := ORGAggregateFromWriteModel(&addedPolicy.PolicyOrgIAMWriteModel.WriteModel)
orgAgg.PushEvents(iam_repo.NewOrgIAMPolicyAddedEvent(ctx, policy.UserLoginMustBeDomain))
err = r.eventstore.PushAggregate(ctx, addedPolicy, orgAgg)
if err != nil {
return nil, err
}
return orgWriteModelToOrgIAMPolicy(addedPolicy), nil
}
func (r *CommandSide) ChangeOrgIAMPolicy(ctx context.Context, policy *iam_model.OrgIAMPolicy) (*iam_model.OrgIAMPolicy, error) {
existingPolicy, err := r.orgIAMPolicyWriteModelByID(ctx, policy.AggregateID)
if err != nil {
return nil, err
}
if !existingPolicy.IsActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "ORG-2N9sd", "Errors.Org.OrgIAMPolicy.NotFound")
}
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, policy.UserLoginMustBeDomain)
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "ORG-3M9ds", "Errors.Org.LabelPolicy.NotChanged")
}
orgAgg := ORGAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)
orgAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingPolicy, orgAgg)
if err != nil {
return nil, err
}
return orgWriteModelToOrgIAMPolicy(existingPolicy), nil
}
func (r *CommandSide) orgIAMPolicyWriteModelByID(ctx context.Context, iamID string) (policy *ORGOrgIAMPolicyWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewORGOrgIAMPolicyWriteModel(iamID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,51 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/org"
)
type ORGOrgIAMPolicyWriteModel struct {
PolicyOrgIAMWriteModel
}
func NewORGOrgIAMPolicyWriteModel(orgID string) *ORGOrgIAMPolicyWriteModel {
return &ORGOrgIAMPolicyWriteModel{
PolicyOrgIAMWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: orgID,
},
},
}
}
func (wm *ORGOrgIAMPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.OrgIAMPolicyAddedEvent:
wm.PolicyOrgIAMWriteModel.AppendEvents(&e.OrgIAMPolicyAddedEvent)
case *org.OrgIAMPolicyChangedEvent:
wm.PolicyOrgIAMWriteModel.AppendEvents(&e.OrgIAMPolicyChangedEvent)
}
}
}
func (wm *ORGOrgIAMPolicyWriteModel) Reduce() error {
return wm.PolicyOrgIAMWriteModel.Reduce()
}
func (wm *ORGOrgIAMPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.PolicyOrgIAMWriteModel.AggregateID)
}
func (wm *ORGOrgIAMPolicyWriteModel) NewChangedEvent(ctx context.Context, userLoginMustBeDomain bool) (*org.OrgIAMPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := org.NewOrgIAMPolicyChangedEvent(ctx)
if wm.UserLoginMustBeDomain != userLoginMustBeDomain {
hasChanged = true
changedEvent.UserLoginMustBeDomain = userLoginMustBeDomain
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,18 @@
package command
import (
"context"
iam_model "github.com/caos/zitadel/internal/iam/model"
)
func (r *CommandSide) GetOrgPasswordComplexityPolicy(ctx context.Context, orgID string) (*iam_model.PasswordComplexityPolicy, error) {
policy := NewOrgPasswordComplexityPolicyWriteModel(orgID)
err := r.eventstore.FilterToQueryReducer(ctx, policy)
if err != nil {
return nil, err
}
if policy.IsActive {
return orgWriteModelToPasswordComplexityPolicy(policy), nil
}
return r.GetDefaultPasswordComplexityPolicy(ctx, r.iamID)
}

View File

@@ -0,0 +1,75 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/org"
)
type OrgPasswordComplexityPolicyWriteModel struct {
PasswordComplexityPolicyWriteModel
}
func NewOrgPasswordComplexityPolicyWriteModel(iamID string) *OrgPasswordComplexityPolicyWriteModel {
return &OrgPasswordComplexityPolicyWriteModel{
PasswordComplexityPolicyWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: iamID,
},
},
}
}
func (wm *OrgPasswordComplexityPolicyWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.PasswordComplexityPolicyAddedEvent:
wm.PasswordComplexityPolicyWriteModel.AppendEvents(&e.PasswordComplexityPolicyAddedEvent)
case *org.PasswordComplexityPolicyChangedEvent:
wm.PasswordComplexityPolicyWriteModel.AppendEvents(&e.PasswordComplexityPolicyChangedEvent)
}
}
}
func (wm *OrgPasswordComplexityPolicyWriteModel) Reduce() error {
return wm.PasswordComplexityPolicyWriteModel.Reduce()
}
func (wm *OrgPasswordComplexityPolicyWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, org.AggregateType).
AggregateIDs(wm.PasswordComplexityPolicyWriteModel.AggregateID)
}
func (wm *OrgPasswordComplexityPolicyWriteModel) NewChangedEvent(
ctx context.Context,
minLength uint64,
hasLowercase,
hasUppercase,
hasNumber,
hasSymbol bool,
) (*org.PasswordComplexityPolicyChangedEvent, bool) {
hasChanged := false
changedEvent := org.NewPasswordComplexityPolicyChangedEvent(ctx)
if wm.MinLength != minLength {
hasChanged = true
changedEvent.MinLength = minLength
}
if wm.HasLowercase != hasLowercase {
hasChanged = true
changedEvent.HasLowercase = hasLowercase
}
if wm.HasUpperCase != hasUppercase {
hasChanged = true
changedEvent.HasUpperCase = hasUppercase
}
if wm.HasNumber != hasNumber {
hasChanged = true
changedEvent.HasNumber = hasNumber
}
if wm.HasSymbol != hasSymbol {
hasChanged = true
changedEvent.HasSymbol = hasSymbol
}
return changedEvent, hasChanged
}

View File

@@ -1,25 +1,30 @@
package label
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type WriteModel struct {
type LabelPolicyWriteModel struct {
eventstore.WriteModel
PrimaryColor string
SecondaryColor string
IsActive bool
}
func (wm *WriteModel) Reduce() error {
func (wm *LabelPolicyWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *AddedEvent:
case *policy.LabelPolicyAddedEvent:
wm.PrimaryColor = e.PrimaryColor
wm.SecondaryColor = e.SecondaryColor
case *ChangedEvent:
wm.IsActive = true
case *policy.LabelPolicyChangedEvent:
wm.PrimaryColor = e.PrimaryColor
wm.SecondaryColor = e.SecondaryColor
case *policy.LabelPolicyRemovedEvent:
wm.IsActive = false
}
}
return wm.WriteModel.Reduce()

View File

@@ -1,19 +1,26 @@
package factors
package command
import "github.com/caos/zitadel/internal/eventstore/v2"
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type SecondFactorWriteModel struct {
eventstore.WriteModel
MFAType SecondFactorType
MFAType domain.SecondFactorType
IsActive bool
}
func (wm *SecondFactorWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *SecondFactorAddedEvent:
case *policy.SecondFactorAddedEvent:
wm.MFAType = e.MFAType
case *SecondFactorRemovedEvent:
wm.IsActive = true
case *policy.SecondFactorRemovedEvent:
wm.MFAType = e.MFAType
wm.IsActive = false
}
}
return wm.WriteModel.Reduce()
@@ -21,16 +28,19 @@ func (wm *SecondFactorWriteModel) Reduce() error {
type MultiFactoryWriteModel struct {
eventstore.WriteModel
MFAType MultiFactorType
MFAType domain.MultiFactorType
IsActive bool
}
func (wm *MultiFactoryWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *MultiFactorAddedEvent:
case *policy.MultiFactorAddedEvent:
wm.MFAType = e.MFAType
case *MultiFactorRemovedEvent:
wm.IsActive = true
case *policy.MultiFactorRemovedEvent:
wm.MFAType = e.MFAType
wm.IsActive = false
}
}
return wm.WriteModel.Reduce()

View File

@@ -1,34 +1,40 @@
package login
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type WriteModel struct {
type LoginPolicyWriteModel struct {
eventstore.WriteModel
AllowUserNamePassword bool
AllowRegister bool
AllowExternalIDP bool
ForceMFA bool
PasswordlessType PasswordlessType
PasswordlessType domain.PasswordlessType
IsActive bool
}
func (wm *WriteModel) Reduce() error {
func (wm *LoginPolicyWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *AddedEvent:
case *policy.LoginPolicyAddedEvent:
wm.AllowRegister = e.AllowRegister
wm.AllowUserNamePassword = e.AllowUserNamePassword
wm.AllowExternalIDP = e.AllowExternalIDP
wm.ForceMFA = e.ForceMFA
wm.PasswordlessType = e.PasswordlessType
case *ChangedEvent:
wm.IsActive = true
case *policy.LoginPolicyChangedEvent:
wm.AllowRegister = e.AllowRegister
wm.AllowUserNamePassword = e.AllowUserNamePassword
wm.AllowExternalIDP = e.AllowExternalIDP
wm.ForceMFA = e.ForceMFA
wm.PasswordlessType = e.PasswordlessType
case *policy.LoginPolicyRemovedEvent:
wm.IsActive = false
}
}
return wm.WriteModel.Reduce()

View File

@@ -0,0 +1,26 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type PolicyOrgIAMWriteModel struct {
eventstore.WriteModel
UserLoginMustBeDomain bool
IsActive bool
}
func (wm *PolicyOrgIAMWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *policy.OrgIAMPolicyAddedEvent:
wm.UserLoginMustBeDomain = e.UserLoginMustBeDomain
wm.IsActive = true
case *policy.OrgIAMPolicyChangedEvent:
wm.UserLoginMustBeDomain = e.UserLoginMustBeDomain
}
}
return wm.WriteModel.Reduce()
}

View File

@@ -1,25 +1,30 @@
package password_age
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type WriteModel struct {
type PasswordAgePolicyWriteModel struct {
eventstore.WriteModel
ExpireWarnDays uint64
MaxAgeDays uint64
IsActive bool
}
func (wm *WriteModel) Reduce() error {
func (wm *PasswordAgePolicyWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *AddedEvent:
case *policy.PasswordAgePolicyAddedEvent:
wm.ExpireWarnDays = e.ExpireWarnDays
wm.MaxAgeDays = e.MaxAgeDays
case *ChangedEvent:
wm.IsActive = true
case *policy.PasswordAgePolicyChangedEvent:
wm.ExpireWarnDays = e.ExpireWarnDays
wm.MaxAgeDays = e.MaxAgeDays
case *policy.PasswordAgePolicyRemovedEvent:
wm.IsActive = false
}
}
return wm.WriteModel.Reduce()

View File

@@ -1,10 +1,11 @@
package password_complexity
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type WriteModel struct {
type PasswordComplexityPolicyWriteModel struct {
eventstore.WriteModel
MinLength uint64
@@ -12,23 +13,27 @@ type WriteModel struct {
HasUpperCase bool
HasNumber bool
HasSymbol bool
IsActive bool
}
func (wm *WriteModel) Reduce() error {
func (wm *PasswordComplexityPolicyWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *AddedEvent:
case *policy.PasswordComplexityPolicyAddedEvent:
wm.MinLength = e.MinLength
wm.HasLowercase = e.HasLowercase
wm.HasUpperCase = e.HasUpperCase
wm.HasNumber = e.HasNumber
wm.HasSymbol = e.HasSymbol
case *ChangedEvent:
wm.IsActive = true
case *policy.PasswordComplexityPolicyChangedEvent:
wm.MinLength = e.MinLength
wm.HasLowercase = e.HasLowercase
wm.HasUpperCase = e.HasUpperCase
wm.HasNumber = e.HasNumber
wm.HasSymbol = e.HasSymbol
case *policy.PasswordComplexityPolicyRemovedEvent:
wm.IsActive = false
}
}
return wm.WriteModel.Reduce()

View File

@@ -1,25 +1,30 @@
package password_lockout
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type WriteModel struct {
type PasswordLockoutPolicyWriteModel struct {
eventstore.WriteModel
MaxAttempts uint64
ShowLockOutFailures bool
IsActive bool
}
func (wm *WriteModel) Reduce() error {
func (wm *PasswordLockoutPolicyWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *AddedEvent:
case *policy.PasswordLockoutPolicyAddedEvent:
wm.MaxAttempts = e.MaxAttempts
wm.ShowLockOutFailures = e.ShowLockOutFailures
case *ChangedEvent:
wm.IsActive = true
case *policy.PasswordLockoutPolicyChangedEvent:
wm.MaxAttempts = e.MaxAttempts
wm.ShowLockOutFailures = e.ShowLockOutFailures
case *policy.PasswordLockoutPolicyRemovedEvent:
wm.IsActive = false
}
}
return wm.WriteModel.Reduce()

View File

@@ -0,0 +1,65 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
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"
)
func (r *CommandSide) StartSetup(ctx context.Context, iamID string, step domain.Step) (*iam_model.IAM, error) {
iamWriteModel, err := r.iamByID(ctx, iamID)
if err != nil && !caos_errs.IsNotFound(err) {
return nil, err
}
if iamWriteModel.SetUpStarted >= step || iamWriteModel.SetUpStarted != iamWriteModel.SetUpDone {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9so34", "setup error")
}
aggregate := IAMAggregateFromWriteModel(&iamWriteModel.WriteModel).PushEvents(iam_repo.NewSetupStepStartedEvent(ctx, step))
err = r.eventstore.PushAggregate(ctx, iamWriteModel, aggregate)
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Grgh1", "Setup start failed")
}
return writeModelToIAM(iamWriteModel), nil
}
//func (r *CommandSide) setupDone(ctx context.Context, iamAgg *iam_repo.Aggregate, event eventstore.EventPusher, aggregates ...eventstore.Aggregater) error {
// aggregate := iamAgg.PushEvents(event)
//
// aggregates = append(aggregates, aggregate)
// _, err := r.eventstore.PushAggregates(ctx, aggregates...)
// if err != nil {
// return caos_errs.ThrowPreconditionFailed(nil, "EVENT-Dgd2", "Setup done failed")
// }
// return nil
//}
//
////TODO: should not use readmodel
//func (r *CommandSide) setup(ctx context.Context, iamID string, step iam_repo.Step, event eventstore.EventPusher) (*iam_model.IAM, error) {
// iam, err := r.iamByID(ctx, iamID)
// if err != nil && !caos_errs.IsNotFound(err) {
// return nil, err
// }
//
// if iam != nil && (iam.SetUpStarted >= iam_repo.Step(step) || iam.SetUpStarted != iam.SetUpDone) {
// return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9so34", "setup error")
// }
//
// aggregate := query.AggregateFromReadModel(iam).
// PushEvents(event)
//
// events, err := r.eventstore.PushAggregates(ctx, aggregate)
// if err != nil {
// return nil, err
// }
//
// if err = iam.AppendAndReduce(events...); err != nil {
// return nil, err
// }
// return nil, nil
// //TODO: return write model
// //return readModelToIAM(iam), nil
//}

View File

@@ -0,0 +1,107 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
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"
)
type Step1 struct {
GlobalOrg string
IAMProject string
DefaultLoginPolicy LoginPolicy //*iam_model.LoginPolicy
Orgs []Org
Owners []string
//setup *Setup
//createdUsers map[string]*usr_model.User
//createdOrgs map[string]*org_model.Org
//createdProjects map[string]*proj_model.Project
//pwComplexityPolicy *iam_model.PasswordComplexityPolicyView
}
type LoginPolicy struct {
AllowRegister bool
AllowUsernamePassword bool
AllowExternalIdp bool
}
type User struct {
FirstName string
LastName string
UserName string
Email string
Password string
}
type Org struct {
Name string
Domain string
OrgIamPolicy bool
Users []User
Owners []string
Projects []Project
}
type Project struct {
Name string
Users []User
Members []string
OIDCApps []OIDCApp
}
type OIDCApp struct {
Name string
RedirectUris []string
ResponseTypes []string
GrantTypes []string
ApplicationType string
AuthMethodType string
PostLogoutRedirectUris []string
DevMode bool
}
func (r *CommandSide) SetupStep1(ctx context.Context, iamID string, step1 Step1) error {
iam, err := r.iamByID(ctx, iamID)
if err != nil && !caos_errs.IsNotFound(err) {
return err
}
//create default login policy
iamAgg, err := r.addDefaultLoginPolicy(ctx,
NewIAMLoginPolicyWriteModel(iam.AggregateID),
&iam_model.LoginPolicy{
AllowUsernamePassword: step1.DefaultLoginPolicy.AllowUsernamePassword,
AllowRegister: step1.DefaultLoginPolicy.AllowRegister,
AllowExternalIdp: step1.DefaultLoginPolicy.AllowExternalIdp,
})
if err != nil {
return err
}
//create orgs
//create projects
//create applications
//set iam owners
//set global org
//set iam project id
/*aggregates:
iam:
default login policy
iam owner
org:
default
caos
zitadel
*/
iamAgg.PushEvents(iam_repo.NewSetupStepDoneEvent(ctx, domain.Step1))
_, err = r.eventstore.PushAggregates(ctx, iamAgg)
if err != nil {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-Gr2hh", "Setup Step1 failed")
}
return nil
}

View File

@@ -0,0 +1,38 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
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"
)
type Step2 struct {
DefaultPasswordComplexityPolicy iam_model.PasswordComplexityPolicy
}
func (r *CommandSide) SetupStep2(ctx context.Context, iamID string, step Step2) error {
iam, err := r.iamByID(ctx, iamID)
if err != nil && !caos_errs.IsNotFound(err) {
return err
}
iamAgg, err := r.addDefaultPasswordComplexityPolicy(ctx, NewIAMPasswordComplexityPolicyWriteModel(iam.AggregateID), &iam_model.PasswordComplexityPolicy{
MinLength: step.DefaultPasswordComplexityPolicy.MinLength,
HasLowercase: step.DefaultPasswordComplexityPolicy.HasLowercase,
HasUppercase: step.DefaultPasswordComplexityPolicy.HasUppercase,
HasNumber: step.DefaultPasswordComplexityPolicy.HasNumber,
HasSymbol: step.DefaultPasswordComplexityPolicy.HasSymbol,
})
if err != nil {
return err
}
iamAgg.PushEvents(iam_repo.NewSetupStepDoneEvent(ctx, domain.Step1))
_, err = r.eventstore.PushAggregates(ctx, iamAgg)
if err != nil {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-HR2na", "Setup Step2 failed")
}
return nil
}

123
internal/v2/command/user.go Normal file
View File

@@ -0,0 +1,123 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/user"
)
func (r *CommandSide) AddUser(ctx context.Context, user *usr_model.User) (*usr_model.User, error) {
if !user.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2N9fs", "Errors.User.Invalid")
}
if user.Human != nil {
human, err := r.AddHuman(ctx, user.ResourceOwner, user.UserName, user.Human)
if err != nil {
return nil, err
}
return &usr_model.User{UserName: user.UserName, Human: human}, nil
} else if user.Machine != nil {
}
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-8K0df", "Errors.User.TypeUndefined")
}
func (r *CommandSide) DeactivateUser(ctx context.Context, userID string) (*usr_model.User, error) {
existingUser, err := r.userWriteModelByID(ctx, userID)
if err != nil {
return nil, err
}
if existingUser.UserState != domain.UserStateUnspecified || existingUser.UserState != domain.UserStateDeleted {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-3M9ds", "Errors.User.NotFound")
}
if existingUser.UserState == domain.UserStateInactive {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5M0sf", "Errors.User.AlreadyInactive")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserDeactivatedEvent(ctx))
err = r.eventstore.PushAggregate(ctx, existingUser, userAgg)
if err != nil {
return nil, err
}
return writeModelToUser(existingUser), nil
}
func (r *CommandSide) ReactivateUser(ctx context.Context, userID string) (*usr_model.User, error) {
existingUser, err := r.userWriteModelByID(ctx, userID)
if err != nil {
return nil, err
}
if existingUser.UserState != domain.UserStateUnspecified || existingUser.UserState != domain.UserStateDeleted {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-4M0sd", "Errors.User.NotFound")
}
if existingUser.UserState != domain.UserStateInactive {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-6M0sf", "Errors.User.NotInactive")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserReactivatedEvent(ctx))
err = r.eventstore.PushAggregate(ctx, existingUser, userAgg)
if err != nil {
return nil, err
}
return writeModelToUser(existingUser), nil
}
func (r *CommandSide) LockUser(ctx context.Context, userID string) (*usr_model.User, error) {
existingUser, err := r.userWriteModelByID(ctx, userID)
if err != nil {
return nil, err
}
if existingUser.UserState != domain.UserStateUnspecified || existingUser.UserState != domain.UserStateDeleted {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-5M9fs", "Errors.User.NotFound")
}
if existingUser.UserState != domain.UserStateActive && existingUser.UserState != domain.UserStateInitial {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M9fs", "Errors.User.ShouldBeActiveOrInitial")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserLockedEvent(ctx))
err = r.eventstore.PushAggregate(ctx, existingUser, userAgg)
if err != nil {
return nil, err
}
return writeModelToUser(existingUser), nil
}
func (r *CommandSide) UnlockUser(ctx context.Context, userID string) (*usr_model.User, error) {
existingUser, err := r.userWriteModelByID(ctx, userID)
if err != nil {
return nil, err
}
if existingUser.UserState != domain.UserStateUnspecified || existingUser.UserState != domain.UserStateDeleted {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-M0dos", "Errors.User.NotFound")
}
if existingUser.UserState != domain.UserStateLocked {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0ds", "Errors.User.NotLocked")
}
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
userAgg.PushEvents(user.NewUserUnlockedEvent(ctx))
err = r.eventstore.PushAggregate(ctx, existingUser, userAgg)
if err != nil {
return nil, err
}
return writeModelToUser(existingUser), nil
}
func (r *CommandSide) userWriteModelByID(ctx context.Context, userID string) (writeModel *UserWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel = NewUserWriteModel(userID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,62 @@
package command
import (
"github.com/caos/zitadel/internal/user/model"
)
func writeModelToUser(wm *UserWriteModel) *model.User {
return &model.User{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
UserName: wm.UserName,
State: model.UserState(wm.UserState),
}
}
func writeModelToHuman(wm *HumanWriteModel) *model.Human {
return &model.Human{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
Profile: &model.Profile{
FirstName: wm.FirstName,
LastName: wm.LastName,
NickName: wm.NickName,
DisplayName: wm.DisplayName,
PreferredLanguage: wm.PreferredLanguage,
Gender: model.Gender(wm.Gender),
},
Email: &model.Email{
EmailAddress: wm.Email,
IsEmailVerified: wm.IsEmailVerified,
},
}
}
func writeModelToProfile(wm *HumanProfileWriteModel) *model.Profile {
return &model.Profile{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
FirstName: wm.FirstName,
LastName: wm.LastName,
NickName: wm.NickName,
DisplayName: wm.DisplayName,
PreferredLanguage: wm.PreferredLanguage,
Gender: model.Gender(wm.Gender),
}
}
func writeModelToEmail(wm *HumanEmailWriteModel) *model.Email {
return &model.Email{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
EmailAddress: wm.Email,
IsEmailVerified: wm.IsEmailVerified,
}
}
func writeModelToAddress(wm *HumanAddressWriteModel) *model.Address {
return &model.Address{
ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
Country: wm.Country,
Locality: wm.Locality,
PostalCode: wm.PostalCode,
Region: wm.Region,
StreetAddress: wm.StreetAddress,
}
}

View File

@@ -0,0 +1,71 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/user"
)
func (r *CommandSide) AddHuman(ctx context.Context, orgID, username string, human *usr_model.Human) (*usr_model.Human, error) {
if !human.IsValid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M90d", "Errors.User.Invalid")
}
userID, err := r.idGenerator.Next()
if err != nil {
return nil, err
}
human.AggregateID = userID
orgIAMPolicy, err := r.GetOrgIAMPolicy(ctx, orgID)
if err != nil {
return nil, err
}
//pwPolicy, err := r.GetOrgPasswordComplexityPolicy(ctx, orgID)
//if err != nil {
// return nil, err
//}
addedHuman := NewHumanWriteModel(human.AggregateID)
//TODO: Check Unique Username
human.CheckOrgIAMPolicy(username, orgIAMPolicy)
human.SetNamesAsDisplayname()
//human.HashPasswordIfExisting(pwPolicy, r.userPasswordAlg, true)
userAgg := UserAggregateFromWriteModel(&addedHuman.WriteModel)
userAgg.PushEvents(
user.NewHumanAddedEvent(
ctx,
username,
human.FirstName,
human.LastName,
human.NickName,
human.DisplayName,
human.PreferredLanguage,
domain.Gender(human.Gender),
human.EmailAddress,
human.PhoneNumber,
human.Country,
human.Locality,
human.PostalCode,
human.Region,
human.StreetAddress,
),
)
//TODO: HashPassword If existing
//TODO: Generate Init Code if needed
//TODO: Generate Phone Code if needed
if human.Email != nil && human.EmailAddress != "" && human.IsEmailVerified {
userAgg.PushEvents(user.NewHumanEmailVerifiedEvent(ctx))
}
if human.Phone != nil && human.PhoneNumber != "" && human.IsPhoneVerified {
userAgg.PushEvents(user.NewHumanPhoneVerifiedEvent(ctx))
}
err = r.eventstore.PushAggregate(ctx, addedHuman, userAgg)
if err != nil {
return nil, err
}
return writeModelToHuman(addedHuman), nil
}

View File

@@ -0,0 +1,44 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain"
)
func (r *CommandSide) ChangeHumanAddress(ctx context.Context, address *usr_model.Address) (*usr_model.Address, error) {
existingAddress, err := r.addressWriteModel(ctx, address.AggregateID)
if err != nil {
return nil, err
}
if existingAddress.UserState == domain.UserStateUnspecified || existingAddress.UserState == domain.UserStateDeleted {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-0pLdo", "Errors.User.Address.NotFound")
}
changedEvent, hasChanged := existingAddress.NewChangedEvent(ctx, address.Country, address.Locality, address.PostalCode, address.Region, address.StreetAddress)
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-3M0cs", "Errors.User.Address.NotChanged")
}
userAgg := UserAggregateFromWriteModel(&existingAddress.WriteModel)
userAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingAddress, userAgg)
if err != nil {
return nil, err
}
return writeModelToAddress(existingAddress), nil
}
func (r *CommandSide) addressWriteModel(ctx context.Context, userID string) (writeModel *HumanAddressWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel = NewHumanAddressWriteModel(userID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,109 @@
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/user"
)
type HumanAddressWriteModel struct {
eventstore.WriteModel
Country string
Locality string
PostalCode string
Region string
StreetAddress string
UserState domain.UserState
}
func NewHumanAddressWriteModel(userID string) *HumanAddressWriteModel {
return &HumanAddressWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: userID,
},
}
}
func (wm *HumanAddressWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *user.HumanAddressChangedEvent:
wm.AppendEvents(e)
case *user.HumanAddedEvent, *user.HumanRegisteredEvent:
wm.AppendEvents(e)
case *user.UserRemovedEvent:
wm.AppendEvents(e)
}
}
}
func (wm *HumanAddressWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.Country = e.Country
wm.Locality = e.Locality
wm.PostalCode = e.PostalCode
wm.Region = e.Region
wm.StreetAddress = e.StreetAddress
wm.UserState = domain.UserStateActive
case *user.HumanRegisteredEvent:
wm.Country = e.Country
wm.Locality = e.Locality
wm.PostalCode = e.PostalCode
wm.Region = e.Region
wm.StreetAddress = e.StreetAddress
wm.UserState = domain.UserStateActive
case *user.HumanAddressChangedEvent:
wm.Country = e.Country
wm.Locality = e.Locality
wm.PostalCode = e.PostalCode
wm.Region = e.Region
wm.StreetAddress = e.StreetAddress
case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted
}
}
return wm.WriteModel.Reduce()
}
func (wm *HumanAddressWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
AggregateIDs(wm.AggregateID)
}
func (wm *HumanAddressWriteModel) NewChangedEvent(
ctx context.Context,
country,
locality,
postalCode,
region,
streetAddress string,
) (*user.HumanAddressChangedEvent, bool) {
hasChanged := false
changedEvent := user.NewHumanAddressChangedEvent(ctx)
if wm.Country != country {
hasChanged = true
changedEvent.Country = country
}
if wm.Locality != locality {
hasChanged = true
changedEvent.Locality = locality
}
if wm.PostalCode != postalCode {
hasChanged = true
changedEvent.PostalCode = postalCode
}
if wm.Region != region {
hasChanged = true
changedEvent.Region = region
}
if wm.StreetAddress != streetAddress {
hasChanged = true
changedEvent.StreetAddress = streetAddress
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,48 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain"
)
func (r *CommandSide) ChangeHumanEmail(ctx context.Context, email *usr_model.Email) (*usr_model.Email, error) {
if !email.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M9sf", "Errors.Email.Invalid")
}
existingEmail, err := r.emailWriteModel(ctx, email.AggregateID)
if err != nil {
return nil, err
}
if existingEmail.UserState == domain.UserStateUnspecified || existingEmail.UserState == domain.UserStateDeleted {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-0Pe4r", "Errors.User.Email.NotFound")
}
changedEvent, hasChanged := existingEmail.NewChangedEvent(ctx, email.EmailAddress)
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-2M9fs", "Errors.User.Email.NotChanged")
}
userAgg := UserAggregateFromWriteModel(&existingEmail.WriteModel)
userAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingEmail, userAgg)
if err != nil {
return nil, err
}
return writeModelToEmail(existingEmail), nil
}
func (r *CommandSide) emailWriteModel(ctx context.Context, userID string) (writeModel *HumanEmailWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel = NewHumanEmailWriteModel(userID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,79 @@
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/user"
)
type HumanEmailWriteModel struct {
eventstore.WriteModel
Email string
IsEmailVerified bool
UserState domain.UserState
}
func NewHumanEmailWriteModel(userID string) *HumanEmailWriteModel {
return &HumanEmailWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: userID,
},
}
}
func (wm *HumanEmailWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *user.HumanEmailChangedEvent:
wm.AppendEvents(e)
case *user.HumanEmailVerifiedEvent:
wm.AppendEvents(e)
case *user.HumanAddedEvent, *user.HumanRegisteredEvent:
wm.AppendEvents(e)
case *user.UserRemovedEvent:
wm.AppendEvents(e)
}
}
}
func (wm *HumanEmailWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.Email = e.EmailAddress
wm.UserState = domain.UserStateActive
case *user.HumanRegisteredEvent:
wm.Email = e.EmailAddress
wm.UserState = domain.UserStateActive
case *user.HumanEmailChangedEvent:
wm.Email = e.EmailAddress
wm.IsEmailVerified = false
case *user.HumanEmailVerifiedEvent:
wm.IsEmailVerified = true
case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted
}
}
return wm.WriteModel.Reduce()
}
func (wm *HumanEmailWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
AggregateIDs(wm.AggregateID)
}
func (wm *HumanEmailWriteModel) NewChangedEvent(
ctx context.Context,
email string,
) (*user.HumanEmailChangedEvent, bool) {
hasChanged := false
changedEvent := user.NewHumanEmailChangedEvent(ctx)
if wm.Email != email {
hasChanged = true
changedEvent.EmailAddress = email
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,104 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/user"
"golang.org/x/text/language"
)
type HumanWriteModel struct {
eventstore.WriteModel
UserName string
FirstName string
LastName string
NickName string
DisplayName string
PreferredLanguage language.Tag
Gender domain.Gender
Email string
IsEmailVerified bool
Phone string
IsPhoneVerified bool
Country string
Locality string
PostalCode string
Region string
StreetAddress string
UserState domain.UserState
}
func NewHumanWriteModel(userID string) *HumanWriteModel {
return &HumanWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: userID,
},
}
}
func (wm *HumanWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *user.HumanEmailChangedEvent:
wm.AppendEvents(e)
case *user.HumanEmailVerifiedEvent:
wm.AppendEvents(e)
case *user.HumanAddedEvent, *user.HumanRegisteredEvent:
wm.AppendEvents(e)
case *user.UserDeactivatedEvent:
wm.AppendEvents(e)
case *user.UserReactivatedEvent:
wm.AppendEvents(e)
case *user.UserLockedEvent:
wm.AppendEvents(e)
case *user.UserUnlockedEvent:
wm.AppendEvents(e)
case *user.UserRemovedEvent:
wm.AppendEvents(e)
}
}
}
//TODO: Compute State? initial/active
func (wm *HumanWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateInitial
case *user.HumanRegisteredEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateInitial
case *user.UserLockedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateLocked
}
case *user.UserUnlockedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateActive
}
case *user.UserDeactivatedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateInactive
}
case *user.UserReactivatedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateActive
}
case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted
}
}
return wm.WriteModel.Reduce()
}
func (wm *HumanWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
AggregateIDs(wm.AggregateID)
}

View File

@@ -0,0 +1,48 @@
package command
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/v2/domain"
)
func (r *CommandSide) ChangeHumanProfile(ctx context.Context, profile *usr_model.Profile) (*usr_model.Profile, error) {
if !profile.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-8io0d", "Errors.User.Profile.Invalid")
}
existingProfile, err := r.profileWriteModelByID(ctx, profile.AggregateID)
if err != nil {
return nil, err
}
if existingProfile.UserState == domain.UserStateUnspecified || existingProfile.UserState == domain.UserStateDeleted {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-3M9sd", "Errors.User.Profile.NotFound")
}
changedEvent, hasChanged := existingProfile.NewChangedEvent(ctx, profile.FirstName, profile.LastName, profile.NickName, profile.DisplayName, profile.PreferredLanguage, domain.Gender(profile.Gender))
if !hasChanged {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-2M0fs", "Errors.User.Profile.NotChanged")
}
userAgg := UserAggregateFromWriteModel(&existingProfile.WriteModel)
userAgg.PushEvents(changedEvent)
err = r.eventstore.PushAggregate(ctx, existingProfile, userAgg)
if err != nil {
return nil, err
}
return writeModelToProfile(existingProfile), nil
}
func (r *CommandSide) profileWriteModelByID(ctx context.Context, userID string) (writeModel *HumanProfileWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel = NewHumanProfileWriteModel(userID)
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,120 @@
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/user"
"golang.org/x/text/language"
)
type HumanProfileWriteModel struct {
eventstore.WriteModel
FirstName string
LastName string
NickName string
DisplayName string
PreferredLanguage language.Tag
Gender domain.Gender
UserState domain.UserState
}
func NewHumanProfileWriteModel(userID string) *HumanProfileWriteModel {
return &HumanProfileWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: userID,
},
}
}
func (wm *HumanProfileWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *user.HumanProfileChangedEvent:
wm.AppendEvents(e)
case *user.HumanAddedEvent, *user.HumanRegisteredEvent:
wm.AppendEvents(e)
case *user.UserRemovedEvent:
wm.AppendEvents(e)
}
}
}
func (wm *HumanProfileWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.FirstName = e.FirstName
wm.LastName = e.LastName
wm.NickName = e.NickName
wm.DisplayName = e.DisplayName
wm.PreferredLanguage = e.PreferredLanguage
wm.Gender = e.Gender
wm.UserState = domain.UserStateActive
case *user.HumanRegisteredEvent:
wm.FirstName = e.FirstName
wm.LastName = e.LastName
wm.NickName = e.NickName
wm.DisplayName = e.DisplayName
wm.PreferredLanguage = e.PreferredLanguage
wm.Gender = e.Gender
wm.UserState = domain.UserStateActive
case *user.HumanProfileChangedEvent:
wm.FirstName = e.FirstName
wm.LastName = e.LastName
wm.NickName = e.NickName
wm.DisplayName = e.DisplayName
wm.PreferredLanguage = e.PreferredLanguage
wm.Gender = e.Gender
case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted
}
}
return wm.WriteModel.Reduce()
}
func (wm *HumanProfileWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
AggregateIDs(wm.AggregateID)
}
func (wm *HumanProfileWriteModel) NewChangedEvent(
ctx context.Context,
firstName,
lastName,
nickName,
displayName string,
preferredLanguage language.Tag,
gender domain.Gender,
) (*user.HumanProfileChangedEvent, bool) {
hasChanged := false
changedEvent := user.NewHumanProfileChangedEvent(ctx)
if wm.FirstName != firstName {
hasChanged = true
changedEvent.FirstName = firstName
}
if wm.LastName != lastName {
hasChanged = true
changedEvent.LastName = lastName
}
if wm.NickName != nickName {
hasChanged = true
changedEvent.NickName = nickName
}
if wm.DisplayName != displayName {
hasChanged = true
changedEvent.DisplayName = displayName
}
if wm.PreferredLanguage != preferredLanguage {
hasChanged = true
changedEvent.PreferredLanguage = preferredLanguage
}
if gender.Valid() && wm.Gender != gender {
hasChanged = true
changedEvent.Gender = gender
}
return changedEvent, hasChanged
}

View File

@@ -0,0 +1,95 @@
package command
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/user"
)
type UserWriteModel struct {
eventstore.WriteModel
UserName string
UserState domain.UserState
}
func NewUserWriteModel(userID string) *UserWriteModel {
return &UserWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: userID,
},
}
}
func (wm *UserWriteModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *user.HumanEmailChangedEvent:
wm.AppendEvents(e)
case *user.HumanEmailVerifiedEvent:
wm.AppendEvents(e)
case *user.HumanAddedEvent, *user.HumanRegisteredEvent:
wm.AppendEvents(e)
case *user.MachineAddedEvent:
wm.AppendEvents(e)
case *user.UserDeactivatedEvent:
wm.AppendEvents(e)
case *user.UserReactivatedEvent:
wm.AppendEvents(e)
case *user.UserLockedEvent:
wm.AppendEvents(e)
case *user.UserUnlockedEvent:
wm.AppendEvents(e)
case *user.UserRemovedEvent:
wm.AppendEvents(e)
}
}
}
//TODO: Compute State? initial/active
func (wm *UserWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateInitial
case *user.HumanRegisteredEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateInitial
case *user.MachineAddedEvent:
wm.UserName = e.UserName
wm.UserState = domain.UserStateActive
case *user.UserLockedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateLocked
}
case *user.UserUnlockedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateActive
}
case *user.UserDeactivatedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateInactive
}
case *user.UserReactivatedEvent:
if wm.UserState != domain.UserStateDeleted {
wm.UserState = domain.UserStateActive
}
case *user.UserRemovedEvent:
wm.UserState = domain.UserStateDeleted
}
}
return wm.WriteModel.Reduce()
}
func (wm *UserWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
AggregateIDs(wm.AggregateID)
}
func UserAggregateFromWriteModel(wm *eventstore.WriteModel) *user.Aggregate {
return &user.Aggregate{
Aggregate: *eventstore.AggregateFromWriteModel(wm, user.AggregateType, user.AggregateVersion),
}
}

View File

@@ -1,4 +1,4 @@
package factors
package domain
type SecondFactorType int32

View File

@@ -1,4 +1,4 @@
package human
package domain
type Gender int32

View File

@@ -0,0 +1,42 @@
package domain
type IDPConfigType int32
const (
IDPConfigTypeOIDC IDPConfigType = iota
IDPConfigTypeSAML
//count is for validation
idpConfigTypeCount
)
func (f IDPConfigType) Valid() bool {
return f >= 0 && f < idpConfigTypeCount
}
type IDPConfigState int32
const (
IDPConfigStateUnspecified IDPConfigState = iota
IDPConfigStateActive
IDPConfigStateInactive
IDPConfigStateRemoved
idpConfigStateCount
)
func (f IDPConfigState) Valid() bool {
return f >= 0 && f < idpConfigStateCount
}
type IDPConfigStylingType int32
const (
IDPConfigStylingTypeGoogle IDPConfigStylingType = iota + 1
idpConfigStylingTypeCount
)
func (f IDPConfigStylingType) Valid() bool {
return f >= 0 && f < idpConfigStylingTypeCount
}

View File

@@ -1,4 +1,4 @@
package keys
package domain
type MachineKeyType int32

15
internal/v2/domain/mfa.go Normal file
View File

@@ -0,0 +1,15 @@
package domain
type MFAState int32
const (
MFAStateUnspecified MFAState = iota
MFAStateNotReady
MFAStateReady
stateCount
)
func (f MFAState) Valid() bool {
return f >= 0 && f < stateCount
}

View File

@@ -0,0 +1,14 @@
package domain
type NotificationType int32
const (
NotificationTypeEmail NotificationType = iota
NotificationTypeSms
notificationCount
)
func (f NotificationType) Valid() bool {
return f >= 0 && f < notificationCount
}

View File

@@ -0,0 +1,14 @@
package domain
type OIDCMappingField int32
const (
OIDCMappingFieldPreferredLoginName OIDCMappingField = iota + 1
OIDCMappingFieldEmail
// count is for validation purposes
oidcMappingFieldCount
)
func (f OIDCMappingField) Valid() bool {
return f > 0 && f < oidcMappingFieldCount
}

View File

@@ -0,0 +1,14 @@
package domain
type PasswordlessType int32
const (
PasswordlessTypeNotAllowed PasswordlessType = iota
PasswordlessTypeAllowed
passwordlessCount
)
func (f PasswordlessType) Valid() bool {
return f >= 0 && f < passwordlessCount
}

View File

@@ -0,0 +1,14 @@
package domain
type IdentityProviderType int8
const (
IdentityProviderTypeSystem IdentityProviderType = iota
IdentityProviderTypeOrg
identityProviderCount
)
func (f IdentityProviderType) Valid() bool {
return f >= 0 && f < identityProviderCount
}

View File

@@ -0,0 +1,16 @@
package domain
type Step int
const (
Step1 Step = iota + 1
Step2
Step3
Step4
Step5
Step6
Step7
Step8
//StepCount marks the the length of possible steps (StepCount-1 == last possible step)
StepCount
)

View File

@@ -0,0 +1,19 @@
package domain
type UserState int32
const (
UserStateUnspecified UserState = iota
UserStateActive
UserStateInactive
UserStateDeleted
UserStateLocked
UserStateSuspend
UserStateInitial
userStateCount
)
func (f UserState) Valid() bool {
return f >= 0 && f < userStateCount
}

View File

@@ -0,0 +1,168 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/iam/model"
)
func readModelToIAM(readModel *ReadModel) *model.IAM {
return &model.IAM{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel),
GlobalOrgID: readModel.GlobalOrgID,
IAMProjectID: readModel.ProjectID,
SetUpDone: readModel.SetUpDone,
SetUpStarted: readModel.SetUpStarted,
Members: readModelToMembers(&readModel.Members),
DefaultLabelPolicy: readModelToLabelPolicy(&readModel.DefaultLabelPolicy),
DefaultLoginPolicy: readModelToLoginPolicy(&readModel.DefaultLoginPolicy),
DefaultOrgIAMPolicy: readModelToOrgIAMPolicy(&readModel.DefaultOrgIAMPolicy),
DefaultPasswordAgePolicy: readModelToPasswordAgePolicy(&readModel.DefaultPasswordAgePolicy),
DefaultPasswordComplexityPolicy: readModelToPasswordComplexityPolicy(&readModel.DefaultPasswordComplexityPolicy),
DefaultPasswordLockoutPolicy: readModelToPasswordLockoutPolicy(&readModel.DefaultPasswordLockoutPolicy),
IDPs: readModelToIDPConfigs(&readModel.IDPs),
}
}
func readModelToIDPConfigView(rm *IAMIDPConfigReadModel) *model.IDPConfigView {
return &model.IDPConfigView{
AggregateID: rm.AggregateID,
ChangeDate: rm.ChangeDate,
CreationDate: rm.CreationDate,
IDPConfigID: rm.ConfigID,
IDPProviderType: model.IDPProviderType(rm.ProviderType),
IsOIDC: rm.OIDCConfig != nil,
Name: rm.Name,
OIDCClientID: rm.OIDCConfig.ClientID,
OIDCClientSecret: rm.OIDCConfig.ClientSecret,
OIDCIDPDisplayNameMapping: model.OIDCMappingField(rm.OIDCConfig.IDPDisplayNameMapping),
OIDCIssuer: rm.OIDCConfig.Issuer,
OIDCScopes: rm.OIDCConfig.Scopes,
OIDCUsernameMapping: model.OIDCMappingField(rm.OIDCConfig.UserNameMapping),
Sequence: rm.ProcessedSequence,
State: model.IDPConfigState(rm.State),
StylingType: model.IDPStylingType(rm.StylingType),
}
}
func readModelToMember(readModel *MemberReadModel) *model.IAMMember {
return &model.IAMMember{
ObjectRoot: readModelToObjectRoot(readModel.ReadModel),
Roles: readModel.Roles,
UserID: readModel.UserID,
}
}
func readModelToMembers(readModel *IAMMembersReadModel) []*model.IAMMember {
members := make([]*model.IAMMember, len(readModel.Members))
for i, member := range readModel.Members {
members[i] = &model.IAMMember{
ObjectRoot: readModelToObjectRoot(member.ReadModel),
Roles: member.Roles,
UserID: member.UserID,
}
}
return members
}
func readModelToLabelPolicy(readModel *IAMLabelPolicyReadModel) *model.LabelPolicy {
return &model.LabelPolicy{
ObjectRoot: readModelToObjectRoot(readModel.LabelPolicyReadModel.ReadModel),
PrimaryColor: readModel.PrimaryColor,
SecondaryColor: readModel.SecondaryColor,
Default: true,
//TODO: State: int32,
}
}
func readModelToLoginPolicy(readModel *IAMLoginPolicyReadModel) *model.LoginPolicy {
return &model.LoginPolicy{
ObjectRoot: readModelToObjectRoot(readModel.LoginPolicyReadModel.ReadModel),
AllowExternalIdp: readModel.AllowExternalIDP,
AllowRegister: readModel.AllowRegister,
AllowUsernamePassword: readModel.AllowUserNamePassword,
Default: true,
//TODO: IDPProviders: []*model.IDPProvider,
//TODO: State: int32,
}
}
func readModelToOrgIAMPolicy(readModel *IAMOrgIAMPolicyReadModel) *model.OrgIAMPolicy {
return &model.OrgIAMPolicy{
ObjectRoot: readModelToObjectRoot(readModel.OrgIAMPolicyReadModel.ReadModel),
UserLoginMustBeDomain: readModel.UserLoginMustBeDomain,
Default: true,
//TODO: State: int32,
}
}
func readModelToPasswordAgePolicy(readModel *IAMPasswordAgePolicyReadModel) *model.PasswordAgePolicy {
return &model.PasswordAgePolicy{
ObjectRoot: readModelToObjectRoot(readModel.PasswordAgePolicyReadModel.ReadModel),
ExpireWarnDays: uint64(readModel.ExpireWarnDays),
MaxAgeDays: uint64(readModel.MaxAgeDays),
//TODO: State: int32,
}
}
func readModelToPasswordComplexityPolicy(readModel *IAMPasswordComplexityPolicyReadModel) *model.PasswordComplexityPolicy {
return &model.PasswordComplexityPolicy{
ObjectRoot: readModelToObjectRoot(readModel.PasswordComplexityPolicyReadModel.ReadModel),
HasLowercase: readModel.HasLowercase,
HasNumber: readModel.HasNumber,
HasSymbol: readModel.HasSymbol,
HasUppercase: readModel.HasUpperCase,
MinLength: uint64(readModel.MinLength),
//TODO: State: int32,
}
}
func readModelToPasswordLockoutPolicy(readModel *IAMPasswordLockoutPolicyReadModel) *model.PasswordLockoutPolicy {
return &model.PasswordLockoutPolicy{
ObjectRoot: readModelToObjectRoot(readModel.PasswordLockoutPolicyReadModel.ReadModel),
MaxAttempts: uint64(readModel.MaxAttempts),
ShowLockOutFailures: readModel.ShowLockOutFailures,
//TODO: State: int32,
}
}
func readModelToIDPConfigs(rm *IAMIDPConfigsReadModel) []*model.IDPConfig {
configs := make([]*model.IDPConfig, len(rm.Configs))
for i, config := range rm.Configs {
configs[i] = readModelToIDPConfig(&IAMIDPConfigReadModel{IDPConfigReadModel: *config})
}
return configs
}
func readModelToIDPConfig(rm *IAMIDPConfigReadModel) *model.IDPConfig {
return &model.IDPConfig{
ObjectRoot: readModelToObjectRoot(rm.ReadModel),
OIDCConfig: readModelToIDPOIDCConfig(rm.OIDCConfig),
IDPConfigID: rm.ConfigID,
Name: rm.Name,
State: model.IDPConfigState(rm.State),
StylingType: model.IDPStylingType(rm.StylingType),
}
}
func readModelToIDPOIDCConfig(rm *OIDCConfigReadModel) *model.OIDCIDPConfig {
return &model.OIDCIDPConfig{
ObjectRoot: readModelToObjectRoot(rm.ReadModel),
ClientID: rm.ClientID,
ClientSecret: rm.ClientSecret,
ClientSecretString: string(rm.ClientSecret.Crypted),
IDPConfigID: rm.IDPConfigID,
IDPDisplayNameMapping: model.OIDCMappingField(rm.IDPDisplayNameMapping),
Issuer: rm.Issuer,
Scopes: rm.Scopes,
UsernameMapping: model.OIDCMappingField(rm.UserNameMapping),
}
}
func readModelToObjectRoot(readModel eventstore.ReadModel) models.ObjectRoot {
return models.ObjectRoot{
AggregateID: readModel.AggregateID,
ChangeDate: readModel.ChangeDate,
CreationDate: readModel.CreationDate,
ResourceOwner: readModel.ResourceOwner,
Sequence: readModel.ProcessedSequence,
}
}

View File

@@ -0,0 +1,49 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMIDPConfigReadModel struct {
IDPConfigReadModel
iamID string
configID string
}
func NewIAMIDPConfigReadModel(iamID, configID string) *IAMIDPConfigReadModel {
return &IAMIDPConfigReadModel{
iamID: iamID,
configID: configID,
}
}
func (rm *IAMIDPConfigReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.IDPConfigAddedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigAddedEvent)
case *iam.IDPConfigChangedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigChangedEvent)
case *iam.IDPConfigDeactivatedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigDeactivatedEvent)
case *iam.IDPConfigReactivatedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigReactivatedEvent)
case *iam.IDPConfigRemovedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.IDPConfigRemovedEvent)
case *iam.IDPOIDCConfigAddedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.OIDCConfigAddedEvent)
case *iam.IDPOIDCConfigChangedEvent:
rm.IDPConfigReadModel.AppendEvents(&e.OIDCConfigChangedEvent)
}
}
}
func (rm *IAMIDPConfigReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(rm.iamID).
EventData(map[string]interface{}{
"idpConfigId": rm.configID,
})
}

View File

@@ -0,0 +1,31 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMIDPConfigsReadModel struct {
IDPConfigsReadModel
}
func (rm *IAMIDPConfigsReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.IDPConfigAddedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigAddedEvent)
case *iam.IDPConfigChangedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigChangedEvent)
case *iam.IDPConfigDeactivatedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigDeactivatedEvent)
case *iam.IDPConfigReactivatedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigReactivatedEvent)
case *iam.IDPConfigRemovedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.IDPConfigRemovedEvent)
case *iam.IDPOIDCConfigAddedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.OIDCConfigAddedEvent)
case *iam.IDPOIDCConfigChangedEvent:
rm.IDPConfigsReadModel.AppendEvents(&e.OIDCConfigChangedEvent)
}
}
}

View File

@@ -0,0 +1,42 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/member"
)
type IAMMemberReadModel struct {
MemberReadModel
userID string
iamID string
}
func NewIAMMemberReadModel(iamID, userID string) *IAMMemberReadModel {
return &IAMMemberReadModel{
iamID: iamID,
userID: userID,
}
}
func (rm *IAMMemberReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.MemberAddedEvent:
rm.MemberReadModel.AppendEvents(&e.MemberAddedEvent)
case *iam.MemberChangedEvent:
rm.MemberReadModel.AppendEvents(&e.MemberChangedEvent)
case *member.MemberAddedEvent, *member.MemberChangedEvent, *iam.MemberRemovedEvent:
rm.MemberReadModel.AppendEvents(e)
}
}
}
func (rm *IAMMemberReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).
AggregateIDs(rm.iamID).
EventData(map[string]interface{}{
"userId": rm.userID,
})
}

View File

@@ -0,0 +1,23 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
)
type IAMMembersReadModel struct {
MembersReadModel
}
func (rm *IAMMembersReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.MemberAddedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberAddedEvent)
case *iam.MemberChangedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberChangedEvent)
case *iam.MemberRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberRemovedEvent)
}
}
}

View File

@@ -0,0 +1,144 @@
package query
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/member"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type ReadModel struct {
eventstore.ReadModel
SetUpStarted domain.Step
SetUpDone domain.Step
Members IAMMembersReadModel
IDPs IAMIDPConfigsReadModel
GlobalOrgID string
ProjectID string
DefaultLoginPolicy IAMLoginPolicyReadModel
DefaultLabelPolicy IAMLabelPolicyReadModel
DefaultOrgIAMPolicy IAMOrgIAMPolicyReadModel
DefaultPasswordComplexityPolicy IAMPasswordComplexityPolicyReadModel
DefaultPasswordAgePolicy IAMPasswordAgePolicyReadModel
DefaultPasswordLockoutPolicy IAMPasswordLockoutPolicyReadModel
}
func NewReadModel(id string) *ReadModel {
return &ReadModel{
ReadModel: eventstore.ReadModel{
AggregateID: id,
},
}
}
func (rm *ReadModel) IDPByID(idpID string) *IAMIDPConfigReadModel {
_, config := rm.IDPs.ConfigByID(idpID)
if config == nil {
return nil
}
return &IAMIDPConfigReadModel{IDPConfigReadModel: *config}
}
func (rm *ReadModel) AppendEvents(events ...eventstore.EventReader) {
rm.ReadModel.AppendEvents(events...)
for _, event := range events {
switch event.(type) {
case *member.MemberAddedEvent,
*member.MemberChangedEvent,
*member.MemberRemovedEvent:
rm.Members.AppendEvents(event)
case *iam.IDPConfigAddedEvent,
*iam.IDPConfigChangedEvent,
*iam.IDPConfigDeactivatedEvent,
*iam.IDPConfigReactivatedEvent,
*iam.IDPConfigRemovedEvent,
*iam.IDPOIDCConfigAddedEvent,
*iam.IDPOIDCConfigChangedEvent:
rm.IDPs.AppendEvents(event)
case *policy.LabelPolicyAddedEvent,
*policy.LabelPolicyChangedEvent:
rm.DefaultLabelPolicy.AppendEvents(event)
case *policy.LoginPolicyAddedEvent,
*policy.LoginPolicyChangedEvent:
rm.DefaultLoginPolicy.AppendEvents(event)
case *policy.OrgIAMPolicyAddedEvent:
rm.DefaultOrgIAMPolicy.AppendEvents(event)
case *policy.PasswordComplexityPolicyAddedEvent,
*policy.PasswordComplexityPolicyChangedEvent:
rm.DefaultPasswordComplexityPolicy.AppendEvents(event)
case *policy.PasswordAgePolicyAddedEvent,
*policy.PasswordAgePolicyChangedEvent:
rm.DefaultPasswordAgePolicy.AppendEvents(event)
case *policy.PasswordLockoutPolicyAddedEvent,
*policy.PasswordLockoutPolicyChangedEvent:
rm.DefaultPasswordLockoutPolicy.AppendEvents(event)
}
}
}
func (rm *ReadModel) Reduce() (err error) {
for _, event := range rm.Events {
switch e := event.(type) {
case *iam.ProjectSetEvent:
rm.ProjectID = e.ProjectID
case *iam.GlobalOrgSetEvent:
rm.GlobalOrgID = e.OrgID
case *iam.SetupStepEvent:
if e.Done {
rm.SetUpDone = e.Step
} else {
rm.SetUpStarted = e.Step
}
}
}
for _, reduce := range []func() error{
rm.Members.Reduce,
rm.IDPs.Reduce,
rm.DefaultLoginPolicy.Reduce,
rm.DefaultLabelPolicy.Reduce,
rm.DefaultOrgIAMPolicy.Reduce,
rm.DefaultPasswordComplexityPolicy.Reduce,
rm.DefaultPasswordAgePolicy.Reduce,
rm.DefaultPasswordLockoutPolicy.Reduce,
rm.ReadModel.Reduce,
} {
if err = reduce(); err != nil {
return err
}
}
return nil
}
func (rm *ReadModel) AppendAndReduce(events ...eventstore.EventReader) error {
rm.AppendEvents(events...)
return rm.Reduce()
}
func (rm *ReadModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, iam.AggregateType).AggregateIDs(rm.AggregateID)
}
func IAMAggregateFromReadModel(rm *ReadModel) *iam.Aggregate {
return &iam.Aggregate{
Aggregate: *eventstore.NewAggregate(
rm.AggregateID,
iam.AggregateType,
rm.ResourceOwner,
iam.AggregateVersion,
rm.ProcessedSequence,
),
}
}

View File

@@ -0,0 +1,22 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMLabelPolicyReadModel struct{ LabelPolicyReadModel }
func (rm *IAMLabelPolicyReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LabelPolicyAddedEvent:
rm.LabelPolicyReadModel.AppendEvents(&e.LabelPolicyAddedEvent)
case *iam.LabelPolicyChangedEvent:
rm.LabelPolicyReadModel.AppendEvents(&e.LabelPolicyChangedEvent)
case *policy.LabelPolicyAddedEvent, *policy.LabelPolicyChangedEvent:
rm.LabelPolicyReadModel.AppendEvents(e)
}
}
}

View File

@@ -0,0 +1,22 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMLoginPolicyReadModel struct{ LoginPolicyReadModel }
func (rm *IAMLoginPolicyReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.LoginPolicyAddedEvent:
rm.LoginPolicyReadModel.AppendEvents(&e.LoginPolicyAddedEvent)
case *iam.LoginPolicyChangedEvent:
rm.LoginPolicyReadModel.AppendEvents(&e.LoginPolicyChangedEvent)
case *policy.LoginPolicyAddedEvent, *policy.LoginPolicyChangedEvent:
rm.LoginPolicyReadModel.AppendEvents(e)
}
}
}

View File

@@ -0,0 +1,20 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMOrgIAMPolicyReadModel struct{ OrgIAMPolicyReadModel }
func (rm *IAMOrgIAMPolicyReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.OrgIAMPolicyAddedEvent:
rm.OrgIAMPolicyReadModel.AppendEvents(&e.OrgIAMPolicyAddedEvent)
case *policy.OrgIAMPolicyAddedEvent:
rm.OrgIAMPolicyReadModel.AppendEvents(e)
}
}
}

View File

@@ -0,0 +1,26 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMPasswordAgePolicyReadModel struct {
PasswordAgePolicyReadModel
}
func (rm *IAMPasswordAgePolicyReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.PasswordAgePolicyAddedEvent:
rm.PasswordAgePolicyReadModel.AppendEvents(&e.PasswordAgePolicyAddedEvent)
case *iam.PasswordAgePolicyChangedEvent:
rm.PasswordAgePolicyReadModel.AppendEvents(&e.PasswordAgePolicyChangedEvent)
case *policy.PasswordAgePolicyAddedEvent,
*policy.PasswordAgePolicyChangedEvent:
rm.PasswordAgePolicyReadModel.AppendEvents(e)
}
}
}

View File

@@ -0,0 +1,26 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMPasswordComplexityPolicyReadModel struct {
PasswordComplexityPolicyReadModel
}
func (rm *IAMPasswordComplexityPolicyReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.PasswordComplexityPolicyAddedEvent:
rm.PasswordComplexityPolicyReadModel.AppendEvents(&e.PasswordComplexityPolicyAddedEvent)
case *iam.PasswordComplexityPolicyChangedEvent:
rm.PasswordComplexityPolicyReadModel.AppendEvents(&e.PasswordComplexityPolicyChangedEvent)
case *policy.PasswordComplexityPolicyAddedEvent,
*policy.PasswordComplexityPolicyChangedEvent:
rm.PasswordComplexityPolicyReadModel.AppendEvents(e)
}
}
}

View File

@@ -0,0 +1,24 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/iam"
"github.com/caos/zitadel/internal/v2/repository/policy"
)
type IAMPasswordLockoutPolicyReadModel struct {
PasswordLockoutPolicyReadModel
}
func (rm *IAMPasswordLockoutPolicyReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *iam.PasswordLockoutPolicyAddedEvent:
rm.PasswordLockoutPolicyReadModel.AppendEvents(&e.PasswordLockoutPolicyAddedEvent)
case *iam.PasswordLockoutPolicyChangedEvent:
rm.PasswordLockoutPolicyReadModel.AppendEvents(&e.PasswordLockoutPolicyChangedEvent)
case *policy.PasswordLockoutPolicyAddedEvent, *policy.PasswordLockoutPolicyChangedEvent:
rm.PasswordLockoutPolicyReadModel.AppendEvents(e)
}
}
}

View File

@@ -0,0 +1,16 @@
package query
import (
"context"
"github.com/caos/zitadel/internal/iam/model"
)
func (r *QuerySide) DefaultIDPConfigByID(ctx context.Context, iamID, idpConfigID string) (*model.IDPConfigView, error) {
idpConfig := NewIAMIDPConfigReadModel(iamID, idpConfigID)
err := r.eventstore.FilterToQueryReducer(ctx, idpConfig)
if err != nil {
return nil, err
}
return readModelToIDPConfigView(idpConfig), nil
}

View File

@@ -0,0 +1,93 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/idpconfig"
)
type IDPConfigReadModel struct {
eventstore.ReadModel
State domain.IDPConfigState
ConfigID string
Name string
StylingType domain.IDPConfigStylingType
ProviderType domain.IdentityProviderType
OIDCConfig *OIDCConfigReadModel
}
func NewIDPConfigReadModel(configID string) *IDPConfigReadModel {
return &IDPConfigReadModel{
ConfigID: configID,
}
}
func (rm *IDPConfigReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *idpconfig.IDPConfigAddedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.IDPConfigChangedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.IDPConfigDeactivatedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.IDPConfigReactivatedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.IDPConfigRemovedEvent:
rm.ReadModel.AppendEvents(e)
case *idpconfig.OIDCConfigAddedEvent:
rm.OIDCConfig = &OIDCConfigReadModel{}
rm.ReadModel.AppendEvents(e)
rm.OIDCConfig.AppendEvents(event)
case *idpconfig.OIDCConfigChangedEvent:
rm.ReadModel.AppendEvents(e)
rm.OIDCConfig.AppendEvents(event)
}
}
}
func (rm *IDPConfigReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *idpconfig.IDPConfigAddedEvent:
rm.reduceConfigAddedEvent(e)
case *idpconfig.IDPConfigChangedEvent:
rm.reduceConfigChangedEvent(e)
case *idpconfig.IDPConfigDeactivatedEvent:
rm.reduceConfigStateChanged(e.ConfigID, domain.IDPConfigStateInactive)
case *idpconfig.IDPConfigReactivatedEvent:
rm.reduceConfigStateChanged(e.ConfigID, domain.IDPConfigStateActive)
case *idpconfig.IDPConfigRemovedEvent:
rm.reduceConfigStateChanged(e.ConfigID, domain.IDPConfigStateRemoved)
}
}
if rm.OIDCConfig != nil {
if err := rm.OIDCConfig.Reduce(); err != nil {
return err
}
}
return rm.ReadModel.Reduce()
}
func (rm *IDPConfigReadModel) reduceConfigAddedEvent(e *idpconfig.IDPConfigAddedEvent) {
rm.ConfigID = e.ConfigID
rm.Name = e.Name
rm.StylingType = e.StylingType
rm.State = domain.IDPConfigStateActive
}
func (rm *IDPConfigReadModel) reduceConfigChangedEvent(e *idpconfig.IDPConfigChangedEvent) {
if e.Name != "" {
rm.Name = e.Name
}
if e.StylingType.Valid() {
rm.StylingType = e.StylingType
}
}
func (rm *IDPConfigReadModel) reduceConfigStateChanged(configID string, state domain.IDPConfigState) {
rm.State = state
}

View File

@@ -1,17 +1,17 @@
package idp
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/idp/oidc"
"github.com/caos/zitadel/internal/v2/repository/idpconfig"
)
type ConfigsReadModel struct {
type IDPConfigsReadModel struct {
eventstore.ReadModel
Configs []*ConfigReadModel
Configs []*IDPConfigReadModel
}
func (rm *ConfigsReadModel) ConfigByID(id string) (idx int, config *ConfigReadModel) {
func (rm *IDPConfigsReadModel) ConfigByID(id string) (idx int, config *IDPConfigReadModel) {
for idx, config = range rm.Configs {
if config.ConfigID == id {
return idx, config
@@ -20,29 +20,29 @@ func (rm *ConfigsReadModel) ConfigByID(id string) (idx int, config *ConfigReadMo
return -1, nil
}
func (rm *ConfigsReadModel) AppendEvents(events ...eventstore.EventReader) {
func (rm *IDPConfigsReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *ConfigAddedEvent:
config := NewConfigReadModel(e.ConfigID)
case *idpconfig.IDPConfigAddedEvent:
config := NewIDPConfigReadModel(e.ConfigID)
rm.Configs = append(rm.Configs, config)
config.AppendEvents(event)
case *ConfigChangedEvent:
case *idpconfig.IDPConfigChangedEvent:
_, config := rm.ConfigByID(e.ConfigID)
config.AppendEvents(e)
case *ConfigDeactivatedEvent:
case *idpconfig.IDPConfigDeactivatedEvent:
_, config := rm.ConfigByID(e.ConfigID)
config.AppendEvents(e)
case *ConfigReactivatedEvent:
case *idpconfig.IDPConfigReactivatedEvent:
_, config := rm.ConfigByID(e.ConfigID)
config.AppendEvents(e)
case *oidc.ConfigAddedEvent:
case *idpconfig.OIDCConfigAddedEvent:
_, config := rm.ConfigByID(e.IDPConfigID)
config.AppendEvents(e)
case *oidc.ConfigChangedEvent:
case *idpconfig.OIDCConfigChangedEvent:
_, config := rm.ConfigByID(e.IDPConfigID)
config.AppendEvents(e)
case *ConfigRemovedEvent:
case *idpconfig.IDPConfigRemovedEvent:
idx, _ := rm.ConfigByID(e.ConfigID)
if idx < 0 {
continue
@@ -54,7 +54,7 @@ func (rm *ConfigsReadModel) AppendEvents(events ...eventstore.EventReader) {
}
}
func (rm *ConfigsReadModel) Reduce() error {
func (rm *IDPConfigsReadModel) Reduce() error {
for _, config := range rm.Configs {
if err := config.Reduce(); err != nil {
return err

View File

@@ -0,0 +1,19 @@
package query
import (
"context"
"github.com/caos/zitadel/internal/telemetry/tracing"
)
func (r *QuerySide) IAMMemberByID(ctx context.Context, iamID, userID string) (member *IAMMemberReadModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
member = NewIAMMemberReadModel(iamID, userID)
err = r.eventstore.FilterToQueryReducer(ctx, member)
if err != nil {
return nil, err
}
return member, nil
}

View File

@@ -0,0 +1,35 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/member"
)
//MemberReadModel represenets the default member view.
// It's computed from events.
type MemberReadModel struct {
eventstore.ReadModel
UserID string
Roles []string
}
//NewMemberReadModel is the default constructor of MemberReadModel
func NewMemberReadModel(userID string) *MemberReadModel {
return &MemberReadModel{
UserID: userID,
}
}
//Reduce extends eventstore.MemberReadModel
func (rm *MemberReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *member.MemberAddedEvent:
rm.Roles = e.Roles
case *member.MemberChangedEvent:
rm.Roles = e.Roles
}
}
return rm.ReadModel.Reduce()
}

View File

@@ -1,17 +1,17 @@
package members
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/member"
)
type ReadModel struct {
type MembersReadModel struct {
eventstore.ReadModel
Members []*member.ReadModel
Members []*MemberReadModel
}
func (rm *ReadModel) MemberByUserID(id string) (idx int, member *member.ReadModel) {
func (rm *MembersReadModel) MemberByUserID(id string) (idx int, member *MemberReadModel) {
for idx, member = range rm.Members {
if member.UserID == id {
return idx, member
@@ -20,17 +20,17 @@ func (rm *ReadModel) MemberByUserID(id string) (idx int, member *member.ReadMode
return -1, nil
}
func (rm *ReadModel) AppendEvents(events ...eventstore.EventReader) {
func (rm *MembersReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *member.AddedEvent:
m := member.NewReadModel(e.UserID)
case *member.MemberAddedEvent:
m := NewMemberReadModel(e.UserID)
rm.Members = append(rm.Members, m)
m.AppendEvents(e)
case *member.ChangedEvent:
case *member.MemberChangedEvent:
_, m := rm.MemberByUserID(e.UserID)
m.AppendEvents(e)
case *member.RemovedEvent:
case *member.MemberRemovedEvent:
idx, _ := rm.MemberByUserID(e.UserID)
if idx < 0 {
continue
@@ -42,7 +42,7 @@ func (rm *ReadModel) AppendEvents(events ...eventstore.EventReader) {
}
}
func (rm *ReadModel) Reduce() (err error) {
func (rm *MembersReadModel) Reduce() (err error) {
for _, m := range rm.Members {
err = m.Reduce()
if err != nil {

View File

@@ -1,11 +1,13 @@
package oidc
package query
import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/domain"
"github.com/caos/zitadel/internal/v2/repository/idpconfig"
)
type ConfigReadModel struct {
type OIDCConfigReadModel struct {
eventstore.ReadModel
IDPConfigID string
@@ -13,16 +15,16 @@ type ConfigReadModel struct {
ClientSecret *crypto.CryptoValue
Issuer string
Scopes []string
IDPDisplayNameMapping MappingField
UserNameMapping MappingField
IDPDisplayNameMapping domain.OIDCMappingField
UserNameMapping domain.OIDCMappingField
}
func (rm *ConfigReadModel) Reduce() error {
func (rm *OIDCConfigReadModel) Reduce() error {
for _, event := range rm.Events {
switch e := event.(type) {
case *ConfigAddedEvent:
case *idpconfig.OIDCConfigAddedEvent:
rm.reduceConfigAddedEvent(e)
case *ConfigChangedEvent:
case *idpconfig.OIDCConfigChangedEvent:
rm.reduceConfigChangedEvent(e)
}
}
@@ -30,7 +32,7 @@ func (rm *ConfigReadModel) Reduce() error {
return rm.ReadModel.Reduce()
}
func (rm *ConfigReadModel) reduceConfigAddedEvent(e *ConfigAddedEvent) {
func (rm *OIDCConfigReadModel) reduceConfigAddedEvent(e *idpconfig.OIDCConfigAddedEvent) {
rm.IDPConfigID = e.IDPConfigID
rm.ClientID = e.ClientID
rm.ClientSecret = e.ClientSecret
@@ -40,7 +42,7 @@ func (rm *ConfigReadModel) reduceConfigAddedEvent(e *ConfigAddedEvent) {
rm.UserNameMapping = e.UserNameMapping
}
func (rm *ConfigReadModel) reduceConfigChangedEvent(e *ConfigChangedEvent) {
func (rm *OIDCConfigReadModel) reduceConfigChangedEvent(e *idpconfig.OIDCConfigChangedEvent) {
if e.ClientID != "" {
rm.ClientID = e.ClientID
}

View File

@@ -0,0 +1,36 @@
package query
import (
"github.com/caos/zitadel/internal/eventstore/v2"
"github.com/caos/zitadel/internal/v2/repository/org"
)
type OrgMembersReadModel struct {
MembersReadModel
}
func (rm *OrgMembersReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.MemberAddedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberAddedEvent)
case *org.MemberChangedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberChangedEvent)
case *org.MemberRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberRemovedEvent)
}
}
}
type OrgMemberReadModel MemberReadModel
func (rm *OrgMemberReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.MemberAddedEvent:
rm.ReadModel.AppendEvents(&e.MemberAddedEvent)
case *org.MemberChangedEvent:
rm.ReadModel.AppendEvents(&e.MemberChangedEvent)
}
}
}

View File

@@ -0,0 +1,22 @@
package query
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 OrgLabelPolicyReadModel struct{ LabelPolicyReadModel }
func (rm *OrgLabelPolicyReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.LabelPolicyAddedEvent:
rm.LabelPolicyReadModel.AppendEvents(&e.LabelPolicyAddedEvent)
case *org.LabelPolicyChangedEvent:
rm.LabelPolicyReadModel.AppendEvents(&e.LabelPolicyChangedEvent)
case *policy.LabelPolicyAddedEvent, *policy.LabelPolicyChangedEvent:
rm.LabelPolicyReadModel.AppendEvents(e)
}
}
}

View File

@@ -0,0 +1,22 @@
package query
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 OrgLoginPolicyReadModel struct{ LoginPolicyReadModel }
func (rm *OrgLoginPolicyReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.LoginPolicyAddedEvent:
rm.LoginPolicyReadModel.AppendEvents(&e.LoginPolicyAddedEvent)
case *org.LoginPolicyChangedEvent:
rm.LoginPolicyReadModel.AppendEvents(&e.LoginPolicyChangedEvent)
case *policy.LoginPolicyAddedEvent, *policy.LoginPolicyChangedEvent:
rm.LoginPolicyReadModel.AppendEvents(e)
}
}
}

View File

@@ -0,0 +1,20 @@
package query
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 OrgOrgIAMPolicyReadModel struct{ OrgIAMPolicyReadModel }
func (rm *OrgOrgIAMPolicyReadModel) AppendEvents(events ...eventstore.EventReader) {
for _, event := range events {
switch e := event.(type) {
case *org.OrgIAMPolicyAddedEvent:
rm.OrgIAMPolicyReadModel.AppendEvents(&e.OrgIAMPolicyAddedEvent)
case *policy.OrgIAMPolicyAddedEvent:
rm.OrgIAMPolicyReadModel.AppendEvents(e)
}
}
}

Some files were not shown because too many files have changed in this diff Show More