mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
d33d6c2f00
This change implements yamllint and adjusts all yaml files to abide by our linting setup. This excludes config.template.yml as this will be done in an alternate commit.
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], "config key replaced: logs_level is now 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")
|
|
}
|