summaryrefslogtreecommitdiff
path: root/internal/configuration/validator
diff options
context:
space:
mode:
Diffstat (limited to 'internal/configuration/validator')
-rw-r--r--internal/configuration/validator/authentication.go4
-rw-r--r--internal/configuration/validator/authentication_test.go17
-rw-r--r--internal/configuration/validator/configuration.go2
-rw-r--r--internal/configuration/validator/configuration_test.go10
-rw-r--r--internal/configuration/validator/const.go140
-rw-r--r--internal/configuration/validator/keys.go4
-rw-r--r--internal/configuration/validator/secrets.go38
-rw-r--r--internal/configuration/validator/secrets_test.go18
-rw-r--r--internal/configuration/validator/server_test.go12
-rw-r--r--internal/configuration/validator/storage.go4
-rw-r--r--internal/configuration/validator/storage_test.go4
11 files changed, 160 insertions, 93 deletions
diff --git a/internal/configuration/validator/authentication.go b/internal/configuration/validator/authentication.go
index a0a6115e5..a024592cc 100644
--- a/internal/configuration/validator/authentication.go
+++ b/internal/configuration/validator/authentication.go
@@ -92,10 +92,6 @@ func validateLdapURL(ldapURL string, validator *schema.StructValidator) (finalUR
return "", ""
}
- if !parsedURL.IsAbs() {
- validator.Push(fmt.Errorf("URL to LDAP %s is still not absolute, it should be something like ldap://127.0.0.1:389", parsedURL.String()))
- }
-
return parsedURL.String(), parsedURL.Hostname()
}
diff --git a/internal/configuration/validator/authentication_test.go b/internal/configuration/validator/authentication_test.go
index 574a5b041..873ecdea1 100644
--- a/internal/configuration/validator/authentication_test.go
+++ b/internal/configuration/validator/authentication_test.go
@@ -10,7 +10,22 @@ import (
"github.com/authelia/authelia/internal/configuration/schema"
)
-func TestShouldRaiseErrorsWhenNoBackendProvided(t *testing.T) {
+func TestShouldRaiseErrorWhenBothBackendsProvided(t *testing.T) {
+ validator := schema.NewStructValidator()
+ backendConfig := schema.AuthenticationBackendConfiguration{}
+
+ backendConfig.Ldap = &schema.LDAPAuthenticationBackendConfiguration{}
+ backendConfig.File = &schema.FileAuthenticationBackendConfiguration{
+ Path: "/tmp",
+ }
+
+ ValidateAuthenticationBackend(&backendConfig, validator)
+
+ require.Len(t, validator.Errors(), 1)
+ assert.EqualError(t, validator.Errors()[0], "You cannot provide both `ldap` and `file` objects in `authentication_backend`")
+}
+
+func TestShouldRaiseErrorWhenNoBackendProvided(t *testing.T) {
validator := schema.NewStructValidator()
backendConfig := schema.AuthenticationBackendConfiguration{}
diff --git a/internal/configuration/validator/configuration.go b/internal/configuration/validator/configuration.go
index ea60e42df..e589c2177 100644
--- a/internal/configuration/validator/configuration.go
+++ b/internal/configuration/validator/configuration.go
@@ -8,7 +8,7 @@ import (
"github.com/authelia/authelia/internal/configuration/schema"
)
-var defaultPort = 8080
+var defaultPort = 9091
var defaultLogLevel = "info"
// ValidateConfiguration and adapt the configuration read from file.
diff --git a/internal/configuration/validator/configuration_test.go b/internal/configuration/validator/configuration_test.go
index dd036f8d3..3024da0f6 100644
--- a/internal/configuration/validator/configuration_test.go
+++ b/internal/configuration/validator/configuration_test.go
@@ -1,6 +1,7 @@
package validator
import (
+ "runtime"
"testing"
"github.com/stretchr/testify/assert"
@@ -54,7 +55,7 @@ func TestShouldValidateAndUpdatePort(t *testing.T) {
ValidateConfiguration(&config, validator)
require.Len(t, validator.Errors(), 0)
- assert.Equal(t, 8080, config.Port)
+ assert.Equal(t, 9091, config.Port)
}
func TestShouldValidateAndUpdateHost(t *testing.T) {
@@ -170,7 +171,12 @@ func TestShouldRaiseErrorOnInvalidCertificatesDirectory(t *testing.T) {
ValidateConfiguration(&config, validator)
require.Len(t, validator.Errors(), 1)
- assert.EqualError(t, validator.Errors()[0], "Error checking certificate directory: stat not-a-real-file.go: no such file or directory")
+
+ if runtime.GOOS == "windows" {
+ assert.EqualError(t, validator.Errors()[0], "Error checking certificate directory: CreateFile not-a-real-file.go: The system cannot find the file specified.")
+ } else {
+ assert.EqualError(t, validator.Errors()[0], "Error checking certificate directory: stat not-a-real-file.go: no such file or directory")
+ }
validator = schema.NewStructValidator()
config.CertificatesDirectory = "const.go"
diff --git a/internal/configuration/validator/const.go b/internal/configuration/validator/const.go
index fbd0af721..c06484c8d 100644
--- a/internal/configuration/validator/const.go
+++ b/internal/configuration/validator/const.go
@@ -1,7 +1,57 @@
package validator
+const (
+ errFmtSessionSecretRedisProvider = "The session secret must be set when using the %s session provider"
+ errFmtSessionRedisPortRange = "The port must be between 1 and 65535 for the %s session provider"
+ errFmtSessionRedisHostRequired = "The host must be provided when using the %s session provider"
+ errFmtSessionRedisHostOrNodesRequired = "Either the host or a node must be provided when using the %s session provider"
+
+ errFileHashing = "config key incorrect: authentication_backend.file.hashing should be authentication_backend.file.password"
+ errFilePHashing = "config key incorrect: authentication_backend.file.password_hashing should be authentication_backend.file.password"
+ errFilePOptions = "config key incorrect: authentication_backend.file.password_options should be authentication_backend.file.password"
+
+ denyPolicy = "deny"
+ bypassPolicy = "bypass"
+
+ argon2id = "argon2id"
+ sha512 = "sha512"
+
+ schemeLDAP = "ldap"
+ schemeLDAPS = "ldaps"
+
+ testBadTimer = "-1"
+ testInvalidPolicy = "invalid"
+ testJWTSecret = "a_secret"
+ testLDAPBaseDN = "base_dn"
+ testLDAPPassword = "password"
+ testLDAPURL = "ldap://ldap"
+ testLDAPUser = "user"
+ testModeDisabled = "disable"
+ testTLSCert = "/tmp/cert.pem"
+ testTLSKey = "/tmp/key.pem"
+
+ errAccessControlInvalidPolicyWithSubjects = "Policy [bypass] for domain %s with subjects %s is invalid. It is " +
+ "not supported to configure both policy bypass and subjects. For more information see: " +
+ "https://www.authelia.com/docs/configuration/access-control.html#combining-subjects-and-the-bypass-policy"
+)
+
var validRequestMethods = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "TRACE", "CONNECT", "OPTIONS"}
+// SecretNames contains a map of secret names.
+var SecretNames = map[string]string{
+ "JWTSecret": "jwt_secret",
+ "SessionSecret": "session.secret",
+ "DUOSecretKey": "duo_api.secret_key",
+ "RedisPassword": "session.redis.password",
+ "RedisSentinelPassword": "session.redis.high_availability.sentinel_password",
+ "LDAPPassword": "authentication_backend.ldap.password",
+ "SMTPPassword": "notifier.smtp.password",
+ "MySQLPassword": "storage.mysql.password",
+ "PostgreSQLPassword": "storage.postgres.password",
+}
+
+// validKeys is a list of valid keys that are not secret names. For the sake of consistency please place any secret in
+// the secret names map and reuse it in relevant sections.
var validKeys = []string{
// Root Keys.
"host",
@@ -10,7 +60,6 @@ var validKeys = []string{
"log_format",
"log_file_path",
"default_redirection_url",
- "jwt_secret",
"theme",
"tls_key",
"tls_cert",
@@ -33,7 +82,6 @@ var validKeys = []string{
// Session Keys.
"session.name",
- "session.secret",
"session.expiration",
"session.inactivity",
"session.remember_me_duration",
@@ -43,7 +91,6 @@ var validKeys = []string{
"session.redis.host",
"session.redis.port",
"session.redis.username",
- "session.redis.password",
"session.redis.database_index",
"session.redis.maximum_active_connections",
"session.redis.minimum_idle_connections",
@@ -51,7 +98,6 @@ var validKeys = []string{
"session.redis.tls.skip_verify",
"session.redis.tls.server_name",
"session.redis.high_availability.sentinel_name",
- "session.redis.high_availability.sentinel_password",
"session.redis.high_availability.nodes",
"session.redis.high_availability.route_by_latency",
"session.redis.high_availability.route_randomly",
@@ -69,14 +115,12 @@ var validKeys = []string{
"storage.mysql.port",
"storage.mysql.database",
"storage.mysql.username",
- "storage.mysql.password",
// PostgreSQL Storage Keys.
"storage.postgres.host",
"storage.postgres.port",
"storage.postgres.database",
"storage.postgres.username",
- "storage.postgres.password",
"storage.postgres.sslmode",
// FileSystem Notifier Keys.
@@ -85,7 +129,6 @@ var validKeys = []string{
// SMTP Notifier Keys.
"notifier.smtp.username",
- "notifier.smtp.password",
"notifier.smtp.host",
"notifier.smtp.port",
"notifier.smtp.identifier",
@@ -108,7 +151,6 @@ var validKeys = []string{
// DUO API Keys.
"duo_api.hostname",
"duo_api.integration_key",
- "duo_api.secret_key",
// Authentication Backend Keys.
"authentication_backend.disable_reset_password",
@@ -127,7 +169,6 @@ var validKeys = []string{
"authentication_backend.ldap.mail_attribute",
"authentication_backend.ldap.display_name_attribute",
"authentication_backend.ldap.user",
- "authentication_backend.ldap.password",
"authentication_backend.ldap.start_tls",
"authentication_backend.ldap.tls.minimum_version",
"authentication_backend.ldap.tls.skip_verify",
@@ -143,73 +184,28 @@ var validKeys = []string{
"authentication_backend.file.password.salt_length",
"authentication_backend.file.password.memory",
"authentication_backend.file.password.parallelism",
-
- // Secret Keys.
- "authelia.jwt_secret",
- "authelia.duo_api.secret_key",
- "authelia.session.secret",
- "authelia.authentication_backend.ldap.password",
- "authelia.notifier.smtp.password",
- "authelia.session.redis.password",
- "authelia.storage.mysql.password",
- "authelia.storage.postgres.password",
- "authelia.jwt_secret.file",
- "authelia.duo_api.secret_key.file",
- "authelia.session.secret.file",
- "authelia.authentication_backend.ldap.password.file",
- "authelia.notifier.smtp.password.file",
- "authelia.session.redis.password.file",
- "authelia.storage.mysql.password.file",
- "authelia.storage.postgres.password.file",
}
var specificErrorKeys = map[string]string{
"logs_file_path": "config key replaced: logs_file is now log_file",
"logs_level": "config key replaced: logs_level is now log_level",
"google_analytics": "config key removed: google_analytics - this functionality has been deprecated",
- "authentication_backend.file.password_options.algorithm": "config key incorrect: authentication_backend.file.password_options should be authentication_backend.file.password",
- "authentication_backend.file.password_options.iterations": "config key incorrect: authentication_backend.file.password_options should be authentication_backend.file.password",
- "authentication_backend.file.password_options.key_length": "config key incorrect: authentication_backend.file.password_options should be authentication_backend.file.password",
- "authentication_backend.file.password_options.salt_length": "config key incorrect: authentication_backend.file.password_options should be authentication_backend.file.password",
- "authentication_backend.file.password_options.memory": "config key incorrect: authentication_backend.file.password_options should be authentication_backend.file.password",
- "authentication_backend.file.password_options.parallelism": "config key incorrect: authentication_backend.file.password_options should be authentication_backend.file.password",
- "authentication_backend.file.password_hashing.algorithm": "config key incorrect: authentication_backend.file.password_hashing should be authentication_backend.file.password",
- "authentication_backend.file.password_hashing.iterations": "config key incorrect: authentication_backend.file.password_hashing should be authentication_backend.file.password",
- "authentication_backend.file.password_hashing.key_length": "config key incorrect: authentication_backend.file.password_hashing should be authentication_backend.file.password",
- "authentication_backend.file.password_hashing.salt_length": "config key incorrect: authentication_backend.file.password_hashing should be authentication_backend.file.password",
- "authentication_backend.file.password_hashing.memory": "config key incorrect: authentication_backend.file.password_hashing should be authentication_backend.file.password",
- "authentication_backend.file.password_hashing.parallelism": "config key incorrect: authentication_backend.file.password_hashing should be authentication_backend.file.password",
- "authentication_backend.file.hashing.algorithm": "config key incorrect: authentication_backend.file.hashing should be authentication_backend.file.password",
- "authentication_backend.file.hashing.iterations": "config key incorrect: authentication_backend.file.hashing should be authentication_backend.file.password",
- "authentication_backend.file.hashing.key_length": "config key incorrect: authentication_backend.file.hashing should be authentication_backend.file.password",
- "authentication_backend.file.hashing.salt_length": "config key incorrect: authentication_backend.file.hashing should be authentication_backend.file.password",
- "authentication_backend.file.hashing.memory": "config key incorrect: authentication_backend.file.hashing should be authentication_backend.file.password",
- "authentication_backend.file.hashing.parallelism": "config key incorrect: authentication_backend.file.hashing should be authentication_backend.file.password",
+ "authentication_backend.file.password_options.algorithm": errFilePOptions,
+ "authentication_backend.file.password_options.iterations": errFilePOptions,
+ "authentication_backend.file.password_options.key_length": errFilePOptions,
+ "authentication_backend.file.password_options.salt_length": errFilePOptions,
+ "authentication_backend.file.password_options.memory": errFilePOptions,
+ "authentication_backend.file.password_options.parallelism": errFilePOptions,
+ "authentication_backend.file.password_hashing.algorithm": errFilePHashing,
+ "authentication_backend.file.password_hashing.iterations": errFilePHashing,
+ "authentication_backend.file.password_hashing.key_length": errFilePHashing,
+ "authentication_backend.file.password_hashing.salt_length": errFilePHashing,
+ "authentication_backend.file.password_hashing.memory": errFilePHashing,
+ "authentication_backend.file.password_hashing.parallelism": errFilePHashing,
+ "authentication_backend.file.hashing.algorithm": errFileHashing,
+ "authentication_backend.file.hashing.iterations": errFileHashing,
+ "authentication_backend.file.hashing.key_length": errFileHashing,
+ "authentication_backend.file.hashing.salt_length": errFileHashing,
+ "authentication_backend.file.hashing.memory": errFileHashing,
+ "authentication_backend.file.hashing.parallelism": errFileHashing,
}
-
-const errFmtSessionSecretRedisProvider = "The session secret must be set when using the %s session provider"
-const errFmtSessionRedisPortRange = "The port must be between 1 and 65535 for the %s session provider"
-const errFmtSessionRedisHostRequired = "The host must be provided when using the %s session provider"
-const errFmtSessionRedisHostOrNodesRequired = "Either the host or a node must be provided when using the %s session provider"
-
-const denyPolicy = "deny"
-const bypassPolicy = "bypass"
-
-const argon2id = "argon2id"
-const sha512 = "sha512"
-
-const schemeLDAP = "ldap"
-const schemeLDAPS = "ldaps"
-
-const testBadTimer = "-1"
-const testInvalidPolicy = "invalid"
-const testJWTSecret = "a_secret"
-const testLDAPBaseDN = "base_dn"
-const testLDAPPassword = "password"
-const testLDAPURL = "ldap://ldap"
-const testLDAPUser = "user"
-const testModeDisabled = "disable"
-const testTLSCert = "/tmp/cert.pem"
-const testTLSKey = "/tmp/key.pem"
-
-const errAccessControlInvalidPolicyWithSubjects = "Policy [bypass] for domain %s with subjects %s is invalid. It is not supported to configure both policy bypass and subjects. For more information see: https://www.authelia.com/docs/configuration/access-control.html#combining-subjects-and-the-bypass-policy"
diff --git a/internal/configuration/validator/keys.go b/internal/configuration/validator/keys.go
index bc20effcf..6412312a0 100644
--- a/internal/configuration/validator/keys.go
+++ b/internal/configuration/validator/keys.go
@@ -17,6 +17,10 @@ func ValidateKeys(validator *schema.StructValidator, keys []string) {
continue
}
+ if isSecretKey(key) {
+ continue
+ }
+
if err, ok := specificErrorKeys[key]; ok {
if !utils.IsStringInSlice(err, errStrings) {
errStrings = append(errStrings, err)
diff --git a/internal/configuration/validator/secrets.go b/internal/configuration/validator/secrets.go
index cd6305808..244022aef 100644
--- a/internal/configuration/validator/secrets.go
+++ b/internal/configuration/validator/secrets.go
@@ -10,39 +10,59 @@ import (
"github.com/authelia/authelia/internal/configuration/schema"
)
+// SecretNameToEnvName converts a secret name into the env name.
+func SecretNameToEnvName(secretName string) (envName string) {
+ return "authelia." + secretName + ".file"
+}
+
+func isSecretKey(value string) (isSecretKey bool) {
+ for _, secretKey := range SecretNames {
+ if value == secretKey || value == SecretNameToEnvName(secretKey) {
+ return true
+ }
+ }
+
+ return false
+}
+
// ValidateSecrets checks that secrets are either specified by config file/env or by file references.
func ValidateSecrets(configuration *schema.Configuration, validator *schema.StructValidator, viper *viper.Viper) {
- configuration.JWTSecret = getSecretValue("jwt_secret", validator, viper)
- configuration.Session.Secret = getSecretValue("session.secret", validator, viper)
+ configuration.JWTSecret = getSecretValue(SecretNames["JWTSecret"], validator, viper)
+ configuration.Session.Secret = getSecretValue(SecretNames["SessionSecret"], validator, viper)
if configuration.DuoAPI != nil {
- configuration.DuoAPI.SecretKey = getSecretValue("duo_api.secret_key", validator, viper)
+ configuration.DuoAPI.SecretKey = getSecretValue(SecretNames["DUOSecretKey"], validator, viper)
}
if configuration.Session.Redis != nil {
- configuration.Session.Redis.Password = getSecretValue("session.redis.password", validator, viper)
+ configuration.Session.Redis.Password = getSecretValue(SecretNames["RedisPassword"], validator, viper)
+
+ if configuration.Session.Redis.HighAvailability != nil {
+ configuration.Session.Redis.HighAvailability.SentinelPassword =
+ getSecretValue(SecretNames["RedisSentinelPassword"], validator, viper)
+ }
}
if configuration.AuthenticationBackend.Ldap != nil {
- configuration.AuthenticationBackend.Ldap.Password = getSecretValue("authentication_backend.ldap.password", validator, viper)
+ configuration.AuthenticationBackend.Ldap.Password = getSecretValue(SecretNames["LDAPPassword"], validator, viper)
}
if configuration.Notifier != nil && configuration.Notifier.SMTP != nil {
- configuration.Notifier.SMTP.Password = getSecretValue("notifier.smtp.password", validator, viper)
+ configuration.Notifier.SMTP.Password = getSecretValue(SecretNames["SMTPPassword"], validator, viper)
}
if configuration.Storage.MySQL != nil {
- configuration.Storage.MySQL.Password = getSecretValue("storage.mysql.password", validator, viper)
+ configuration.Storage.MySQL.Password = getSecretValue(SecretNames["MySQLPassword"], validator, viper)
}
if configuration.Storage.PostgreSQL != nil {
- configuration.Storage.PostgreSQL.Password = getSecretValue("storage.postgres.password", validator, viper)
+ configuration.Storage.PostgreSQL.Password = getSecretValue(SecretNames["PostgreSQLPassword"], validator, viper)
}
}
func getSecretValue(name string, validator *schema.StructValidator, viper *viper.Viper) string {
configValue := viper.GetString(name)
- fileEnvValue := viper.GetString("authelia." + name + ".file")
+ fileEnvValue := viper.GetString(SecretNameToEnvName(name))
// Error Checking.
if fileEnvValue != "" && configValue != "" {
diff --git a/internal/configuration/validator/secrets_test.go b/internal/configuration/validator/secrets_test.go
new file mode 100644
index 000000000..6d180dfde
--- /dev/null
+++ b/internal/configuration/validator/secrets_test.go
@@ -0,0 +1,18 @@
+package validator
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestShouldValidateCorrectSecretKeys(t *testing.T) {
+ assert.True(t, isSecretKey("jwt_secret"))
+ assert.True(t, isSecretKey("authelia.jwt_secret.file"))
+ assert.False(t, isSecretKey("totp.issuer"))
+}
+
+func TestShouldCreateCorrectSecretEnvNames(t *testing.T) {
+ assert.Equal(t, "authelia.jwt_secret.file", SecretNameToEnvName("jwt_secret"))
+ assert.Equal(t, "authelia.not_a_real_secret.file", SecretNameToEnvName("not_a_real_secret"))
+}
diff --git a/internal/configuration/validator/server_test.go b/internal/configuration/validator/server_test.go
index dee5b5746..25c1bde71 100644
--- a/internal/configuration/validator/server_test.go
+++ b/internal/configuration/validator/server_test.go
@@ -18,6 +18,18 @@ func TestShouldSetDefaultConfig(t *testing.T) {
assert.Equal(t, defaultWriteBufferSize, config.WriteBufferSize)
}
+func TestShouldParsePathCorrectly(t *testing.T) {
+ validator := schema.NewStructValidator()
+ config := schema.ServerConfiguration{
+ Path: "apple",
+ }
+
+ ValidateServer(&config, validator)
+ require.Len(t, validator.Errors(), 0)
+
+ assert.Equal(t, "/apple", config.Path)
+}
+
func TestShouldRaiseOnNegativeValues(t *testing.T) {
validator := schema.NewStructValidator()
config := schema.ServerConfiguration{
diff --git a/internal/configuration/validator/storage.go b/internal/configuration/validator/storage.go
index f0033a174..d1596757e 100644
--- a/internal/configuration/validator/storage.go
+++ b/internal/configuration/validator/storage.go
@@ -24,11 +24,11 @@ func ValidateStorage(configuration schema.StorageConfiguration, validator *schem
func validateSQLConfiguration(configuration *schema.SQLStorageConfiguration, validator *schema.StructValidator) {
if configuration.Password == "" || configuration.Username == "" {
- validator.Push(errors.New("Username and password must be provided"))
+ validator.Push(errors.New("the SQL username and password must be provided"))
}
if configuration.Database == "" {
- validator.Push(errors.New("A database must be provided"))
+ validator.Push(errors.New("the SQL database must be provided"))
}
}
diff --git a/internal/configuration/validator/storage_test.go b/internal/configuration/validator/storage_test.go
index a9f442004..dc2550924 100644
--- a/internal/configuration/validator/storage_test.go
+++ b/internal/configuration/validator/storage_test.go
@@ -55,8 +55,8 @@ func (suite *StorageSuite) TestShouldValidateSQLUsernamePasswordAndDatabaseArePr
ValidateStorage(suite.configuration, suite.validator)
suite.Require().Len(suite.validator.Errors(), 2)
- suite.Assert().EqualError(suite.validator.Errors()[0], "Username and password must be provided")
- suite.Assert().EqualError(suite.validator.Errors()[1], "A database must be provided")
+ suite.Assert().EqualError(suite.validator.Errors()[0], "the SQL username and password must be provided")
+ suite.Assert().EqualError(suite.validator.Errors()[1], "the SQL database must be provided")
suite.validator.Clear()
suite.configuration.MySQL = &schema.MySQLStorageConfiguration{