From 0aa674505928f1d1d28f70db777710f5c7a4713a Mon Sep 17 00:00:00 2001 From: James Elliott Date: Mon, 5 Dec 2022 09:37:08 +1100 Subject: [PATCH] build(deps): update module github.com/go-crypt/crypt to v0.2.2 (#4452) --- go.mod | 4 +- go.sum | 10 +- internal/authentication/file_user_provider.go | 66 +++++---- .../file_user_provider_database.go | 5 +- .../authentication/file_user_provider_test.go | 4 +- internal/commands/crypto_hash.go | 19 +-- internal/configuration/decode_hooks.go | 8 +- internal/configuration/provider.go | 2 +- internal/configuration/schema/types.go | 29 ++-- .../configuration/validator/authentication.go | 125 ++++++++++-------- .../validator/authentication_test.go | 30 ++++- .../validator/identity_providers_test.go | 2 +- internal/oidc/client_test.go | 2 +- internal/oidc/config.go | 3 +- internal/oidc/hasher.go | 31 ++++- internal/oidc/hasher_test.go | 28 +++- internal/oidc/types.go | 7 +- 17 files changed, 232 insertions(+), 143 deletions(-) diff --git a/go.mod b/go.mod index 64590c58c..86ddc399f 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/fasthttp/session/v2 v2.4.13 github.com/fsnotify/fsnotify v1.6.0 github.com/go-asn1-ber/asn1-ber v1.5.4 - github.com/go-crypt/crypt v0.1.14 + github.com/go-crypt/crypt v0.2.2-0.20221204130046-b13cb0ef6218 github.com/go-ldap/ldap/v3 v3.4.4 github.com/go-rod/rod v0.112.2 github.com/go-sql-driver/mysql v1.7.0 @@ -63,7 +63,7 @@ require ( github.com/ecordell/optgen v0.0.6 // indirect github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect - github.com/go-crypt/x v0.1.3 // indirect + github.com/go-crypt/x v0.1.7 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-webauthn/revoke v0.1.6 // indirect github.com/golang/glog v1.0.0 // indirect diff --git a/go.sum b/go.sum index 7a1d2593e..420915d70 100644 --- a/go.sum +++ b/go.sum @@ -162,10 +162,12 @@ github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrt github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-crypt/crypt v0.1.14 h1:Pd8iBYlbwDXJNi0lz8CS/qYvpvxCfP0XO/f5PYvVQ4o= -github.com/go-crypt/crypt v0.1.14/go.mod h1:VNLdWMD0go46arq5WVZB2MV/9Vw02FOWhKDORXl7K2c= -github.com/go-crypt/x v0.1.3 h1:3YSlHqOZsw4gcPzfqrcc5kg4GIhTKmkjl/ZVqJ3CbbU= -github.com/go-crypt/x v0.1.3/go.mod h1:/6X1DjQki055ajXV/7pCHZM0OmMR1+csiXFkxK73Kc8= +github.com/go-crypt/crypt v0.2.2-0.20221204120525-4373dc528789 h1:y7pQxv0gsIDxE2tHivIDl/XPWengErnLp3gHziZO4aI= +github.com/go-crypt/crypt v0.2.2-0.20221204120525-4373dc528789/go.mod h1:7SeCrKOWqS3D2kHUVflBbWhL+MvLCZh+knAcnaFbjLM= +github.com/go-crypt/crypt v0.2.2-0.20221204130046-b13cb0ef6218 h1:UviO2jAV5i6WUy9HzaabOVVLuMBhnU//HrwkJ+ZcJBA= +github.com/go-crypt/crypt v0.2.2-0.20221204130046-b13cb0ef6218/go.mod h1:7SeCrKOWqS3D2kHUVflBbWhL+MvLCZh+knAcnaFbjLM= +github.com/go-crypt/x v0.1.7 h1:iSkIkmwFlRLrPraB2rge7WIjomAlSUHI+H200p9pPdc= +github.com/go-crypt/x v0.1.7/go.mod h1:io9lPvPf2qNHWLZWdvxjXT7Z4zBGRNvWq60t/vqrBgY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= diff --git a/internal/authentication/file_user_provider.go b/internal/authentication/file_user_provider.go index 1099b47be..9da2c4178 100644 --- a/internal/authentication/file_user_provider.go +++ b/internal/authentication/file_user_provider.go @@ -8,7 +8,12 @@ import ( "sync" "time" - "github.com/go-crypt/crypt" + "github.com/go-crypt/crypt/algorithm" + "github.com/go-crypt/crypt/algorithm/argon2" + "github.com/go-crypt/crypt/algorithm/bcrypt" + "github.com/go-crypt/crypt/algorithm/pbkdf2" + "github.com/go-crypt/crypt/algorithm/scrypt" + "github.com/go-crypt/crypt/algorithm/shacrypt" "github.com/authelia/authelia/v4/internal/configuration/schema" "github.com/authelia/authelia/v4/internal/logging" @@ -17,7 +22,7 @@ import ( // FileUserProvider is a provider reading details from a file. type FileUserProvider struct { config *schema.FileAuthenticationBackend - hash crypt.Hash + hash algorithm.Hash database *FileUserDatabase mutex *sync.Mutex timeoutReload time.Time @@ -145,39 +150,50 @@ func (p *FileUserProvider) setTimeoutReload(now time.Time) { } // NewFileCryptoHashFromConfig returns a crypt.Hash given a valid configuration. -func NewFileCryptoHashFromConfig(config schema.Password) (hash crypt.Hash, err error) { +func NewFileCryptoHashFromConfig(config schema.Password) (hash algorithm.Hash, err error) { switch config.Algorithm { case hashArgon2, "": - hash = crypt.NewArgon2Hash(). - WithVariant(crypt.NewArgon2Variant(config.Argon2.Variant)). - WithT(config.Argon2.Iterations). - WithM(config.Argon2.Memory). - WithP(config.Argon2.Parallelism). - WithK(config.Argon2.KeyLength). - WithS(config.Argon2.SaltLength) + hash, err = argon2.New( + argon2.WithVariantName(config.Argon2.Variant), + argon2.WithT(config.Argon2.Iterations), + argon2.WithM(uint32(config.Argon2.Memory)), + argon2.WithP(config.Argon2.Parallelism), + argon2.WithK(config.Argon2.KeyLength), + argon2.WithS(config.Argon2.SaltLength), + ) case hashSHA2Crypt: - hash = crypt.NewSHA2CryptHash(). - WithVariant(crypt.NewSHA2CryptVariant(config.SHA2Crypt.Variant)). - WithRounds(config.SHA2Crypt.Iterations). - WithSaltLength(config.SHA2Crypt.SaltLength) + hash, err = shacrypt.New( + shacrypt.WithVariantName(config.SHA2Crypt.Variant), + shacrypt.WithIterations(config.SHA2Crypt.Iterations), + shacrypt.WithSaltLength(config.SHA2Crypt.SaltLength), + ) case hashPBKDF2: - hash = crypt.NewPBKDF2Hash(). - WithVariant(crypt.NewPBKDF2Variant(config.PBKDF2.Variant)). - WithIterations(config.PBKDF2.Iterations). - WithSaltLength(config.PBKDF2.SaltLength) + hash, err = pbkdf2.New( + pbkdf2.WithVariantName(config.PBKDF2.Variant), + pbkdf2.WithIterations(config.PBKDF2.Iterations), + pbkdf2.WithSaltLength(config.PBKDF2.SaltLength), + ) case hashSCrypt: - hash = crypt.NewScryptHash(). - WithLN(config.SCrypt.Iterations). - WithP(config.SCrypt.Parallelism). - WithR(config.SCrypt.BlockSize) + hash, err = scrypt.New( + scrypt.WithLN(config.SCrypt.Iterations), + scrypt.WithP(config.SCrypt.Parallelism), + scrypt.WithR(config.SCrypt.BlockSize), + scrypt.WithKeyLength(config.SCrypt.KeyLength), + scrypt.WithSaltLength(config.SCrypt.SaltLength), + ) case hashBCrypt: - hash = crypt.NewBcryptHash(). - WithVariant(crypt.NewBcryptVariant(config.BCrypt.Variant)). - WithCost(config.BCrypt.Cost) + hash, err = bcrypt.New( + bcrypt.WithVariantName(config.BCrypt.Variant), + bcrypt.WithIterations(config.BCrypt.Cost), + ) default: return nil, fmt.Errorf("algorithm '%s' is unknown", config.Algorithm) } + if err != nil { + return nil, fmt.Errorf("failed to initialize hash settings: %w", err) + } + if err = hash.Validate(); err != nil { return nil, fmt.Errorf("failed to validate hash settings: %w", err) } diff --git a/internal/authentication/file_user_provider_database.go b/internal/authentication/file_user_provider_database.go index 4d710e34b..509f025e0 100644 --- a/internal/authentication/file_user_provider_database.go +++ b/internal/authentication/file_user_provider_database.go @@ -8,6 +8,7 @@ import ( "github.com/asaskevich/govalidator" "github.com/go-crypt/crypt" + "github.com/go-crypt/crypt/algorithm" "gopkg.in/yaml.v3" ) @@ -203,7 +204,7 @@ func (m *FileUserDatabase) ToDatabaseModel() (model *DatabaseModel) { // DatabaseUserDetails is the model of user details in the file database. type DatabaseUserDetails struct { Username string - Digest crypt.Digest + Digest algorithm.Digest Disabled bool DisplayName string Email string @@ -308,7 +309,7 @@ type UserDetailsModel struct { // ToDatabaseUserDetailsModel converts a UserDetailsModel into a *DatabaseUserDetails. func (m UserDetailsModel) ToDatabaseUserDetailsModel(username string) (model *DatabaseUserDetails, err error) { - var d crypt.Digest + var d algorithm.Digest if d, err = crypt.Decode(m.HashedPassword); err != nil { return nil, err diff --git a/internal/authentication/file_user_provider_test.go b/internal/authentication/file_user_provider_test.go index 4b6039f69..feb26700b 100644 --- a/internal/authentication/file_user_provider_test.go +++ b/internal/authentication/file_user_provider_test.go @@ -252,7 +252,7 @@ func TestShouldRaiseWhenLoadingDatabaseWithBadSHA512HashesForTheFirstTime(t *tes provider := NewFileUserProvider(&config) - assert.EqualError(t, provider.StartupCheck(), "error decoding the authentication database: failed to parse hash for user 'john': sha2crypt decode error: provided encoded hash has an invalid option: option 'rounds00000' is invalid") + assert.EqualError(t, provider.StartupCheck(), "error decoding the authentication database: failed to parse hash for user 'john': shacrypt decode error: parameter pair 'rounds00000' is not properly encoded: does not contain kv separator '='") }) } @@ -263,7 +263,7 @@ func TestShouldRaiseWhenLoadingDatabaseWithBadArgon2idHashSettingsForTheFirstTim provider := NewFileUserProvider(&config) - assert.EqualError(t, provider.StartupCheck(), "error decoding the authentication database: failed to parse hash for user 'john': argon2 decode error: provided encoded hash has an invalid option: option 'm65536' is invalid") + assert.EqualError(t, provider.StartupCheck(), "error decoding the authentication database: failed to parse hash for user 'john': argon2 decode error: parameter pair 'm65536' is not properly encoded: does not contain kv separator '='") }) } diff --git a/internal/commands/crypto_hash.go b/internal/commands/crypto_hash.go index 282abbd45..317a875af 100644 --- a/internal/commands/crypto_hash.go +++ b/internal/commands/crypto_hash.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/go-crypt/crypt" + "github.com/go-crypt/crypt/algorithm" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -272,8 +273,8 @@ func newCryptoHashValidateCmd() (cmd *cobra.Command) { func cmdCryptoHashGenerateFinish(cmd *cobra.Command, args []string, flagsMap map[string]string) (err error) { var ( - algorithm string - configs []string + algName string + configs []string c schema.Password ) @@ -294,25 +295,25 @@ func cmdCryptoHashGenerateFinish(cmd *cobra.Command, args []string, flagsMap map break case legacy: if sha512, _ := cmd.Flags().GetBool(cmdFlagNameSHA512); sha512 { - algorithm = cmdUseHashSHA2Crypt + algName = cmdUseHashSHA2Crypt } else { - algorithm = cmdUseHashArgon2 + algName = cmdUseHashArgon2 } default: - algorithm = cmd.Use + algName = cmd.Use } - if c, err = cmdCryptoHashGetConfig(algorithm, configs, cmd.Flags(), flagsMap); err != nil { + if c, err = cmdCryptoHashGetConfig(algName, configs, cmd.Flags(), flagsMap); err != nil { return err } - if legacy && algorithm == cmdUseHashArgon2 && cmd.Flags().Changed(cmdFlagNameMemory) { + if legacy && algName == cmdUseHashArgon2 && cmd.Flags().Changed(cmdFlagNameMemory) { c.Argon2.Memory *= 1024 } var ( - hash crypt.Hash - digest crypt.Digest + hash algorithm.Hash + digest algorithm.Digest password string random bool ) diff --git a/internal/configuration/decode_hooks.go b/internal/configuration/decode_hooks.go index a5872627f..5f059e8be 100644 --- a/internal/configuration/decode_hooks.go +++ b/internal/configuration/decode_hooks.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "github.com/go-crypt/crypt" + "github.com/go-crypt/crypt/algorithm/plaintext" "github.com/mitchellh/mapstructure" "github.com/authelia/authelia/v4/internal/configuration/schema" @@ -486,7 +486,7 @@ func StringToPrivateKeyHookFunc() mapstructure.DecodeHookFuncType { } // StringToPasswordDigestHookFunc decodes a string into a crypt.Digest. -func StringToPasswordDigestHookFunc(plaintext bool) mapstructure.DecodeHookFuncType { +func StringToPasswordDigestHookFunc() mapstructure.DecodeHookFuncType { return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) { var ptr bool @@ -514,11 +514,11 @@ func StringToPasswordDigestHookFunc(plaintext bool) mapstructure.DecodeHookFuncT var result *schema.PasswordDigest if !strings.HasPrefix(dataStr, "$") { - dataStr = fmt.Sprintf(crypt.StorageFormatSimple, crypt.AlgorithmPrefixPlainText, dataStr) + dataStr = fmt.Sprintf(plaintext.EncodingFmt, plaintext.AlgIdentifierPlainText, dataStr) } if dataStr != "" { - if result, err = schema.NewPasswordDigest(dataStr, plaintext); err != nil { + if result, err = schema.DecodePasswordDigest(dataStr); err != nil { return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, prefixType, expectedType.String(), err) } } diff --git a/internal/configuration/provider.go b/internal/configuration/provider.go index e64a3b661..b19585bd6 100644 --- a/internal/configuration/provider.go +++ b/internal/configuration/provider.go @@ -66,7 +66,7 @@ func unmarshal(ko *koanf.Koanf, val *schema.StructValidator, path string, o any) StringToPrivateKeyHookFunc(), StringToCryptoPrivateKeyHookFunc(), StringToTLSVersionHookFunc(), - StringToPasswordDigestHookFunc(true), + StringToPasswordDigestHookFunc(), ToTimeDurationHookFunc(), ), Metadata: nil, diff --git a/internal/configuration/schema/types.go b/internal/configuration/schema/types.go index ee4ed3934..342a81fc7 100644 --- a/internal/configuration/schema/types.go +++ b/internal/configuration/schema/types.go @@ -16,6 +16,8 @@ import ( "time" "github.com/go-crypt/crypt" + "github.com/go-crypt/crypt/algorithm" + "github.com/go-crypt/crypt/algorithm/plaintext" ) // NewAddressFromString returns an *Address and error depending on the ability to parse the string as an Address. @@ -110,27 +112,32 @@ func (a Address) Listener() (net.Listener, error) { return net.Listen(a.Scheme, a.HostPort()) } -// NewPasswordDigest returns a new PasswordDigest. -func NewPasswordDigest(value string, plaintext bool) (digest *PasswordDigest, err error) { - var d crypt.Digest +var cdecoder algorithm.DecoderRegister - switch { - case plaintext: - d, err = crypt.DecodeWithPlainText(value) - default: - d, err = crypt.Decode(value) +// DecodePasswordDigest returns a new PasswordDigest if it can be decoded. +func DecodePasswordDigest(encodedDigest string) (digest *PasswordDigest, err error) { + if cdecoder == nil { + if cdecoder, err = crypt.NewDefaultDecoder(); err != nil { + return nil, fmt.Errorf("failed to initialize decoder: %w", err) + } + + if err = plaintext.RegisterDecoderPlainText(cdecoder); err != nil { + return nil, fmt.Errorf("failed to initialize decoder: could not register the plaintext decoder: %w", err) + } } - if err != nil { + var d algorithm.Digest + + if d, err = cdecoder.Decode(encodedDigest); err != nil { return nil, err } - return &PasswordDigest{d}, err + return &PasswordDigest{Digest: d}, nil } // PasswordDigest is a configuration type for the crypt.Digest. type PasswordDigest struct { - crypt.Digest + algorithm.Digest } // NewX509CertificateChain creates a new *X509CertificateChain from a given string, parsing each PEM block one by one. diff --git a/internal/configuration/validator/authentication.go b/internal/configuration/validator/authentication.go index 62fe289b2..5aa74bba6 100644 --- a/internal/configuration/validator/authentication.go +++ b/internal/configuration/validator/authentication.go @@ -5,7 +5,11 @@ import ( "net/url" "strings" - "github.com/go-crypt/crypt" + "github.com/go-crypt/crypt/algorithm/argon2" + "github.com/go-crypt/crypt/algorithm/bcrypt" + "github.com/go-crypt/crypt/algorithm/pbkdf2" + "github.com/go-crypt/crypt/algorithm/scrypt" + "github.com/go-crypt/crypt/algorithm/shacrypt" "github.com/authelia/authelia/v4/internal/configuration/schema" "github.com/authelia/authelia/v4/internal/utils" @@ -91,46 +95,48 @@ func validateFileAuthenticationBackendPasswordConfigArgon2(config *schema.Passwo switch { case config.Argon2.Iterations == 0: config.Argon2.Iterations = schema.DefaultPasswordConfig.Argon2.Iterations - case config.Argon2.Iterations < crypt.Argon2IterationsMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "iterations", config.Argon2.Iterations, crypt.Argon2IterationsMin)) - case config.Argon2.Iterations > crypt.Argon2IterationsMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "iterations", config.Argon2.Iterations, crypt.Argon2IterationsMax)) + case config.Argon2.Iterations < argon2.IterationsMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "iterations", config.Argon2.Iterations, argon2.IterationsMin)) + case config.Argon2.Iterations > argon2.IterationsMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "iterations", config.Argon2.Iterations, argon2.IterationsMax)) } switch { case config.Argon2.Parallelism == 0: config.Argon2.Parallelism = schema.DefaultPasswordConfig.Argon2.Parallelism - case config.Argon2.Parallelism < crypt.Argon2ParallelismMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "parallelism", config.Argon2.Parallelism, crypt.Argon2ParallelismMin)) - case config.Argon2.Parallelism > crypt.Argon2ParallelismMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "parallelism", config.Argon2.Parallelism, crypt.Argon2ParallelismMax)) + case config.Argon2.Parallelism < argon2.ParallelismMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "parallelism", config.Argon2.Parallelism, argon2.ParallelismMin)) + case config.Argon2.Parallelism > argon2.ParallelismMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "parallelism", config.Argon2.Parallelism, argon2.ParallelismMax)) } switch { case config.Argon2.Memory == 0: config.Argon2.Memory = schema.DefaultPasswordConfig.Argon2.Memory - case config.Argon2.Memory < 0: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "memory", config.Argon2.Parallelism, 1)) - case config.Argon2.Memory < (crypt.Argon2MemoryMinParallelismMultiplier * config.Argon2.Parallelism): - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordArgon2MemoryTooLow, config.Argon2.Memory, config.Argon2.Parallelism*crypt.Argon2MemoryMinParallelismMultiplier, config.Argon2.Parallelism, crypt.Argon2MemoryMinParallelismMultiplier)) + case config.Argon2.Memory < argon2.MemoryMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "memory", config.Argon2.Memory, argon2.MemoryMin)) + case uint64(config.Argon2.Memory) > uint64(argon2.MemoryMax): + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "memory", config.Argon2.Memory, argon2.MemoryMax)) + case config.Argon2.Memory < (config.Argon2.Parallelism * argon2.MemoryMinParallelismMultiplier): + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordArgon2MemoryTooLow, config.Argon2.Memory, config.Argon2.Parallelism*argon2.MemoryMinParallelismMultiplier, config.Argon2.Parallelism, argon2.MemoryMinParallelismMultiplier)) } switch { case config.Argon2.KeyLength == 0: config.Argon2.KeyLength = schema.DefaultPasswordConfig.Argon2.KeyLength - case config.Argon2.KeyLength < crypt.Argon2KeySizeMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "key_length", config.Argon2.KeyLength, crypt.Argon2KeySizeMin)) - case config.Argon2.KeyLength > crypt.Argon2KeySizeMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "key_length", config.Argon2.KeyLength, crypt.Argon2KeySizeMax)) + case config.Argon2.KeyLength < argon2.KeyLengthMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "key_length", config.Argon2.KeyLength, argon2.KeyLengthMin)) + case config.Argon2.KeyLength > argon2.KeyLengthMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "key_length", config.Argon2.KeyLength, argon2.KeyLengthMax)) } switch { case config.Argon2.SaltLength == 0: config.Argon2.SaltLength = schema.DefaultPasswordConfig.Argon2.SaltLength - case config.Argon2.SaltLength < crypt.Argon2SaltSizeMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "salt_length", config.Argon2.SaltLength, crypt.Argon2SaltSizeMin)) - case config.Argon2.SaltLength > crypt.Argon2SaltSizeMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "salt_length", config.Argon2.SaltLength, crypt.Argon2SaltSizeMax)) + case config.Argon2.SaltLength < argon2.SaltLengthMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "salt_length", config.Argon2.SaltLength, argon2.SaltLengthMin)) + case config.Argon2.SaltLength > argon2.SaltLengthMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "salt_length", config.Argon2.SaltLength, argon2.SaltLengthMax)) } } @@ -147,19 +153,19 @@ func validateFileAuthenticationBackendPasswordConfigSHA2Crypt(config *schema.Pas switch { case config.SHA2Crypt.Iterations == 0: config.SHA2Crypt.Iterations = schema.DefaultPasswordConfig.SHA2Crypt.Iterations - case config.SHA2Crypt.Iterations < crypt.SHA2CryptIterationsMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, crypt.SHA2CryptIterationsMin)) - case config.SHA2Crypt.Iterations > crypt.SHA2CryptIterationsMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, crypt.SHA2CryptIterationsMax)) + case config.SHA2Crypt.Iterations < shacrypt.IterationsMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, shacrypt.IterationsMin)) + case config.SHA2Crypt.Iterations > shacrypt.IterationsMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, shacrypt.IterationsMax)) } switch { case config.SHA2Crypt.SaltLength == 0: config.SHA2Crypt.SaltLength = schema.DefaultPasswordConfig.SHA2Crypt.SaltLength - case config.SHA2Crypt.SaltLength < crypt.SHA2CryptSaltSizeMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, crypt.SHA2CryptSaltSizeMin)) - case config.SHA2Crypt.SaltLength > crypt.SHA2CryptSaltSizeMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, crypt.SHA2CryptSaltSizeMax)) + case config.SHA2Crypt.SaltLength < shacrypt.SaltLengthMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, shacrypt.SaltLengthMin)) + case config.SHA2Crypt.SaltLength > shacrypt.SaltLengthMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, shacrypt.SaltLengthMax)) } } @@ -176,19 +182,19 @@ func validateFileAuthenticationBackendPasswordConfigPBKDF2(config *schema.Passwo switch { case config.PBKDF2.Iterations == 0: config.PBKDF2.Iterations = schema.DefaultPasswordConfig.PBKDF2.Iterations - case config.PBKDF2.Iterations < crypt.PBKDF2IterationsMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "iterations", config.PBKDF2.Iterations, crypt.PBKDF2IterationsMin)) - case config.PBKDF2.Iterations > crypt.PBKDF2IterationsMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "iterations", config.PBKDF2.Iterations, crypt.PBKDF2IterationsMax)) + case config.PBKDF2.Iterations < pbkdf2.IterationsMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "iterations", config.PBKDF2.Iterations, pbkdf2.IterationsMin)) + case config.PBKDF2.Iterations > pbkdf2.IterationsMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "iterations", config.PBKDF2.Iterations, pbkdf2.IterationsMax)) } switch { case config.PBKDF2.SaltLength == 0: config.PBKDF2.SaltLength = schema.DefaultPasswordConfig.PBKDF2.SaltLength - case config.PBKDF2.SaltLength < crypt.PBKDF2SaltSizeMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, crypt.PBKDF2SaltSizeMin)) - case config.PBKDF2.SaltLength > crypt.PBKDF2SaltSizeMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, crypt.PBKDF2SaltSizeMax)) + case config.PBKDF2.SaltLength < pbkdf2.SaltLengthMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, pbkdf2.SaltLengthMin)) + case config.PBKDF2.SaltLength > pbkdf2.SaltLengthMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, pbkdf2.SaltLengthMax)) } } @@ -205,53 +211,58 @@ func validateFileAuthenticationBackendPasswordConfigBCrypt(config *schema.Passwo switch { case config.BCrypt.Cost == 0: config.BCrypt.Cost = schema.DefaultPasswordConfig.BCrypt.Cost - case config.BCrypt.Cost < crypt.BcryptCostMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashBCrypt, "cost", config.BCrypt.Cost, crypt.BcryptCostMin)) - case config.BCrypt.Cost > crypt.BcryptCostMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashBCrypt, "cost", config.BCrypt.Cost, crypt.BcryptCostMax)) + case config.BCrypt.Cost < bcrypt.IterationsMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashBCrypt, "cost", config.BCrypt.Cost, bcrypt.IterationsMin)) + case config.BCrypt.Cost > bcrypt.IterationsMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashBCrypt, "cost", config.BCrypt.Cost, bcrypt.IterationsMax)) } } +//nolint:gocyclo func validateFileAuthenticationBackendPasswordConfigSCrypt(config *schema.Password, validator *schema.StructValidator) { switch { case config.SCrypt.Iterations == 0: config.SCrypt.Iterations = schema.DefaultPasswordConfig.SCrypt.Iterations - case config.SCrypt.Iterations < crypt.ScryptIterationsMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "iterations", config.SCrypt.Iterations, crypt.ScryptIterationsMin)) + case config.SCrypt.Iterations < scrypt.IterationsMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "iterations", config.SCrypt.Iterations, scrypt.IterationsMin)) + case config.SCrypt.Iterations > scrypt.IterationsMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "iterations", config.SCrypt.Iterations, scrypt.IterationsMax)) } switch { case config.SCrypt.BlockSize == 0: config.SCrypt.BlockSize = schema.DefaultPasswordConfig.SCrypt.BlockSize - case config.SCrypt.BlockSize < crypt.ScryptBlockSizeMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "block_size", config.SCrypt.BlockSize, crypt.ScryptBlockSizeMin)) - case config.SCrypt.BlockSize > crypt.ScryptBlockSizeMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "block_size", config.SCrypt.BlockSize, crypt.ScryptBlockSizeMax)) + case config.SCrypt.BlockSize < scrypt.BlockSizeMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "block_size", config.SCrypt.BlockSize, scrypt.BlockSizeMin)) + case config.SCrypt.BlockSize > scrypt.BlockSizeMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "block_size", config.SCrypt.BlockSize, scrypt.BlockSizeMax)) } switch { case config.SCrypt.Parallelism == 0: config.SCrypt.Parallelism = schema.DefaultPasswordConfig.SCrypt.Parallelism - case config.SCrypt.Parallelism < crypt.ScryptParallelismMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "parallelism", config.SCrypt.Parallelism, crypt.ScryptParallelismMin)) + case config.SCrypt.Parallelism < scrypt.ParallelismMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "parallelism", config.SCrypt.Parallelism, scrypt.ParallelismMin)) + case config.SCrypt.Parallelism > scrypt.ParallelismMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "parallelism", config.SCrypt.Parallelism, scrypt.ParallelismMax)) } switch { case config.SCrypt.KeyLength == 0: config.SCrypt.KeyLength = schema.DefaultPasswordConfig.SCrypt.KeyLength - case config.SCrypt.KeyLength < crypt.ScryptKeySizeMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "key_length", config.SCrypt.KeyLength, crypt.ScryptKeySizeMin)) - case config.SCrypt.KeyLength > crypt.ScryptKeySizeMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "key_length", config.SCrypt.KeyLength, crypt.ScryptKeySizeMax)) + case config.SCrypt.KeyLength < scrypt.KeyLengthMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "key_length", config.SCrypt.KeyLength, scrypt.KeyLengthMin)) + case config.SCrypt.KeyLength > scrypt.KeyLengthMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "key_length", config.SCrypt.KeyLength, scrypt.KeyLengthMax)) } switch { case config.SCrypt.SaltLength == 0: config.SCrypt.SaltLength = schema.DefaultPasswordConfig.SCrypt.SaltLength - case config.SCrypt.SaltLength < crypt.ScryptSaltSizeMin: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "salt_length", config.SCrypt.SaltLength, crypt.ScryptSaltSizeMin)) - case config.SCrypt.SaltLength > crypt.ScryptSaltSizeMax: - validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "salt_length", config.SCrypt.SaltLength, crypt.ScryptSaltSizeMax)) + case config.SCrypt.SaltLength < scrypt.SaltLengthMin: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "salt_length", config.SCrypt.SaltLength, scrypt.SaltLengthMin)) + case config.SCrypt.SaltLength > scrypt.SaltLengthMax: + validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "salt_length", config.SCrypt.SaltLength, scrypt.SaltLengthMax)) } } diff --git a/internal/configuration/validator/authentication_test.go b/internal/configuration/validator/authentication_test.go index 5f589063c..61482b53a 100644 --- a/internal/configuration/validator/authentication_test.go +++ b/internal/configuration/validator/authentication_test.go @@ -409,18 +409,22 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSCryptOptio } func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSCryptOptionsTooHigh() { + suite.config.File.Password.SCrypt.Iterations = 59 suite.config.File.Password.SCrypt.BlockSize = 360287970189639672 + suite.config.File.Password.SCrypt.Parallelism = 1073741825 suite.config.File.Password.SCrypt.KeyLength = 1374389534409 suite.config.File.Password.SCrypt.SaltLength = 2147483647 ValidateAuthenticationBackend(&suite.config, suite.validator) suite.Assert().Len(suite.validator.Warnings(), 0) - suite.Require().Len(suite.validator.Errors(), 3) + suite.Require().Len(suite.validator.Errors(), 5) - suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: scrypt: option 'block_size' is configured as '360287970189639672' but must be less than or equal to '36028797018963967'") - suite.Assert().EqualError(suite.validator.Errors()[1], "authentication_backend: file: password: scrypt: option 'key_length' is configured as '1374389534409' but must be less than or equal to '137438953440'") - suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: scrypt: option 'salt_length' is configured as '2147483647' but must be less than or equal to '1024'") + suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: scrypt: option 'iterations' is configured as '59' but must be less than or equal to '58'") + suite.Assert().EqualError(suite.validator.Errors()[1], "authentication_backend: file: password: scrypt: option 'block_size' is configured as '360287970189639672' but must be less than or equal to '36028797018963967'") + suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: scrypt: option 'parallelism' is configured as '1073741825' but must be less than or equal to '1073741823'") + suite.Assert().EqualError(suite.validator.Errors()[3], "authentication_backend: file: password: scrypt: option 'key_length' is configured as '1374389534409' but must be less than or equal to '137438953440'") + suite.Assert().EqualError(suite.validator.Errors()[4], "authentication_backend: file: password: scrypt: option 'salt_length' is configured as '2147483647' but must be less than or equal to '1024'") } func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2OptionsTooLow() { @@ -437,13 +441,14 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2Optio suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'iterations' is configured as '-1' but must be greater than or equal to '1'") suite.Assert().EqualError(suite.validator.Errors()[1], "authentication_backend: file: password: argon2: option 'parallelism' is configured as '-1' but must be greater than or equal to '1'") - suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: argon2: option 'memory' is configured as '-1' but must be greater than or equal to '1'") + suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: argon2: option 'memory' is configured as '-1' but must be greater than or equal to '8'") suite.Assert().EqualError(suite.validator.Errors()[3], "authentication_backend: file: password: argon2: option 'key_length' is configured as '1' but must be greater than or equal to '4'") suite.Assert().EqualError(suite.validator.Errors()[4], "authentication_backend: file: password: argon2: option 'salt_length' is configured as '-1' but must be greater than or equal to '1'") } func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2OptionsTooHigh() { suite.config.File.Password.Argon2.Iterations = 9999999999 + suite.config.File.Password.Argon2.Memory = 4294967296 suite.config.File.Password.Argon2.Parallelism = 16777216 suite.config.File.Password.Argon2.KeyLength = 9999999998 suite.config.File.Password.Argon2.SaltLength = 9999999997 @@ -455,6 +460,7 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2Optio suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'iterations' is configured as '9999999999' but must be less than or equal to '2147483647'") suite.Assert().EqualError(suite.validator.Errors()[1], "authentication_backend: file: password: argon2: option 'parallelism' is configured as '16777216' but must be less than or equal to '16777215'") + suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: argon2: option 'memory' is configured as '4294967296' but must be less than or equal to '4294967295'") suite.Assert().EqualError(suite.validator.Errors()[3], "authentication_backend: file: password: argon2: option 'key_length' is configured as '9999999998' but must be less than or equal to '2147483647'") suite.Assert().EqualError(suite.validator.Errors()[4], "authentication_backend: file: password: argon2: option 'salt_length' is configured as '9999999997' but must be less than or equal to '2147483647'") } @@ -468,7 +474,19 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2Memor suite.Assert().Len(suite.validator.Warnings(), 0) suite.Require().Len(suite.validator.Errors(), 1) - suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'memory' is configured as '4' but must be greater than or equal to '32' or '4' (the value of 'parallelism) multiplied by '8'") + suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'memory' is configured as '4' but must be greater than or equal to '8'") +} + +func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2MemoryTooLowMultiplier() { + suite.config.File.Password.Argon2.Memory = 8 + suite.config.File.Password.Argon2.Parallelism = 4 + + ValidateAuthenticationBackend(&suite.config, suite.validator) + + suite.Assert().Len(suite.validator.Warnings(), 0) + suite.Require().Len(suite.validator.Errors(), 1) + + suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'memory' is configured as '8' but must be greater than or equal to '32' or '4' (the value of 'parallelism) multiplied by '8'") } func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenBadAlgorithmDefined() { diff --git a/internal/configuration/validator/identity_providers_test.go b/internal/configuration/validator/identity_providers_test.go index fad289432..32118a066 100644 --- a/internal/configuration/validator/identity_providers_test.go +++ b/internal/configuration/validator/identity_providers_test.go @@ -838,7 +838,7 @@ func TestValidateOIDCClientRedirectURIsSupportingPrivateUseURISchemes(t *testing } func MustDecodeSecret(value string) *schema.PasswordDigest { - if secret, err := schema.NewPasswordDigest(value, true); err != nil { + if secret, err := schema.DecodePasswordDigest(value); err != nil { panic(err) } else { return secret diff --git a/internal/oidc/client_test.go b/internal/oidc/client_test.go index 01722d21a..1f1a7b860 100644 --- a/internal/oidc/client_test.go +++ b/internal/oidc/client_test.go @@ -227,7 +227,7 @@ func TestClient_IsPublic(t *testing.T) { } func MustDecodeSecret(value string) *schema.PasswordDigest { - if secret, err := schema.NewPasswordDigest(value, true); err != nil { + if secret, err := schema.DecodePasswordDigest(value); err != nil { panic(err) } else { return secret diff --git a/internal/oidc/config.go b/internal/oidc/config.go index 5be51eed8..89949980d 100644 --- a/internal/oidc/config.go +++ b/internal/oidc/config.go @@ -66,6 +66,7 @@ type Config struct { JWTScopeField jwt.JWTScopeFieldEnum JWTMaxDuration time.Duration + Hasher *AdaptiveHasher Hash HashConfig Strategy StrategyConfig PAR PARConfig @@ -513,7 +514,7 @@ func (c *Config) GetTokenURL(ctx context.Context) (tokenURL string) { // GetSecretsHasher returns the client secrets hashing function. func (c *Config) GetSecretsHasher(ctx context.Context) (hasher fosite.Hasher) { if c.Hash.ClientSecrets == nil { - c.Hash.ClientSecrets = &AdaptiveHasher{} + c.Hash.ClientSecrets, _ = NewAdaptiveHasher() } return c.Hash.ClientSecrets diff --git a/internal/oidc/hasher.go b/internal/oidc/hasher.go index 7aad32b25..746f92ced 100644 --- a/internal/oidc/hasher.go +++ b/internal/oidc/hasher.go @@ -4,13 +4,34 @@ import ( "context" "github.com/go-crypt/crypt" + "github.com/go-crypt/crypt/algorithm" + "github.com/go-crypt/crypt/algorithm/plaintext" ) -// Compare compares the hash with the data and returns an error if they don't match. -func (h AdaptiveHasher) Compare(_ context.Context, hash, data []byte) (err error) { - var digest crypt.Digest +func NewAdaptiveHasher() (hasher *AdaptiveHasher, err error) { + hasher = &AdaptiveHasher{} - if digest, err = crypt.DecodeWithPlainText(string(hash)); err != nil { + if hasher.decoder, err = crypt.NewDefaultDecoder(); err != nil { + return nil, err + } + + if err = plaintext.RegisterDecoderPlainText(hasher.decoder); err != nil { + return nil, err + } + + return hasher, nil +} + +// AdaptiveHasher implements the fosite.Hasher interface without an actual hashing algo. +type AdaptiveHasher struct { + decoder algorithm.DecoderRegister +} + +// Compare compares the hash with the data and returns an error if they don't match. +func (h *AdaptiveHasher) Compare(_ context.Context, hash, data []byte) (err error) { + var digest algorithm.Digest + + if digest, err = h.decoder.Decode(string(hash)); err != nil { return err } @@ -22,6 +43,6 @@ func (h AdaptiveHasher) Compare(_ context.Context, hash, data []byte) (err error } // Hash creates a new hash from data. -func (h AdaptiveHasher) Hash(_ context.Context, data []byte) (hash []byte, err error) { +func (h *AdaptiveHasher) Hash(_ context.Context, data []byte) (hash []byte, err error) { return data, nil } diff --git a/internal/oidc/hasher_test.go b/internal/oidc/hasher_test.go index bc3dfac1b..04f1b0f41 100644 --- a/internal/oidc/hasher_test.go +++ b/internal/oidc/hasher_test.go @@ -5,32 +5,46 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestShouldNotRaiseErrorOnEqualPasswordsPlainText(t *testing.T) { - hasher := AdaptiveHasher{} + hasher, err := NewAdaptiveHasher() + + require.NoError(t, err) a := []byte("$plaintext$abc") b := []byte("abc") ctx := context.Background() - err := hasher.Compare(ctx, a, b) + assert.NoError(t, hasher.Compare(ctx, a, b)) +} - assert.NoError(t, err) +func TestShouldNotRaiseErrorOnEqualPasswordsPlainTextWithSeparator(t *testing.T) { + hasher, err := NewAdaptiveHasher() + + require.NoError(t, err) + + a := []byte("$plaintext$abc$123") + b := []byte("abc$123") + + ctx := context.Background() + + assert.NoError(t, hasher.Compare(ctx, a, b)) } func TestShouldRaiseErrorOnNonEqualPasswordsPlainText(t *testing.T) { - hasher := AdaptiveHasher{} + hasher, err := NewAdaptiveHasher() + + require.NoError(t, err) a := []byte("$plaintext$abc") b := []byte("abcd") ctx := context.Background() - err := hasher.Compare(ctx, a, b) - - assert.Equal(t, errPasswordsDoNotMatch, err) + assert.Equal(t, errPasswordsDoNotMatch, hasher.Compare(ctx, a, b)) } func TestShouldHashPassword(t *testing.T) { diff --git a/internal/oidc/types.go b/internal/oidc/types.go index 41f35373b..58328d119 100644 --- a/internal/oidc/types.go +++ b/internal/oidc/types.go @@ -4,7 +4,7 @@ import ( "net/url" "time" - "github.com/go-crypt/crypt" + "github.com/go-crypt/crypt/algorithm" "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/token/jwt" @@ -103,7 +103,7 @@ type Store struct { type Client struct { ID string Description string - Secret crypt.Digest + Secret algorithm.Digest SectorIdentifier string Public bool @@ -184,9 +184,6 @@ type KeyManager struct { jwks *jose.JSONWebKeySet } -// AdaptiveHasher implements the fosite.Hasher interface without an actual hashing algo. -type AdaptiveHasher struct{} - // ConsentGetResponseBody schema of the response body of the consent GET endpoint. type ConsentGetResponseBody struct { ClientID string `json:"client_id"`