diff options
| author | James Elliott <james-d-elliott@users.noreply.github.com> | 2020-03-06 12:38:02 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-06 12:38:02 +1100 |
| commit | 26369fff3d8d397018a08ae044f36b723fc7d880 (patch) | |
| tree | b91dace87f3bb683491975cb5eb74e8babd6b7f4 /internal/configuration/validator/authentication_test.go | |
| parent | 72a3f1e0d7524a1d86e87781d264d5db195ea3e6 (diff) | |
[FEATURE] Support Argon2id password hasing and improved entropy (#679)
* [FEATURE] Support Argon2id Passwords
- Updated go module github.com/simia-tech/crypt
- Added Argon2id support for file based authentication backend
- Made it the default method
- Made it so backwards compatibility with SHA512 exists
- Force seeding of the random string generator used for salts to ensure they are all different
- Added command params to the authelia hash-password command
- Automatically remove {CRYPT} from hashes as they are updated
- Automatically change hashes when they are updated to the configured algorithm
- Made the hashing algorithm parameters completely configurable
- Added reasonably comprehensive test suites
- Updated docs
- Updated config template
* Adjust error output
* Fix unit test
* Add unit tests and argon2 version check
* Fix new unit tests
* Update docs, added tests
* Implement configurable values and more comprehensive testing
* Added cmd params to hash_password, updated docs, misc fixes
* More detailed error for cmd, fixed a typo
* Fixed cmd flag error, minor refactoring
* Requested Changes and Minor refactoring
* Increase entropy
* Update docs for entropy changes
* Refactor to reduce nesting and easier code maintenance
* Cleanup Errors (uniformity for the function call)
* Check salt length, fix docs
* Add Base64 string validation for argon2id
* Cleanup and Finalization
- Moved RandomString function from ./internal/authentication/password_hash.go to ./internal/utils/strings.go
- Added SplitStringToArrayOfStrings func that splits strings into an array with a fixed max string len
- Fixed an error in validator that would allow a zero salt length
- Added a test to verify the upstream crypt module supports our defined random salt chars
- Updated docs
- Removed unused "HashingAlgorithm" string type
* Update crypt go mod, support argon2id key length and major refactor
* Config Template Update, Final Tests
* Use schema defaults for hash-password cmd
* Iterations check
* Docs requested changes
* Test Coverage, suggested edits
* Wording edit
* Doc changes
* Default sanity changes
* Default sanity changes - docs
* CI Sanity changes
* Memory in MB
Diffstat (limited to 'internal/configuration/validator/authentication_test.go')
| -rw-r--r-- | internal/configuration/validator/authentication_test.go | 112 |
1 files changed, 110 insertions, 2 deletions
diff --git a/internal/configuration/validator/authentication_test.go b/internal/configuration/validator/authentication_test.go index f61dbebdc..a3333f172 100644 --- a/internal/configuration/validator/authentication_test.go +++ b/internal/configuration/validator/authentication_test.go @@ -28,9 +28,16 @@ type FileBasedAuthenticationBackend struct { func (suite *FileBasedAuthenticationBackend) SetupTest() { suite.validator = schema.NewStructValidator() suite.configuration = schema.AuthenticationBackendConfiguration{} - suite.configuration.File = &schema.FileAuthenticationBackendConfiguration{Path: "/a/path"} + 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.PasswordHashing.Algorithm = schema.DefaultPasswordOptionsConfiguration.Algorithm } - func (suite *FileBasedAuthenticationBackend) TestShouldValidateCompleteConfiguration() { ValidateAuthenticationBackend(&suite.configuration, suite.validator) assert.Len(suite.T(), suite.validator.Errors(), 0) @@ -43,6 +50,107 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenNoPathProvi assert.EqualError(suite.T(), suite.validator.Errors()[0], "Please provide a `path` for the users database in `authentication_backend`") } +func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenMemoryNotMoreThanEightTimesParallelism() { + suite.configuration.File.PasswordHashing.Memory = 8 + suite.configuration.File.PasswordHashing.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{} + + 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) + + 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) +} + +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" + + 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) +} +func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenKeyLengthTooLow() { + suite.configuration.File.PasswordHashing.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 + 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 + 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" + 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 + 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 + 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 + 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) +} + func TestFileBasedAuthenticationBackend(t *testing.T) { suite.Run(t, new(FileBasedAuthenticationBackend)) } |
