[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.
# Therefore, this backend is meant to be used in a dev environment
# 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
# you leave the default values. Before considering changing these settings
# please read the docs page below:
@ -148,7 +148,7 @@ authentication_backend:
#
## file:
## path: ./users_database.yml
## password_options:
## password:
## algorithm: argon2id
## iterations: 1
## key_length: 32

View File

@ -19,7 +19,7 @@ file in the configuration file.
disable_reset_password: false
file:
path: /var/lib/authelia/users.yml
password_hashing:
password:
algorithm: argon2id
iterations: 1
salt_length: 16
@ -97,26 +97,38 @@ Flags:
## 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
[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
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).
Additionally SHA512 is supported for backwards compatibility and user choice. While it's a reasonable
hash function given high enough iterations, as hardware gets better it has a higher chance of being
brute-forced.
For backwards compatibility and user choice support for the SHA512 algorithm is still available.
While it's a reasonable hashing function given high enough iterations, as hardware improves it
has a higher chance of being brute-forced.
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)).
**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
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
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
parameters below, or for a more in depth understanding see the referenced documentation in
[Argon2 links](./file.md#argon2-links).

View File

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

View File

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

View File

@ -22,14 +22,14 @@ func TestShouldHashSHA512Password(t *testing.T) {
assert.Equal(t, "6", code)
assert.Equal(t, "aFr56HjK3DrB8t3S", salt)
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) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordConfiguration.SaltLength)
assert.NoError(t, err)
@ -39,10 +39,10 @@ func TestShouldHashArgon2idPassword(t *testing.T) {
assert.Equal(t, "argon2id", code)
assert.Equal(t, "BpLnfgDsc2WD8F2q", salt)
assert.Equal(t, "O126GHPeZ5fwj7OLSs7PndXsTbje76R+QW9/EGfhkJg", key)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Iterations, parameters.GetInt("t", HashingDefaultArgon2idTime))
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, parameters.GetInt("m", HashingDefaultArgon2idMemory))
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Parallelism, parameters.GetInt("p", HashingDefaultArgon2idParallelism))
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, parameters.GetInt("k", HashingDefaultArgon2idKeyLength))
assert.Equal(t, schema.DefaultCIPasswordConfiguration.Iterations, parameters.GetInt("t", HashingDefaultArgon2idTime))
assert.Equal(t, schema.DefaultCIPasswordConfiguration.Memory*1024, parameters.GetInt("m", HashingDefaultArgon2idMemory))
assert.Equal(t, schema.DefaultCIPasswordConfiguration.Parallelism, parameters.GetInt("p", HashingDefaultArgon2idParallelism))
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
@ -73,9 +73,9 @@ func TestSHA512HashSaltValidValues(t *testing.T) {
func TestShouldNotHashPasswordWithNonExistentAlgorithm(t *testing.T) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", "bogus",
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash)
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) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, 8, 2,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
schema.DefaultCIPasswordConfiguration.Iterations, 8, 2,
schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
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")
@ -92,8 +92,8 @@ func TestShouldNotHashArgon2idPasswordDueToMemoryParallelismMismatch(t *testing.
func TestShouldNotHashArgon2idPasswordDueToMemoryLessThanEight(t *testing.T) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, 1, schema.DefaultCIPasswordOptionsConfiguration.Parallelism,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
schema.DefaultCIPasswordConfiguration.Iterations, 1, schema.DefaultCIPasswordConfiguration.Parallelism,
schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash)
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) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, 5, schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordConfiguration.Parallelism, 5, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash)
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) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, -1,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024, -1,
schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash)
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) {
hash, err := HashPassword("password", "BpLnfgDsc2WD8F2q", HashingAlgorithmArgon2id,
0, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordOptionsConfiguration.Parallelism,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
0, schema.DefaultCIPasswordConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Parallelism,
schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash)
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) {
hash, err := HashPassword("password", "", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, 0)
schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength, 0)
assert.Equal(t, "", hash)
assert.EqualError(t, err, "Salt length input of 0 is invalid, it must be 2 or higher")
hash, err = HashPassword("password", "", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, 20)
schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength, 20)
assert.Equal(t, "", hash)
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) {
hash, err := HashPassword("password", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash)
assert.EqualError(t, err, "Salt input of abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 is invalid (62 characters), it must be 16 or fewer characters")
}
func TestShouldNotHashPasswordDueToSaltCharLengthTooShort(t *testing.T) {
hash, err := HashPassword("password", "a", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordConfiguration.SaltLength)
assert.Equal(t, "", hash)
assert.EqualError(t, err, "Salt input of a is invalid (1 characters), it must be 2 or more characters")
}
func TestShouldNotHashPasswordWithNonBase64CharsInSalt(t *testing.T) {
hash, err := HashPassword("password", "abc&123", HashingAlgorithmArgon2id,
schema.DefaultCIPasswordOptionsConfiguration.Iterations, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024,
schema.DefaultCIPasswordOptionsConfiguration.Parallelism, schema.DefaultCIPasswordOptionsConfiguration.KeyLength,
schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
schema.DefaultCIPasswordConfiguration.Iterations, schema.DefaultCIPasswordConfiguration.Memory*1024,
schema.DefaultCIPasswordConfiguration.Parallelism, schema.DefaultCIPasswordConfiguration.KeyLength,
schema.DefaultCIPasswordConfiguration.SaltLength)
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")
}
@ -223,10 +223,10 @@ func TestShouldNotParseArgon2idHashWithWrongKeyLength(t *testing.T) {
func TestShouldParseArgon2idHash(t *testing.T) {
passwordHash, err := ParseHash("$argon2id$v=19$m=131072,t=1,p=8$BpLnfgDsc2WD8F2q$G4fD5nJwXHDMS+u0eEMKvU0LF23jxbSmJSxhSLTteHE")
assert.NoError(t, err)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Iterations, passwordHash.Iterations)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Parallelism, passwordHash.Parallelism)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.KeyLength, passwordHash.KeyLength)
assert.Equal(t, schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, passwordHash.Memory)
assert.Equal(t, schema.DefaultCIPasswordConfiguration.Iterations, passwordHash.Iterations)
assert.Equal(t, schema.DefaultCIPasswordConfiguration.Parallelism, passwordHash.Parallelism)
assert.Equal(t, schema.DefaultCIPasswordConfiguration.KeyLength, passwordHash.KeyLength)
assert.Equal(t, schema.DefaultCIPasswordConfiguration.Memory*1024, passwordHash.Memory)
}
func TestShouldCheckSHA512Password(t *testing.T) {
@ -300,9 +300,9 @@ func TestNumberOfRoundsNotInt(t *testing.T) {
func TestShouldCheckPasswordArgon2idHashedWithAuthelia(t *testing.T) {
password := "my;secure*password"
hash, err := HashPassword(password, "", HashingAlgorithmArgon2id, schema.DefaultCIPasswordOptionsConfiguration.Iterations,
schema.DefaultCIPasswordOptionsConfiguration.Memory*1024, schema.DefaultCIPasswordOptionsConfiguration.Parallelism,
schema.DefaultCIPasswordOptionsConfiguration.KeyLength, schema.DefaultCIPasswordOptionsConfiguration.SaltLength)
hash, err := HashPassword(password, "", HashingAlgorithmArgon2id, schema.DefaultCIPasswordConfiguration.Iterations,
schema.DefaultCIPasswordConfiguration.Memory*1024, schema.DefaultCIPasswordConfiguration.Parallelism,
schema.DefaultCIPasswordConfiguration.KeyLength, schema.DefaultCIPasswordConfiguration.SaltLength)
assert.NoError(t, err)
@ -314,8 +314,8 @@ func TestShouldCheckPasswordArgon2idHashedWithAuthelia(t *testing.T) {
func TestShouldCheckPasswordSHA512HashedWithAuthelia(t *testing.T) {
password := "my;secure*password"
hash, err := HashPassword(password, "", HashingAlgorithmSHA512, schema.DefaultPasswordOptionsSHA512Configuration.Iterations,
0, 0, 0, schema.DefaultPasswordOptionsSHA512Configuration.SaltLength)
hash, err := HashPassword(password, "", HashingAlgorithmSHA512, schema.DefaultPasswordSHA512Configuration.Iterations,
0, 0, 0, schema.DefaultPasswordSHA512Configuration.SaltLength)
assert.NoError(t, err)

View File

@ -10,13 +10,13 @@ import (
)
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().IntP("iterations", "i", schema.DefaultPasswordOptionsConfiguration.Iterations, "set the number of hashing 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.DefaultPasswordConfiguration.Iterations, "set the number of hashing iterations")
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("parallelism", "p", schema.DefaultPasswordOptionsConfiguration.Parallelism, "[argon2id] set the parallelism param")
HashPasswordCmd.Flags().IntP("key-length", "k", schema.DefaultPasswordOptionsConfiguration.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("memory", "m", schema.DefaultPasswordConfiguration.Memory, "[argon2id] set the amount of memory param (in MB)")
HashPasswordCmd.Flags().IntP("parallelism", "p", schema.DefaultPasswordConfiguration.Parallelism, "[argon2id] set the parallelism param")
HashPasswordCmd.Flags().IntP("key-length", "k", schema.DefaultPasswordConfiguration.KeyLength, "[argon2id] set the key length param")
HashPasswordCmd.Flags().IntP("salt-length", "l", schema.DefaultPasswordConfiguration.SaltLength, "set the auto-generated salt length")
}
var HashPasswordCmd = &cobra.Command{
@ -36,8 +36,8 @@ var HashPasswordCmd = &cobra.Command{
var algorithm string
if sha512 {
if iterations == schema.DefaultPasswordOptionsConfiguration.Iterations {
iterations = schema.DefaultPasswordOptionsSHA512Configuration.Iterations
if iterations == schema.DefaultPasswordConfiguration.Iterations {
iterations = schema.DefaultPasswordSHA512Configuration.Iterations
}
algorithm = authentication.HashingAlgorithmSHA512
} else {

View File

@ -19,10 +19,10 @@ type LDAPAuthenticationBackendConfiguration struct {
// FileAuthenticationBackendConfiguration represents the configuration related to file-based backend
type FileAuthenticationBackendConfiguration struct {
Path string `mapstructure:"path"`
PasswordHashing *PasswordHashingConfiguration `mapstructure:"password"`
Password *PasswordConfiguration `mapstructure:"password"`
}
type PasswordHashingConfiguration struct {
type PasswordConfiguration struct {
Iterations int `mapstructure:"iterations"`
KeyLength int `mapstructure:"key_length"`
SaltLength int `mapstructure:"salt_length"`
@ -31,8 +31,8 @@ type PasswordHashingConfiguration struct {
Parallelism int `mapstructure:"parallelism"`
}
// DefaultPasswordOptionsConfiguration represents the default configuration related to Argon2id hashing
var DefaultPasswordOptionsConfiguration = PasswordHashingConfiguration{
// DefaultPasswordConfiguration represents the default configuration related to Argon2id hashing
var DefaultPasswordConfiguration = PasswordConfiguration{
Iterations: 1,
KeyLength: 32,
SaltLength: 16,
@ -41,8 +41,8 @@ var DefaultPasswordOptionsConfiguration = PasswordHashingConfiguration{
Parallelism: 8,
}
// DefaultCIPasswordOptionsConfiguration represents the default configuration related to Argon2id hashing for CI
var DefaultCIPasswordOptionsConfiguration = PasswordHashingConfiguration{
// DefaultCIPasswordConfiguration represents the default configuration related to Argon2id hashing for CI
var DefaultCIPasswordConfiguration = PasswordConfiguration{
Iterations: 1,
KeyLength: 32,
SaltLength: 16,
@ -51,8 +51,8 @@ var DefaultCIPasswordOptionsConfiguration = PasswordHashingConfiguration{
Parallelism: 8,
}
// DefaultPasswordOptionsSHA512Configuration represents the default configuration related to SHA512 hashing
var DefaultPasswordOptionsSHA512Configuration = PasswordHashingConfiguration{
// DefaultPasswordSHA512Configuration represents the default configuration related to SHA512 hashing
var DefaultPasswordSHA512Configuration = PasswordConfiguration{
Iterations: 50000,
SaltLength: 16,
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`"))
}
if configuration.PasswordHashing == nil {
configuration.PasswordHashing = &schema.DefaultPasswordOptionsConfiguration
if configuration.Password == nil {
configuration.Password = &schema.DefaultPasswordConfiguration
} else {
if configuration.PasswordHashing.Algorithm == "" {
configuration.PasswordHashing.Algorithm = schema.DefaultPasswordOptionsConfiguration.Algorithm
if configuration.Password.Algorithm == "" {
configuration.Password.Algorithm = schema.DefaultPasswordConfiguration.Algorithm
} else {
configuration.PasswordHashing.Algorithm = strings.ToLower(configuration.PasswordHashing.Algorithm)
if configuration.PasswordHashing.Algorithm != "argon2id" && configuration.PasswordHashing.Algorithm != "sha512" {
validator.Push(fmt.Errorf("Unknown hashing algorithm supplied, valid values are argon2id and sha512, you configured '%s'", configuration.PasswordHashing.Algorithm))
configuration.Password.Algorithm = strings.ToLower(configuration.Password.Algorithm)
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.Password.Algorithm))
}
}
// Iterations (time)
if configuration.PasswordHashing.Iterations == 0 {
if configuration.PasswordHashing.Algorithm == "argon2id" {
configuration.PasswordHashing.Iterations = schema.DefaultPasswordOptionsConfiguration.Iterations
if configuration.Password.Iterations == 0 {
if configuration.Password.Algorithm == "argon2id" {
configuration.Password.Iterations = schema.DefaultPasswordConfiguration.Iterations
} else {
configuration.PasswordHashing.Iterations = schema.DefaultPasswordOptionsSHA512Configuration.Iterations
configuration.Password.Iterations = schema.DefaultPasswordSHA512Configuration.Iterations
}
} else if configuration.PasswordHashing.Iterations < 1 {
validator.Push(fmt.Errorf("The number of iterations specified is invalid, must be 1 or more, you configured %d", configuration.PasswordHashing.Iterations))
} 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.Password.Iterations))
}
//Salt Length
if configuration.PasswordHashing.SaltLength == 0 {
configuration.PasswordHashing.SaltLength = schema.DefaultPasswordOptionsConfiguration.SaltLength
} else if configuration.PasswordHashing.SaltLength < 2 {
validator.Push(fmt.Errorf("The salt length must be 2 or more, you configured %d", configuration.PasswordHashing.SaltLength))
} else if configuration.PasswordHashing.SaltLength > 16 {
validator.Push(fmt.Errorf("The salt length must be 16 or less, you configured %d", configuration.PasswordHashing.SaltLength))
if configuration.Password.SaltLength == 0 {
configuration.Password.SaltLength = schema.DefaultPasswordConfiguration.SaltLength
} else if configuration.Password.SaltLength < 2 {
validator.Push(fmt.Errorf("The salt length must be 2 or more, you configured %d", configuration.Password.SaltLength))
} else if configuration.Password.SaltLength > 16 {
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
if configuration.PasswordHashing.Parallelism == 0 {
configuration.PasswordHashing.Parallelism = schema.DefaultPasswordOptionsConfiguration.Parallelism
} else if configuration.PasswordHashing.Parallelism < 1 {
validator.Push(fmt.Errorf("Parallelism for argon2id must be 1 or more, you configured %d", configuration.PasswordHashing.Parallelism))
if configuration.Password.Parallelism == 0 {
configuration.Password.Parallelism = schema.DefaultPasswordConfiguration.Parallelism
} else if configuration.Password.Parallelism < 1 {
validator.Push(fmt.Errorf("Parallelism for argon2id must be 1 or more, you configured %d", configuration.Password.Parallelism))
}
// Memory
if configuration.PasswordHashing.Memory == 0 {
configuration.PasswordHashing.Memory = schema.DefaultPasswordOptionsConfiguration.Memory
} else if configuration.PasswordHashing.Memory < configuration.PasswordHashing.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))
if configuration.Password.Memory == 0 {
configuration.Password.Memory = schema.DefaultPasswordConfiguration.Memory
} 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.Password.Parallelism*8, configuration.Password.Memory, configuration.Password.Parallelism))
}
// Key Length
if configuration.PasswordHashing.KeyLength == 0 {
configuration.PasswordHashing.KeyLength = schema.DefaultPasswordOptionsConfiguration.KeyLength
} else if configuration.PasswordHashing.KeyLength < 16 {
validator.Push(fmt.Errorf("Key length for argon2id must be 16, you configured %d", configuration.PasswordHashing.KeyLength))
if configuration.Password.KeyLength == 0 {
configuration.Password.KeyLength = schema.DefaultPasswordConfiguration.KeyLength
} else if configuration.Password.KeyLength < 16 {
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() {
suite.validator = schema.NewStructValidator()
suite.configuration = schema.AuthenticationBackendConfiguration{}
suite.configuration.File = &schema.FileAuthenticationBackendConfiguration{Path: "/a/path", PasswordHashing: &schema.PasswordHashingConfiguration{
Algorithm: schema.DefaultPasswordOptionsConfiguration.Algorithm,
Iterations: schema.DefaultPasswordOptionsConfiguration.Iterations,
Parallelism: schema.DefaultPasswordOptionsConfiguration.Parallelism,
Memory: schema.DefaultPasswordOptionsConfiguration.Memory,
KeyLength: schema.DefaultPasswordOptionsConfiguration.KeyLength,
SaltLength: schema.DefaultPasswordOptionsConfiguration.SaltLength,
suite.configuration.File = &schema.FileAuthenticationBackendConfiguration{Path: "/a/path", Password: &schema.PasswordConfiguration{
Algorithm: schema.DefaultPasswordConfiguration.Algorithm,
Iterations: schema.DefaultPasswordConfiguration.Iterations,
Parallelism: schema.DefaultPasswordConfiguration.Parallelism,
Memory: schema.DefaultPasswordConfiguration.Memory,
KeyLength: schema.DefaultPasswordConfiguration.KeyLength,
SaltLength: schema.DefaultPasswordConfiguration.SaltLength,
}}
suite.configuration.File.PasswordHashing.Algorithm = schema.DefaultPasswordOptionsConfiguration.Algorithm
suite.configuration.File.Password.Algorithm = schema.DefaultPasswordConfiguration.Algorithm
}
func (suite *FileBasedAuthenticationBackend) TestShouldValidateCompleteConfiguration() {
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
@ -52,104 +52,104 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenNoPathProvi
}
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenMemoryNotMoreThanEightTimesParallelism() {
suite.configuration.File.PasswordHashing.Memory = 8
suite.configuration.File.PasswordHashing.Parallelism = 2
suite.configuration.File.Password.Memory = 8
suite.configuration.File.Password.Parallelism = 2
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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")
}
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.PasswordHashing.Iterations)
assert.Equal(suite.T(), 0, suite.configuration.File.PasswordHashing.SaltLength)
assert.Equal(suite.T(), "", suite.configuration.File.PasswordHashing.Algorithm)
assert.Equal(suite.T(), 0, suite.configuration.File.PasswordHashing.Memory)
assert.Equal(suite.T(), 0, suite.configuration.File.PasswordHashing.Parallelism)
assert.Equal(suite.T(), 0, suite.configuration.File.Password.KeyLength)
assert.Equal(suite.T(), 0, suite.configuration.File.Password.Iterations)
assert.Equal(suite.T(), 0, suite.configuration.File.Password.SaltLength)
assert.Equal(suite.T(), "", suite.configuration.File.Password.Algorithm)
assert.Equal(suite.T(), 0, suite.configuration.File.Password.Memory)
assert.Equal(suite.T(), 0, suite.configuration.File.Password.Parallelism)
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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.DefaultPasswordOptionsConfiguration.Iterations, suite.configuration.File.PasswordHashing.Iterations)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.SaltLength, suite.configuration.File.PasswordHashing.SaltLength)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Algorithm, suite.configuration.File.PasswordHashing.Algorithm)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Memory, suite.configuration.File.PasswordHashing.Memory)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Parallelism, suite.configuration.File.PasswordHashing.Parallelism)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.KeyLength, suite.configuration.File.Password.KeyLength)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Iterations, suite.configuration.File.Password.Iterations)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.SaltLength, suite.configuration.File.Password.SaltLength)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Algorithm, suite.configuration.File.Password.Algorithm)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Memory, suite.configuration.File.Password.Memory)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Parallelism, suite.configuration.File.Password.Parallelism)
}
func (suite *FileBasedAuthenticationBackend) TestShouldSetDefaultConfigurationWhenOnlySHA512Set() {
suite.configuration.File.PasswordHashing = &schema.PasswordHashingConfiguration{}
assert.Equal(suite.T(), "", suite.configuration.File.PasswordHashing.Algorithm)
suite.configuration.File.PasswordHashing.Algorithm = "sha512"
suite.configuration.File.Password = &schema.PasswordConfiguration{}
assert.Equal(suite.T(), "", suite.configuration.File.Password.Algorithm)
suite.configuration.File.Password.Algorithm = "sha512"
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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.DefaultPasswordOptionsSHA512Configuration.Iterations, suite.configuration.File.PasswordHashing.Iterations)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.SaltLength, suite.configuration.File.PasswordHashing.SaltLength)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.Algorithm, suite.configuration.File.PasswordHashing.Algorithm)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.Memory, suite.configuration.File.PasswordHashing.Memory)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsSHA512Configuration.Parallelism, suite.configuration.File.PasswordHashing.Parallelism)
assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.KeyLength, suite.configuration.File.Password.KeyLength)
assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.Iterations, suite.configuration.File.Password.Iterations)
assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.SaltLength, suite.configuration.File.Password.SaltLength)
assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.Algorithm, suite.configuration.File.Password.Algorithm)
assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.Memory, suite.configuration.File.Password.Memory)
assert.Equal(suite.T(), schema.DefaultPasswordSHA512Configuration.Parallelism, suite.configuration.File.Password.Parallelism)
}
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenKeyLengthTooLow() {
suite.configuration.File.PasswordHashing.KeyLength = 1
suite.configuration.File.Password.KeyLength = 1
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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")
}
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSaltLengthTooLow() {
suite.configuration.File.PasswordHashing.SaltLength = -1
suite.configuration.File.Password.SaltLength = -1
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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")
}
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSaltLengthTooHigh() {
suite.configuration.File.PasswordHashing.SaltLength = 20
suite.configuration.File.Password.SaltLength = 20
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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")
}
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenBadAlgorithmDefined() {
suite.configuration.File.PasswordHashing.Algorithm = "bogus"
suite.configuration.File.Password.Algorithm = "bogus"
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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'")
}
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenIterationsTooLow() {
suite.configuration.File.PasswordHashing.Iterations = -1
suite.configuration.File.Password.Iterations = -1
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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")
}
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenParallelismTooLow() {
suite.configuration.File.PasswordHashing.Parallelism = -1
suite.configuration.File.Password.Parallelism = -1
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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")
}
func (suite *FileBasedAuthenticationBackend) TestShouldSetDefaultValues() {
suite.configuration.File.PasswordHashing.Algorithm = ""
suite.configuration.File.PasswordHashing.Iterations = 0
suite.configuration.File.PasswordHashing.SaltLength = 0
suite.configuration.File.PasswordHashing.Memory = 0
suite.configuration.File.PasswordHashing.Parallelism = 0
suite.configuration.File.Password.Algorithm = ""
suite.configuration.File.Password.Iterations = 0
suite.configuration.File.Password.SaltLength = 0
suite.configuration.File.Password.Memory = 0
suite.configuration.File.Password.Parallelism = 0
ValidateAuthenticationBackend(&suite.configuration, suite.validator)
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.DefaultPasswordOptionsConfiguration.Iterations, suite.configuration.File.PasswordHashing.Iterations)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.SaltLength, suite.configuration.File.PasswordHashing.SaltLength)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Memory, suite.configuration.File.PasswordHashing.Memory)
assert.Equal(suite.T(), schema.DefaultPasswordOptionsConfiguration.Parallelism, suite.configuration.File.PasswordHashing.Parallelism)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Algorithm, suite.configuration.File.Password.Algorithm)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Iterations, suite.configuration.File.Password.Iterations)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.SaltLength, suite.configuration.File.Password.SaltLength)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Memory, suite.configuration.File.Password.Memory)
assert.Equal(suite.T(), schema.DefaultPasswordConfiguration.Parallelism, suite.configuration.File.Password.Parallelism)
}
func TestFileBasedAuthenticationBackend(t *testing.T) {

View File

@ -29,7 +29,7 @@ const (
const operationFailedMessage = "Operation failed."
const authenticationFailedMessage = "Authentication failed. Check your credentials."
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 unableToResetPasswordMessage = "Unable to reset your password."
const mfaValidationFailedMessage = "Authentication failed, please retry later."