fix: use system secret config if generator type does not exist on instance (#6420)

* fix: use system secret config if generator type does not exist on instance

* remove unused idGenerator
This commit is contained in:
Livio Spring 2023-08-23 10:04:29 +02:00 committed by GitHub
parent 37c527f18e
commit cbd2ef0612
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 195 additions and 42 deletions

View File

@ -91,6 +91,7 @@ func (mig *FirstInstance) Execute(ctx context.Context) error {
0, 0,
0, 0,
0, 0,
nil,
) )
if err != nil { if err != nil {
return err return err

View File

@ -57,6 +57,7 @@ func (mig *externalConfigChange) Execute(ctx context.Context) error {
0, 0,
0, 0,
0, 0,
nil,
) )
if err != nil { if err != nil {

View File

@ -202,6 +202,7 @@ func startZitadel(config *Config, masterKey string, server chan<- *Server) error
config.OIDC.DefaultAccessTokenLifetime, config.OIDC.DefaultAccessTokenLifetime,
config.OIDC.DefaultRefreshTokenExpiration, config.OIDC.DefaultRefreshTokenExpiration,
config.OIDC.DefaultRefreshTokenIdleExpiration, config.OIDC.DefaultRefreshTokenIdleExpiration,
config.DefaultInstance.SecretGenerators,
) )
if err != nil { if err != nil {
return fmt.Errorf("cannot start commands: %w", err) return fmt.Errorf("cannot start commands: %w", err)

View File

@ -71,6 +71,7 @@ type Commands struct {
privateKeyLifetime time.Duration privateKeyLifetime time.Duration
publicKeyLifetime time.Duration publicKeyLifetime time.Duration
certificateLifetime time.Duration certificateLifetime time.Duration
defaultSecretGenerators *SecretGenerators
} }
func StartCommands( func StartCommands(
@ -89,6 +90,7 @@ func StartCommands(
defaultAccessTokenLifetime, defaultAccessTokenLifetime,
defaultRefreshTokenLifetime, defaultRefreshTokenLifetime,
defaultRefreshTokenIdleLifetime time.Duration, defaultRefreshTokenIdleLifetime time.Duration,
defaultSecretGenerators *SecretGenerators,
) (repo *Commands, err error) { ) (repo *Commands, err error) {
if externalDomain == "" { if externalDomain == "" {
return nil, errors.ThrowInvalidArgument(nil, "COMMAND-Df21s", "no external domain specified") return nil, errors.ThrowInvalidArgument(nil, "COMMAND-Df21s", "no external domain specified")
@ -125,6 +127,7 @@ func StartCommands(
defaultAccessTokenLifetime: defaultAccessTokenLifetime, defaultAccessTokenLifetime: defaultAccessTokenLifetime,
defaultRefreshTokenLifetime: defaultRefreshTokenLifetime, defaultRefreshTokenLifetime: defaultRefreshTokenLifetime,
defaultRefreshTokenIdleLifetime: defaultRefreshTokenIdleLifetime, defaultRefreshTokenIdleLifetime: defaultRefreshTokenIdleLifetime,
defaultSecretGenerators: defaultSecretGenerators,
} }
instance_repo.RegisterEventMappers(repo.eventstore) instance_repo.RegisterEventMappers(repo.eventstore)

View File

@ -76,3 +76,26 @@ func secretGeneratorConfig(ctx context.Context, filter preparation.FilterToQuery
IncludeSymbols: wm.IncludeSymbols, IncludeSymbols: wm.IncludeSymbols,
}, nil }, nil
} }
func secretGeneratorConfigWithDefault(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, defaultGenerator *crypto.GeneratorConfig) (*crypto.GeneratorConfig, error) {
wm := NewInstanceSecretGeneratorConfigWriteModel(ctx, typ)
events, err := filter(ctx, wm.Query())
if err != nil {
return nil, err
}
wm.AppendEvents(events...)
if err := wm.Reduce(); err != nil {
return nil, err
}
if wm.State != domain.SecretGeneratorStateActive {
return defaultGenerator, nil
}
return &crypto.GeneratorConfig{
Length: wm.Length,
Expiry: wm.Expiry,
IncludeLowerLetters: wm.IncludeLowerLetters,
IncludeUpperLetters: wm.IncludeUpperLetters,
IncludeDigits: wm.IncludeDigits,
IncludeSymbols: wm.IncludeSymbols,
}, nil
}

View File

@ -34,23 +34,11 @@ const (
type InstanceSetup struct { type InstanceSetup struct {
zitadel ZitadelConfig zitadel ZitadelConfig
idGenerator id.Generator
InstanceName string InstanceName string
CustomDomain string CustomDomain string
DefaultLanguage language.Tag DefaultLanguage language.Tag
Org InstanceOrgSetup Org InstanceOrgSetup
SecretGenerators struct { SecretGenerators *SecretGenerators
PasswordSaltCost uint
ClientSecret *crypto.GeneratorConfig
InitializeUserCode *crypto.GeneratorConfig
EmailVerificationCode *crypto.GeneratorConfig
PhoneVerificationCode *crypto.GeneratorConfig
PasswordVerificationCode *crypto.GeneratorConfig
PasswordlessInitCode *crypto.GeneratorConfig
DomainVerification *crypto.GeneratorConfig
OTPSMS *crypto.GeneratorConfig
OTPEmail *crypto.GeneratorConfig
}
PasswordComplexityPolicy struct { PasswordComplexityPolicy struct {
MinLength uint64 MinLength uint64
HasLowercase bool HasLowercase bool
@ -126,6 +114,19 @@ type InstanceSetup struct {
} }
} }
type SecretGenerators struct {
PasswordSaltCost uint
ClientSecret *crypto.GeneratorConfig
InitializeUserCode *crypto.GeneratorConfig
EmailVerificationCode *crypto.GeneratorConfig
PhoneVerificationCode *crypto.GeneratorConfig
PasswordVerificationCode *crypto.GeneratorConfig
PasswordlessInitCode *crypto.GeneratorConfig
DomainVerification *crypto.GeneratorConfig
OTPSMS *crypto.GeneratorConfig
OTPEmail *crypto.GeneratorConfig
}
type ZitadelConfig struct { type ZitadelConfig struct {
projectID string projectID string
mgmtAppID string mgmtAppID string

View File

@ -278,6 +278,7 @@ func (c *Commands) HumanSendOTPSMS(ctx context.Context, userID, resourceOwner st
authRequest, authRequest,
smsWriteModel, smsWriteModel,
domain.SecretGeneratorTypeOTPSMS, domain.SecretGeneratorTypeOTPSMS,
c.defaultSecretGenerators.OTPSMS,
codeAddedEvent, codeAddedEvent,
) )
} }
@ -398,6 +399,7 @@ func (c *Commands) HumanSendOTPEmail(ctx context.Context, userID, resourceOwner
authRequest, authRequest,
smsWriteModel, smsWriteModel,
domain.SecretGeneratorTypeOTPEmail, domain.SecretGeneratorTypeOTPEmail,
c.defaultSecretGenerators.OTPEmail,
codeAddedEvent, codeAddedEvent,
) )
} }
@ -442,6 +444,7 @@ func (c *Commands) sendHumanOTP(
authRequest *domain.AuthRequest, authRequest *domain.AuthRequest,
writeModelByID func(ctx context.Context, userID string, resourceOwner string) (OTPWriteModel, error), writeModelByID func(ctx context.Context, userID string, resourceOwner string) (OTPWriteModel, error),
secretGeneratorType domain.SecretGeneratorType, secretGeneratorType domain.SecretGeneratorType,
defaultSecretGenerator *crypto.GeneratorConfig,
codeAddedEvent func(ctx context.Context, aggregate *eventstore.Aggregate, code *crypto.CryptoValue, expiry time.Duration, info *user.AuthRequestInfo) eventstore.Command, codeAddedEvent func(ctx context.Context, aggregate *eventstore.Aggregate, code *crypto.CryptoValue, expiry time.Duration, info *user.AuthRequestInfo) eventstore.Command,
) (err error) { ) (err error) {
if userID == "" { if userID == "" {
@ -454,7 +457,7 @@ func (c *Commands) sendHumanOTP(
if !existingOTP.OTPAdded() { if !existingOTP.OTPAdded() {
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SFD52", "Errors.User.MFA.OTP.NotReady") return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-SFD52", "Errors.User.MFA.OTP.NotReady")
} }
config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, secretGeneratorType) config, err := secretGeneratorConfigWithDefault(ctx, c.eventstore.Filter, secretGeneratorType, defaultSecretGenerator)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1249,9 +1249,20 @@ func TestCommandSide_RemoveHumanOTPSMS(t *testing.T) {
func TestCommandSide_HumanSendOTPSMS(t *testing.T) { func TestCommandSide_HumanSendOTPSMS(t *testing.T) {
ctx := authz.NewMockContext("inst1", "org1", "user1") ctx := authz.NewMockContext("inst1", "org1", "user1")
defaultGenerators := &SecretGenerators{
OTPSMS: &crypto.GeneratorConfig{
Length: 8,
Expiry: time.Hour,
IncludeLowerLetters: true,
IncludeUpperLetters: true,
IncludeDigits: true,
IncludeSymbols: true,
},
}
type fields struct { type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore eventstore func(*testing.T) *eventstore.Eventstore
userEncryption crypto.EncryptionAlgorithm userEncryption crypto.EncryptionAlgorithm
defaultSecretGenerators *SecretGenerators
} }
type ( type (
args struct { args struct {
@ -1275,6 +1286,7 @@ func TestCommandSide_HumanSendOTPSMS(t *testing.T) {
name: "userid missing, invalid argument error", name: "userid missing, invalid argument error",
fields: fields{ fields: fields{
eventstore: expectEventstore(), eventstore: expectEventstore(),
defaultSecretGenerators: defaultGenerators,
}, },
args: args{ args: args{
ctx: ctx, ctx: ctx,
@ -1291,6 +1303,7 @@ func TestCommandSide_HumanSendOTPSMS(t *testing.T) {
eventstore: expectEventstore( eventstore: expectEventstore(
expectFilter(), expectFilter(),
), ),
defaultSecretGenerators: defaultGenerators,
}, },
args: args{ args: args{
ctx: ctx, ctx: ctx,
@ -1344,6 +1357,51 @@ func TestCommandSide_HumanSendOTPSMS(t *testing.T) {
), ),
), ),
userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"), userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"),
defaultSecretGenerators: defaultGenerators,
},
args: args{
ctx: ctx,
userID: "user1",
resourceOwner: "org1",
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "successful add (without secret config)",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPSMSAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
),
),
),
expectFilter(),
expectPush(
[]*repository.Event{
eventFromEventPusherWithInstanceID("inst1",
user.NewHumanOTPSMSCodeAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("12345678"),
},
time.Hour,
nil,
),
),
},
),
),
userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"),
defaultSecretGenerators: defaultGenerators,
}, },
args: args{ args: args{
ctx: ctx, ctx: ctx,
@ -1407,6 +1465,7 @@ func TestCommandSide_HumanSendOTPSMS(t *testing.T) {
), ),
), ),
userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"), userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"),
defaultSecretGenerators: defaultGenerators,
}, },
args: args{ args: args{
ctx: ctx, ctx: ctx,
@ -1434,6 +1493,7 @@ func TestCommandSide_HumanSendOTPSMS(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore(t), eventstore: tt.fields.eventstore(t),
userEncryption: tt.fields.userEncryption, userEncryption: tt.fields.userEncryption,
defaultSecretGenerators: tt.fields.defaultSecretGenerators,
} }
err := r.HumanSendOTPSMS(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.authRequest) err := r.HumanSendOTPSMS(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.authRequest)
assert.ErrorIs(t, err, tt.res.err) assert.ErrorIs(t, err, tt.res.err)
@ -2176,9 +2236,20 @@ func TestCommandSide_RemoveHumanOTPEmail(t *testing.T) {
func TestCommandSide_HumanSendOTPEmail(t *testing.T) { func TestCommandSide_HumanSendOTPEmail(t *testing.T) {
ctx := authz.NewMockContext("inst1", "org1", "user1") ctx := authz.NewMockContext("inst1", "org1", "user1")
defaultGenerators := &SecretGenerators{
OTPEmail: &crypto.GeneratorConfig{
Length: 8,
Expiry: time.Hour,
IncludeLowerLetters: true,
IncludeUpperLetters: true,
IncludeDigits: true,
IncludeSymbols: true,
},
}
type fields struct { type fields struct {
eventstore func(*testing.T) *eventstore.Eventstore eventstore func(*testing.T) *eventstore.Eventstore
userEncryption crypto.EncryptionAlgorithm userEncryption crypto.EncryptionAlgorithm
defaultSecretGenerators *SecretGenerators
} }
type ( type (
args struct { args struct {
@ -2202,6 +2273,7 @@ func TestCommandSide_HumanSendOTPEmail(t *testing.T) {
name: "userid missing, invalid argument error", name: "userid missing, invalid argument error",
fields: fields{ fields: fields{
eventstore: expectEventstore(), eventstore: expectEventstore(),
defaultSecretGenerators: defaultGenerators,
}, },
args: args{ args: args{
ctx: ctx, ctx: ctx,
@ -2218,6 +2290,7 @@ func TestCommandSide_HumanSendOTPEmail(t *testing.T) {
eventstore: expectEventstore( eventstore: expectEventstore(
expectFilter(), expectFilter(),
), ),
defaultSecretGenerators: defaultGenerators,
}, },
args: args{ args: args{
ctx: ctx, ctx: ctx,
@ -2271,6 +2344,51 @@ func TestCommandSide_HumanSendOTPEmail(t *testing.T) {
), ),
), ),
userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"), userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"),
defaultSecretGenerators: defaultGenerators,
},
args: args{
ctx: ctx,
userID: "user1",
resourceOwner: "org1",
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "successful add (without secret config)",
fields: fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
user.NewHumanOTPEmailAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
),
),
),
expectFilter(),
expectPush(
[]*repository.Event{
eventFromEventPusherWithInstanceID("inst1",
user.NewHumanOTPEmailCodeAddedEvent(ctx,
&user.NewAggregate("user1", "org1").Aggregate,
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("12345678"),
},
time.Hour,
nil,
),
),
},
),
),
userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"),
defaultSecretGenerators: defaultGenerators,
}, },
args: args{ args: args{
ctx: ctx, ctx: ctx,
@ -2334,6 +2452,7 @@ func TestCommandSide_HumanSendOTPEmail(t *testing.T) {
), ),
), ),
userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"), userEncryption: crypto.CreateMockEncryptionAlgWithCode(gomock.NewController(t), "12345678"),
defaultSecretGenerators: defaultGenerators,
}, },
args: args{ args: args{
ctx: ctx, ctx: ctx,
@ -2361,6 +2480,7 @@ func TestCommandSide_HumanSendOTPEmail(t *testing.T) {
r := &Commands{ r := &Commands{
eventstore: tt.fields.eventstore(t), eventstore: tt.fields.eventstore(t),
userEncryption: tt.fields.userEncryption, userEncryption: tt.fields.userEncryption,
defaultSecretGenerators: tt.fields.defaultSecretGenerators,
} }
err := r.HumanSendOTPEmail(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.authRequest) err := r.HumanSendOTPEmail(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.authRequest)
assert.ErrorIs(t, err, tt.res.err) assert.ErrorIs(t, err, tt.res.err)