feat: Config to eventstore (#3158)

* feat: add default language to eventstore

* feat: add secret generator configs events

* feat: tests

* feat: secret generators in eventstore

* feat: secret generators in eventstore

* feat: smtp config in eventstore

* feat: smtp config in eventstore

* feat: smtp config in eventstore

* feat: smtp config in eventstore

* feat: smtp config in eventstore

* fix: migrations

* fix migration version

* fix test

* feat: change secret generator type to enum

* feat: change smtp attribute names

* feat: change smtp attribute names

* feat: remove engryption algorithms from command side

* feat: remove engryption algorithms from command side

* feat: smtp config

* feat: smtp config

* format smtp from header

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi
2022-02-16 16:49:17 +01:00
committed by GitHub
parent 4272ea6fe1
commit e3528ff0b2
118 changed files with 5216 additions and 686 deletions

View File

@@ -20,7 +20,6 @@ import (
usr_repo "github.com/caos/zitadel/internal/repository/user"
usr_grant_repo "github.com/caos/zitadel/internal/repository/usergrant"
"github.com/caos/zitadel/internal/static"
"github.com/caos/zitadel/internal/telemetry/tracing"
webauthn_helper "github.com/caos/zitadel/internal/webauthn"
)
@@ -32,17 +31,11 @@ type Commands struct {
zitadelRoles []authz.RoleMapping
idpConfigSecretCrypto crypto.EncryptionAlgorithm
smtpPasswordCrypto crypto.EncryptionAlgorithm
userPasswordAlg crypto.HashAlgorithm
initializeUserCode crypto.Generator
emailVerificationCode crypto.Generator
phoneVerificationCode crypto.Generator
passwordVerificationCode crypto.Generator
passwordlessInitCode crypto.Generator
machineKeyAlg crypto.EncryptionAlgorithm
machineKeySize int
applicationKeySize int
applicationSecretGenerator crypto.Generator
domainVerificationAlg crypto.EncryptionAlgorithm
domainVerificationGenerator crypto.Generator
domainVerificationValidator func(domain, token, verifier string, checkType http.CheckType) error
@@ -60,7 +53,16 @@ type orgFeatureChecker interface {
CheckOrgFeatures(ctx context.Context, orgID string, requiredFeatures ...string) error
}
func StartCommands(es *eventstore.Eventstore, defaults sd.SystemDefaults, authZConfig authz.Config, staticStore static.Storage, authZRepo authz_repo.Repository, keyConfig *crypto.KeyConfig, webAuthN webauthn_helper.Config) (repo *Commands, err error) {
func StartCommands(
es *eventstore.Eventstore,
defaults sd.SystemDefaults,
authZConfig authz.Config,
staticStore static.Storage,
authZRepo authz_repo.Repository,
keyConfig *crypto.KeyConfig,
smtpPasswordEncAlg crypto.EncryptionAlgorithm,
webAuthN webauthn_helper.Config,
) (repo *Commands, err error) {
repo = &Commands{
eventstore: es,
static: staticStore,
@@ -70,6 +72,7 @@ func StartCommands(es *eventstore.Eventstore, defaults sd.SystemDefaults, authZC
keySize: defaults.KeyConfig.Size,
privateKeyLifetime: defaults.KeyConfig.PrivateKeyLifetime,
publicKeyLifetime: defaults.KeyConfig.PublicKeyLifetime,
smtpPasswordCrypto: smtpPasswordEncAlg,
}
iam_repo.RegisterEventMappers(repo.eventstore)
org.RegisterEventMappers(repo.eventstore)
@@ -83,17 +86,8 @@ func StartCommands(es *eventstore.Eventstore, defaults sd.SystemDefaults, authZC
if err != nil {
return nil, err
}
userEncryptionAlgorithm, err := crypto.NewAESCrypto(defaults.UserVerificationKey)
if err != nil {
return nil, err
}
repo.initializeUserCode = crypto.NewEncryptionGenerator(defaults.SecretGenerators.InitializeUserCode, userEncryptionAlgorithm)
repo.emailVerificationCode = crypto.NewEncryptionGenerator(defaults.SecretGenerators.EmailVerificationCode, userEncryptionAlgorithm)
repo.phoneVerificationCode = crypto.NewEncryptionGenerator(defaults.SecretGenerators.PhoneVerificationCode, userEncryptionAlgorithm)
repo.passwordVerificationCode = crypto.NewEncryptionGenerator(defaults.SecretGenerators.PasswordVerificationCode, userEncryptionAlgorithm)
repo.passwordlessInitCode = crypto.NewEncryptionGenerator(defaults.SecretGenerators.PasswordlessInitCode, userEncryptionAlgorithm)
repo.userPasswordAlg = crypto.NewBCrypt(defaults.SecretGenerators.PasswordSaltCost)
repo.machineKeyAlg = userEncryptionAlgorithm
repo.machineKeySize = int(defaults.SecretGenerators.MachineKeySize)
repo.applicationKeySize = int(defaults.SecretGenerators.ApplicationKeySize)
@@ -107,8 +101,6 @@ func StartCommands(es *eventstore.Eventstore, defaults sd.SystemDefaults, authZC
Issuer: defaults.Multifactors.OTP.Issuer,
},
}
passwordAlg := crypto.NewBCrypt(defaults.SecretGenerators.PasswordSaltCost)
repo.applicationSecretGenerator = crypto.NewHashGenerator(defaults.SecretGenerators.ClientSecretGenerator, passwordAlg)
repo.domainVerificationAlg, err = crypto.NewAESCrypto(defaults.DomainVerification.VerificationKey)
if err != nil {
@@ -132,19 +124,6 @@ func StartCommands(es *eventstore.Eventstore, defaults sd.SystemDefaults, authZC
return repo, nil
}
func (c *Commands) getIAMWriteModel(ctx context.Context) (_ *IAMWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMWriteModel()
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}
func AppendAndReduce(object interface {
AppendEvents(...eventstore.Event)
Reduce() error

View File

@@ -7,6 +7,8 @@ import (
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/telemetry/tracing"
"golang.org/x/text/language"
)
//TODO: private as soon as setup uses query
@@ -40,3 +42,33 @@ func (c *Commands) setIAMProject(ctx context.Context, iamAgg *eventstore.Aggrega
}
return iam.NewIAMProjectSetEvent(ctx, iamAgg, projectID), nil
}
func (c *Commands) SetDefaultLanguage(ctx context.Context, language language.Tag) (*domain.ObjectDetails, error) {
iamWriteModel, err := c.getIAMWriteModel(ctx)
if err != nil {
return nil, err
}
iamAgg := IAMAggregateFromWriteModel(&iamWriteModel.WriteModel)
pushedEvents, err := c.eventstore.Push(ctx, iam.NewDefaultLanguageSetEvent(ctx, iamAgg, language))
if err != nil {
return nil, err
}
err = AppendAndReduce(iamWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&iamWriteModel.WriteModel), nil
}
func (c *Commands) getIAMWriteModel(ctx context.Context) (_ *IAMWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
writeModel := NewIAMWriteModel()
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -15,9 +15,8 @@ import (
func (c *Commands) AddDefaultIDPConfig(ctx context.Context, config *domain.IDPConfig) (*domain.IDPConfig, error) {
if config.OIDCConfig == nil && config.JWTConfig == nil {
return nil, errors.ThrowInvalidArgument(nil, "IAM-eUpQU", "Errors.idp.config.notset")
return nil, caos_errs.ThrowInvalidArgument(nil, "IDP-s8nn3", "Errors.IDPConfig.Invalid")
}
idpConfigID, err := c.idGenerator.Next()
if err != nil {
return nil, err

View File

@@ -4,6 +4,7 @@ import (
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"golang.org/x/text/language"
)
type IAMWriteModel struct {
@@ -12,8 +13,9 @@ type IAMWriteModel struct {
SetUpStarted domain.Step
SetUpDone domain.Step
GlobalOrgID string
ProjectID string
GlobalOrgID string
ProjectID string
DefaultLanguage language.Tag
}
func NewIAMWriteModel() *IAMWriteModel {
@@ -32,6 +34,8 @@ func (wm *IAMWriteModel) Reduce() error {
wm.ProjectID = e.ProjectID
case *iam.GlobalOrgSetEvent:
wm.GlobalOrgID = e.OrgID
case *iam.DefaultLanguageSetEvent:
wm.DefaultLanguage = e.Language
case *iam.SetupStepEvent:
if e.Done {
wm.SetUpDone = e.Step
@@ -52,6 +56,7 @@ func (wm *IAMWriteModel) Query() *eventstore.SearchQueryBuilder {
EventTypes(
iam.ProjectSetEventType,
iam.GlobalOrgSetEventType,
iam.DefaultLanguageSetEventType,
iam.SetupStartedEventType,
iam.SetupDoneEventType).
Builder()

View File

@@ -0,0 +1,140 @@
package command
import (
"context"
"time"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
)
type IAMSecretGeneratorConfigWriteModel struct {
eventstore.WriteModel
GeneratorType domain.SecretGeneratorType
Length uint
Expiry time.Duration
IncludeLowerLetters bool
IncludeUpperLetters bool
IncludeDigits bool
IncludeSymbols bool
State domain.SecretGeneratorState
}
func NewIAMSecretGeneratorConfigWriteModel(GeneratorType domain.SecretGeneratorType) *IAMSecretGeneratorConfigWriteModel {
return &IAMSecretGeneratorConfigWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: domain.IAMID,
ResourceOwner: domain.IAMID,
},
GeneratorType: GeneratorType,
}
}
func (wm *IAMSecretGeneratorConfigWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *iam.SecretGeneratorAddedEvent:
if wm.GeneratorType != e.GeneratorType {
continue
}
wm.Length = e.Length
wm.Expiry = e.Expiry
wm.IncludeLowerLetters = e.IncludeLowerLetters
wm.IncludeUpperLetters = e.IncludeUpperLetters
wm.IncludeDigits = e.IncludeDigits
wm.IncludeSymbols = e.IncludeDigits
wm.State = domain.SecretGeneratorStateActive
case *iam.SecretGeneratorChangedEvent:
if wm.GeneratorType != e.GeneratorType {
continue
}
if e.Length != nil {
wm.Length = *e.Length
}
if e.Expiry != nil {
wm.Expiry = *e.Expiry
}
if e.IncludeUpperLetters != nil {
wm.IncludeUpperLetters = *e.IncludeUpperLetters
}
if e.IncludeLowerLetters != nil {
wm.IncludeLowerLetters = *e.IncludeLowerLetters
}
if e.IncludeDigits != nil {
wm.IncludeDigits = *e.IncludeDigits
}
if e.IncludeSymbols != nil {
wm.IncludeSymbols = *e.IncludeSymbols
}
case *iam.SecretGeneratorRemovedEvent:
if wm.GeneratorType != e.GeneratorType {
continue
}
wm.State = domain.SecretGeneratorStateRemoved
wm.Length = 0
wm.Expiry = 0
wm.IncludeLowerLetters = false
wm.IncludeUpperLetters = false
wm.IncludeDigits = false
wm.IncludeSymbols = false
}
}
return wm.WriteModel.Reduce()
}
func (wm *IAMSecretGeneratorConfigWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
ResourceOwner(wm.ResourceOwner).
AddQuery().
AggregateTypes(iam.AggregateType).
AggregateIDs(wm.AggregateID).
EventTypes(
iam.SecretGeneratorAddedEventType,
iam.SecretGeneratorChangedEventType,
iam.SecretGeneratorRemovedEventType).
Builder()
}
func (wm *IAMSecretGeneratorConfigWriteModel) NewChangedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
generatorType domain.SecretGeneratorType,
length uint,
expiry time.Duration,
includeLowerLetters,
includeUpperLetters,
includeDigits,
includeSymbols bool,
) (*iam.SecretGeneratorChangedEvent, bool, error) {
changes := make([]iam.SecretGeneratorChanges, 0)
var err error
if wm.Length != length {
changes = append(changes, iam.ChangeSecretGeneratorLength(length))
}
if wm.Expiry != expiry {
changes = append(changes, iam.ChangeSecretGeneratorExpiry(expiry))
}
if wm.IncludeLowerLetters != includeLowerLetters {
changes = append(changes, iam.ChangeSecretGeneratorIncludeLowerLetters(includeLowerLetters))
}
if wm.IncludeUpperLetters != includeUpperLetters {
changes = append(changes, iam.ChangeSecretGeneratorIncludeUpperLetters(includeUpperLetters))
}
if wm.IncludeDigits != includeDigits {
changes = append(changes, iam.ChangeSecretGeneratorIncludeDigits(includeDigits))
}
if wm.IncludeSymbols != includeSymbols {
changes = append(changes, iam.ChangeSecretGeneratorIncludeSymbols(includeSymbols))
}
if len(changes) == 0 {
return nil, false, nil
}
changeEvent, err := iam.NewSecretGeneratorChangeEvent(ctx, aggregate, generatorType, changes)
if err != nil {
return nil, false, err
}
return changeEvent, true, nil
}

View File

@@ -0,0 +1,118 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/repository/iam"
)
func (c *Commands) AddSecretGeneratorConfig(ctx context.Context, generatorType domain.SecretGeneratorType, config *crypto.GeneratorConfig) (*domain.ObjectDetails, error) {
if generatorType == domain.SecretGeneratorTypeUnspecified {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-0pkwf", "Errors.SecretGenerator.TypeMissing")
}
generatorWriteModel, err := c.getSecretConfig(ctx, generatorType)
if err != nil {
return nil, err
}
if generatorWriteModel.State == domain.SecretGeneratorStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-3n9ls", "Errors.SecretGenerator.AlreadyExists")
}
iamAgg := IAMAggregateFromWriteModel(&generatorWriteModel.WriteModel)
pushedEvents, err := c.eventstore.Push(ctx, iam.NewSecretGeneratorAddedEvent(
ctx,
iamAgg,
generatorType,
config.Length,
config.Expiry,
config.IncludeLowerLetters,
config.IncludeUpperLetters,
config.IncludeDigits,
config.IncludeSymbols))
if err != nil {
return nil, err
}
err = AppendAndReduce(generatorWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&generatorWriteModel.WriteModel), nil
}
func (c *Commands) ChangeSecretGeneratorConfig(ctx context.Context, generatorType domain.SecretGeneratorType, config *crypto.GeneratorConfig) (*domain.ObjectDetails, error) {
if generatorType == domain.SecretGeneratorTypeUnspecified {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-33k9f", "Errors.SecretGenerator.TypeMissing")
}
generatorWriteModel, err := c.getSecretConfig(ctx, generatorType)
if err != nil {
return nil, err
}
if generatorWriteModel.State == domain.SecretGeneratorStateUnspecified || generatorWriteModel.State == domain.SecretGeneratorStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3n9ls", "Errors.SecretGenerator.NotFound")
}
iamAgg := IAMAggregateFromWriteModel(&generatorWriteModel.WriteModel)
changedEvent, hasChanged, err := generatorWriteModel.NewChangedEvent(
ctx,
iamAgg,
generatorType,
config.Length,
config.Expiry,
config.IncludeLowerLetters,
config.IncludeUpperLetters,
config.IncludeDigits,
config.IncludeSymbols)
if err != nil {
return nil, err
}
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-m0o3f", "Errors.NoChangesFound")
}
pushedEvents, err := c.eventstore.Push(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(generatorWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&generatorWriteModel.WriteModel), nil
}
func (c *Commands) RemoveSecretGeneratorConfig(ctx context.Context, generatorType domain.SecretGeneratorType) (*domain.ObjectDetails, error) {
if generatorType == domain.SecretGeneratorTypeUnspecified {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-2j9lw", "Errors.SecretGenerator.TypeMissing")
}
generatorWriteModel, err := c.getSecretConfig(ctx, generatorType)
if err != nil {
return nil, err
}
if generatorWriteModel.State == domain.SecretGeneratorStateUnspecified || generatorWriteModel.State == domain.SecretGeneratorStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-b8les", "Errors.SecretGenerator.NotFound")
}
iamAgg := IAMAggregateFromWriteModel(&generatorWriteModel.WriteModel)
pushedEvents, err := c.eventstore.Push(ctx, iam.NewSecretGeneratorRemovedEvent(ctx, iamAgg, generatorType))
if err != nil {
return nil, err
}
err = AppendAndReduce(generatorWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&generatorWriteModel.WriteModel), nil
}
func (c *Commands) getSecretConfig(ctx context.Context, generatorType domain.SecretGeneratorType) (_ *IAMSecretGeneratorConfigWriteModel, err error) {
writeModel := NewIAMSecretGeneratorConfigWriteModel(generatorType)
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,512 @@
package command
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/repository"
"github.com/caos/zitadel/internal/repository/iam"
)
func TestCommandSide_AddSecretGenerator(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
generator *crypto.GeneratorConfig
generatorType domain.SecretGeneratorType
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
name: "invalid empty type, error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
},
args: args{
ctx: context.Background(),
generator: &crypto.GeneratorConfig{},
generatorType: domain.SecretGeneratorTypeUnspecified,
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
},
},
{
name: "secret generator config, error already exists",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSecretGeneratorAddedEvent(context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode,
4,
time.Hour*1,
true,
true,
true,
true,
),
),
),
),
},
args: args{
ctx: context.Background(),
generator: &crypto.GeneratorConfig{
Length: 4,
Expiry: 1 * time.Hour,
IncludeLowerLetters: true,
IncludeUpperLetters: true,
IncludeDigits: true,
IncludeSymbols: true,
},
generatorType: domain.SecretGeneratorTypeInitCode,
},
res: res{
err: caos_errs.IsErrorAlreadyExists,
},
},
{
name: "add secret generator, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
expectPush(
[]*repository.Event{
eventFromEventPusher(iam.NewSecretGeneratorAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode,
4,
time.Hour*1,
true,
true,
true,
true,
),
),
},
uniqueConstraintsFromEventConstraint(iam.NewAddSecretGeneratorTypeUniqueConstraint(domain.SecretGeneratorTypeInitCode)),
),
),
},
args: args{
ctx: context.Background(),
generator: &crypto.GeneratorConfig{
Length: 4,
Expiry: 1 * time.Hour,
IncludeLowerLetters: true,
IncludeUpperLetters: true,
IncludeDigits: true,
IncludeSymbols: true,
},
generatorType: domain.SecretGeneratorTypeInitCode,
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "IAM",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
got, err := r.AddSecretGeneratorConfig(tt.args.ctx, tt.args.generatorType, tt.args.generator)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.want, got)
}
})
}
}
func TestCommandSide_ChangeSecretGenerator(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
generator *crypto.GeneratorConfig
generatorType domain.SecretGeneratorType
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
name: "empty generatortype, invalid error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
},
args: args{
ctx: context.Background(),
generator: &crypto.GeneratorConfig{},
generatorType: domain.SecretGeneratorTypeUnspecified,
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
},
},
{
name: "generator not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
),
},
args: args{
ctx: context.Background(),
generatorType: domain.SecretGeneratorTypeInitCode,
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "generator removed, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSecretGeneratorAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode,
4,
time.Hour*1,
true,
true,
true,
true,
),
),
eventFromEventPusher(
iam.NewSecretGeneratorRemovedEvent(context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode),
),
),
),
},
args: args{
ctx: context.Background(),
generatorType: domain.SecretGeneratorTypeInitCode,
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "no changes, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSecretGeneratorAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode,
4,
time.Hour*1,
true,
true,
true,
true,
),
),
),
),
},
args: args{
ctx: context.Background(),
generator: &crypto.GeneratorConfig{
Length: 4,
Expiry: 1 * time.Hour,
IncludeLowerLetters: true,
IncludeUpperLetters: true,
IncludeDigits: true,
IncludeSymbols: true,
},
generatorType: domain.SecretGeneratorTypeInitCode,
},
res: res{
err: caos_errs.IsPreconditionFailed,
},
},
{
name: "secret generator change, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSecretGeneratorAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode,
4,
time.Hour*1,
true,
true,
true,
true,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
newSecretGeneratorChangedEvent(context.Background(),
domain.SecretGeneratorTypeInitCode,
8,
time.Hour*2,
false,
false,
false,
false),
),
},
),
),
},
args: args{
ctx: context.Background(),
generator: &crypto.GeneratorConfig{
Length: 8,
Expiry: 2 * time.Hour,
IncludeLowerLetters: false,
IncludeUpperLetters: false,
IncludeDigits: false,
IncludeSymbols: false,
},
generatorType: domain.SecretGeneratorTypeInitCode,
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "IAM",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
got, err := r.ChangeSecretGeneratorConfig(tt.args.ctx, tt.args.generatorType, tt.args.generator)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.want, got)
}
})
}
}
func TestCommandSide_RemoveSecretGenerator(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
generatorType domain.SecretGeneratorType
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
name: "empty type, invalid error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
},
args: args{
ctx: context.Background(),
generatorType: domain.SecretGeneratorTypeUnspecified,
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
},
},
{
name: "generator not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
),
},
args: args{
ctx: context.Background(),
generatorType: domain.SecretGeneratorTypeInitCode,
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "generator removed, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSecretGeneratorAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode,
4,
time.Hour*1,
true,
true,
true,
true,
),
),
eventFromEventPusher(
iam.NewSecretGeneratorRemovedEvent(context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode),
),
),
),
},
args: args{
ctx: context.Background(),
generatorType: domain.SecretGeneratorTypeInitCode,
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "generator config remove, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSecretGeneratorAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode,
4,
time.Hour*1,
true,
true,
true,
true,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
iam.NewSecretGeneratorRemovedEvent(context.Background(),
&iam.NewAggregate().Aggregate,
domain.SecretGeneratorTypeInitCode),
),
},
uniqueConstraintsFromEventConstraint(iam.NewRemoveSecretGeneratorTypeUniqueConstraint(domain.SecretGeneratorTypeInitCode)),
),
),
},
args: args{
ctx: context.Background(),
generatorType: domain.SecretGeneratorTypeInitCode,
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "IAM",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
got, err := r.RemoveSecretGeneratorConfig(tt.args.ctx, tt.args.generatorType)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.want, got)
}
})
}
}
func newSecretGeneratorChangedEvent(ctx context.Context, generatorType domain.SecretGeneratorType, length uint, expiry time.Duration, lowerCase, upperCase, digits, symbols bool) *iam.SecretGeneratorChangedEvent {
changes := []iam.SecretGeneratorChanges{
iam.ChangeSecretGeneratorLength(length),
iam.ChangeSecretGeneratorExpiry(expiry),
iam.ChangeSecretGeneratorIncludeLowerLetters(lowerCase),
iam.ChangeSecretGeneratorIncludeUpperLetters(upperCase),
iam.ChangeSecretGeneratorIncludeDigits(digits),
iam.ChangeSecretGeneratorIncludeSymbols(symbols),
}
event, _ := iam.NewSecretGeneratorChangeEvent(ctx,
&iam.NewAggregate().Aggregate,
generatorType,
changes,
)
return event
}

View File

@@ -0,0 +1,106 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
)
type IAMSMTPConfigWriteModel struct {
eventstore.WriteModel
SenderAddress string
SenderName string
TLS bool
Host string
User string
Password *crypto.CryptoValue
State domain.SMTPConfigState
}
func NewIAMSMTPConfigWriteModel() *IAMSMTPConfigWriteModel {
return &IAMSMTPConfigWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: domain.IAMID,
ResourceOwner: domain.IAMID,
},
}
}
func (wm *IAMSMTPConfigWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *iam.SMTPConfigAddedEvent:
wm.TLS = e.TLS
wm.SenderAddress = e.SenderAddress
wm.SenderName = e.SenderName
wm.Host = e.Host
wm.User = e.User
wm.Password = e.Password
wm.State = domain.SMTPConfigStateActive
case *iam.SMTPConfigChangedEvent:
if e.TLS != nil {
wm.TLS = *e.TLS
}
if e.FromAddress != nil {
wm.SenderAddress = *e.FromAddress
}
if e.FromName != nil {
wm.SenderName = *e.FromName
}
if e.Host != nil {
wm.Host = *e.Host
}
if e.User != nil {
wm.User = *e.User
}
}
}
return wm.WriteModel.Reduce()
}
func (wm *IAMSMTPConfigWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
ResourceOwner(wm.ResourceOwner).
AddQuery().
AggregateTypes(iam.AggregateType).
AggregateIDs(wm.AggregateID).
EventTypes(
iam.SMTPConfigAddedEventType,
iam.SMTPConfigChangedEventType,
iam.SMTPConfigPasswordChangedEventType).
Builder()
}
func (wm *IAMSMTPConfigWriteModel) NewChangedEvent(ctx context.Context, aggregate *eventstore.Aggregate, tls bool, fromAddress, fromName, smtpHost, smtpUser string) (*iam.SMTPConfigChangedEvent, bool, error) {
changes := make([]iam.SMTPConfigChanges, 0)
var err error
if wm.TLS != tls {
changes = append(changes, iam.ChangeSMTPConfigTLS(tls))
}
if wm.SenderAddress != fromAddress {
changes = append(changes, iam.ChangeSMTPConfigFromAddress(fromAddress))
}
if wm.SenderName != fromName {
changes = append(changes, iam.ChangeSMTPConfigFromName(fromName))
}
if wm.Host != smtpHost {
changes = append(changes, iam.ChangeSMTPConfigSMTPHost(smtpHost))
}
if wm.User != smtpUser {
changes = append(changes, iam.ChangeSMTPConfigSMTPUser(smtpUser))
}
if len(changes) == 0 {
return nil, false, nil
}
changeEvent, err := iam.NewSMTPConfigChangeEvent(ctx, aggregate, changes)
if err != nil {
return nil, false, err
}
return changeEvent, true, nil
}

View File

@@ -3,6 +3,7 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
@@ -31,7 +32,7 @@ func (c *Commands) checkOrgExists(ctx context.Context, orgID string) error {
return nil
}
func (c *Commands) SetUpOrg(ctx context.Context, organisation *domain.Org, admin *domain.Human, claimedUserIDs []string, selfregistered bool) (*domain.ObjectDetails, error) {
func (c *Commands) SetUpOrg(ctx context.Context, organisation *domain.Org, admin *domain.Human, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator, claimedUserIDs []string, selfregistered bool) (*domain.ObjectDetails, error) {
orgIAMPolicy, err := c.getDefaultOrgIAMPolicy(ctx)
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-33M9f", "Errors.IAM.OrgIAMPolicy.NotFound")
@@ -40,7 +41,7 @@ func (c *Commands) SetUpOrg(ctx context.Context, organisation *domain.Org, admin
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.IAM.PasswordComplexity.NotFound")
}
_, orgWriteModel, _, _, events, err := c.setUpOrg(ctx, organisation, admin, orgIAMPolicy, pwPolicy, claimedUserIDs, selfregistered)
_, orgWriteModel, _, _, events, err := c.setUpOrg(ctx, organisation, admin, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, claimedUserIDs, selfregistered)
if err != nil {
return nil, err
}
@@ -168,6 +169,8 @@ func (c *Commands) setUpOrg(
admin *domain.Human,
loginPolicy *domain.OrgIAMPolicy,
pwPolicy *domain.PasswordComplexityPolicy,
initCodeGenerator crypto.Generator,
phoneCodeGenerator crypto.Generator,
claimedUserIDs []string,
selfregistered bool,
) (orgAgg *eventstore.Aggregate, org *OrgWriteModel, human *HumanWriteModel, orgMember *OrgMemberWriteModel, events []eventstore.Command, err error) {
@@ -178,9 +181,9 @@ func (c *Commands) setUpOrg(
var userEvents []eventstore.Command
if selfregistered {
userEvents, human, err = c.registerHuman(ctx, orgAgg.ID, admin, nil, loginPolicy, pwPolicy)
userEvents, human, err = c.registerHuman(ctx, orgAgg.ID, admin, nil, loginPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
} else {
userEvents, human, err = c.addHuman(ctx, orgAgg.ID, admin, loginPolicy, pwPolicy)
userEvents, human, err = c.addHuman(ctx, orgAgg.ID, admin, loginPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
}
if err != nil {
return nil, nil, nil, nil, nil, err

View File

@@ -13,7 +13,7 @@ import (
"github.com/caos/zitadel/internal/telemetry/tracing"
)
func (c *Commands) AddAPIApplication(ctx context.Context, application *domain.APIApp, resourceOwner string) (_ *domain.APIApp, err error) {
func (c *Commands) AddAPIApplication(ctx context.Context, application *domain.APIApp, resourceOwner string, appSecretGenerator crypto.Generator) (_ *domain.APIApp, err error) {
if application == nil || application.AggregateID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "PROJECT-5m9E", "Errors.Application.Invalid")
}
@@ -23,7 +23,7 @@ func (c *Commands) AddAPIApplication(ctx context.Context, application *domain.AP
}
addedApplication := NewAPIApplicationWriteModel(application.AggregateID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
events, stringPw, err := c.addAPIApplication(ctx, projectAgg, project, application, resourceOwner)
events, stringPw, err := c.addAPIApplication(ctx, projectAgg, project, application, resourceOwner, appSecretGenerator)
if err != nil {
return nil, err
}
@@ -41,7 +41,7 @@ func (c *Commands) AddAPIApplication(ctx context.Context, application *domain.AP
return result, nil
}
func (c *Commands) addAPIApplication(ctx context.Context, projectAgg *eventstore.Aggregate, proj *domain.Project, apiAppApp *domain.APIApp, resourceOwner string) (events []eventstore.Command, stringPW string, err error) {
func (c *Commands) addAPIApplication(ctx context.Context, projectAgg *eventstore.Aggregate, proj *domain.Project, apiAppApp *domain.APIApp, resourceOwner string, appSecretGenerator crypto.Generator) (events []eventstore.Command, stringPW string, err error) {
if !apiAppApp.IsValid() {
return nil, "", caos_errs.ThrowInvalidArgument(nil, "PROJECT-Bff2g", "Errors.Application.Invalid")
}
@@ -59,7 +59,7 @@ func (c *Commands) addAPIApplication(ctx context.Context, projectAgg *eventstore
if err != nil {
return nil, "", err
}
stringPw, err = domain.SetNewClientSecretIfNeeded(apiAppApp, c.applicationSecretGenerator)
stringPw, err = domain.SetNewClientSecretIfNeeded(apiAppApp, appSecretGenerator)
if err != nil {
return nil, "", err
}
@@ -113,7 +113,7 @@ func (c *Commands) ChangeAPIApplication(ctx context.Context, apiApp *domain.APIA
return apiWriteModelToAPIConfig(existingAPI), nil
}
func (c *Commands) ChangeAPIApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string) (*domain.APIApp, error) {
func (c *Commands) ChangeAPIApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string, appSecretGenerator crypto.Generator) (*domain.APIApp, error) {
if projectID == "" || appID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-99i83", "Errors.IDMissing")
}
@@ -128,7 +128,7 @@ func (c *Commands) ChangeAPIApplicationSecret(ctx context.Context, projectID, ap
if !existingAPI.IsAPI() {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-aeH4", "Errors.Project.App.IsNotAPI")
}
cryptoSecret, stringPW, err := domain.NewClientSecret(c.applicationSecretGenerator)
cryptoSecret, stringPW, err := domain.NewClientSecret(appSecretGenerator)
if err != nil {
return nil, err
}

View File

@@ -2,6 +2,8 @@ package command
import (
"context"
"testing"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
@@ -12,19 +14,18 @@ import (
id_mock "github.com/caos/zitadel/internal/id/mock"
"github.com/caos/zitadel/internal/repository/project"
"github.com/stretchr/testify/assert"
"testing"
)
func TestCommandSide_AddAPIApplication(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
idGenerator id.Generator
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
idGenerator id.Generator
}
type args struct {
ctx context.Context
apiApp *domain.APIApp
resourceOwner string
ctx context.Context
apiApp *domain.APIApp
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.APIApp
@@ -144,8 +145,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
uniqueConstraintsFromEventConstraint(project.NewAddApplicationUniqueConstraint("app", "project1")),
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "app1", "client1"),
secretGenerator: GetMockSecretGenerator(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "app1", "client1"),
},
args: args{
ctx: context.Background(),
@@ -156,7 +156,8 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
AppName: "app",
AuthMethodType: domain.APIAuthMethodTypeBasic,
},
resourceOwner: "org1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.APIApp{
@@ -238,11 +239,10 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
applicationSecretGenerator: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
}
got, err := r.AddAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
got, err := r.AddAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -472,14 +472,14 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
appID string
projectID string
resourceOwner string
ctx context.Context
appID string
projectID string
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.APIApp
@@ -585,13 +585,13 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
projectID: "project1",
appID: "app1",
resourceOwner: "org1",
ctx: context.Background(),
projectID: "project1",
appID: "app1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.APIApp{
@@ -612,10 +612,9 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
applicationSecretGenerator: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.ChangeAPIApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
got, err := r.ChangeAPIApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -2,6 +2,8 @@ package command
import (
"context"
"testing"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
@@ -11,15 +13,13 @@ import (
id_mock "github.com/caos/zitadel/internal/id/mock"
"github.com/caos/zitadel/internal/repository/project"
"github.com/stretchr/testify/assert"
"testing"
)
func TestCommandSide_AddAPIApplicationKey(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
idGenerator id.Generator
secretGenerator crypto.Generator
keySize int
eventstore *eventstore.Eventstore
idGenerator id.Generator
keySize int
}
type args struct {
ctx context.Context
@@ -126,8 +126,7 @@ func TestCommandSide_AddAPIApplicationKey(t *testing.T) {
),
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "key1"),
secretGenerator: GetMockSecretGenerator(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "key1"),
},
args: args{
ctx: context.Background(),
@@ -173,9 +172,8 @@ func TestCommandSide_AddAPIApplicationKey(t *testing.T) {
),
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "key1"),
secretGenerator: GetMockSecretGenerator(t),
keySize: 10,
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "key1"),
keySize: 10,
},
args: args{
ctx: context.Background(),
@@ -195,10 +193,9 @@ func TestCommandSide_AddAPIApplicationKey(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
applicationSecretGenerator: tt.fields.secretGenerator,
applicationKeySize: tt.fields.keySize,
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
applicationKeySize: tt.fields.keySize,
}
got, err := r.AddApplicationKey(tt.args.ctx, tt.args.key, tt.args.resourceOwner)
if tt.res.err == nil {

View File

@@ -13,7 +13,7 @@ import (
"github.com/caos/zitadel/internal/telemetry/tracing"
)
func (c *Commands) AddOIDCApplication(ctx context.Context, application *domain.OIDCApp, resourceOwner string) (_ *domain.OIDCApp, err error) {
func (c *Commands) AddOIDCApplication(ctx context.Context, application *domain.OIDCApp, resourceOwner string, appSecretGenerator crypto.Generator) (_ *domain.OIDCApp, err error) {
if application == nil || application.AggregateID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Application.Invalid")
}
@@ -23,7 +23,7 @@ func (c *Commands) AddOIDCApplication(ctx context.Context, application *domain.O
}
addedApplication := NewOIDCApplicationWriteModel(application.AggregateID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
events, stringPw, err := c.addOIDCApplication(ctx, projectAgg, project, application, resourceOwner)
events, stringPw, err := c.addOIDCApplication(ctx, projectAgg, project, application, resourceOwner, appSecretGenerator)
if err != nil {
return nil, err
}
@@ -42,7 +42,7 @@ func (c *Commands) AddOIDCApplication(ctx context.Context, application *domain.O
return result, nil
}
func (c *Commands) addOIDCApplication(ctx context.Context, projectAgg *eventstore.Aggregate, proj *domain.Project, oidcApp *domain.OIDCApp, resourceOwner string) (events []eventstore.Command, stringPW string, err error) {
func (c *Commands) addOIDCApplication(ctx context.Context, projectAgg *eventstore.Aggregate, proj *domain.Project, oidcApp *domain.OIDCApp, resourceOwner string, appSecretGenerator crypto.Generator) (events []eventstore.Command, stringPW string, err error) {
if oidcApp.AppName == "" || !oidcApp.IsValid() {
return nil, "", caos_errs.ThrowInvalidArgument(nil, "PROJECT-1n8df", "Errors.Application.Invalid")
}
@@ -60,7 +60,7 @@ func (c *Commands) addOIDCApplication(ctx context.Context, projectAgg *eventstor
if err != nil {
return nil, "", err
}
stringPw, err = domain.SetNewClientSecretIfNeeded(oidcApp, c.applicationSecretGenerator)
stringPw, err = domain.SetNewClientSecretIfNeeded(oidcApp, appSecretGenerator)
if err != nil {
return nil, "", err
}
@@ -142,7 +142,7 @@ func (c *Commands) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCA
return result, nil
}
func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string) (*domain.OIDCApp, error) {
func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string, appSecretGenerator crypto.Generator) (*domain.OIDCApp, error) {
if projectID == "" || appID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-99i83", "Errors.IDMissing")
}
@@ -157,7 +157,7 @@ func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, a
if !existingOIDC.IsOIDC() {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Ghrh3", "Errors.Project.App.IsNotOIDC")
}
cryptoSecret, stringPW, err := domain.NewClientSecret(c.applicationSecretGenerator)
cryptoSecret, stringPW, err := domain.NewClientSecret(appSecretGenerator)
if err != nil {
return nil, err
}

View File

@@ -20,14 +20,14 @@ import (
func TestCommandSide_AddOIDCApplication(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
idGenerator id.Generator
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
idGenerator id.Generator
}
type args struct {
ctx context.Context
oidcApp *domain.OIDCApp
resourceOwner string
ctx context.Context
oidcApp *domain.OIDCApp
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.OIDCApp
@@ -160,8 +160,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
uniqueConstraintsFromEventConstraint(project.NewAddApplicationUniqueConstraint("app", "project1")),
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "app1", "client1"),
secretGenerator: GetMockSecretGenerator(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "app1", "client1"),
},
args: args{
ctx: context.Background(),
@@ -185,7 +184,8 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
ClockSkew: time.Second * 1,
AdditionalOrigins: []string{"https://sub.test.ch"},
},
resourceOwner: "org1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.OIDCApp{
@@ -220,11 +220,10 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
applicationSecretGenerator: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
}
got, err := r.AddOIDCApplication(tt.args.ctx, tt.args.oidcApp, tt.args.resourceOwner)
got, err := r.AddOIDCApplication(tt.args.ctx, tt.args.oidcApp, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -549,14 +548,14 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
appID string
projectID string
resourceOwner string
ctx context.Context
appID string
projectID string
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.OIDCApp
@@ -675,13 +674,13 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
projectID: "project1",
appID: "app1",
resourceOwner: "org1",
ctx: context.Background(),
projectID: "project1",
appID: "app1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.OIDCApp{
@@ -715,10 +714,9 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
applicationSecretGenerator: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.ChangeOIDCApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
got, err := r.ChangeOIDCApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -3,6 +3,7 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/v1/models"
@@ -134,7 +135,10 @@ func (c *Commands) SetupStep1(ctx context.Context, step1 *Step1) error {
EmailAddress: organisation.Owner.Email,
IsEmailVerified: true,
},
}, orgIAMPolicy, pwPolicy, nil, false)
}, orgIAMPolicy, pwPolicy,
nil, //TODO: Code Generator missing! Should be setuped in step1 create iam
nil, //TODO: Code Generator missing! Should be setuped in step1 create iam
nil, false)
if err != nil {
return err
}
@@ -180,14 +184,16 @@ func (c *Commands) SetupStep1(ctx context.Context, step1 *Step1) error {
}
//create applications
for _, app := range proj.OIDCApps {
applicationEvents, err := setUpOIDCApplication(ctx, c, projectWriteModel, project, app, orgAgg.ID)
//TODO: Add Secret Generator
applicationEvents, err := setUpOIDCApplication(ctx, c, projectWriteModel, project, app, orgAgg.ID, nil)
if err != nil {
return err
}
events = append(events, applicationEvents...)
}
for _, app := range proj.APIs {
applicationEvents, err := setUpAPI(ctx, c, projectWriteModel, project, app, orgAgg.ID)
//TODO: Add Secret Generator
applicationEvents, err := setUpAPI(ctx, c, projectWriteModel, project, app, orgAgg.ID, nil)
if err != nil {
return err
}
@@ -205,7 +211,7 @@ func (c *Commands) SetupStep1(ctx context.Context, step1 *Step1) error {
return nil
}
func setUpOIDCApplication(ctx context.Context, r *Commands, projectWriteModel *ProjectWriteModel, project *domain.Project, oidcApp OIDCApp, resourceOwner string) ([]eventstore.Command, error) {
func setUpOIDCApplication(ctx context.Context, r *Commands, projectWriteModel *ProjectWriteModel, project *domain.Project, oidcApp OIDCApp, resourceOwner string, appSecretGenerator crypto.Generator) ([]eventstore.Command, error) {
app := &domain.OIDCApp{
ObjectRoot: models.ObjectRoot{
AggregateID: projectWriteModel.AggregateID,
@@ -220,7 +226,7 @@ func setUpOIDCApplication(ctx context.Context, r *Commands, projectWriteModel *P
}
projectAgg := ProjectAggregateFromWriteModel(&projectWriteModel.WriteModel)
events, _, err := r.addOIDCApplication(ctx, projectAgg, project, app, resourceOwner)
events, _, err := r.addOIDCApplication(ctx, projectAgg, project, app, resourceOwner, appSecretGenerator)
if err != nil {
return nil, err
}
@@ -228,7 +234,7 @@ func setUpOIDCApplication(ctx context.Context, r *Commands, projectWriteModel *P
return events, nil
}
func setUpAPI(ctx context.Context, r *Commands, projectWriteModel *ProjectWriteModel, project *domain.Project, apiApp API, resourceOwner string) ([]eventstore.Command, error) {
func setUpAPI(ctx context.Context, r *Commands, projectWriteModel *ProjectWriteModel, project *domain.Project, apiApp API, resourceOwner string, appSecretGenerator crypto.Generator) ([]eventstore.Command, error) {
app := &domain.APIApp{
ObjectRoot: models.ObjectRoot{
AggregateID: projectWriteModel.AggregateID,
@@ -238,7 +244,7 @@ func setUpAPI(ctx context.Context, r *Commands, projectWriteModel *ProjectWriteM
}
projectAgg := ProjectAggregateFromWriteModel(&projectWriteModel.WriteModel)
events, _, err := r.addAPIApplication(ctx, projectAgg, project, app, resourceOwner)
events, _, err := r.addAPIApplication(ctx, projectAgg, project, app, resourceOwner, appSecretGenerator)
if err != nil {
return nil, err
}

119
internal/command/smtp.go Normal file
View File

@@ -0,0 +1,119 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/notification/channels/smtp"
"github.com/caos/zitadel/internal/repository/iam"
)
func (c *Commands) AddSMTPConfig(ctx context.Context, config *smtp.EmailConfig) (*domain.ObjectDetails, error) {
smtpConfigWriteModel, err := c.getSMTPConfig(ctx)
if err != nil {
return nil, err
}
if smtpConfigWriteModel.State == domain.SMTPConfigStateActive {
return nil, caos_errs.ThrowAlreadyExists(nil, "COMMAND-en9lw", "Errors.SMTPConfig.AlreadyExists")
}
var smtpPassword *crypto.CryptoValue
if config.SMTP.Password != "" {
smtpPassword, err = crypto.Encrypt([]byte(config.SMTP.Password), c.smtpPasswordCrypto)
if err != nil {
return nil, err
}
}
iamAgg := IAMAggregateFromWriteModel(&smtpConfigWriteModel.WriteModel)
pushedEvents, err := c.eventstore.Push(ctx, iam.NewSMTPConfigAddedEvent(
ctx,
iamAgg,
config.Tls,
config.From,
config.FromName,
config.SMTP.Host,
config.SMTP.User,
smtpPassword))
if err != nil {
return nil, err
}
err = AppendAndReduce(smtpConfigWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&smtpConfigWriteModel.WriteModel), nil
}
func (c *Commands) ChangeSMTPConfig(ctx context.Context, config *smtp.EmailConfig) (*domain.ObjectDetails, error) {
smtpConfigWriteModel, err := c.getSMTPConfig(ctx)
if err != nil {
return nil, err
}
if smtpConfigWriteModel.State == domain.SMTPConfigStateUnspecified {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3n9ls", "Errors.SMTPConfig.NotFound")
}
iamAgg := IAMAggregateFromWriteModel(&smtpConfigWriteModel.WriteModel)
changedEvent, hasChanged, err := smtpConfigWriteModel.NewChangedEvent(
ctx,
iamAgg,
config.Tls,
config.From,
config.FromName,
config.SMTP.Host,
config.SMTP.User)
if err != nil {
return nil, err
}
if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-m0o3f", "Errors.NoChangesFound")
}
pushedEvents, err := c.eventstore.Push(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(smtpConfigWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&smtpConfigWriteModel.WriteModel), nil
}
func (c *Commands) ChangeSMTPConfigPassword(ctx context.Context, password string) (*domain.ObjectDetails, error) {
smtpConfigWriteModel, err := c.getSMTPConfig(ctx)
if err != nil {
return nil, err
}
if smtpConfigWriteModel.State == domain.SMTPConfigStateUnspecified {
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3n9ls", "Errors.SMTPConfig.NotFound")
}
iamAgg := IAMAggregateFromWriteModel(&smtpConfigWriteModel.WriteModel)
newPW, err := crypto.Encrypt([]byte(password), c.smtpPasswordCrypto)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.Push(ctx, iam.NewSMTPConfigPasswordChangedEvent(
ctx,
iamAgg,
newPW))
if err != nil {
return nil, err
}
err = AppendAndReduce(smtpConfigWriteModel, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&smtpConfigWriteModel.WriteModel), nil
}
func (c *Commands) getSMTPConfig(ctx context.Context) (_ *IAMSMTPConfigWriteModel, err error) {
writeModel := NewIAMSMTPConfigWriteModel()
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
if err != nil {
return nil, err
}
return writeModel, nil
}

View File

@@ -0,0 +1,398 @@
package command
import (
"context"
"testing"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/notification/channels/smtp"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/repository"
"github.com/caos/zitadel/internal/repository/iam"
)
func TestCommandSide_AddSMTPConfig(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
alg crypto.EncryptionAlgorithm
}
type args struct {
ctx context.Context
smtp *smtp.EmailConfig
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
name: "smtp config, error already exists",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSMTPConfigAddedEvent(context.Background(),
&iam.NewAggregate().Aggregate,
true,
"from",
"name",
"host",
"user",
&crypto.CryptoValue{},
),
),
),
),
},
args: args{
ctx: context.Background(),
smtp: &smtp.EmailConfig{
Tls: true,
},
},
res: res{
err: caos_errs.IsErrorAlreadyExists,
},
},
{
name: "add smtp config, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
expectPush(
[]*repository.Event{
eventFromEventPusher(iam.NewSMTPConfigAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
true,
"from",
"name",
"host",
"user",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("password"),
},
),
),
},
),
),
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
smtp: &smtp.EmailConfig{
Tls: true,
From: "from",
FromName: "name",
SMTP: smtp.SMTP{
Host: "host",
User: "user",
Password: "password",
},
},
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "IAM",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
smtpPasswordCrypto: tt.fields.alg,
}
got, err := r.AddSMTPConfig(tt.args.ctx, tt.args.smtp)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.want, got)
}
})
}
}
func TestCommandSide_ChangeSMTPConfig(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
smtp *smtp.EmailConfig
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
name: "smtp not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
),
},
args: args{
ctx: context.Background(),
smtp: &smtp.EmailConfig{},
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "no changes, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSMTPConfigAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
true,
"from",
"name",
"host",
"user",
&crypto.CryptoValue{},
),
),
),
),
},
args: args{
ctx: context.Background(),
smtp: &smtp.EmailConfig{
Tls: true,
From: "from",
FromName: "name",
SMTP: smtp.SMTP{
Host: "host",
User: "user",
},
},
},
res: res{
err: caos_errs.IsPreconditionFailed,
},
},
{
name: "smtp config change, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSMTPConfigAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
true,
"from",
"name",
"host",
"user",
&crypto.CryptoValue{},
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
newSMTPConfigChangedEvent(
context.Background(),
false,
"from2",
"name2",
"host2",
"user2",
),
),
},
),
),
},
args: args{
ctx: context.Background(),
smtp: &smtp.EmailConfig{
Tls: false,
From: "from2",
FromName: "name2",
SMTP: smtp.SMTP{
Host: "host2",
User: "user2",
},
},
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "IAM",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
got, err := r.ChangeSMTPConfig(tt.args.ctx, tt.args.smtp)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.want, got)
}
})
}
}
func TestCommandSide_ChangeSMTPConfigPassword(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
alg crypto.EncryptionAlgorithm
}
type args struct {
ctx context.Context
password string
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
name: "smtp config, error not found",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
),
},
args: args{
ctx: context.Background(),
password: "",
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "change smtp config password, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
iam.NewSMTPConfigAddedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
true,
"from",
"name",
"host",
"user",
&crypto.CryptoValue{},
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(iam.NewSMTPConfigPasswordChangedEvent(
context.Background(),
&iam.NewAggregate().Aggregate,
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("password"),
},
),
),
},
),
),
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
password: "password",
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "IAM",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
smtpPasswordCrypto: tt.fields.alg,
}
got, err := r.ChangeSMTPConfigPassword(tt.args.ctx, tt.args.password)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.want, got)
}
})
}
}
func newSMTPConfigChangedEvent(ctx context.Context, tls bool, fromAddress, fromName, host, user string) *iam.SMTPConfigChangedEvent {
changes := []iam.SMTPConfigChanges{
iam.ChangeSMTPConfigTLS(tls),
iam.ChangeSMTPConfigFromAddress(fromAddress),
iam.ChangeSMTPConfigFromName(fromName),
iam.ChangeSMTPConfigSMTPHost(host),
iam.ChangeSMTPConfigSMTPUser(user),
}
event, _ := iam.NewSMTPConfigChangeEvent(ctx,
&iam.NewAggregate().Aggregate,
changes,
)
return event
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"strings"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/domain"
@@ -23,7 +24,7 @@ func (c *Commands) getHuman(ctx context.Context, userID, resourceowner string) (
return writeModelToHuman(human), nil
}
func (c *Commands) AddHuman(ctx context.Context, orgID string, human *domain.Human) (*domain.Human, error) {
func (c *Commands) AddHuman(ctx context.Context, orgID string, human *domain.Human, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) (*domain.Human, error) {
if orgID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-XYFk9", "Errors.ResourceOwnerMissing")
}
@@ -35,7 +36,7 @@ func (c *Commands) AddHuman(ctx context.Context, orgID string, human *domain.Hum
if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexity.NotFound")
}
events, addedHuman, err := c.addHuman(ctx, orgID, human, orgIAMPolicy, pwPolicy)
events, addedHuman, err := c.addHuman(ctx, orgID, human, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
if err != nil {
return nil, err
}
@@ -52,7 +53,7 @@ func (c *Commands) AddHuman(ctx context.Context, orgID string, human *domain.Hum
return writeModelToHuman(addedHuman), nil
}
func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool) (_ *domain.Human, passwordlessCode *domain.PasswordlessInitCode, err error) {
func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator, passwordlessCodeGenerator crypto.Generator) (_ *domain.Human, passwordlessCode *domain.PasswordlessInitCode, err error) {
if orgID == "" {
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-5N8fs", "Errors.ResourceOwnerMissing")
}
@@ -64,7 +65,7 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
if err != nil {
return nil, nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-4N8gs", "Errors.Org.PasswordComplexity.NotFound")
}
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, orgIAMPolicy, pwPolicy)
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
if err != nil {
return nil, nil, err
}
@@ -88,27 +89,27 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
return writeModelToHuman(addedHuman), passwordlessCode, nil
}
func (c *Commands) addHuman(ctx context.Context, orgID string, human *domain.Human, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.Command, *HumanWriteModel, error) {
func (c *Commands) addHuman(ctx context.Context, orgID string, human *domain.Human, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
if orgID == "" || !human.IsValid() {
return nil, nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-67Ms8", "Errors.User.Invalid")
}
if human.Password != nil && human.SecretString != "" {
human.ChangeRequired = true
}
return c.createHuman(ctx, orgID, human, nil, false, false, orgIAMPolicy, pwPolicy)
return c.createHuman(ctx, orgID, human, nil, false, false, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
}
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) (events []eventstore.Command, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.Human, passwordless bool, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator, passwordlessCodeGenerator crypto.Generator) (events []eventstore.Command, humanWriteModel *HumanWriteModel, passwordlessCodeWriteModel *HumanPasswordlessInitCodeWriteModel, code string, err error) {
if orgID == "" || !human.IsValid() {
return nil, nil, nil, "", caos_errs.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.User.Invalid")
}
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, nil, false, passwordless, orgIAMPolicy, pwPolicy)
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, nil, false, passwordless, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
if err != nil {
return nil, nil, nil, "", err
}
if passwordless {
var codeEvent eventstore.Command
codeEvent, passwordlessCodeWriteModel, code, err = c.humanAddPasswordlessInitCode(ctx, human.AggregateID, orgID, true)
codeEvent, passwordlessCodeWriteModel, code, err = c.humanAddPasswordlessInitCode(ctx, human.AggregateID, orgID, true, passwordlessCodeGenerator)
if err != nil {
return nil, nil, nil, "", err
}
@@ -117,7 +118,7 @@ func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.
return events, humanWriteModel, passwordlessCodeWriteModel, code, nil
}
func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgMemberRoles []string) (*domain.Human, error) {
func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgMemberRoles []string, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) (*domain.Human, error) {
if orgID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-GEdf2", "Errors.ResourceOwnerMissing")
}
@@ -136,7 +137,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
if !loginPolicy.AllowRegister {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-SAbr3", "Errors.Org.LoginPolicy.RegistrationNotAllowed")
}
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, link, orgIAMPolicy, pwPolicy)
userEvents, registeredHuman, err := c.registerHuman(ctx, orgID, human, link, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
if err != nil {
return nil, err
}
@@ -170,7 +171,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
return writeModelToHuman(registeredHuman), nil
}
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.Command, *HumanWriteModel, error) {
func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
if human != nil && human.Username == "" {
human.Username = human.EmailAddress
}
@@ -180,10 +181,10 @@ func (c *Commands) registerHuman(ctx context.Context, orgID string, human *domai
if human.Password != nil && human.SecretString != "" {
human.ChangeRequired = false
}
return c.createHuman(ctx, orgID, human, link, true, false, orgIAMPolicy, pwPolicy)
return c.createHuman(ctx, orgID, human, link, true, false, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
}
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, selfregister, passwordless bool, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy) ([]eventstore.Command, *HumanWriteModel, error) {
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, link *domain.UserIDPLink, selfregister, passwordless bool, orgIAMPolicy *domain.OrgIAMPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator crypto.Generator, phoneCodeGenerator crypto.Generator) ([]eventstore.Command, *HumanWriteModel, error) {
if err := human.CheckOrgIAMPolicy(orgIAMPolicy); err != nil {
return nil, nil, err
}
@@ -232,7 +233,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
}
if human.IsInitialState(passwordless, link != nil) {
initCode, err := domain.NewInitUserCode(c.initializeUserCode)
initCode, err := domain.NewInitUserCode(initCodeGenerator)
if err != nil {
return nil, nil, err
}
@@ -244,7 +245,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
}
if human.Phone != nil && human.PhoneNumber != "" && !human.IsPhoneVerified {
phoneCode, err := domain.NewPhoneCode(c.phoneVerificationCode)
phoneCode, err := domain.NewPhoneCode(phoneCodeGenerator)
if err != nil {
return nil, nil, err
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/caos/zitadel/internal/telemetry/tracing"
)
func (c *Commands) ChangeHumanEmail(ctx context.Context, email *domain.Email) (*domain.Email, error) {
func (c *Commands) ChangeHumanEmail(ctx context.Context, email *domain.Email, emailCodeGenerator crypto.Generator) (*domain.Email, error) {
if !email.IsValid() || email.AggregateID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M9sf", "Errors.Email.Invalid")
}
@@ -38,7 +38,7 @@ func (c *Commands) ChangeHumanEmail(ctx context.Context, email *domain.Email) (*
if email.IsEmailVerified {
events = append(events, user.NewHumanEmailVerifiedEvent(ctx, userAgg))
} else {
emailCode, err := domain.NewEmailCode(c.emailVerificationCode)
emailCode, err := domain.NewEmailCode(emailCodeGenerator)
if err != nil {
return nil, err
}
@@ -56,7 +56,7 @@ func (c *Commands) ChangeHumanEmail(ctx context.Context, email *domain.Email) (*
return writeModelToEmail(existingEmail), nil
}
func (c *Commands) VerifyHumanEmail(ctx context.Context, userID, code, resourceowner string) (*domain.ObjectDetails, error) {
func (c *Commands) VerifyHumanEmail(ctx context.Context, userID, code, resourceowner string, emailCodeGenerator crypto.Generator) (*domain.ObjectDetails, error) {
if userID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M0ds", "Errors.User.UserIDMissing")
}
@@ -73,7 +73,7 @@ func (c *Commands) VerifyHumanEmail(ctx context.Context, userID, code, resourceo
}
userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel)
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, c.emailVerificationCode)
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, emailCodeGenerator)
if err == nil {
pushedEvents, err := c.eventstore.Push(ctx, user.NewHumanEmailVerifiedEvent(ctx, userAgg))
if err != nil {
@@ -91,7 +91,7 @@ func (c *Commands) VerifyHumanEmail(ctx context.Context, userID, code, resourceo
return nil, caos_errs.ThrowInvalidArgument(err, "COMMAND-Gdsgs", "Errors.User.Code.Invalid")
}
func (c *Commands) CreateHumanEmailVerificationCode(ctx context.Context, userID, resourceOwner string) (*domain.ObjectDetails, error) {
func (c *Commands) CreateHumanEmailVerificationCode(ctx context.Context, userID, resourceOwner string, emailCodeGenerator crypto.Generator) (*domain.ObjectDetails, error) {
if userID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M0ds", "Errors.User.UserIDMissing")
}
@@ -110,7 +110,7 @@ func (c *Commands) CreateHumanEmailVerificationCode(ctx context.Context, userID,
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-3M9ds", "Errors.User.Email.AlreadyVerified")
}
userAgg := UserAggregateFromWriteModel(&existingEmail.WriteModel)
emailCode, err := domain.NewEmailCode(c.emailVerificationCode)
emailCode, err := domain.NewEmailCode(emailCodeGenerator)
if err != nil {
return nil, err
}

View File

@@ -19,13 +19,13 @@ import (
func TestCommandSide_ChangeHumanEmail(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
email *domain.Email
resourceOwner string
ctx context.Context
email *domain.Email
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.Email
@@ -263,7 +263,6 @@ func TestCommandSide_ChangeHumanEmail(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
@@ -273,7 +272,8 @@ func TestCommandSide_ChangeHumanEmail(t *testing.T) {
},
EmailAddress: "email-changed@test.ch",
},
resourceOwner: "org1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Email{
@@ -289,10 +289,9 @@ func TestCommandSide_ChangeHumanEmail(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
emailVerificationCode: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.ChangeHumanEmail(tt.args.ctx, tt.args.email)
got, err := r.ChangeHumanEmail(tt.args.ctx, tt.args.email, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -308,14 +307,14 @@ func TestCommandSide_ChangeHumanEmail(t *testing.T) {
func TestCommandSide_VerifyHumanEmail(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
userID string
code string
resourceOwner string
ctx context.Context
userID string
code string
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.ObjectDetails
@@ -453,13 +452,13 @@ func TestCommandSide_VerifyHumanEmail(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
code: "test",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
code: "test",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
@@ -508,13 +507,13 @@ func TestCommandSide_VerifyHumanEmail(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
code: "a",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
code: "a",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -526,10 +525,9 @@ func TestCommandSide_VerifyHumanEmail(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
emailVerificationCode: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.VerifyHumanEmail(tt.args.ctx, tt.args.userID, tt.args.code, tt.args.resourceOwner)
got, err := r.VerifyHumanEmail(tt.args.ctx, tt.args.userID, tt.args.code, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -545,13 +543,13 @@ func TestCommandSide_VerifyHumanEmail(t *testing.T) {
func TestCommandSide_CreateVerificationCodeHumanEmail(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
userID string
resourceOwner string
ctx context.Context
userID string
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.ObjectDetails
@@ -719,12 +717,12 @@ func TestCommandSide_CreateVerificationCodeHumanEmail(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -736,10 +734,9 @@ func TestCommandSide_CreateVerificationCodeHumanEmail(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
emailVerificationCode: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.CreateHumanEmailVerificationCode(tt.args.ctx, tt.args.userID, tt.args.resourceOwner)
got, err := r.CreateHumanEmailVerificationCode(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -12,7 +12,7 @@ import (
)
//ResendInitialMail resend inital mail and changes email if provided
func (c *Commands) ResendInitialMail(ctx context.Context, userID, email, resourceOwner string) (objectDetails *domain.ObjectDetails, err error) {
func (c *Commands) ResendInitialMail(ctx context.Context, userID, email, resourceOwner string, initCodeGenerator crypto.Generator) (objectDetails *domain.ObjectDetails, err error) {
if userID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-2n8vs", "Errors.User.UserIDMissing")
}
@@ -33,7 +33,7 @@ func (c *Commands) ResendInitialMail(ctx context.Context, userID, email, resourc
changedEvent, _ := existingCode.NewChangedEvent(ctx, userAgg, email)
events = append(events, changedEvent)
}
initCode, err := domain.NewInitUserCode(c.initializeUserCode)
initCode, err := domain.NewInitUserCode(initCodeGenerator)
if err != nil {
return nil, err
}
@@ -49,7 +49,7 @@ func (c *Commands) ResendInitialMail(ctx context.Context, userID, email, resourc
return writeModelToObjectDetails(&existingCode.WriteModel), nil
}
func (c *Commands) HumanVerifyInitCode(ctx context.Context, userID, resourceOwner, code, passwordString string) error {
func (c *Commands) HumanVerifyInitCode(ctx context.Context, userID, resourceOwner, code, passwordString string, initCodeGenerator crypto.Generator) error {
if userID == "" {
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-mkM9f", "Errors.User.UserIDMissing")
}
@@ -66,7 +66,7 @@ func (c *Commands) HumanVerifyInitCode(ctx context.Context, userID, resourceOwne
}
userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel)
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, c.initializeUserCode)
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, initCodeGenerator)
if err != nil {
_, err = c.eventstore.Push(ctx, user.NewHumanInitializedCheckFailedEvent(ctx, userAgg))
logging.LogWithFields("COMMAND-Dg2z5", "userID", userAgg.ID).OnError(err).Error("NewHumanInitializedCheckFailedEvent push failed")

View File

@@ -20,14 +20,14 @@ import (
func TestCommandSide_ResendInitialMail(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
userID string
email string
resourceOwner string
ctx context.Context
userID string
email string
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.ObjectDetails
@@ -150,13 +150,13 @@ func TestCommandSide_ResendInitialMail(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
email: "email@test.ch",
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
email: "email@test.ch",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -208,12 +208,12 @@ func TestCommandSide_ResendInitialMail(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -269,13 +269,13 @@ func TestCommandSide_ResendInitialMail(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
email: "email2@test.ch",
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
email: "email2@test.ch",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -287,10 +287,9 @@ func TestCommandSide_ResendInitialMail(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
initializeUserCode: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.ResendInitialMail(tt.args.ctx, tt.args.userID, tt.args.email, tt.args.resourceOwner)
got, err := r.ResendInitialMail(tt.args.ctx, tt.args.userID, tt.args.email, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -307,15 +306,15 @@ func TestCommandSide_ResendInitialMail(t *testing.T) {
func TestCommandSide_VerifyInitCode(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
userPasswordAlg crypto.HashAlgorithm
}
type args struct {
ctx context.Context
userID string
code string
resourceOwner string
password string
ctx context.Context
userID string
code string
resourceOwner string
password string
secretGenerator crypto.Generator
}
type res struct {
want *domain.ObjectDetails
@@ -453,13 +452,13 @@ func TestCommandSide_VerifyInitCode(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
code: "test",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
code: "test",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
@@ -513,13 +512,13 @@ func TestCommandSide_VerifyInitCode(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
code: "a",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
code: "a",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -596,15 +595,15 @@ func TestCommandSide_VerifyInitCode(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
userID: "user1",
code: "a",
resourceOwner: "org1",
password: "password",
ctx: context.Background(),
userID: "user1",
code: "a",
resourceOwner: "org1",
password: "password",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -616,11 +615,10 @@ func TestCommandSide_VerifyInitCode(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
initializeUserCode: tt.fields.secretGenerator,
userPasswordAlg: tt.fields.userPasswordAlg,
eventstore: tt.fields.eventstore,
userPasswordAlg: tt.fields.userPasswordAlg,
}
err := r.HumanVerifyInitCode(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.code, tt.args.password)
err := r.HumanVerifyInitCode(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.code, tt.args.password, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -46,7 +46,7 @@ func (c *Commands) SetPassword(ctx context.Context, orgID, userID, passwordStrin
return writeModelToObjectDetails(&existingPassword.WriteModel), nil
}
func (c *Commands) SetPasswordWithVerifyCode(ctx context.Context, orgID, userID, code, passwordString, userAgentID string) (err error) {
func (c *Commands) SetPasswordWithVerifyCode(ctx context.Context, orgID, userID, code, passwordString, userAgentID string, passwordVerificationCode crypto.Generator) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@@ -65,7 +65,7 @@ func (c *Commands) SetPasswordWithVerifyCode(ctx context.Context, orgID, userID,
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M9fs", "Errors.User.Code.NotFound")
}
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, c.passwordVerificationCode)
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, passwordVerificationCode)
if err != nil {
return err
}
@@ -148,7 +148,7 @@ func (c *Commands) changePassword(ctx context.Context, userAgentID string, passw
return user.NewHumanPasswordChangedEvent(ctx, userAgg, password.SecretCrypto, password.ChangeRequired, userAgentID), nil
}
func (c *Commands) RequestSetPassword(ctx context.Context, userID, resourceOwner string, notifyType domain.NotificationType) (objectDetails *domain.ObjectDetails, err error) {
func (c *Commands) RequestSetPassword(ctx context.Context, userID, resourceOwner string, notifyType domain.NotificationType, passwordVerificationCode crypto.Generator) (objectDetails *domain.ObjectDetails, err error) {
if userID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-M00oL", "Errors.User.UserIDMissing")
}
@@ -164,7 +164,7 @@ func (c *Commands) RequestSetPassword(ctx context.Context, userID, resourceOwner
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M9sd", "Errors.User.NotInitialised")
}
userAgg := UserAggregateFromWriteModel(&existingHuman.WriteModel)
passwordCode, err := domain.NewPasswordCode(c.passwordVerificationCode)
passwordCode, err := domain.NewPasswordCode(passwordVerificationCode)
if err != nil {
return nil, err
}

View File

@@ -239,15 +239,15 @@ func TestCommandSide_SetPassword(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
userPasswordAlg crypto.HashAlgorithm
secretGenerator crypto.Generator
}
type args struct {
ctx context.Context
userID string
code string
resourceOwner string
password string
agentID string
ctx context.Context
userID string
code string
resourceOwner string
password string
agentID string
secretGenerator crypto.Generator
}
type res struct {
want *domain.ObjectDetails
@@ -377,14 +377,14 @@ func TestCommandSide_SetPassword(t *testing.T) {
),
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
code: "test",
resourceOwner: "org1",
password: "password",
ctx: context.Background(),
userID: "user1",
code: "test",
resourceOwner: "org1",
password: "password",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
err: caos_errs.IsPreconditionFailed,
@@ -459,15 +459,15 @@ func TestCommandSide_SetPassword(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
password: "password",
code: "a",
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
password: "password",
code: "a",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -479,11 +479,10 @@ func TestCommandSide_SetPassword(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
userPasswordAlg: tt.fields.userPasswordAlg,
passwordVerificationCode: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
userPasswordAlg: tt.fields.userPasswordAlg,
}
err := r.SetPasswordWithVerifyCode(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, tt.args.code, tt.args.password, tt.args.agentID)
err := r.SetPasswordWithVerifyCode(tt.args.ctx, tt.args.resourceOwner, tt.args.userID, tt.args.code, tt.args.password, tt.args.agentID, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -778,14 +777,14 @@ func TestCommandSide_ChangePassword(t *testing.T) {
func TestCommandSide_RequestSetPassword(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
userID string
resourceOwner string
notifyType domain.NotificationType
ctx context.Context
userID string
resourceOwner string
notifyType domain.NotificationType
secretGenerator crypto.Generator
}
type res struct {
want *domain.ObjectDetails
@@ -925,12 +924,12 @@ func TestCommandSide_RequestSetPassword(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -942,10 +941,9 @@ func TestCommandSide_RequestSetPassword(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
passwordVerificationCode: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.RequestSetPassword(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.notifyType)
got, err := r.RequestSetPassword(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.notifyType, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -13,7 +13,7 @@ import (
"github.com/caos/zitadel/internal/telemetry/tracing"
)
func (c *Commands) ChangeHumanPhone(ctx context.Context, phone *domain.Phone, resourceOwner string) (*domain.Phone, error) {
func (c *Commands) ChangeHumanPhone(ctx context.Context, phone *domain.Phone, resourceOwner string, phoneCodeGenerator crypto.Generator) (*domain.Phone, error) {
if !phone.IsValid() {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-6M0ds", "Errors.Phone.Invalid")
}
@@ -36,7 +36,7 @@ func (c *Commands) ChangeHumanPhone(ctx context.Context, phone *domain.Phone, re
if phone.IsPhoneVerified {
events = append(events, user.NewHumanPhoneVerifiedEvent(ctx, userAgg))
} else {
phoneCode, err := domain.NewPhoneCode(c.phoneVerificationCode)
phoneCode, err := domain.NewPhoneCode(phoneCodeGenerator)
if err != nil {
return nil, err
}
@@ -55,7 +55,7 @@ func (c *Commands) ChangeHumanPhone(ctx context.Context, phone *domain.Phone, re
return writeModelToPhone(existingPhone), nil
}
func (c *Commands) VerifyHumanPhone(ctx context.Context, userID, code, resourceowner string) (*domain.ObjectDetails, error) {
func (c *Commands) VerifyHumanPhone(ctx context.Context, userID, code, resourceowner string, phoneCodeGenerator crypto.Generator) (*domain.ObjectDetails, error) {
if userID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Km9ds", "Errors.User.UserIDMissing")
}
@@ -75,7 +75,7 @@ func (c *Commands) VerifyHumanPhone(ctx context.Context, userID, code, resourceo
}
userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel)
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, c.phoneVerificationCode)
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, phoneCodeGenerator)
if err == nil {
pushedEvents, err := c.eventstore.Push(ctx, user.NewHumanPhoneVerifiedEvent(ctx, userAgg))
if err != nil {
@@ -92,7 +92,7 @@ func (c *Commands) VerifyHumanPhone(ctx context.Context, userID, code, resourceo
return nil, caos_errs.ThrowInvalidArgument(err, "COMMAND-sM0cs", "Errors.User.Code.Invalid")
}
func (c *Commands) CreateHumanPhoneVerificationCode(ctx context.Context, userID, resourceowner string) (*domain.ObjectDetails, error) {
func (c *Commands) CreateHumanPhoneVerificationCode(ctx context.Context, userID, resourceowner string, phoneCodeGenerator crypto.Generator) (*domain.ObjectDetails, error) {
if userID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4M0ds", "Errors.User.UserIDMissing")
}
@@ -112,7 +112,7 @@ func (c *Commands) CreateHumanPhoneVerificationCode(ctx context.Context, userID,
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M9sf", "Errors.User.Phone.AlreadyVerified")
}
phoneCode, err := domain.NewPhoneCode(c.phoneVerificationCode)
phoneCode, err := domain.NewPhoneCode(phoneCodeGenerator)
if err != nil {
return nil, err
}

View File

@@ -19,13 +19,13 @@ import (
func TestCommandSide_ChangeHumanPhone(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
email *domain.Phone
resourceOwner string
ctx context.Context
email *domain.Phone
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.Phone
@@ -232,7 +232,6 @@ func TestCommandSide_ChangeHumanPhone(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
@@ -242,7 +241,8 @@ func TestCommandSide_ChangeHumanPhone(t *testing.T) {
},
PhoneNumber: "0711234567",
},
resourceOwner: "org1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Phone{
@@ -258,10 +258,9 @@ func TestCommandSide_ChangeHumanPhone(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
phoneVerificationCode: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.ChangeHumanPhone(tt.args.ctx, tt.args.email, tt.args.resourceOwner)
got, err := r.ChangeHumanPhone(tt.args.ctx, tt.args.email, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -277,14 +276,14 @@ func TestCommandSide_ChangeHumanPhone(t *testing.T) {
func TestCommandSide_VerifyHumanPhone(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
userID string
code string
resourceOwner string
ctx context.Context
userID string
code string
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.ObjectDetails
@@ -428,13 +427,13 @@ func TestCommandSide_VerifyHumanPhone(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
code: "test",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
code: "test",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
@@ -489,13 +488,13 @@ func TestCommandSide_VerifyHumanPhone(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
code: "a",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
code: "a",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -507,10 +506,9 @@ func TestCommandSide_VerifyHumanPhone(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
phoneVerificationCode: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.VerifyHumanPhone(tt.args.ctx, tt.args.userID, tt.args.code, tt.args.resourceOwner)
got, err := r.VerifyHumanPhone(tt.args.ctx, tt.args.userID, tt.args.code, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -526,13 +524,13 @@ func TestCommandSide_VerifyHumanPhone(t *testing.T) {
func TestCommandSide_CreateVerificationCodeHumanPhone(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
secretGenerator crypto.Generator
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
userID string
resourceOwner string
ctx context.Context
userID string
resourceOwner string
secretGenerator crypto.Generator
}
type res struct {
want *domain.ObjectDetails
@@ -663,12 +661,12 @@ func TestCommandSide_CreateVerificationCodeHumanPhone(t *testing.T) {
},
),
),
secretGenerator: GetMockSecretGenerator(t),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.ObjectDetails{
@@ -680,10 +678,9 @@ func TestCommandSide_CreateVerificationCodeHumanPhone(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
phoneVerificationCode: tt.fields.secretGenerator,
eventstore: tt.fields.eventstore,
}
got, err := r.CreateHumanPhoneVerificationCode(tt.args.ctx, tt.args.userID, tt.args.resourceOwner)
got, err := r.CreateHumanPhoneVerificationCode(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -25,13 +25,13 @@ func TestCommandSide_AddHuman(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
idGenerator id.Generator
secretGenerator crypto.Generator
userPasswordAlg crypto.HashAlgorithm
}
type args struct {
ctx context.Context
orgID string
human *domain.Human
ctx context.Context
orgID string
human *domain.Human
secretGenerator crypto.Generator
}
type res struct {
want *domain.Human
@@ -228,8 +228,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)),
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
},
args: args{
ctx: context.Background(),
@@ -244,6 +243,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
EmailAddress: "email@test.ch",
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -312,7 +312,6 @@ func TestCommandSide_AddHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -331,6 +330,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
EmailAddress: "email@test.ch",
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -391,7 +391,6 @@ func TestCommandSide_AddHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -411,6 +410,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
IsEmailVerified: true,
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -489,8 +489,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)),
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
},
args: args{
ctx: context.Background(),
@@ -508,6 +507,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
PhoneNumber: "+41711234567",
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -582,8 +582,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)),
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
},
args: args{
ctx: context.Background(),
@@ -602,6 +601,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
IsPhoneVerified: true,
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -630,13 +630,11 @@ func TestCommandSide_AddHuman(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
initializeUserCode: tt.fields.secretGenerator,
phoneVerificationCode: tt.fields.secretGenerator,
userPasswordAlg: tt.fields.userPasswordAlg,
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
userPasswordAlg: tt.fields.userPasswordAlg,
}
got, err := r.AddHuman(tt.args.ctx, tt.args.orgID, tt.args.human)
got, err := r.AddHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.secretGenerator, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -652,17 +650,17 @@ func TestCommandSide_AddHuman(t *testing.T) {
func TestCommandSide_ImportHuman(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
idGenerator id.Generator
secretGenerator crypto.Generator
userPasswordAlg crypto.HashAlgorithm
passwordlessInitCode crypto.Generator
eventstore *eventstore.Eventstore
idGenerator id.Generator
userPasswordAlg crypto.HashAlgorithm
}
type args struct {
ctx context.Context
orgID string
human *domain.Human
passwordless bool
ctx context.Context
orgID string
human *domain.Human
passwordless bool
secretGenerator crypto.Generator
passwordlessInitCode crypto.Generator
}
type res struct {
wantHuman *domain.Human
@@ -850,7 +848,6 @@ func TestCommandSide_ImportHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -870,6 +867,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
EmailAddress: "email@test.ch",
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
wantHuman: &domain.Human{
@@ -930,7 +928,6 @@ func TestCommandSide_ImportHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -951,6 +948,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
IsEmailVerified: true,
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
wantHuman: &domain.Human{
@@ -1025,10 +1023,8 @@ func TestCommandSide_ImportHuman(t *testing.T) {
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)),
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1", "code1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
passwordlessInitCode: GetMockSecretGenerator(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1", "code1"),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
@@ -1044,7 +1040,9 @@ func TestCommandSide_ImportHuman(t *testing.T) {
IsEmailVerified: true,
},
},
passwordless: true,
passwordless: true,
secretGenerator: GetMockSecretGenerator(t),
passwordlessInitCode: GetMockSecretGenerator(t),
},
res: res{
wantHuman: &domain.Human{
@@ -1129,10 +1127,8 @@ func TestCommandSide_ImportHuman(t *testing.T) {
uniqueConstraintsFromEventConstraint(user.NewAddUsernameUniqueConstraint("username", "org1", true)),
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1", "code1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
passwordlessInitCode: GetMockSecretGenerator(t),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1", "code1"),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
ctx: context.Background(),
@@ -1152,7 +1148,9 @@ func TestCommandSide_ImportHuman(t *testing.T) {
IsEmailVerified: true,
},
},
passwordless: true,
passwordless: true,
secretGenerator: GetMockSecretGenerator(t),
passwordlessInitCode: GetMockSecretGenerator(t),
},
res: res{
wantHuman: &domain.Human{
@@ -1242,7 +1240,6 @@ func TestCommandSide_ImportHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -1265,6 +1262,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
PhoneNumber: "+41711234567",
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
wantHuman: &domain.Human{
@@ -1340,7 +1338,6 @@ func TestCommandSide_ImportHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -1364,6 +1361,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
IsPhoneVerified: true,
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
wantHuman: &domain.Human{
@@ -1392,14 +1390,11 @@ func TestCommandSide_ImportHuman(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
initializeUserCode: tt.fields.secretGenerator,
phoneVerificationCode: tt.fields.secretGenerator,
userPasswordAlg: tt.fields.userPasswordAlg,
passwordlessInitCode: tt.fields.passwordlessInitCode,
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
userPasswordAlg: tt.fields.userPasswordAlg,
}
gotHuman, gotCode, err := r.ImportHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.passwordless)
gotHuman, gotCode, err := r.ImportHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.passwordless, tt.args.secretGenerator, tt.args.secretGenerator, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}
@@ -1418,15 +1413,15 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
idGenerator id.Generator
secretGenerator crypto.Generator
userPasswordAlg crypto.HashAlgorithm
}
type args struct {
ctx context.Context
orgID string
human *domain.Human
link *domain.UserIDPLink
orgMemberRoles []string
ctx context.Context
orgID string
human *domain.Human
link *domain.UserIDPLink
orgMemberRoles []string
secretGenerator crypto.Generator
}
type res struct {
want *domain.Human
@@ -1858,7 +1853,6 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -1876,6 +1870,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
EmailAddress: "email@test.ch",
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -1957,7 +1952,6 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -1976,6 +1970,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
EmailAddress: "email@test.ch",
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -2049,7 +2044,6 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -2069,6 +2063,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
IsEmailVerified: true,
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -2161,7 +2156,6 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -2183,6 +2177,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
SecretString: "password",
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -2271,7 +2266,6 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
),
),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
secretGenerator: GetMockSecretGenerator(t),
userPasswordAlg: crypto.CreateMockHashAlg(gomock.NewController(t)),
},
args: args{
@@ -2294,6 +2288,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
SecretString: "password",
},
},
secretGenerator: GetMockSecretGenerator(t),
},
res: res{
want: &domain.Human{
@@ -2322,13 +2317,11 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
initializeUserCode: tt.fields.secretGenerator,
phoneVerificationCode: tt.fields.secretGenerator,
userPasswordAlg: tt.fields.userPasswordAlg,
eventstore: tt.fields.eventstore,
idGenerator: tt.fields.idGenerator,
userPasswordAlg: tt.fields.userPasswordAlg,
}
got, err := r.RegisterHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.link, tt.args.orgMemberRoles)
got, err := r.RegisterHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.link, tt.args.orgMemberRoles, tt.args.secretGenerator, tt.args.secretGenerator)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@@ -129,8 +129,8 @@ func (c *Commands) HumanAddPasswordlessSetup(ctx context.Context, userID, resour
return createdWebAuthN, nil
}
func (c *Commands) HumanAddPasswordlessSetupInitCode(ctx context.Context, userID, resourceowner, codeID, verificationCode string, preferredPlatformType domain.AuthenticatorAttachment) (*domain.WebAuthNToken, error) {
err := c.humanVerifyPasswordlessInitCode(ctx, userID, resourceowner, codeID, verificationCode)
func (c *Commands) HumanAddPasswordlessSetupInitCode(ctx context.Context, userID, resourceowner, codeID, verificationCode string, preferredPlatformType domain.AuthenticatorAttachment, passwordlessCodeGenerator crypto.Generator) (*domain.WebAuthNToken, error) {
err := c.humanVerifyPasswordlessInitCode(ctx, userID, resourceowner, codeID, verificationCode, passwordlessCodeGenerator)
if err != nil {
return nil, err
}
@@ -208,8 +208,8 @@ func (c *Commands) HumanVerifyU2FSetup(ctx context.Context, userID, resourceowne
return writeModelToObjectDetails(&verifyWebAuthN.WriteModel), nil
}
func (c *Commands) HumanPasswordlessSetupInitCode(ctx context.Context, userID, resourceowner, tokenName, userAgentID, codeID, verificationCode string, credentialData []byte) (*domain.ObjectDetails, error) {
err := c.humanVerifyPasswordlessInitCode(ctx, userID, resourceowner, codeID, verificationCode)
func (c *Commands) HumanPasswordlessSetupInitCode(ctx context.Context, userID, resourceowner, tokenName, userAgentID, codeID, verificationCode string, credentialData []byte, passwordlessCodeGenerator crypto.Generator) (*domain.ObjectDetails, error) {
err := c.humanVerifyPasswordlessInitCode(ctx, userID, resourceowner, codeID, verificationCode, passwordlessCodeGenerator)
if err != nil {
return nil, err
}
@@ -483,8 +483,8 @@ func (c *Commands) HumanRemovePasswordless(ctx context.Context, userID, webAuthN
return c.removeHumanWebAuthN(ctx, userID, webAuthNID, resourceOwner, event)
}
func (c *Commands) HumanAddPasswordlessInitCode(ctx context.Context, userID, resourceOwner string) (*domain.PasswordlessInitCode, error) {
codeEvent, initCode, code, err := c.humanAddPasswordlessInitCode(ctx, userID, resourceOwner, true)
func (c *Commands) HumanAddPasswordlessInitCode(ctx context.Context, userID, resourceOwner string, passwordlessCodeGenerator crypto.Generator) (*domain.PasswordlessInitCode, error) {
codeEvent, initCode, code, err := c.humanAddPasswordlessInitCode(ctx, userID, resourceOwner, true, passwordlessCodeGenerator)
pushedEvents, err := c.eventstore.Push(ctx, codeEvent)
if err != nil {
return nil, err
@@ -496,8 +496,8 @@ func (c *Commands) HumanAddPasswordlessInitCode(ctx context.Context, userID, res
return writeModelToPasswordlessInitCode(initCode, code), nil
}
func (c *Commands) HumanSendPasswordlessInitCode(ctx context.Context, userID, resourceOwner string) (*domain.PasswordlessInitCode, error) {
codeEvent, initCode, code, err := c.humanAddPasswordlessInitCode(ctx, userID, resourceOwner, false)
func (c *Commands) HumanSendPasswordlessInitCode(ctx context.Context, userID, resourceOwner string, passwordlessCodeGenerator crypto.Generator) (*domain.PasswordlessInitCode, error) {
codeEvent, initCode, code, err := c.humanAddPasswordlessInitCode(ctx, userID, resourceOwner, false, passwordlessCodeGenerator)
if err != nil {
return nil, err
}
@@ -512,7 +512,7 @@ func (c *Commands) HumanSendPasswordlessInitCode(ctx context.Context, userID, re
return writeModelToPasswordlessInitCode(initCode, code), nil
}
func (c *Commands) humanAddPasswordlessInitCode(ctx context.Context, userID, resourceOwner string, direct bool) (eventstore.Command, *HumanPasswordlessInitCodeWriteModel, string, error) {
func (c *Commands) humanAddPasswordlessInitCode(ctx context.Context, userID, resourceOwner string, direct bool, passwordlessCodeGenerator crypto.Generator) (eventstore.Command, *HumanPasswordlessInitCodeWriteModel, string, error) {
if userID == "" {
return nil, nil, "", caos_errs.ThrowPreconditionFailed(nil, "COMMAND-GVfg3", "Errors.IDMissing")
}
@@ -527,7 +527,7 @@ func (c *Commands) humanAddPasswordlessInitCode(ctx context.Context, userID, res
return nil, nil, "", err
}
cryptoCode, code, err := crypto.NewCode(c.passwordlessInitCode)
cryptoCode, code, err := crypto.NewCode(passwordlessCodeGenerator)
if err != nil {
return nil, nil, "", err
}
@@ -539,7 +539,7 @@ func (c *Commands) humanAddPasswordlessInitCode(ctx context.Context, userID, res
return usr_repo.NewHumanPasswordlessInitCodeRequestedEvent(ctx, agg, id, cryptoCode, exp)
}
}
codeEvent := codeEventCreator(ctx, UserAggregateFromWriteModel(&initCode.WriteModel), codeID, cryptoCode, c.passwordlessInitCode.Expiry())
codeEvent := codeEventCreator(ctx, UserAggregateFromWriteModel(&initCode.WriteModel), codeID, cryptoCode, passwordlessCodeGenerator.Expiry())
return codeEvent, initCode, code, nil
}
@@ -563,7 +563,7 @@ func (c *Commands) HumanPasswordlessInitCodeSent(ctx context.Context, userID, re
return err
}
func (c *Commands) humanVerifyPasswordlessInitCode(ctx context.Context, userID, resourceOwner, codeID, verificationCode string) error {
func (c *Commands) humanVerifyPasswordlessInitCode(ctx context.Context, userID, resourceOwner, codeID, verificationCode string, passwordlessCodeGenerator crypto.Generator) error {
if userID == "" || codeID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-GVfg3", "Errors.IDMissing")
}
@@ -572,7 +572,7 @@ func (c *Commands) humanVerifyPasswordlessInitCode(ctx context.Context, userID,
if err != nil {
return err
}
err = crypto.VerifyCode(initCode.ChangeDate, initCode.Expiration, initCode.CryptoCode, verificationCode, c.passwordlessInitCode)
err = crypto.VerifyCode(initCode.ChangeDate, initCode.Expiration, initCode.CryptoCode, verificationCode, passwordlessCodeGenerator)
if err != nil || initCode.State != domain.PasswordlessInitCodeStateActive {
userAgg := UserAggregateFromWriteModel(&initCode.WriteModel)
_, err = c.eventstore.Push(ctx, usr_repo.NewHumanPasswordlessInitCodeCheckFailedEvent(ctx, userAgg, codeID))