[BUGFIX] Password hashing schema map mismatch with docs (#852)

* add a nolint for gosec 'possibly hardcoded password' that was incorrect
* make all parameters consistent
* update the docs for the correct key name 'password' instead of 'password_options' or 'password_hashing'
* reword some of the docs
* apply suggestions from code review

Co-Authored-By: Amir Zarrinkafsh <nightah@me.com>
pull/855/head
James Elliott 2020-04-11 13:54:18 +10:00 committed by GitHub
parent b0f81380c2
commit b3ce7fc379
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 177 additions and 165 deletions

View File

@ -140,7 +140,7 @@ authentication_backend:
# which is updated when users reset their passwords. # which is updated when users reset their passwords.
# Therefore, this backend is meant to be used in a dev environment # Therefore, this backend is meant to be used in a dev environment
# and not in production since it prevents Authelia to be scaled to # and not in production since it prevents Authelia to be scaled to
# more than one instance. The options under password_options have sane # more than one instance. The options under 'password' have sane
# defaults, and as it has security implications it is highly recommended # defaults, and as it has security implications it is highly recommended
# you leave the default values. Before considering changing these settings # you leave the default values. Before considering changing these settings
# please read the docs page below: # please read the docs page below:
@ -148,7 +148,7 @@ authentication_backend:
# #
## file: ## file:
## path: ./users_database.yml ## path: ./users_database.yml
## password_options: ## password:
## algorithm: argon2id ## algorithm: argon2id
## iterations: 1 ## iterations: 1
## key_length: 32 ## key_length: 32

View File

@ -19,7 +19,7 @@ file in the configuration file.
disable_reset_password: false disable_reset_password: false
file: file:
path: /var/lib/authelia/users.yml path: /var/lib/authelia/users.yml
password_hashing: password:
algorithm: argon2id algorithm: argon2id
iterations: 1 iterations: 1
salt_length: 16 salt_length: 16
@ -97,26 +97,38 @@ Flags:
## Password hash algorithm ## Password hash algorithm
The default hash algorithm is salted Argon2id version 19. Argon2id is currently considered The default hash algorithm is Argon2id version 19 with a salt. Argon2id is currently considered
the best hashing algorithm, and in 2015 won the the best hashing algorithm, and in 2015 won the
[Password Hashing Competition](https://en.wikipedia.org/wiki/Password_Hashing_Competition). [Password Hashing Competition](https://en.wikipedia.org/wiki/Password_Hashing_Competition).
It benefits from customizable parameters allowing the cost of computing a hash to scale It benefits from customizable parameters allowing the cost of computing a hash to scale
into the future which makes it harder to brute-force. Argon2id was implemented due to community into the future which makes it harder to brute-force. Argon2id was implemented due to community
feedback as you can see in this closed [issue](https://github.com/authelia/authelia/issues/577). feedback as you can see in this closed [issue](https://github.com/authelia/authelia/issues/577).
Additionally SHA512 is supported for backwards compatibility and user choice. While it's a reasonable For backwards compatibility and user choice support for the SHA512 algorithm is still available.
hash function given high enough iterations, as hardware gets better it has a higher chance of being While it's a reasonable hashing function given high enough iterations, as hardware improves it
brute-forced. has a higher chance of being brute-forced.
Hashes are identifiable as argon2id or SHA512 by their prefix of either `$argon2id$` and `$6$` Hashes are identifiable as argon2id or SHA512 by their prefix of either `$argon2id$` and `$6$`
respectively, as described in this [wiki page](https://en.wikipedia.org/wiki/Crypt_(C)). respectively, as described in this [wiki page](https://en.wikipedia.org/wiki/Crypt_(C)).
**Important Note:** When using argon2id Authelia will appear to remain using the memory allocated
to creating the hash. This is due to how [Go](https://golang.org/) allocates memory to the heap when
generating an argon2id hash. Go periodically garbage collects the heap, however this doesn't remove
the memory allocation, it keeps it allocated even though it's technically unused. Under memory
pressure the unused allocated memory will be reclaimed by the operating system, you can test
this on linux with
`stress-ng --vm-bytes $(awk '/MemFree/{printf "%d\n", $2 * 0.9;}' < /proc/meminfo)k --vm-keep -m 1`.
If this is not desirable we recommend investigating the following options in order of most to least secure:
1. using the [LDAP authentication provider](./ldap.md)
2. adjusting the [memory](#memory) parameter
3. changing the [algorithm](#algorithm)
### Password hash algorithm tuning ### Password hash algorithm tuning
All algorithm tuning is supported for Argon2id. The only configuration variables that affect All algorithm tuning for Argon2id is supported. The only configuration variables that affect
SHA512 are iterations and salt length. The configuration variables are unique to the file SHA512 are iterations and salt length. The configuration variables are unique to the file
authentication provider, thus they all exist in a key under the file authentication configuration authentication provider, thus they all exist in a key under the file authentication configuration
key called `password_hashing`. We have set what are considered as sane and recommended defaults key called `password`. We have set what are considered as sane and recommended defaults
to cater for a reasonable system, if you're unsure about which settings to tune, please see the to cater for a reasonable system, if you're unsure about which settings to tune, please see the
parameters below, or for a more in depth understanding see the referenced documentation in parameters below, or for a more in depth understanding see the referenced documentation in
[Argon2 links](./file.md#argon2-links). [Argon2 links](./file.md#argon2-links).

View File

@ -118,18 +118,18 @@ func (p *FileUserProvider) UpdatePassword(username string, newPassword string) e
} }
var algorithm string var algorithm string
if p.configuration.PasswordHashing.Algorithm == "argon2id" { if p.configuration.Password.Algorithm == "argon2id" {
algorithm = HashingAlgorithmArgon2id algorithm = HashingAlgorithmArgon2id
} else if p.configuration.PasswordHashing.Algorithm == "sha512" { } else if p.configuration.Password.Algorithm == "sha512" {
algorithm = HashingAlgorithmSHA512 algorithm = HashingAlgorithmSHA512
} else { } else {
return errors.New("Invalid algorithm in configuration. It should be `argon2id` or `sha512`") return errors.New("Invalid algorithm in configuration. It should be `argon2id` or `sha512`")
} }
hash, err := HashPassword( hash, err := HashPassword(
newPassword, "", algorithm, p.configuration.PasswordHashing.Iterations, newPassword, "", algorithm, p.configuration.Password.Iterations,
p.configuration.PasswordHashing.Memory*1024, p.configuration.PasswordHashing.Parallelism, p.configuration.Password.Memory*1024, p.configuration.Password.Parallelism,
p.configuration.PasswordHashing.KeyLength, p.configuration.PasswordHashing.SaltLength) p.configuration.Password.KeyLength, p.configuration.Password.SaltLength)
if err != nil { if err != nil {
return err return err

View File

@ -131,8 +131,8 @@ func TestShouldUpdatePasswordHashingAlgorithmToSHA512(t *testing.T) {
WithDatabase(UserDatabaseContent, func(path string) { WithDatabase(UserDatabaseContent, func(path string) {
config := DefaultFileAuthenticationBackendConfiguration config := DefaultFileAuthenticationBackendConfiguration
config.Path = path config.Path = path
config.PasswordHashing.Algorithm = "sha512" config.Password.Algorithm = "sha512"
config.PasswordHashing.Iterations = 50000 config.Password.Iterations = 50000
provider := NewFileUserProvider(&config) provider := NewFileUserProvider(&config)
assert.True(t, strings.HasPrefix(provider.database.Users["john"].HashedPassword, "{CRYPT}$argon2id$")) assert.True(t, strings.HasPrefix(provider.database.Users["john"].HashedPassword, "{CRYPT}$argon2id$"))
@ -223,13 +223,13 @@ func TestShouldSupportHashPasswordWithoutCRYPT(t *testing.T) {
var ( var (
DefaultFileAuthenticationBackendConfiguration = schema.FileAuthenticationBackendConfiguration{ DefaultFileAuthenticationBackendConfiguration = schema.FileAuthenticationBackendConfiguration{
Path: "", Path: "",
PasswordHashing: &schema.PasswordHashingConfiguration{ Password: &schema.PasswordConfiguration{
Iterations: schema.DefaultCIPasswordOptionsConfiguration.Iterations, Iterations: schema.DefaultCIPasswordConfiguration.Iterations,
KeyLength: schema.DefaultCIPasswordOptionsConfiguration.KeyLength, KeyLength: schema.DefaultCIPasswordConfiguration.KeyLength,
SaltLength: schema.DefaultCIPasswordOptionsConfiguration.SaltLength, SaltLength: schema.DefaultCIPasswordConfiguration.SaltLength,
Algorithm: schema.DefaultCIPasswordOptionsConfiguration.Algorithm, Algorithm: schema.DefaultCIPasswordConfiguration.Algorithm,
Memory: schema.DefaultCIPasswordOptionsConfiguration.Memory, Memory: schema.DefaultCIPasswordConfiguration.Memory,
Parallelism: schema.DefaultCIPasswordOptionsConfiguration.Parallelism, Parallelism: schema.DefaultCIPasswordConfiguration.Parallelism,
}, },
} }
) )

View File

@ -22,14 +22,14 @@ func TestShouldHashSHA512Password(t *testing.T) {
assert.Equal(t, "6", code) assert.Equal(t, "6", code)
assert.Equal(t, "aFr56HjK3DrB8t3S", salt) assert.Equal(t, "aFr56HjK3DrB8t3S", salt)
assert.Equal(t, "zhPQiS85cgBlNhUKKE6n/AHMlpqrvYSnSL3fEVkK0yHFQ.oFFAd8D4OhPAy18K5U61Z2eBhxQXExGU/eknXlY1", hash) assert.Equal(t, "zhPQiS85cgBlNhUKKE6n/AHMlpqrvYSnSL3fEVkK0yHFQ.oFFAd8D4OhPAy18K5U61Z2eBhxQXExGU/eknXlY1", hash)
assert.Equal(t, schema.DefaultPasswordOptionsSHA512Configuration.Iterations, parameters.GetInt("rounds", HashingDefaultSHA512Iterations)) assert.Equal(t, schema.DefaultPasswordSHA512Configuration.Iterations, parameters.GetInt("rounds", HashingDefaultSHA512Iterations))
} }
func TestShouldHashArgon2idPassword(t *testing.T) { func TestShouldHashArgon2idPassword(t *testing.T) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.SaltLength)
assert.NoError(t, err) assert.NoError(t, err)
@ -39,10 +39,10 @@ func TestShouldHashArgon2idPassword(t *testing.T) {
assert.Equal(t, "argon2id", code) assert.Equal(t, "argon2id", code)
assert.Equal(t, "BpLnfgDsc2WD8F2q", salt) assert.Equal(t, "BpLnfgDsc2WD8F2q", salt)
assert.Equal(t, "O126GHPeZ5fwj7OLSs7PndXsTbje76R+QW9/EGfhkJg", key) assert.Equal(t, "O126GHPeZ5fwj7OLSs7PndXsTbje76R+QW9/EGfhkJg", key)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Iterations, parameters.GetInt("t", HashingDefaultArgon2idTime)) assert.Equal(t, schema.DefaultCIPasswordConfiguration.Iterations, parameters.GetInt("t", HashingDefaultArgon2idTime))
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, parameters.GetInt("m", HashingDefaultArgon2idMemory)) assert.Equal(t, schema.DefaultCIPasswordConfiguration.Memory*1024, parameters.GetInt("m", HashingDefaultArgon2idMemory))
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Parallelism, parameters.GetInt("p", HashingDefaultArgon2idParallelism)) assert.Equal(t, schema.DefaultCIPasswordConfiguration.Parallelism, parameters.GetInt("p", HashingDefaultArgon2idParallelism))
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, parameters.GetInt("k", HashingDefaultArgon2idKeyLength)) assert.Equal(t, schema.DefaultCIPasswordConfiguration.KeyLength, parameters.GetInt("k", HashingDefaultArgon2idKeyLength))
} }
// This checks the method of hashing (for argon2id) supports all the characters we allow in Authelia's hash function // This checks the method of hashing (for argon2id) supports all the characters we allow in Authelia's hash function
@ -73,9 +73,9 @@ func TestSHA512HashSaltValidValues(t *testing.T) {
func TestShouldNotHashPasswordWithNonExistentAlgorithm(t *testing.T) { func TestShouldNotHashPasswordWithNonExistentAlgorithm(t *testing.T) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", "bogus", hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", "bogus",
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Hashing algorithm input of 'bogus' is invalid, only values of argon2id and 6 are supported") assert.EqualError(t, err, "Hashing algorithm input of 'bogus' is invalid, only values of argon2id and 6 are supported")
@ -83,8 +83,8 @@ func TestShouldNotHashPasswordWithNonExistentAlgorithm(t *testing.T) {
func TestShouldNotHashArgon2idPasswordDueToMemoryParallelismMismatch(t *testing.T) { func TestShouldNotHashArgon2idPasswordDueToMemoryParallelismMismatch(t *testing.T) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, 8, 2, schema.DefaultCIPasswordConfiguration.Iterations, 8, 2,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Memory (argon2id) input of 8 is invalid with a parallelism input of 2, it must be 16 (parallelism * 8) or higher") assert.EqualError(t, err, "Memory (argon2id) input of 8 is invalid with a parallelism input of 2, it must be 16 (parallelism * 8) or higher")
@ -92,8 +92,8 @@ func TestShouldNotHashArgon2idPasswordDueToMemoryParallelismMismatch(t *testing.
func TestShouldNotHashArgon2idPasswordDueToMemoryLessThanEight(t *testing.T) { func TestShouldNotHashArgon2idPasswordDueToMemoryLessThanEight(t *testing.T) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, 1, schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.Iterations, 1, schema.DefaultCIPasswordConfiguration.Parallelism,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Memory (argon2id) input of 1 is invalid, it must be 8 or higher") assert.EqualError(t, err, "Memory (argon2id) input of 1 is invalid, it must be 8 or higher")
@ -101,8 +101,8 @@ func TestShouldNotHashArgon2idPasswordDueToMemoryLessThanEight(t *testing.T) {
func TestShouldNotHashArgon2idPasswordDueToKeyLengthLessThanSixteen(t *testing.T) { func TestShouldNotHashArgon2idPasswordDueToKeyLengthLessThanSixteen(t *testing.T) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, 5, schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.Parallelism, 5, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Key length (argon2id) input of 5 is invalid, it must be 16 or higher") assert.EqualError(t, err, "Key length (argon2id) input of 5 is invalid, it must be 16 or higher")
@ -110,8 +110,8 @@ func TestShouldNotHashArgon2idPasswordDueToKeyLengthLessThanSixteen(t *testing.T
func TestShouldNotHashArgon2idPasswordDueParallelismLessThanOne(t *testing.T) { func TestShouldNotHashArgon2idPasswordDueParallelismLessThanOne(t *testing.T) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, -1, schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024, -1,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Parallelism (argon2id) input of -1 is invalid, it must be 1 or higher") assert.EqualError(t, err, "Parallelism (argon2id) input of -1 is invalid, it must be 1 or higher")
@ -119,8 +119,8 @@ func TestShouldNotHashArgon2idPasswordDueParallelismLessThanOne(t *testing.T) {
func TestShouldNotHashArgon2idPasswordDueIterationsLessThanOne(t *testing.T) { func TestShouldNotHashArgon2idPasswordDueIterationsLessThanOne(t *testing.T) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
0, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordOptionsConfiguration.Parallelism, 0, schema.DefaultCIPasswordConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Parallelism,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Iterations (argon2id) input of 0 is invalid, it must be 1 or more") assert.EqualError(t, err, "Iterations (argon2id) input of 0 is invalid, it must be 1 or more")
@ -128,15 +128,15 @@ func TestShouldNotHashArgon2idPasswordDueIterationsLessThanOne(t *testing.T) {
func TestShouldNotHashPasswordDueToSaltLength(t *testing.T) { func TestShouldNotHashPasswordDueToSaltLength(t *testing.T) {
hash, err := HashPassword("password", "", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, 0) schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength, 0)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Salt length input of 0 is invalid, it must be 2 or higher") assert.EqualError(t, err, "Salt length input of 0 is invalid, it must be 2 or higher")
hash, err = HashPassword("password", "", HashingAlgorithmArgon2id, hash, err = HashPassword("password", "", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, 20) schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength, 20)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Salt length input of 20 is invalid, it must be 16 or lower") assert.EqualError(t, err, "Salt length input of 20 is invalid, it must be 16 or lower")
@ -144,27 +144,27 @@ func TestShouldNotHashPasswordDueToSaltLength(t *testing.T) {
func TestShouldNotHashPasswordDueToSaltCharLengthTooLong(t *testing.T) { func TestShouldNotHashPasswordDueToSaltCharLengthTooLong(t *testing.T) {
hash, err := HashPassword("password", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Salt input of abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 is invalid (62 characters), it must be 16 or fewer characters") assert.EqualError(t, err, "Salt input of abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 is invalid (62 characters), it must be 16 or fewer characters")
} }
func TestShouldNotHashPasswordDueToSaltCharLengthTooShort(t *testing.T) { func TestShouldNotHashPasswordDueToSaltCharLengthTooShort(t *testing.T) {
hash, err := HashPassword("password", "a", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "a", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Salt input of a is invalid (1 characters), it must be 2 or more characters") assert.EqualError(t, err, "Salt input of a is invalid (1 characters), it must be 2 or more characters")
} }
func TestShouldNotHashPasswordWithNonBase64CharsInSalt(t *testing.T) { func TestShouldNotHashPasswordWithNonBase64CharsInSalt(t *testing.T) {
hash, err := HashPassword("password", "abc&123", HashingAlgorithmArgon2id, hash, err := HashPassword("password", "abc&123", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash) assert.Equal(t, "", hash)
assert.EqualError(t, err, "Salt input of abc&123 is invalid, only characters [a-zA-Z0-9+/] are valid for input") assert.EqualError(t, err, "Salt input of abc&123 is invalid, only characters [a-zA-Z0-9+/] are valid for input")
} }
@ -223,10 +223,10 @@ func TestShouldNotParseArgon2idHashWithWrongKeyLength(t *testing.T) {
func TestShouldParseArgon2idHash(t *testing.T) { func TestShouldParseArgon2idHash(t *testing.T) {
passwordHash, err := ParseHash("$argon2id$v=19$m=131072,t=1,p=8$BpLnfgDsc2WD8F2q$G4fD5nJwXHDMS+u0eEMKvU0LF23jxbSmJSxhSLTteHE") passwordHash, err := ParseHash("$argon2id$v=19$m=131072,t=1,p=8$BpLnfgDsc2WD8F2q$G4fD5nJwXHDMS+u0eEMKvU0LF23jxbSmJSxhSLTteHE")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Iterations, passwordHash.Iterations) assert.Equal(t, schema.DefaultCIPasswordConfiguration.Iterations, passwordHash.Iterations)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Parallelism, passwordHash.Parallelism) assert.Equal(t, schema.DefaultCIPasswordConfiguration.Parallelism, passwordHash.Parallelism)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, passwordHash.KeyLength) assert.Equal(t, schema.DefaultCIPasswordConfiguration.KeyLength, passwordHash.KeyLength)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, passwordHash.Memory) assert.Equal(t, schema.DefaultCIPasswordConfiguration.Memory*1024, passwordHash.Memory)
} }
func TestShouldCheckSHA512Password(t *testing.T) { func TestShouldCheckSHA512Password(t *testing.T) {
@ -300,9 +300,9 @@ func TestNumberOfRoundsNotInt(t *testing.T) {
func TestShouldCheckPasswordArgon2idHashedWithAuthelia(t *testing.T) { func TestShouldCheckPasswordArgon2idHashedWithAuthelia(t *testing.T) {
password := "my;secure*password" password := "my;secure*password"
hash, err := HashPassword(password, "", HashingAlgorithmArgon2id, schema.DefaultCIPasswordOptionsConfiguration.Iterations, hash, err := HashPassword(password, "", HashingAlgorithmArgon2id, schema.DefaultCIPasswordConfiguration.Iterations,
schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Parallelism,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength) schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.NoError(t, err) assert.NoError(t, err)
@ -314,8 +314,8 @@ func TestShouldCheckPasswordArgon2idHashedWithAuthelia(t *testing.T) {
func TestShouldCheckPasswordSHA512HashedWithAuthelia(t *testing.T) { func TestShouldCheckPasswordSHA512HashedWithAuthelia(t *testing.T) {
password := "my;secure*password" password := "my;secure*password"
hash, err := HashPassword(password, "", HashingAlgorithmSHA512, schema.DefaultPasswordOptionsSHA512Configuration.Iterations, hash, err := HashPassword(password, "", HashingAlgorithmSHA512, schema.DefaultPasswordSHA512Configuration.Iterations,
0, 0, 0, schema.DefaultPasswordOptionsSHA512Configuration.SaltLength) 0, 0, 0, schema.DefaultPasswordSHA512Configuration.SaltLength)
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -10,13 +10,13 @@ import (
) )
func init() { func init() {
HashPasswordCmd.Flags().BoolP("sha512", "z", false, fmt.Sprintf("use sha512 as the algorithm (changes iterations to %d, change with -i)", schema.DefaultPasswordOptionsSHA512Configuration.Iterations)) HashPasswordCmd.Flags().BoolP("sha512", "z", false, fmt.Sprintf("use sha512 as the algorithm (changes iterations to %d, change with -i)", schema.DefaultPasswordSHA512Configuration.Iterations))
HashPasswordCmd.Flags().IntP("iterations", "i", schema.DefaultPasswordOptionsConfiguration.Iterations, "set the number of hashing iterations") HashPasswordCmd.Flags().IntP("iterations", "i", schema.DefaultPasswordConfiguration.Iterations, "set the number of hashing iterations")
HashPasswordCmd.Flags().StringP("salt", "s", "", "set the salt string") HashPasswordCmd.Flags().StringP("salt", "s", "", "set the salt string")
HashPasswordCmd.Flags().IntP("memory", "m", schema.DefaultPasswordOptionsConfiguration.Memory, "[argon2id] set the amount of memory param (in MB)") HashPasswordCmd.Flags().IntP("memory", "m", schema.DefaultPasswordConfiguration.Memory, "[argon2id] set the amount of memory param (in MB)")
HashPasswordCmd.Flags().IntP("parallelism", "p", schema.DefaultPasswordOptionsConfiguration.Parallelism, "[argon2id] set the parallelism param") HashPasswordCmd.Flags().IntP("parallelism", "p", schema.DefaultPasswordConfiguration.Parallelism, "[argon2id] set the parallelism param")
HashPasswordCmd.Flags().IntP("key-length", "k", schema.DefaultPasswordOptionsConfiguration.KeyLength, "[argon2id] set the key length param") HashPasswordCmd.Flags().IntP("key-length", "k", schema.DefaultPasswordConfiguration.KeyLength, "[argon2id] set the key length param")
HashPasswordCmd.Flags().IntP("salt-length", "l", schema.DefaultPasswordOptionsConfiguration.SaltLength, "set the auto-generated salt length") HashPasswordCmd.Flags().IntP("salt-length", "l", schema.DefaultPasswordConfiguration.SaltLength, "set the auto-generated salt length")
} }
var HashPasswordCmd = &cobra.Command{ var HashPasswordCmd = &cobra.Command{
@ -36,8 +36,8 @@ var HashPasswordCmd = &cobra.Command{
var algorithm string var algorithm string
if sha512 { if sha512 {
if iterations == schema.DefaultPasswordOptionsConfiguration.Iterations { if iterations == schema.DefaultPasswordConfiguration.Iterations {
iterations = schema.DefaultPasswordOptionsSHA512Configuration.Iterations iterations = schema.DefaultPasswordSHA512Configuration.Iterations
} }
algorithm = authentication.HashingAlgorithmSHA512 algorithm = authentication.HashingAlgorithmSHA512
} else { } else {

View File

@ -19,10 +19,10 @@ type LDAPAuthenticationBackendConfiguration struct {
// FileAuthenticationBackendConfiguration represents the configuration related to file-based backend // FileAuthenticationBackendConfiguration represents the configuration related to file-based backend
type FileAuthenticationBackendConfiguration struct { type FileAuthenticationBackendConfiguration struct {
Path string `mapstructure:"path"` Path string `mapstructure:"path"`
PasswordHashing *PasswordHashingConfiguration `mapstructure:"password"` Password *PasswordConfiguration `mapstructure:"password"`
} }
type PasswordHashingConfiguration struct { type PasswordConfiguration struct {
Iterations int `mapstructure:"iterations"` Iterations int `mapstructure:"iterations"`
KeyLength int `mapstructure:"key_length"` KeyLength int `mapstructure:"key_length"`
SaltLength int `mapstructure:"salt_length"` SaltLength int `mapstructure:"salt_length"`
@ -31,8 +31,8 @@ type PasswordHashingConfiguration struct {
Parallelism int `mapstructure:"parallelism"` Parallelism int `mapstructure:"parallelism"`
} }
// DefaultPasswordOptionsConfiguration represents the default configuration related to Argon2id hashing // DefaultPasswordConfiguration represents the default configuration related to Argon2id hashing
var DefaultPasswordOptionsConfiguration = PasswordHashingConfiguration{ var DefaultPasswordConfiguration = PasswordConfiguration{
Iterations: 1, Iterations: 1,
KeyLength: 32, KeyLength: 32,
SaltLength: 16, SaltLength: 16,
@ -41,8 +41,8 @@ var DefaultPasswordOptionsConfiguration = PasswordHashingConfiguration{
Parallelism: 8, Parallelism: 8,
} }
// DefaultCIPasswordOptionsConfiguration represents the default configuration related to Argon2id hashing for CI // DefaultCIPasswordConfiguration represents the default configuration related to Argon2id hashing for CI
var DefaultCIPasswordOptionsConfiguration = PasswordHashingConfiguration{ var DefaultCIPasswordConfiguration = PasswordConfiguration{
Iterations: 1, Iterations: 1,
KeyLength: 32, KeyLength: 32,
SaltLength: 16, SaltLength: 16,
@ -51,8 +51,8 @@ var DefaultCIPasswordOptionsConfiguration = PasswordHashingConfiguration{
Parallelism: 8, Parallelism: 8,
} }
// DefaultPasswordOptionsSHA512Configuration represents the default configuration related to SHA512 hashing // DefaultPasswordSHA512Configuration represents the default configuration related to SHA512 hashing
var DefaultPasswordOptionsSHA512Configuration = PasswordHashingConfiguration{ var DefaultPasswordSHA512Configuration = PasswordConfiguration{
Iterations: 50000, Iterations: 50000,
SaltLength: 16, SaltLength: 16,
Algorithm: "sha512", Algorithm: "sha512",

View File

@ -15,58 +15,58 @@ func validateFileAuthenticationBackend(configuration *schema.FileAuthenticationB
validator.Push(errors.New("Please provide a `path` for the users database in `authentication_backend`")) validator.Push(errors.New("Please provide a `path` for the users database in `authentication_backend`"))
} }
if configuration.PasswordHashing == nil { if configuration.Password == nil {
configuration.PasswordHashing = &schema.DefaultPasswordOptionsConfiguration configuration.Password = &schema.DefaultPasswordConfiguration
} else { } else {
if configuration.PasswordHashing.Algorithm == "" { if configuration.Password.Algorithm == "" {
configuration.PasswordHashing.Algorithm = schema.DefaultPasswordOptionsConfiguration.Algorithm configuration.Password.Algorithm = schema.DefaultPasswordConfiguration.Algorithm
} else { } else {
configuration.PasswordHashing.Algorithm = strings.ToLower(configuration.PasswordHashing.Algorithm) configuration.Password.Algorithm = strings.ToLower(configuration.Password.Algorithm)
if configuration.PasswordHashing.Algorithm != "argon2id" && configuration.PasswordHashing.Algorithm != "sha512" { if configuration.Password.Algorithm != "argon2id" && configuration.Password.Algorithm != "sha512" {
validator.Push(fmt.Errorf("Unknown hashing algorithm supplied, valid values are argon2id and sha512, you configured '%s'", configuration.PasswordHashing.Algorithm)) validator.Push(fmt.Errorf("Unknown hashing algorithm supplied, valid values are argon2id and sha512, you configured '%s'", configuration.Password.Algorithm))
} }
} }
// Iterations (time) // Iterations (time)
if configuration.PasswordHashing.Iterations == 0 { if configuration.Password.Iterations == 0 {
if configuration.PasswordHashing.Algorithm == "argon2id" { if configuration.Password.Algorithm == "argon2id" {
configuration.PasswordHashing.Iterations = schema.DefaultPasswordOptionsConfiguration.Iterations configuration.Password.Iterations = schema.DefaultPasswordConfiguration.Iterations
} else { } else {
configuration.PasswordHashing.Iterations = schema.DefaultPasswordOptionsSHA512Configuration.Iterations configuration.Password.Iterations = schema.DefaultPasswordSHA512Configuration.Iterations
} }
} else if configuration.PasswordHashing.Iterations < 1 { } else if configuration.Password.Iterations < 1 {
validator.Push(fmt.Errorf("The number of iterations specified is invalid, must be 1 or more, you configured %d", configuration.PasswordHashing.Iterations)) validator.Push(fmt.Errorf("The number of iterations specified is invalid, must be 1 or more, you configured %d", configuration.Password.Iterations))
} }
//Salt Length //Salt Length
if configuration.PasswordHashing.SaltLength == 0 { if configuration.Password.SaltLength == 0 {
configuration.PasswordHashing.SaltLength = schema.DefaultPasswordOptionsConfiguration.SaltLength configuration.Password.SaltLength = schema.DefaultPasswordConfiguration.SaltLength
} else if configuration.PasswordHashing.SaltLength < 2 { } else if configuration.Password.SaltLength < 2 {
validator.Push(fmt.Errorf("The salt length must be 2 or more, you configured %d", configuration.PasswordHashing.SaltLength)) validator.Push(fmt.Errorf("The salt length must be 2 or more, you configured %d", configuration.Password.SaltLength))
} else if configuration.PasswordHashing.SaltLength > 16 { } else if configuration.Password.SaltLength > 16 {
validator.Push(fmt.Errorf("The salt length must be 16 or less, you configured %d", configuration.PasswordHashing.SaltLength)) validator.Push(fmt.Errorf("The salt length must be 16 or less, you configured %d", configuration.Password.SaltLength))
} }
if configuration.PasswordHashing.Algorithm == "argon2id" { if configuration.Password.Algorithm == "argon2id" {
// Parallelism // Parallelism
if configuration.PasswordHashing.Parallelism == 0 { if configuration.Password.Parallelism == 0 {
configuration.PasswordHashing.Parallelism = schema.DefaultPasswordOptionsConfiguration.Parallelism configuration.Password.Parallelism = schema.DefaultPasswordConfiguration.Parallelism
} else if configuration.PasswordHashing.Parallelism < 1 { } else if configuration.Password.Parallelism < 1 {
validator.Push(fmt.Errorf("Parallelism for argon2id must be 1 or more, you configured %d", configuration.PasswordHashing.Parallelism)) validator.Push(fmt.Errorf("Parallelism for argon2id must be 1 or more, you configured %d", configuration.Password.Parallelism))
} }
// Memory // Memory
if configuration.PasswordHashing.Memory == 0 { if configuration.Password.Memory == 0 {
configuration.PasswordHashing.Memory = schema.DefaultPasswordOptionsConfiguration.Memory configuration.Password.Memory = schema.DefaultPasswordConfiguration.Memory
} else if configuration.PasswordHashing.Memory < configuration.PasswordHashing.Parallelism*8 { } else if configuration.Password.Memory < configuration.Password.Parallelism*8 {
validator.Push(fmt.Errorf("Memory for argon2id must be %d or more (parallelism * 8), you configured memory as %d and parallelism as %d", configuration.PasswordHashing.Parallelism*8, configuration.PasswordHashing.Memory, configuration.PasswordHashing.Parallelism)) validator.Push(fmt.Errorf("Memory for argon2id must be %d or more (parallelism * 8), you configured memory as %d and parallelism as %d", configuration.Password.Parallelism*8, configuration.Password.Memory, configuration.Password.Parallelism))
} }
// Key Length // Key Length
if configuration.PasswordHashing.KeyLength == 0 { if configuration.Password.KeyLength == 0 {
configuration.PasswordHashing.KeyLength = schema.DefaultPasswordOptionsConfiguration.KeyLength configuration.Password.KeyLength = schema.DefaultPasswordConfiguration.KeyLength
} else if configuration.PasswordHashing.KeyLength < 16 { } else if configuration.Password.KeyLength < 16 {
validator.Push(fmt.Errorf("Key length for argon2id must be 16, you configured %d", configuration.PasswordHashing.KeyLength)) validator.Push(fmt.Errorf("Key length for argon2id must be 16, you configured %d", configuration.Password.KeyLength))
} }
} }
} }

View File

@ -29,15 +29,15 @@ type FileBasedAuthenticationBackend struct {
func (suite *FileBasedAuthenticationBackend) SetupTest() { func (suite *FileBasedAuthenticationBackend) SetupTest() {
suite.validator = schema.NewStructValidator() suite.validator = schema.NewStructValidator()
suite.configuration = schema.AuthenticationBackendConfiguration{} suite.configuration = schema.AuthenticationBackendConfiguration{}
suite.configuration.File = &schema.FileAuthenticationBackendConfiguration{Path: "/a/path", PasswordHashing: &schema.PasswordHashingConfiguration{ suite.configuration.File = &schema.FileAuthenticationBackendConfiguration{Path: "/a/path", Password: &schema.PasswordConfiguration{
Algorithm: schema.DefaultPasswordOptionsConfiguration.Algorithm, Algorithm: schema.DefaultPasswordConfiguration.Algorithm,
Iterations: schema.DefaultPasswordOptionsConfiguration.Iterations, Iterations: schema.DefaultPasswordConfiguration.Iterations,
Parallelism: schema.DefaultPasswordOptionsConfiguration.Parallelism, Parallelism: schema.DefaultPasswordConfiguration.Parallelism,
Memory: schema.DefaultPasswordOptionsConfiguration.Memory, Memory: schema.DefaultPasswordConfiguration.Memory,
KeyLength: schema.DefaultPasswordOptionsConfiguration.KeyLength, KeyLength: schema.DefaultPasswordConfiguration.KeyLength,
SaltLength: schema.DefaultPasswordOptionsConfiguration.SaltLength, SaltLength: schema.DefaultPasswordConfiguration.SaltLength,
}} }}
suite.configuration.File.PasswordHashing.Algorithm = schema.DefaultPasswordOptionsConfiguration.Algorithm suite.configuration.File.Password.Algorithm = schema.DefaultPasswordConfiguration.Algorithm
} }
func (suite *FileBasedAuthenticationBackend) TestShouldValidateCompleteConfiguration() { func (suite *FileBasedAuthenticationBackend) TestShouldValidateCompleteConfiguration() {
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
@ -52,104 +52,104 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenNoPathProvi
} }
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenMemoryNotMoreThanEightTimesParallelism() { func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenMemoryNotMoreThanEightTimesParallelism() {
suite.configuration.File.PasswordHashing.Memory = 8 suite.configuration.File.Password.Memory = 8
suite.configuration.File.PasswordHashing.Parallelism = 2 suite.configuration.File.Password.Parallelism = 2
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 1) assert.Len(suite.T(), suite.validator.Errors(), 1)
assert.EqualError(suite.T(), suite.validator.Errors()[0], "Memory for argon2id must be 16 or more (parallelism * 8), you configured memory as 8 and parallelism as 2") assert.EqualError(suite.T(), suite.validator.Errors()[0], "Memory for argon2id must be 16 or more (parallelism * 8), you configured memory as 8 and parallelism as 2")
} }
func (suite *FileBasedAuthenticationBackend) TestShouldSetDefaultConfigurationWhenBlank() { func (suite *FileBasedAuthenticationBackend) TestShouldSetDefaultConfigurationWhenBlank() {
suite.configuration.File.PasswordHashing = &schema.PasswordHashingConfiguration{} suite.configuration.File.Password = &schema.PasswordConfiguration{}
assert.Equal(suite.T(), 0, suite.configuration.File.PasswordHashing.KeyLength) assert.Equal(suite.T(), 0, suite.configuration.File.Password.KeyLength)
assert.Equal(suite.T(), 0, suite.configuration.File.PasswordHashing.Iterations) assert.Equal(suite.T(), 0, suite.configuration.File.Password.Iterations)
assert.Equal(suite.T(), 0, suite.configuration.File.PasswordHashing.SaltLength) assert.Equal(suite.T(), 0, suite.configuration.File.Password.SaltLength)
assert.Equal(suite.T(), "", suite.configuration.File.PasswordHashing.Algorithm) assert.Equal(suite.T(), "", suite.configuration.File.Password.Algorithm)
assert.Equal(suite.T(), 0, suite.configuration.File.PasswordHashing.Memory) assert.Equal(suite.T(), 0, suite.configuration.File.Password.Memory)
assert.Equal(suite.T(), 0, suite.configuration.File.PasswordHashing.Parallelism) assert.Equal(suite.T(), 0, suite.configuration.File.Password.Parallelism)
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 0) assert.Len(suite.T(), suite.validator.Errors(), 0)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.KeyLength, suite.configuration.File.PasswordHashing.KeyLength) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.KeyLength, suite.configuration.File.Password.KeyLength)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Iterations, suite.configuration.File.PasswordHashing.Iterations) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Iterations, suite.configuration.File.Password.Iterations)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.SaltLength, suite.configuration.File.PasswordHashing.SaltLength) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.SaltLength, suite.configuration.File.Password.SaltLength)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Algorithm, suite.configuration.File.PasswordHashing.Algorithm) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Algorithm, suite.configuration.File.Password.Algorithm)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Memory, suite.configuration.File.PasswordHashing.Memory) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Memory, suite.configuration.File.Password.Memory)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Parallelism, suite.configuration.File.PasswordHashing.Parallelism) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Parallelism, suite.configuration.File.Password.Parallelism)
} }
func (suite *FileBasedAuthenticationBackend) TestShouldSetDefaultConfigurationWhenOnlySHA512Set() { func (suite *FileBasedAuthenticationBackend) TestShouldSetDefaultConfigurationWhenOnlySHA512Set() {
suite.configuration.File.PasswordHashing = &schema.PasswordHashingConfiguration{} suite.configuration.File.Password = &schema.PasswordConfiguration{}
assert.Equal(suite.T(), "", suite.configuration.File.PasswordHashing.Algorithm) assert.Equal(suite.T(), "", suite.configuration.File.Password.Algorithm)
suite.configuration.File.PasswordHashing.Algorithm = "sha512" suite.configuration.File.Password.Algorithm = "sha512"
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 0) assert.Len(suite.T(), suite.validator.Errors(), 0)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.KeyLength, suite.configuration.File.PasswordHashing.KeyLength) assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.KeyLength, suite.configuration.File.Password.KeyLength)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.Iterations, suite.configuration.File.PasswordHashing.Iterations) assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.Iterations, suite.configuration.File.Password.Iterations)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.SaltLength, suite.configuration.File.PasswordHashing.SaltLength) assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.SaltLength, suite.configuration.File.Password.SaltLength)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.Algorithm, suite.configuration.File.PasswordHashing.Algorithm) assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.Algorithm, suite.configuration.File.Password.Algorithm)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.Memory, suite.configuration.File.PasswordHashing.Memory) assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.Memory, suite.configuration.File.Password.Memory)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.Parallelism, suite.configuration.File.PasswordHashing.Parallelism) assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.Parallelism, suite.configuration.File.Password.Parallelism)
} }
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenKeyLengthTooLow() { func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenKeyLengthTooLow() {
suite.configuration.File.PasswordHashing.KeyLength = 1 suite.configuration.File.Password.KeyLength = 1
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 1) assert.Len(suite.T(), suite.validator.Errors(), 1)
assert.EqualError(suite.T(), suite.validator.Errors()[0], "Key length for argon2id must be 16, you configured 1") assert.EqualError(suite.T(), suite.validator.Errors()[0], "Key length for argon2id must be 16, you configured 1")
} }
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSaltLengthTooLow() { func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSaltLengthTooLow() {
suite.configuration.File.PasswordHashing.SaltLength = -1 suite.configuration.File.Password.SaltLength = -1
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 1) assert.Len(suite.T(), suite.validator.Errors(), 1)
assert.EqualError(suite.T(), suite.validator.Errors()[0], "The salt length must be 2 or more, you configured -1") assert.EqualError(suite.T(), suite.validator.Errors()[0], "The salt length must be 2 or more, you configured -1")
} }
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSaltLengthTooHigh() { func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSaltLengthTooHigh() {
suite.configuration.File.PasswordHashing.SaltLength = 20 suite.configuration.File.Password.SaltLength = 20
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 1) assert.Len(suite.T(), suite.validator.Errors(), 1)
assert.EqualError(suite.T(), suite.validator.Errors()[0], "The salt length must be 16 or less, you configured 20") assert.EqualError(suite.T(), suite.validator.Errors()[0], "The salt length must be 16 or less, you configured 20")
} }
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenBadAlgorithmDefined() { func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenBadAlgorithmDefined() {
suite.configuration.File.PasswordHashing.Algorithm = "bogus" suite.configuration.File.Password.Algorithm = "bogus"
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 1) assert.Len(suite.T(), suite.validator.Errors(), 1)
assert.EqualError(suite.T(), suite.validator.Errors()[0], "Unknown hashing algorithm supplied, valid values are argon2id and sha512, you configured 'bogus'") assert.EqualError(suite.T(), suite.validator.Errors()[0], "Unknown hashing algorithm supplied, valid values are argon2id and sha512, you configured 'bogus'")
} }
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenIterationsTooLow() { func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenIterationsTooLow() {
suite.configuration.File.PasswordHashing.Iterations = -1 suite.configuration.File.Password.Iterations = -1
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 1) assert.Len(suite.T(), suite.validator.Errors(), 1)
assert.EqualError(suite.T(), suite.validator.Errors()[0], "The number of iterations specified is invalid, must be 1 or more, you configured -1") assert.EqualError(suite.T(), suite.validator.Errors()[0], "The number of iterations specified is invalid, must be 1 or more, you configured -1")
} }
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenParallelismTooLow() { func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenParallelismTooLow() {
suite.configuration.File.PasswordHashing.Parallelism = -1 suite.configuration.File.Password.Parallelism = -1
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 1) assert.Len(suite.T(), suite.validator.Errors(), 1)
assert.EqualError(suite.T(), suite.validator.Errors()[0], "Parallelism for argon2id must be 1 or more, you configured -1") assert.EqualError(suite.T(), suite.validator.Errors()[0], "Parallelism for argon2id must be 1 or more, you configured -1")
} }
func (suite *FileBasedAuthenticationBackend) TestShouldSetDefaultValues() { func (suite *FileBasedAuthenticationBackend) TestShouldSetDefaultValues() {
suite.configuration.File.PasswordHashing.Algorithm = "" suite.configuration.File.Password.Algorithm = ""
suite.configuration.File.PasswordHashing.Iterations = 0 suite.configuration.File.Password.Iterations = 0
suite.configuration.File.PasswordHashing.SaltLength = 0 suite.configuration.File.Password.SaltLength = 0
suite.configuration.File.PasswordHashing.Memory = 0 suite.configuration.File.Password.Memory = 0
suite.configuration.File.PasswordHashing.Parallelism = 0 suite.configuration.File.Password.Parallelism = 0
ValidateAuthenticationBackend(&suite.configuration, suite.validator) ValidateAuthenticationBackend(&suite.configuration, suite.validator)
assert.Len(suite.T(), suite.validator.Errors(), 0) assert.Len(suite.T(), suite.validator.Errors(), 0)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Algorithm, suite.configuration.File.PasswordHashing.Algorithm) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Algorithm, suite.configuration.File.Password.Algorithm)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Iterations, suite.configuration.File.PasswordHashing.Iterations) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Iterations, suite.configuration.File.Password.Iterations)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.SaltLength, suite.configuration.File.PasswordHashing.SaltLength) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.SaltLength, suite.configuration.File.Password.SaltLength)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Memory, suite.configuration.File.PasswordHashing.Memory) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Memory, suite.configuration.File.Password.Memory)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Parallelism, suite.configuration.File.PasswordHashing.Parallelism) assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Parallelism, suite.configuration.File.Password.Parallelism)
} }
func TestFileBasedAuthenticationBackend(t *testing.T) { func TestFileBasedAuthenticationBackend(t *testing.T) {

View File

@ -29,7 +29,7 @@ const (
const operationFailedMessage = "Operation failed." const operationFailedMessage = "Operation failed."
const authenticationFailedMessage = "Authentication failed. Check your credentials." const authenticationFailedMessage = "Authentication failed. Check your credentials."
const userBannedMessage = "Please retry in a few minutes." const userBannedMessage = "Please retry in a few minutes."
const unableToRegisterOneTimePasswordMessage = "Unable to set up one-time passwords." const unableToRegisterOneTimePasswordMessage = "Unable to set up one-time passwords." //nolint:gosec
const unableToRegisterSecurityKeyMessage = "Unable to register your security key." const unableToRegisterSecurityKeyMessage = "Unable to register your security key."
const unableToResetPasswordMessage = "Unable to reset your password." const unableToResetPasswordMessage = "Unable to reset your password."
const mfaValidationFailedMessage = "Authentication failed, please retry later." const mfaValidationFailedMessage = "Authentication failed, please retry later."