mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
cc4f47f21c
This removes the deprecated options from 4.25. This includes the LDAP filters which allow {0} or {1} placeholders. The new aliases are documented. Additionally it refactors the keys validator to use uniform messages for most replaced keys.
283 lines
13 KiB
Go
283 lines
13 KiB
Go
package configuration
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"runtime"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/authelia/authelia/internal/authentication"
|
|
"github.com/authelia/authelia/internal/utils"
|
|
)
|
|
|
|
func createTestingTempFile(t *testing.T, dir, name, content string) {
|
|
err := ioutil.WriteFile(path.Join(dir, name), []byte(content), 0600)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func resetEnv() {
|
|
_ = os.Unsetenv("AUTHELIA_JWT_SECRET_FILE")
|
|
_ = os.Unsetenv("AUTHELIA_DUO_API_SECRET_KEY_FILE")
|
|
_ = os.Unsetenv("AUTHELIA_SESSION_SECRET_FILE")
|
|
_ = os.Unsetenv("AUTHELIA_SESSION_SECRET_FILE")
|
|
_ = os.Unsetenv("AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE")
|
|
_ = os.Unsetenv("AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE")
|
|
_ = os.Unsetenv("AUTHELIA_SESSION_REDIS_PASSWORD_FILE")
|
|
_ = os.Unsetenv("AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_PASSWORD_FILE")
|
|
_ = os.Unsetenv("AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE")
|
|
_ = os.Unsetenv("AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE")
|
|
}
|
|
|
|
func setupEnv(t *testing.T) string {
|
|
resetEnv()
|
|
|
|
dirEnv := os.Getenv("AUTHELIA_TESTING_DIR")
|
|
if dirEnv != "" {
|
|
return dirEnv
|
|
}
|
|
|
|
dir := "/tmp/authelia" + utils.RandomString(10, authentication.HashingPossibleSaltCharacters) + "/"
|
|
err := os.MkdirAll(dir, 0700)
|
|
require.NoError(t, err)
|
|
|
|
createTestingTempFile(t, dir, "jwt", "secret_from_env")
|
|
createTestingTempFile(t, dir, "duo", "duo_secret_from_env")
|
|
createTestingTempFile(t, dir, "session", "session_secret_from_env")
|
|
createTestingTempFile(t, dir, "authentication", "ldap_secret_from_env")
|
|
createTestingTempFile(t, dir, "notifier", "smtp_secret_from_env")
|
|
createTestingTempFile(t, dir, "redis", "redis_secret_from_env")
|
|
createTestingTempFile(t, dir, "redis-sentinel", "redis-sentinel_secret_from_env")
|
|
createTestingTempFile(t, dir, "mysql", "mysql_secret_from_env")
|
|
createTestingTempFile(t, dir, "postgres", "postgres_secret_from_env")
|
|
|
|
require.NoError(t, os.Setenv("AUTHELIA_TESTING_DIR", dir))
|
|
|
|
return dir
|
|
}
|
|
|
|
func TestShouldErrorNoConfigPath(t *testing.T) {
|
|
_, errors := Read("")
|
|
|
|
require.Len(t, errors, 1)
|
|
|
|
require.EqualError(t, errors[0], "No config file path provided")
|
|
}
|
|
|
|
func TestShouldErrorSecretNotExist(t *testing.T) {
|
|
dir := "/path/not/exist"
|
|
|
|
require.NoError(t, os.Setenv("AUTHELIA_JWT_SECRET_FILE", dir+"jwt"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_DUO_API_SECRET_KEY_FILE", dir+"duo"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_SECRET_FILE", dir+"session"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE", dir+"authentication"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE", dir+"notifier"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_REDIS_PASSWORD_FILE", dir+"redis"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_PASSWORD_FILE", dir+"redis-sentinel"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE", dir+"mysql"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE", dir+"postgres"))
|
|
|
|
_, errors := Read("./test_resources/config.yml")
|
|
|
|
require.Len(t, errors, 12)
|
|
|
|
if runtime.GOOS == windows {
|
|
assert.EqualError(t, errors[0], "error loading secret file (jwt_secret): open /path/not/existjwt: The system cannot find the path specified.")
|
|
assert.EqualError(t, errors[1], "error loading secret file (session.secret): open /path/not/existsession: The system cannot find the path specified.")
|
|
assert.EqualError(t, errors[2], "error loading secret file (duo_api.secret_key): open /path/not/existduo: The system cannot find the path specified.")
|
|
assert.EqualError(t, errors[3], "error loading secret file (session.redis.password): open /path/not/existredis: The system cannot find the path specified.")
|
|
assert.EqualError(t, errors[4], "error loading secret file (session.redis.high_availability.sentinel_password): open /path/not/existredis-sentinel: The system cannot find the path specified.")
|
|
assert.EqualError(t, errors[5], "error loading secret file (authentication_backend.ldap.password): open /path/not/existauthentication: The system cannot find the path specified.")
|
|
assert.EqualError(t, errors[6], "error loading secret file (notifier.smtp.password): open /path/not/existnotifier: The system cannot find the path specified.")
|
|
assert.EqualError(t, errors[7], "error loading secret file (storage.mysql.password): open /path/not/existmysql: The system cannot find the path specified.")
|
|
} else {
|
|
assert.EqualError(t, errors[0], "error loading secret file (jwt_secret): open /path/not/existjwt: no such file or directory")
|
|
assert.EqualError(t, errors[1], "error loading secret file (session.secret): open /path/not/existsession: no such file or directory")
|
|
assert.EqualError(t, errors[2], "error loading secret file (duo_api.secret_key): open /path/not/existduo: no such file or directory")
|
|
assert.EqualError(t, errors[3], "error loading secret file (session.redis.password): open /path/not/existredis: no such file or directory")
|
|
assert.EqualError(t, errors[4], "error loading secret file (session.redis.high_availability.sentinel_password): open /path/not/existredis-sentinel: no such file or directory")
|
|
assert.EqualError(t, errors[5], "error loading secret file (authentication_backend.ldap.password): open /path/not/existauthentication: no such file or directory")
|
|
assert.EqualError(t, errors[6], "error loading secret file (notifier.smtp.password): open /path/not/existnotifier: no such file or directory")
|
|
assert.EqualError(t, errors[7], "error loading secret file (storage.mysql.password): open /path/not/existmysql: no such file or directory")
|
|
}
|
|
|
|
assert.EqualError(t, errors[8], "Provide a JWT secret using \"jwt_secret\" key")
|
|
assert.EqualError(t, errors[9], "Please provide a password to connect to the LDAP server")
|
|
assert.EqualError(t, errors[10], "The session secret must be set when using the redis sentinel session provider")
|
|
assert.EqualError(t, errors[11], "the SQL username and password must be provided")
|
|
}
|
|
|
|
func TestShouldErrorPermissionsOnLocalFS(t *testing.T) {
|
|
if runtime.GOOS == windows {
|
|
t.Skip("skipping test due to being on windows")
|
|
}
|
|
|
|
resetEnv()
|
|
|
|
_ = os.Mkdir("/tmp/noperms/", 0000)
|
|
_, errors := Read("/tmp/noperms/configuration.yml")
|
|
|
|
require.Len(t, errors, 3)
|
|
|
|
require.EqualError(t, errors[0], "Unable to find config file: /tmp/noperms/configuration.yml")
|
|
require.EqualError(t, errors[1], "Generating config file: /tmp/noperms/configuration.yml")
|
|
require.EqualError(t, errors[2], "Unable to generate /tmp/noperms/configuration.yml: open /tmp/noperms/configuration.yml: permission denied")
|
|
}
|
|
|
|
func TestShouldErrorAndGenerateConfigFile(t *testing.T) {
|
|
_, errors := Read("./nonexistent.yml")
|
|
_ = os.Remove("./nonexistent.yml")
|
|
|
|
require.Len(t, errors, 3)
|
|
|
|
require.EqualError(t, errors[0], "Unable to find config file: ./nonexistent.yml")
|
|
require.EqualError(t, errors[1], "Generating config file: ./nonexistent.yml")
|
|
require.EqualError(t, errors[2], "Generated configuration at: ./nonexistent.yml")
|
|
}
|
|
|
|
func TestShouldErrorPermissionsConfigFile(t *testing.T) {
|
|
resetEnv()
|
|
|
|
_ = ioutil.WriteFile("/tmp/authelia/permissions.yml", []byte{}, 0000) // nolint:gosec
|
|
_, errors := Read("/tmp/authelia/permissions.yml")
|
|
|
|
if runtime.GOOS == windows {
|
|
require.Len(t, errors, 5)
|
|
assert.EqualError(t, errors[0], "Provide a JWT secret using \"jwt_secret\" key")
|
|
assert.EqualError(t, errors[1], "Please provide `ldap` or `file` object in `authentication_backend`")
|
|
assert.EqualError(t, errors[2], "Set domain of the session object")
|
|
assert.EqualError(t, errors[3], "A storage configuration must be provided. It could be 'local', 'mysql' or 'postgres'")
|
|
assert.EqualError(t, errors[4], "A notifier configuration must be provided")
|
|
} else {
|
|
require.Len(t, errors, 1)
|
|
|
|
assert.EqualError(t, errors[0], "Failed to open /tmp/authelia/permissions.yml: permission denied")
|
|
}
|
|
}
|
|
|
|
func TestShouldErrorParseBadConfigFile(t *testing.T) {
|
|
_, errors := Read("./test_resources/config_bad_quoting.yml")
|
|
|
|
require.Len(t, errors, 1)
|
|
|
|
require.EqualError(t, errors[0], "Error malformed yaml: line 24: did not find expected alphabetic or numeric character")
|
|
}
|
|
|
|
func TestShouldParseConfigFile(t *testing.T) {
|
|
dir := setupEnv(t)
|
|
|
|
require.NoError(t, os.Setenv("AUTHELIA_JWT_SECRET_FILE", dir+"jwt"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_DUO_API_SECRET_KEY_FILE", dir+"duo"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_SECRET_FILE", dir+"session"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE", dir+"authentication"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE", dir+"notifier"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_REDIS_PASSWORD_FILE", dir+"redis"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_PASSWORD_FILE", dir+"redis-sentinel"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE", dir+"mysql"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE", dir+"postgres"))
|
|
|
|
config, errors := Read("./test_resources/config.yml")
|
|
|
|
require.Len(t, errors, 0)
|
|
|
|
assert.Equal(t, 9091, config.Port)
|
|
assert.Equal(t, "debug", config.LogLevel)
|
|
assert.Equal(t, "https://home.example.com:8080/", config.DefaultRedirectionURL)
|
|
assert.Equal(t, "authelia.com", config.TOTP.Issuer)
|
|
assert.Equal(t, "secret_from_env", config.JWTSecret)
|
|
|
|
assert.Equal(t, "api-123456789.example.com", config.DuoAPI.Hostname)
|
|
assert.Equal(t, "ABCDEF", config.DuoAPI.IntegrationKey)
|
|
assert.Equal(t, "duo_secret_from_env", config.DuoAPI.SecretKey)
|
|
|
|
assert.Equal(t, "session_secret_from_env", config.Session.Secret)
|
|
assert.Equal(t, "ldap_secret_from_env", config.AuthenticationBackend.LDAP.Password)
|
|
assert.Equal(t, "smtp_secret_from_env", config.Notifier.SMTP.Password)
|
|
assert.Equal(t, "redis_secret_from_env", config.Session.Redis.Password)
|
|
assert.Equal(t, "redis-sentinel_secret_from_env", config.Session.Redis.HighAvailability.SentinelPassword)
|
|
assert.Equal(t, "mysql_secret_from_env", config.Storage.MySQL.Password)
|
|
|
|
assert.Equal(t, "deny", config.AccessControl.DefaultPolicy)
|
|
assert.Len(t, config.AccessControl.Rules, 12)
|
|
|
|
require.NotNil(t, config.Session)
|
|
require.NotNil(t, config.Session.Redis)
|
|
require.NotNil(t, config.Session.Redis.HighAvailability)
|
|
}
|
|
|
|
func TestShouldParseAltConfigFile(t *testing.T) {
|
|
dir := setupEnv(t)
|
|
|
|
require.NoError(t, os.Setenv("AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE", dir+"postgres"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE", dir+"authentication"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_JWT_SECRET_FILE", dir+"jwt"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_SECRET_FILE", dir+"session"))
|
|
|
|
config, errors := Read("./test_resources/config_alt.yml")
|
|
require.Len(t, errors, 0)
|
|
|
|
assert.Equal(t, 9091, config.Port)
|
|
assert.Equal(t, "debug", config.LogLevel)
|
|
assert.Equal(t, "https://home.example.com:8080/", config.DefaultRedirectionURL)
|
|
assert.Equal(t, "authelia.com", config.TOTP.Issuer)
|
|
assert.Equal(t, "secret_from_env", config.JWTSecret)
|
|
|
|
assert.Equal(t, "api-123456789.example.com", config.DuoAPI.Hostname)
|
|
assert.Equal(t, "ABCDEF", config.DuoAPI.IntegrationKey)
|
|
assert.Equal(t, "postgres_secret_from_env", config.Storage.PostgreSQL.Password)
|
|
|
|
assert.Equal(t, "deny", config.AccessControl.DefaultPolicy)
|
|
assert.Len(t, config.AccessControl.Rules, 12)
|
|
}
|
|
|
|
func TestShouldNotParseConfigFileWithOldOrUnexpectedKeys(t *testing.T) {
|
|
dir := setupEnv(t)
|
|
|
|
require.NoError(t, os.Setenv("AUTHELIA_JWT_SECRET_FILE", dir+"jwt"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_DUO_API_SECRET_KEY_FILE", dir+"duo"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_SECRET_FILE", dir+"session"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE", dir+"authentication"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE", dir+"notifier"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_REDIS_PASSWORD_FILE", dir+"redis"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE", dir+"mysql"))
|
|
|
|
_, errors := Read("./test_resources/config_bad_keys.yml")
|
|
require.Len(t, errors, 2)
|
|
|
|
// Sort error slice to prevent shenanigans that somehow occur
|
|
sort.Slice(errors, func(i, j int) bool {
|
|
return errors[i].Error() < errors[j].Error()
|
|
})
|
|
assert.EqualError(t, errors[0], "config key not expected: loggy_file")
|
|
assert.EqualError(t, errors[1], "invalid configuration key 'logs_level' was replaced by 'log_level'")
|
|
}
|
|
|
|
func TestShouldValidateConfigurationTemplate(t *testing.T) {
|
|
resetEnv()
|
|
|
|
_, errors := Read("../../config.template.yml")
|
|
assert.Len(t, errors, 0)
|
|
}
|
|
|
|
func TestShouldOnlyAllowEnvOrConfig(t *testing.T) {
|
|
dir := setupEnv(t)
|
|
|
|
resetEnv()
|
|
require.NoError(t, os.Setenv("AUTHELIA_JWT_SECRET_FILE", dir+"jwt"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_DUO_API_SECRET_KEY_FILE", dir+"duo"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_SECRET_FILE", dir+"session"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE", dir+"authentication"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE", dir+"notifier"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_SESSION_REDIS_PASSWORD_FILE", dir+"redis"))
|
|
require.NoError(t, os.Setenv("AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE", dir+"mysql"))
|
|
|
|
_, errors := Read("./test_resources/config_with_secret.yml")
|
|
|
|
require.Len(t, errors, 1)
|
|
require.EqualError(t, errors[0], "error loading secret (jwt_secret): it's already defined in the config file")
|
|
}
|