build(deps): update module github.com/go-crypt/crypt to v0.2.2 (#4452)
parent
87004ccb57
commit
0aa6745059
4
go.mod
4
go.mod
|
@ -11,7 +11,7 @@ require (
|
||||||
github.com/fasthttp/session/v2 v2.4.13
|
github.com/fasthttp/session/v2 v2.4.13
|
||||||
github.com/fsnotify/fsnotify v1.6.0
|
github.com/fsnotify/fsnotify v1.6.0
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4
|
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-ldap/ldap/v3 v3.4.4
|
||||||
github.com/go-rod/rod v0.112.2
|
github.com/go-rod/rod v0.112.2
|
||||||
github.com/go-sql-driver/mysql v1.7.0
|
github.com/go-sql-driver/mysql v1.7.0
|
||||||
|
@ -63,7 +63,7 @@ require (
|
||||||
github.com/ecordell/optgen v0.0.6 // indirect
|
github.com/ecordell/optgen v0.0.6 // indirect
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.4.0 // 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-redis/redis/v8 v8.11.5 // indirect
|
||||||
github.com/go-webauthn/revoke v0.1.6 // indirect
|
github.com/go-webauthn/revoke v0.1.6 // indirect
|
||||||
github.com/golang/glog v1.0.0 // indirect
|
github.com/golang/glog v1.0.0 // indirect
|
||||||
|
|
10
go.sum
10
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/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 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
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.2.2-0.20221204120525-4373dc528789 h1:y7pQxv0gsIDxE2tHivIDl/XPWengErnLp3gHziZO4aI=
|
||||||
github.com/go-crypt/crypt v0.1.14/go.mod h1:VNLdWMD0go46arq5WVZB2MV/9Vw02FOWhKDORXl7K2c=
|
github.com/go-crypt/crypt v0.2.2-0.20221204120525-4373dc528789/go.mod h1:7SeCrKOWqS3D2kHUVflBbWhL+MvLCZh+knAcnaFbjLM=
|
||||||
github.com/go-crypt/x v0.1.3 h1:3YSlHqOZsw4gcPzfqrcc5kg4GIhTKmkjl/ZVqJ3CbbU=
|
github.com/go-crypt/crypt v0.2.2-0.20221204130046-b13cb0ef6218 h1:UviO2jAV5i6WUy9HzaabOVVLuMBhnU//HrwkJ+ZcJBA=
|
||||||
github.com/go-crypt/x v0.1.3/go.mod h1:/6X1DjQki055ajXV/7pCHZM0OmMR1+csiXFkxK73Kc8=
|
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 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-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
|
|
@ -8,7 +8,12 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"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/configuration/schema"
|
||||||
"github.com/authelia/authelia/v4/internal/logging"
|
"github.com/authelia/authelia/v4/internal/logging"
|
||||||
|
@ -17,7 +22,7 @@ import (
|
||||||
// FileUserProvider is a provider reading details from a file.
|
// FileUserProvider is a provider reading details from a file.
|
||||||
type FileUserProvider struct {
|
type FileUserProvider struct {
|
||||||
config *schema.FileAuthenticationBackend
|
config *schema.FileAuthenticationBackend
|
||||||
hash crypt.Hash
|
hash algorithm.Hash
|
||||||
database *FileUserDatabase
|
database *FileUserDatabase
|
||||||
mutex *sync.Mutex
|
mutex *sync.Mutex
|
||||||
timeoutReload time.Time
|
timeoutReload time.Time
|
||||||
|
@ -145,39 +150,50 @@ func (p *FileUserProvider) setTimeoutReload(now time.Time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileCryptoHashFromConfig returns a crypt.Hash given a valid configuration.
|
// 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 {
|
switch config.Algorithm {
|
||||||
case hashArgon2, "":
|
case hashArgon2, "":
|
||||||
hash = crypt.NewArgon2Hash().
|
hash, err = argon2.New(
|
||||||
WithVariant(crypt.NewArgon2Variant(config.Argon2.Variant)).
|
argon2.WithVariantName(config.Argon2.Variant),
|
||||||
WithT(config.Argon2.Iterations).
|
argon2.WithT(config.Argon2.Iterations),
|
||||||
WithM(config.Argon2.Memory).
|
argon2.WithM(uint32(config.Argon2.Memory)),
|
||||||
WithP(config.Argon2.Parallelism).
|
argon2.WithP(config.Argon2.Parallelism),
|
||||||
WithK(config.Argon2.KeyLength).
|
argon2.WithK(config.Argon2.KeyLength),
|
||||||
WithS(config.Argon2.SaltLength)
|
argon2.WithS(config.Argon2.SaltLength),
|
||||||
|
)
|
||||||
case hashSHA2Crypt:
|
case hashSHA2Crypt:
|
||||||
hash = crypt.NewSHA2CryptHash().
|
hash, err = shacrypt.New(
|
||||||
WithVariant(crypt.NewSHA2CryptVariant(config.SHA2Crypt.Variant)).
|
shacrypt.WithVariantName(config.SHA2Crypt.Variant),
|
||||||
WithRounds(config.SHA2Crypt.Iterations).
|
shacrypt.WithIterations(config.SHA2Crypt.Iterations),
|
||||||
WithSaltLength(config.SHA2Crypt.SaltLength)
|
shacrypt.WithSaltLength(config.SHA2Crypt.SaltLength),
|
||||||
|
)
|
||||||
case hashPBKDF2:
|
case hashPBKDF2:
|
||||||
hash = crypt.NewPBKDF2Hash().
|
hash, err = pbkdf2.New(
|
||||||
WithVariant(crypt.NewPBKDF2Variant(config.PBKDF2.Variant)).
|
pbkdf2.WithVariantName(config.PBKDF2.Variant),
|
||||||
WithIterations(config.PBKDF2.Iterations).
|
pbkdf2.WithIterations(config.PBKDF2.Iterations),
|
||||||
WithSaltLength(config.PBKDF2.SaltLength)
|
pbkdf2.WithSaltLength(config.PBKDF2.SaltLength),
|
||||||
|
)
|
||||||
case hashSCrypt:
|
case hashSCrypt:
|
||||||
hash = crypt.NewScryptHash().
|
hash, err = scrypt.New(
|
||||||
WithLN(config.SCrypt.Iterations).
|
scrypt.WithLN(config.SCrypt.Iterations),
|
||||||
WithP(config.SCrypt.Parallelism).
|
scrypt.WithP(config.SCrypt.Parallelism),
|
||||||
WithR(config.SCrypt.BlockSize)
|
scrypt.WithR(config.SCrypt.BlockSize),
|
||||||
|
scrypt.WithKeyLength(config.SCrypt.KeyLength),
|
||||||
|
scrypt.WithSaltLength(config.SCrypt.SaltLength),
|
||||||
|
)
|
||||||
case hashBCrypt:
|
case hashBCrypt:
|
||||||
hash = crypt.NewBcryptHash().
|
hash, err = bcrypt.New(
|
||||||
WithVariant(crypt.NewBcryptVariant(config.BCrypt.Variant)).
|
bcrypt.WithVariantName(config.BCrypt.Variant),
|
||||||
WithCost(config.BCrypt.Cost)
|
bcrypt.WithIterations(config.BCrypt.Cost),
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("algorithm '%s' is unknown", config.Algorithm)
|
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 {
|
if err = hash.Validate(); err != nil {
|
||||||
return nil, fmt.Errorf("failed to validate hash settings: %w", err)
|
return nil, fmt.Errorf("failed to validate hash settings: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
"github.com/go-crypt/crypt"
|
"github.com/go-crypt/crypt"
|
||||||
|
"github.com/go-crypt/crypt/algorithm"
|
||||||
"gopkg.in/yaml.v3"
|
"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.
|
// DatabaseUserDetails is the model of user details in the file database.
|
||||||
type DatabaseUserDetails struct {
|
type DatabaseUserDetails struct {
|
||||||
Username string
|
Username string
|
||||||
Digest crypt.Digest
|
Digest algorithm.Digest
|
||||||
Disabled bool
|
Disabled bool
|
||||||
DisplayName string
|
DisplayName string
|
||||||
Email string
|
Email string
|
||||||
|
@ -308,7 +309,7 @@ type UserDetailsModel struct {
|
||||||
|
|
||||||
// ToDatabaseUserDetailsModel converts a UserDetailsModel into a *DatabaseUserDetails.
|
// ToDatabaseUserDetailsModel converts a UserDetailsModel into a *DatabaseUserDetails.
|
||||||
func (m UserDetailsModel) ToDatabaseUserDetailsModel(username string) (model *DatabaseUserDetails, err error) {
|
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 {
|
if d, err = crypt.Decode(m.HashedPassword); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -252,7 +252,7 @@ func TestShouldRaiseWhenLoadingDatabaseWithBadSHA512HashesForTheFirstTime(t *tes
|
||||||
|
|
||||||
provider := NewFileUserProvider(&config)
|
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)
|
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 '='")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-crypt/crypt"
|
"github.com/go-crypt/crypt"
|
||||||
|
"github.com/go-crypt/crypt/algorithm"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"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) {
|
func cmdCryptoHashGenerateFinish(cmd *cobra.Command, args []string, flagsMap map[string]string) (err error) {
|
||||||
var (
|
var (
|
||||||
algorithm string
|
algName string
|
||||||
configs []string
|
configs []string
|
||||||
|
|
||||||
c schema.Password
|
c schema.Password
|
||||||
)
|
)
|
||||||
|
@ -294,25 +295,25 @@ func cmdCryptoHashGenerateFinish(cmd *cobra.Command, args []string, flagsMap map
|
||||||
break
|
break
|
||||||
case legacy:
|
case legacy:
|
||||||
if sha512, _ := cmd.Flags().GetBool(cmdFlagNameSHA512); sha512 {
|
if sha512, _ := cmd.Flags().GetBool(cmdFlagNameSHA512); sha512 {
|
||||||
algorithm = cmdUseHashSHA2Crypt
|
algName = cmdUseHashSHA2Crypt
|
||||||
} else {
|
} else {
|
||||||
algorithm = cmdUseHashArgon2
|
algName = cmdUseHashArgon2
|
||||||
}
|
}
|
||||||
default:
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if legacy && algorithm == cmdUseHashArgon2 && cmd.Flags().Changed(cmdFlagNameMemory) {
|
if legacy && algName == cmdUseHashArgon2 && cmd.Flags().Changed(cmdFlagNameMemory) {
|
||||||
c.Argon2.Memory *= 1024
|
c.Argon2.Memory *= 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
hash crypt.Hash
|
hash algorithm.Hash
|
||||||
digest crypt.Digest
|
digest algorithm.Digest
|
||||||
password string
|
password string
|
||||||
random bool
|
random bool
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-crypt/crypt"
|
"github.com/go-crypt/crypt/algorithm/plaintext"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
|
@ -486,7 +486,7 @@ func StringToPrivateKeyHookFunc() mapstructure.DecodeHookFuncType {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringToPasswordDigestHookFunc decodes a string into a crypt.Digest.
|
// 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) {
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
||||||
var ptr bool
|
var ptr bool
|
||||||
|
|
||||||
|
@ -514,11 +514,11 @@ func StringToPasswordDigestHookFunc(plaintext bool) mapstructure.DecodeHookFuncT
|
||||||
var result *schema.PasswordDigest
|
var result *schema.PasswordDigest
|
||||||
|
|
||||||
if !strings.HasPrefix(dataStr, "$") {
|
if !strings.HasPrefix(dataStr, "$") {
|
||||||
dataStr = fmt.Sprintf(crypt.StorageFormatSimple, crypt.AlgorithmPrefixPlainText, dataStr)
|
dataStr = fmt.Sprintf(plaintext.EncodingFmt, plaintext.AlgIdentifierPlainText, dataStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if 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)
|
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, prefixType, expectedType.String(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ func unmarshal(ko *koanf.Koanf, val *schema.StructValidator, path string, o any)
|
||||||
StringToPrivateKeyHookFunc(),
|
StringToPrivateKeyHookFunc(),
|
||||||
StringToCryptoPrivateKeyHookFunc(),
|
StringToCryptoPrivateKeyHookFunc(),
|
||||||
StringToTLSVersionHookFunc(),
|
StringToTLSVersionHookFunc(),
|
||||||
StringToPasswordDigestHookFunc(true),
|
StringToPasswordDigestHookFunc(),
|
||||||
ToTimeDurationHookFunc(),
|
ToTimeDurationHookFunc(),
|
||||||
),
|
),
|
||||||
Metadata: nil,
|
Metadata: nil,
|
||||||
|
|
|
@ -16,6 +16,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-crypt/crypt"
|
"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.
|
// 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())
|
return net.Listen(a.Scheme, a.HostPort())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPasswordDigest returns a new PasswordDigest.
|
var cdecoder algorithm.DecoderRegister
|
||||||
func NewPasswordDigest(value string, plaintext bool) (digest *PasswordDigest, err error) {
|
|
||||||
var d crypt.Digest
|
|
||||||
|
|
||||||
switch {
|
// DecodePasswordDigest returns a new PasswordDigest if it can be decoded.
|
||||||
case plaintext:
|
func DecodePasswordDigest(encodedDigest string) (digest *PasswordDigest, err error) {
|
||||||
d, err = crypt.DecodeWithPlainText(value)
|
if cdecoder == nil {
|
||||||
default:
|
if cdecoder, err = crypt.NewDefaultDecoder(); err != nil {
|
||||||
d, err = crypt.Decode(value)
|
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 nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &PasswordDigest{d}, err
|
return &PasswordDigest{Digest: d}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordDigest is a configuration type for the crypt.Digest.
|
// PasswordDigest is a configuration type for the crypt.Digest.
|
||||||
type PasswordDigest struct {
|
type PasswordDigest struct {
|
||||||
crypt.Digest
|
algorithm.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewX509CertificateChain creates a new *X509CertificateChain from a given string, parsing each PEM block one by one.
|
// NewX509CertificateChain creates a new *X509CertificateChain from a given string, parsing each PEM block one by one.
|
||||||
|
|
|
@ -5,7 +5,11 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"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/configuration/schema"
|
||||||
"github.com/authelia/authelia/v4/internal/utils"
|
"github.com/authelia/authelia/v4/internal/utils"
|
||||||
|
@ -91,46 +95,48 @@ func validateFileAuthenticationBackendPasswordConfigArgon2(config *schema.Passwo
|
||||||
switch {
|
switch {
|
||||||
case config.Argon2.Iterations == 0:
|
case config.Argon2.Iterations == 0:
|
||||||
config.Argon2.Iterations = schema.DefaultPasswordConfig.Argon2.Iterations
|
config.Argon2.Iterations = schema.DefaultPasswordConfig.Argon2.Iterations
|
||||||
case config.Argon2.Iterations < crypt.Argon2IterationsMin:
|
case config.Argon2.Iterations < argon2.IterationsMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "iterations", config.Argon2.Iterations, crypt.Argon2IterationsMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "iterations", config.Argon2.Iterations, argon2.IterationsMin))
|
||||||
case config.Argon2.Iterations > crypt.Argon2IterationsMax:
|
case config.Argon2.Iterations > argon2.IterationsMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "iterations", config.Argon2.Iterations, crypt.Argon2IterationsMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "iterations", config.Argon2.Iterations, argon2.IterationsMax))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case config.Argon2.Parallelism == 0:
|
case config.Argon2.Parallelism == 0:
|
||||||
config.Argon2.Parallelism = schema.DefaultPasswordConfig.Argon2.Parallelism
|
config.Argon2.Parallelism = schema.DefaultPasswordConfig.Argon2.Parallelism
|
||||||
case config.Argon2.Parallelism < crypt.Argon2ParallelismMin:
|
case config.Argon2.Parallelism < argon2.ParallelismMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "parallelism", config.Argon2.Parallelism, crypt.Argon2ParallelismMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "parallelism", config.Argon2.Parallelism, argon2.ParallelismMin))
|
||||||
case config.Argon2.Parallelism > crypt.Argon2ParallelismMax:
|
case config.Argon2.Parallelism > argon2.ParallelismMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "parallelism", config.Argon2.Parallelism, crypt.Argon2ParallelismMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "parallelism", config.Argon2.Parallelism, argon2.ParallelismMax))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case config.Argon2.Memory == 0:
|
case config.Argon2.Memory == 0:
|
||||||
config.Argon2.Memory = schema.DefaultPasswordConfig.Argon2.Memory
|
config.Argon2.Memory = schema.DefaultPasswordConfig.Argon2.Memory
|
||||||
case config.Argon2.Memory < 0:
|
case config.Argon2.Memory < argon2.MemoryMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "memory", config.Argon2.Parallelism, 1))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "memory", config.Argon2.Memory, argon2.MemoryMin))
|
||||||
case config.Argon2.Memory < (crypt.Argon2MemoryMinParallelismMultiplier * config.Argon2.Parallelism):
|
case uint64(config.Argon2.Memory) > uint64(argon2.MemoryMax):
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordArgon2MemoryTooLow, config.Argon2.Memory, config.Argon2.Parallelism*crypt.Argon2MemoryMinParallelismMultiplier, config.Argon2.Parallelism, crypt.Argon2MemoryMinParallelismMultiplier))
|
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 {
|
switch {
|
||||||
case config.Argon2.KeyLength == 0:
|
case config.Argon2.KeyLength == 0:
|
||||||
config.Argon2.KeyLength = schema.DefaultPasswordConfig.Argon2.KeyLength
|
config.Argon2.KeyLength = schema.DefaultPasswordConfig.Argon2.KeyLength
|
||||||
case config.Argon2.KeyLength < crypt.Argon2KeySizeMin:
|
case config.Argon2.KeyLength < argon2.KeyLengthMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "key_length", config.Argon2.KeyLength, crypt.Argon2KeySizeMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "key_length", config.Argon2.KeyLength, argon2.KeyLengthMin))
|
||||||
case config.Argon2.KeyLength > crypt.Argon2KeySizeMax:
|
case config.Argon2.KeyLength > argon2.KeyLengthMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "key_length", config.Argon2.KeyLength, crypt.Argon2KeySizeMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "key_length", config.Argon2.KeyLength, argon2.KeyLengthMax))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case config.Argon2.SaltLength == 0:
|
case config.Argon2.SaltLength == 0:
|
||||||
config.Argon2.SaltLength = schema.DefaultPasswordConfig.Argon2.SaltLength
|
config.Argon2.SaltLength = schema.DefaultPasswordConfig.Argon2.SaltLength
|
||||||
case config.Argon2.SaltLength < crypt.Argon2SaltSizeMin:
|
case config.Argon2.SaltLength < argon2.SaltLengthMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "salt_length", config.Argon2.SaltLength, crypt.Argon2SaltSizeMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "salt_length", config.Argon2.SaltLength, argon2.SaltLengthMin))
|
||||||
case config.Argon2.SaltLength > crypt.Argon2SaltSizeMax:
|
case config.Argon2.SaltLength > argon2.SaltLengthMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "salt_length", config.Argon2.SaltLength, crypt.Argon2SaltSizeMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "salt_length", config.Argon2.SaltLength, argon2.SaltLengthMax))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,19 +153,19 @@ func validateFileAuthenticationBackendPasswordConfigSHA2Crypt(config *schema.Pas
|
||||||
switch {
|
switch {
|
||||||
case config.SHA2Crypt.Iterations == 0:
|
case config.SHA2Crypt.Iterations == 0:
|
||||||
config.SHA2Crypt.Iterations = schema.DefaultPasswordConfig.SHA2Crypt.Iterations
|
config.SHA2Crypt.Iterations = schema.DefaultPasswordConfig.SHA2Crypt.Iterations
|
||||||
case config.SHA2Crypt.Iterations < crypt.SHA2CryptIterationsMin:
|
case config.SHA2Crypt.Iterations < shacrypt.IterationsMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, crypt.SHA2CryptIterationsMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, shacrypt.IterationsMin))
|
||||||
case config.SHA2Crypt.Iterations > crypt.SHA2CryptIterationsMax:
|
case config.SHA2Crypt.Iterations > shacrypt.IterationsMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, crypt.SHA2CryptIterationsMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, shacrypt.IterationsMax))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case config.SHA2Crypt.SaltLength == 0:
|
case config.SHA2Crypt.SaltLength == 0:
|
||||||
config.SHA2Crypt.SaltLength = schema.DefaultPasswordConfig.SHA2Crypt.SaltLength
|
config.SHA2Crypt.SaltLength = schema.DefaultPasswordConfig.SHA2Crypt.SaltLength
|
||||||
case config.SHA2Crypt.SaltLength < crypt.SHA2CryptSaltSizeMin:
|
case config.SHA2Crypt.SaltLength < shacrypt.SaltLengthMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, crypt.SHA2CryptSaltSizeMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, shacrypt.SaltLengthMin))
|
||||||
case config.SHA2Crypt.SaltLength > crypt.SHA2CryptSaltSizeMax:
|
case config.SHA2Crypt.SaltLength > shacrypt.SaltLengthMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, crypt.SHA2CryptSaltSizeMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, shacrypt.SaltLengthMax))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,19 +182,19 @@ func validateFileAuthenticationBackendPasswordConfigPBKDF2(config *schema.Passwo
|
||||||
switch {
|
switch {
|
||||||
case config.PBKDF2.Iterations == 0:
|
case config.PBKDF2.Iterations == 0:
|
||||||
config.PBKDF2.Iterations = schema.DefaultPasswordConfig.PBKDF2.Iterations
|
config.PBKDF2.Iterations = schema.DefaultPasswordConfig.PBKDF2.Iterations
|
||||||
case config.PBKDF2.Iterations < crypt.PBKDF2IterationsMin:
|
case config.PBKDF2.Iterations < pbkdf2.IterationsMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "iterations", config.PBKDF2.Iterations, crypt.PBKDF2IterationsMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "iterations", config.PBKDF2.Iterations, pbkdf2.IterationsMin))
|
||||||
case config.PBKDF2.Iterations > crypt.PBKDF2IterationsMax:
|
case config.PBKDF2.Iterations > pbkdf2.IterationsMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "iterations", config.PBKDF2.Iterations, crypt.PBKDF2IterationsMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "iterations", config.PBKDF2.Iterations, pbkdf2.IterationsMax))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case config.PBKDF2.SaltLength == 0:
|
case config.PBKDF2.SaltLength == 0:
|
||||||
config.PBKDF2.SaltLength = schema.DefaultPasswordConfig.PBKDF2.SaltLength
|
config.PBKDF2.SaltLength = schema.DefaultPasswordConfig.PBKDF2.SaltLength
|
||||||
case config.PBKDF2.SaltLength < crypt.PBKDF2SaltSizeMin:
|
case config.PBKDF2.SaltLength < pbkdf2.SaltLengthMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, crypt.PBKDF2SaltSizeMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, pbkdf2.SaltLengthMin))
|
||||||
case config.PBKDF2.SaltLength > crypt.PBKDF2SaltSizeMax:
|
case config.PBKDF2.SaltLength > pbkdf2.SaltLengthMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, crypt.PBKDF2SaltSizeMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, pbkdf2.SaltLengthMax))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,53 +211,58 @@ func validateFileAuthenticationBackendPasswordConfigBCrypt(config *schema.Passwo
|
||||||
switch {
|
switch {
|
||||||
case config.BCrypt.Cost == 0:
|
case config.BCrypt.Cost == 0:
|
||||||
config.BCrypt.Cost = schema.DefaultPasswordConfig.BCrypt.Cost
|
config.BCrypt.Cost = schema.DefaultPasswordConfig.BCrypt.Cost
|
||||||
case config.BCrypt.Cost < crypt.BcryptCostMin:
|
case config.BCrypt.Cost < bcrypt.IterationsMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashBCrypt, "cost", config.BCrypt.Cost, crypt.BcryptCostMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashBCrypt, "cost", config.BCrypt.Cost, bcrypt.IterationsMin))
|
||||||
case config.BCrypt.Cost > crypt.BcryptCostMax:
|
case config.BCrypt.Cost > bcrypt.IterationsMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashBCrypt, "cost", config.BCrypt.Cost, crypt.BcryptCostMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashBCrypt, "cost", config.BCrypt.Cost, bcrypt.IterationsMax))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:gocyclo
|
||||||
func validateFileAuthenticationBackendPasswordConfigSCrypt(config *schema.Password, validator *schema.StructValidator) {
|
func validateFileAuthenticationBackendPasswordConfigSCrypt(config *schema.Password, validator *schema.StructValidator) {
|
||||||
switch {
|
switch {
|
||||||
case config.SCrypt.Iterations == 0:
|
case config.SCrypt.Iterations == 0:
|
||||||
config.SCrypt.Iterations = schema.DefaultPasswordConfig.SCrypt.Iterations
|
config.SCrypt.Iterations = schema.DefaultPasswordConfig.SCrypt.Iterations
|
||||||
case config.SCrypt.Iterations < crypt.ScryptIterationsMin:
|
case config.SCrypt.Iterations < scrypt.IterationsMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "iterations", config.SCrypt.Iterations, crypt.ScryptIterationsMin))
|
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 {
|
switch {
|
||||||
case config.SCrypt.BlockSize == 0:
|
case config.SCrypt.BlockSize == 0:
|
||||||
config.SCrypt.BlockSize = schema.DefaultPasswordConfig.SCrypt.BlockSize
|
config.SCrypt.BlockSize = schema.DefaultPasswordConfig.SCrypt.BlockSize
|
||||||
case config.SCrypt.BlockSize < crypt.ScryptBlockSizeMin:
|
case config.SCrypt.BlockSize < scrypt.BlockSizeMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "block_size", config.SCrypt.BlockSize, crypt.ScryptBlockSizeMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "block_size", config.SCrypt.BlockSize, scrypt.BlockSizeMin))
|
||||||
case config.SCrypt.BlockSize > crypt.ScryptBlockSizeMax:
|
case config.SCrypt.BlockSize > scrypt.BlockSizeMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "block_size", config.SCrypt.BlockSize, crypt.ScryptBlockSizeMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "block_size", config.SCrypt.BlockSize, scrypt.BlockSizeMax))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case config.SCrypt.Parallelism == 0:
|
case config.SCrypt.Parallelism == 0:
|
||||||
config.SCrypt.Parallelism = schema.DefaultPasswordConfig.SCrypt.Parallelism
|
config.SCrypt.Parallelism = schema.DefaultPasswordConfig.SCrypt.Parallelism
|
||||||
case config.SCrypt.Parallelism < crypt.ScryptParallelismMin:
|
case config.SCrypt.Parallelism < scrypt.ParallelismMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "parallelism", config.SCrypt.Parallelism, crypt.ScryptParallelismMin))
|
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 {
|
switch {
|
||||||
case config.SCrypt.KeyLength == 0:
|
case config.SCrypt.KeyLength == 0:
|
||||||
config.SCrypt.KeyLength = schema.DefaultPasswordConfig.SCrypt.KeyLength
|
config.SCrypt.KeyLength = schema.DefaultPasswordConfig.SCrypt.KeyLength
|
||||||
case config.SCrypt.KeyLength < crypt.ScryptKeySizeMin:
|
case config.SCrypt.KeyLength < scrypt.KeyLengthMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "key_length", config.SCrypt.KeyLength, crypt.ScryptKeySizeMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "key_length", config.SCrypt.KeyLength, scrypt.KeyLengthMin))
|
||||||
case config.SCrypt.KeyLength > crypt.ScryptKeySizeMax:
|
case config.SCrypt.KeyLength > scrypt.KeyLengthMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "key_length", config.SCrypt.KeyLength, crypt.ScryptKeySizeMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "key_length", config.SCrypt.KeyLength, scrypt.KeyLengthMax))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case config.SCrypt.SaltLength == 0:
|
case config.SCrypt.SaltLength == 0:
|
||||||
config.SCrypt.SaltLength = schema.DefaultPasswordConfig.SCrypt.SaltLength
|
config.SCrypt.SaltLength = schema.DefaultPasswordConfig.SCrypt.SaltLength
|
||||||
case config.SCrypt.SaltLength < crypt.ScryptSaltSizeMin:
|
case config.SCrypt.SaltLength < scrypt.SaltLengthMin:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "salt_length", config.SCrypt.SaltLength, crypt.ScryptSaltSizeMin))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "salt_length", config.SCrypt.SaltLength, scrypt.SaltLengthMin))
|
||||||
case config.SCrypt.SaltLength > crypt.ScryptSaltSizeMax:
|
case config.SCrypt.SaltLength > scrypt.SaltLengthMax:
|
||||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "salt_length", config.SCrypt.SaltLength, crypt.ScryptSaltSizeMax))
|
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "salt_length", config.SCrypt.SaltLength, scrypt.SaltLengthMax))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -409,18 +409,22 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSCryptOptio
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSCryptOptionsTooHigh() {
|
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSCryptOptionsTooHigh() {
|
||||||
|
suite.config.File.Password.SCrypt.Iterations = 59
|
||||||
suite.config.File.Password.SCrypt.BlockSize = 360287970189639672
|
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.KeyLength = 1374389534409
|
||||||
suite.config.File.Password.SCrypt.SaltLength = 2147483647
|
suite.config.File.Password.SCrypt.SaltLength = 2147483647
|
||||||
|
|
||||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
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()[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 'key_length' is configured as '1374389534409' but must be less than or equal to '137438953440'")
|
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 'salt_length' is configured as '2147483647' but must be less than or equal to '1024'")
|
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() {
|
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()[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()[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()[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'")
|
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() {
|
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2OptionsTooHigh() {
|
||||||
suite.config.File.Password.Argon2.Iterations = 9999999999
|
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.Parallelism = 16777216
|
||||||
suite.config.File.Password.Argon2.KeyLength = 9999999998
|
suite.config.File.Password.Argon2.KeyLength = 9999999998
|
||||||
suite.config.File.Password.Argon2.SaltLength = 9999999997
|
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()[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()[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()[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'")
|
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.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
suite.Require().Len(suite.validator.Errors(), 1)
|
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() {
|
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenBadAlgorithmDefined() {
|
||||||
|
|
|
@ -838,7 +838,7 @@ func TestValidateOIDCClientRedirectURIsSupportingPrivateUseURISchemes(t *testing
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustDecodeSecret(value string) *schema.PasswordDigest {
|
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)
|
panic(err)
|
||||||
} else {
|
} else {
|
||||||
return secret
|
return secret
|
||||||
|
|
|
@ -227,7 +227,7 @@ func TestClient_IsPublic(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustDecodeSecret(value string) *schema.PasswordDigest {
|
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)
|
panic(err)
|
||||||
} else {
|
} else {
|
||||||
return secret
|
return secret
|
||||||
|
|
|
@ -66,6 +66,7 @@ type Config struct {
|
||||||
JWTScopeField jwt.JWTScopeFieldEnum
|
JWTScopeField jwt.JWTScopeFieldEnum
|
||||||
JWTMaxDuration time.Duration
|
JWTMaxDuration time.Duration
|
||||||
|
|
||||||
|
Hasher *AdaptiveHasher
|
||||||
Hash HashConfig
|
Hash HashConfig
|
||||||
Strategy StrategyConfig
|
Strategy StrategyConfig
|
||||||
PAR PARConfig
|
PAR PARConfig
|
||||||
|
@ -513,7 +514,7 @@ func (c *Config) GetTokenURL(ctx context.Context) (tokenURL string) {
|
||||||
// GetSecretsHasher returns the client secrets hashing function.
|
// GetSecretsHasher returns the client secrets hashing function.
|
||||||
func (c *Config) GetSecretsHasher(ctx context.Context) (hasher fosite.Hasher) {
|
func (c *Config) GetSecretsHasher(ctx context.Context) (hasher fosite.Hasher) {
|
||||||
if c.Hash.ClientSecrets == nil {
|
if c.Hash.ClientSecrets == nil {
|
||||||
c.Hash.ClientSecrets = &AdaptiveHasher{}
|
c.Hash.ClientSecrets, _ = NewAdaptiveHasher()
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Hash.ClientSecrets
|
return c.Hash.ClientSecrets
|
||||||
|
|
|
@ -4,13 +4,34 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/go-crypt/crypt"
|
"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 NewAdaptiveHasher() (hasher *AdaptiveHasher, err error) {
|
||||||
func (h AdaptiveHasher) Compare(_ context.Context, hash, data []byte) (err error) {
|
hasher = &AdaptiveHasher{}
|
||||||
var digest crypt.Digest
|
|
||||||
|
|
||||||
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +43,6 @@ func (h AdaptiveHasher) Compare(_ context.Context, hash, data []byte) (err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash creates a new hash from data.
|
// 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
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,32 +5,46 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestShouldNotRaiseErrorOnEqualPasswordsPlainText(t *testing.T) {
|
func TestShouldNotRaiseErrorOnEqualPasswordsPlainText(t *testing.T) {
|
||||||
hasher := AdaptiveHasher{}
|
hasher, err := NewAdaptiveHasher()
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
a := []byte("$plaintext$abc")
|
a := []byte("$plaintext$abc")
|
||||||
b := []byte("abc")
|
b := []byte("abc")
|
||||||
|
|
||||||
ctx := context.Background()
|
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) {
|
func TestShouldRaiseErrorOnNonEqualPasswordsPlainText(t *testing.T) {
|
||||||
hasher := AdaptiveHasher{}
|
hasher, err := NewAdaptiveHasher()
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
a := []byte("$plaintext$abc")
|
a := []byte("$plaintext$abc")
|
||||||
b := []byte("abcd")
|
b := []byte("abcd")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
err := hasher.Compare(ctx, a, b)
|
assert.Equal(t, errPasswordsDoNotMatch, hasher.Compare(ctx, a, b))
|
||||||
|
|
||||||
assert.Equal(t, errPasswordsDoNotMatch, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldHashPassword(t *testing.T) {
|
func TestShouldHashPassword(t *testing.T) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-crypt/crypt"
|
"github.com/go-crypt/crypt/algorithm"
|
||||||
"github.com/ory/fosite"
|
"github.com/ory/fosite"
|
||||||
"github.com/ory/fosite/handler/openid"
|
"github.com/ory/fosite/handler/openid"
|
||||||
"github.com/ory/fosite/token/jwt"
|
"github.com/ory/fosite/token/jwt"
|
||||||
|
@ -103,7 +103,7 @@ type Store struct {
|
||||||
type Client struct {
|
type Client struct {
|
||||||
ID string
|
ID string
|
||||||
Description string
|
Description string
|
||||||
Secret crypt.Digest
|
Secret algorithm.Digest
|
||||||
SectorIdentifier string
|
SectorIdentifier string
|
||||||
Public bool
|
Public bool
|
||||||
|
|
||||||
|
@ -184,9 +184,6 @@ type KeyManager struct {
|
||||||
jwks *jose.JSONWebKeySet
|
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.
|
// ConsentGetResponseBody schema of the response body of the consent GET endpoint.
|
||||||
type ConsentGetResponseBody struct {
|
type ConsentGetResponseBody struct {
|
||||||
ClientID string `json:"client_id"`
|
ClientID string `json:"client_id"`
|
||||||
|
|
Loading…
Reference in New Issue