zitadel/internal/command/crypto.go
Tim Möhlmann 2089992d75
feat(crypto): use passwap for machine and app secrets (#7657)
* feat(crypto): use passwap for machine and app secrets

* fix command package tests

* add hash generator command test

* naming convention, fix query tests

* rename PasswordHasher and cleanup start commands

* add reducer tests

* fix intergration tests, cleanup old config

* add app secret unit tests

* solve setup panics

* fix push of updated events

* add missing event translations

* update documentation

* solve linter errors

* remove nolint:SA1019 as it doesn't seem to help anyway

* add nolint to deprecated filter usage

* update users migration version

* remove unused ClientSecret from APIConfigChangedEvent

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
2024-04-05 09:35:49 +00:00

99 lines
4.0 KiB
Go

package command
import (
"context"
"time"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
)
type encrypedCodeFunc func(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm) (*EncryptedCode, error)
type encryptedCodeWithDefaultFunc func(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm, defaultConfig *crypto.GeneratorConfig) (*EncryptedCode, error)
var emptyConfig = &crypto.GeneratorConfig{}
type EncryptedCode struct {
Crypted *crypto.CryptoValue
Plain string
Expiry time.Duration
}
func newEncryptedCode(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm) (*EncryptedCode, error) {
return newEncryptedCodeWithDefaultConfig(ctx, filter, typ, alg, emptyConfig)
}
func newEncryptedCodeWithDefaultConfig(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm, defaultConfig *crypto.GeneratorConfig) (*EncryptedCode, error) {
gen, config, err := encryptedCodeGenerator(ctx, filter, typ, alg, defaultConfig)
if err != nil {
return nil, err
}
crypted, plain, err := crypto.NewCode(gen)
if err != nil {
return nil, err
}
return &EncryptedCode{
Crypted: crypted,
Plain: plain,
Expiry: config.Expiry,
}, nil
}
func verifyEncryptedCode(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm, creation time.Time, expiry time.Duration, crypted *crypto.CryptoValue, plain string) error {
gen, _, err := encryptedCodeGenerator(ctx, filter, typ, alg, emptyConfig)
if err != nil {
return err
}
return crypto.VerifyCode(creation, expiry, crypted, plain, gen.Alg())
}
func encryptedCodeGenerator(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm, defaultConfig *crypto.GeneratorConfig) (crypto.Generator, *crypto.GeneratorConfig, error) {
config, err := cryptoGeneratorConfigWithDefault(ctx, filter, typ, defaultConfig)
if err != nil {
return nil, nil, err
}
return crypto.NewEncryptionGenerator(*config, alg), config, nil
}
type hashedSecretFunc func(ctx context.Context, filter preparation.FilterToQueryReducer) (encodedHash, plain string, err error)
func newHashedSecretWithDefault(hasher *crypto.Hasher, defaultConfig *crypto.GeneratorConfig) hashedSecretFunc {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) (encodedHash string, plain string, err error) {
config, err := cryptoGeneratorConfigWithDefault(ctx, filter, domain.SecretGeneratorTypeAppSecret, defaultConfig)
if err != nil {
return "", "", err
}
generator := crypto.NewHashGenerator(*config, hasher)
return generator.NewCode()
}
}
func cryptoGeneratorConfig(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType) (*crypto.GeneratorConfig, error) {
return cryptoGeneratorConfigWithDefault(ctx, filter, typ, emptyConfig)
}
func cryptoGeneratorConfigWithDefault(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, defaultConfig *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 defaultConfig, nil
}
return &crypto.GeneratorConfig{
Length: wm.Length,
Expiry: wm.Expiry,
IncludeLowerLetters: wm.IncludeLowerLetters,
IncludeUpperLetters: wm.IncludeUpperLetters,
IncludeDigits: wm.IncludeDigits,
IncludeSymbols: wm.IncludeSymbols,
}, nil
}