2021-08-03 09:55:21 +00:00
package configuration
import (
"fmt"
"os"
"path/filepath"
"runtime"
"sort"
"testing"
2023-05-08 03:30:49 +00:00
"time"
2021-08-03 09:55:21 +00:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2021-08-11 01:04:35 +00:00
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/configuration/validator"
"github.com/authelia/authelia/v4/internal/utils"
2021-08-03 09:55:21 +00:00
)
func TestShouldErrorSecretNotExist ( t * testing . T ) {
2022-12-04 09:57:28 +00:00
dir := t . TempDir ( )
2021-08-03 09:55:21 +00:00
2022-03-03 11:20:43 +00:00
testSetEnv ( t , "JWT_SECRET_FILE" , filepath . Join ( dir , "jwt" ) )
testSetEnv ( t , "DUO_API_SECRET_KEY_FILE" , filepath . Join ( dir , "duo" ) )
testSetEnv ( t , "SESSION_SECRET_FILE" , filepath . Join ( dir , "session" ) )
2023-04-08 06:02:34 +00:00
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE" , dir )
2022-03-03 11:20:43 +00:00
testSetEnv ( t , "NOTIFIER_SMTP_PASSWORD_FILE" , filepath . Join ( dir , "notifier" ) )
testSetEnv ( t , "SESSION_REDIS_PASSWORD_FILE" , filepath . Join ( dir , "redis" ) )
testSetEnv ( t , "SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_PASSWORD_FILE" , filepath . Join ( dir , "redis-sentinel" ) )
testSetEnv ( t , "STORAGE_MYSQL_PASSWORD_FILE" , filepath . Join ( dir , "mysql" ) )
testSetEnv ( t , "STORAGE_POSTGRES_PASSWORD_FILE" , filepath . Join ( dir , "postgres" ) )
testSetEnv ( t , "SERVER_TLS_KEY_FILE" , filepath . Join ( dir , "tls" ) )
testSetEnv ( t , "IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY_FILE" , filepath . Join ( dir , "oidc-key" ) )
testSetEnv ( t , "IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE" , filepath . Join ( dir , "oidc-hmac" ) )
2021-08-03 09:55:21 +00:00
val := schema . NewStructValidator ( )
2022-12-04 09:57:28 +00:00
_ , _ , err := Load ( val , NewEnvironmentSource ( DefaultEnvPrefix , DefaultEnvDelimiter ) , NewSecretsSource ( DefaultEnvPrefix , DefaultEnvDelimiter ) )
2021-08-03 09:55:21 +00:00
assert . NoError ( t , err )
assert . Len ( t , val . Warnings ( ) , 0 )
errs := val . Errors ( )
require . Len ( t , errs , 12 )
sort . Sort ( utils . ErrSliceSortAlphabetical ( errs ) )
errFmt := utils . GetExpectedErrTxt ( "filenotfound" )
2023-04-08 06:02:34 +00:00
errFmtDir := utils . GetExpectedErrTxt ( "isdir" )
2021-08-03 09:55:21 +00:00
2022-10-02 02:07:40 +00:00
// ignore the errors before this as they are checked by the validator.
2023-04-08 06:02:34 +00:00
assert . EqualError ( t , errs [ 0 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'authentication_backend.ldap.password': %s" , dir , fmt . Sprintf ( errFmtDir , dir ) ) )
assert . EqualError ( t , errs [ 1 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'duo_api.secret_key': file does not exist error occurred: %s" , filepath . Join ( dir , "duo" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "duo" ) ) ) )
assert . EqualError ( t , errs [ 2 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'jwt_secret': file does not exist error occurred: %s" , filepath . Join ( dir , "jwt" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "jwt" ) ) ) )
assert . EqualError ( t , errs [ 3 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'storage.mysql.password': file does not exist error occurred: %s" , filepath . Join ( dir , "mysql" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "mysql" ) ) ) )
assert . EqualError ( t , errs [ 4 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'notifier.smtp.password': file does not exist error occurred: %s" , filepath . Join ( dir , "notifier" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "notifier" ) ) ) )
assert . EqualError ( t , errs [ 5 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'identity_providers.oidc.hmac_secret': file does not exist error occurred: %s" , filepath . Join ( dir , "oidc-hmac" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "oidc-hmac" ) ) ) )
assert . EqualError ( t , errs [ 6 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'identity_providers.oidc.issuer_private_key': file does not exist error occurred: %s" , filepath . Join ( dir , "oidc-key" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "oidc-key" ) ) ) )
assert . EqualError ( t , errs [ 7 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'storage.postgres.password': file does not exist error occurred: %s" , filepath . Join ( dir , "postgres" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "postgres" ) ) ) )
assert . EqualError ( t , errs [ 8 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'session.redis.password': file does not exist error occurred: %s" , filepath . Join ( dir , "redis" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "redis" ) ) ) )
assert . EqualError ( t , errs [ 9 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'session.redis.high_availability.sentinel_password': file does not exist error occurred: %s" , filepath . Join ( dir , "redis-sentinel" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "redis-sentinel" ) ) ) )
assert . EqualError ( t , errs [ 10 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'session.secret': file does not exist error occurred: %s" , filepath . Join ( dir , "session" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "session" ) ) ) )
assert . EqualError ( t , errs [ 11 ] , fmt . Sprintf ( "secrets: error loading secret path %s into key 'server.tls.key': file does not exist error occurred: %s" , filepath . Join ( dir , "tls" ) , fmt . Sprintf ( errFmt , filepath . Join ( dir , "tls" ) ) ) )
2021-08-03 09:55:21 +00:00
}
func TestLoadShouldReturnErrWithoutValidator ( t * testing . T ) {
_ , _ , err := Load ( nil , NewEnvironmentSource ( DefaultEnvPrefix , DefaultEnvDelimiter ) )
assert . EqualError ( t , err , "no validator provided" )
}
func TestLoadShouldReturnErrWithoutSources ( t * testing . T ) {
_ , _ , err := Load ( schema . NewStructValidator ( ) )
assert . EqualError ( t , err , "no sources provided" )
}
func TestShouldHaveNotifier ( t * testing . T ) {
2022-03-03 11:20:43 +00:00
testSetEnv ( t , "SESSION_SECRET" , "abc" )
testSetEnv ( t , "STORAGE_MYSQL_PASSWORD" , "abc" )
testSetEnv ( t , "JWT_SECRET" , "abc" )
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_PASSWORD" , "abc" )
2021-08-03 09:55:21 +00:00
val := schema . NewStructValidator ( )
_ , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
assert . NotNil ( t , config . Notifier )
}
2023-05-08 03:30:49 +00:00
func TestShouldParseLargeIntegerDurations ( t * testing . T ) {
val := schema . NewStructValidator ( )
_ , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.durations.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
assert . Equal ( t , durationMax , config . Regulation . FindTime )
assert . Equal ( t , time . Second * 1000 , config . Regulation . BanTime )
}
2021-08-03 09:55:21 +00:00
func TestShouldValidateConfigurationWithEnv ( t * testing . T ) {
2022-03-03 11:20:43 +00:00
testSetEnv ( t , "SESSION_SECRET" , "abc" )
testSetEnv ( t , "STORAGE_MYSQL_PASSWORD" , "abc" )
testSetEnv ( t , "JWT_SECRET" , "abc" )
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_PASSWORD" , "abc" )
2021-08-03 09:55:21 +00:00
val := schema . NewStructValidator ( )
_ , _ , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
}
2022-12-21 09:48:14 +00:00
func TestShouldValidateConfigurationWithFilters ( t * testing . T ) {
testSetEnv ( t , "SESSION_SECRET" , "abc" )
testSetEnv ( t , "STORAGE_MYSQL_PASSWORD" , "abc" )
testSetEnv ( t , "JWT_SECRET" , "abc" )
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_PASSWORD" , "abc" )
2023-02-02 23:36:38 +00:00
t . Setenv ( "ABC_CLIENT_SECRET" , "$plaintext$example-abc" )
t . Setenv ( "XYZ_CLIENT_SECRET" , "$plaintext$example-xyz" )
t . Setenv ( "ANOTHER_CLIENT_SECRET" , "$plaintext$example-123" )
2022-12-25 20:16:05 +00:00
t . Setenv ( "SERVICES_SERVER" , "10.10.10.10" )
t . Setenv ( "ROOT_DOMAIN" , "example.org" )
2022-12-21 09:48:14 +00:00
val := schema . NewStructValidator ( )
_ , config , err := Load ( val , NewDefaultSourcesFiltered ( [ ] string { "./test_resources/config.filtered.yml" } , NewFileFiltersDefault ( ) , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
require . Len ( t , val . Errors ( ) , 0 )
require . Len ( t , val . Warnings ( ) , 0 )
assert . Equal ( t , "api-123456789.example.org" , config . DuoAPI . Hostname )
2023-05-07 06:39:17 +00:00
assert . Equal ( t , "smtp://10.10.10.10:1025" , config . Notifier . SMTP . Address . String ( ) )
2022-12-21 09:48:14 +00:00
assert . Equal ( t , "10.10.10.10" , config . Session . Redis . Host )
2023-02-02 23:36:38 +00:00
require . Len ( t , config . IdentityProviders . OIDC . Clients , 3 )
assert . Equal ( t , "$plaintext$example-abc" , config . IdentityProviders . OIDC . Clients [ 0 ] . Secret . String ( ) )
assert . Equal ( t , "$plaintext$example-xyz" , config . IdentityProviders . OIDC . Clients [ 1 ] . Secret . String ( ) )
assert . Equal ( t , "$plaintext$example-123" , config . IdentityProviders . OIDC . Clients [ 2 ] . Secret . String ( ) )
2022-12-21 09:48:14 +00:00
}
2021-08-03 09:55:21 +00:00
func TestShouldNotIgnoreInvalidEnvs ( t * testing . T ) {
2022-03-03 11:20:43 +00:00
testSetEnv ( t , "SESSION_SECRET" , "an env session secret" )
testSetEnv ( t , "STORAGE_MYSQL_PASSWORD" , "an env storage mysql password" )
testSetEnv ( t , "STORAGE_MYSQL" , "a bad env" )
testSetEnv ( t , "JWT_SECRET" , "an env jwt secret" )
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_PASSWORD" , "an env authentication backend ldap password" )
2023-05-07 06:39:17 +00:00
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_ADDRESS" , "an env authentication backend ldap password" )
2021-08-03 09:55:21 +00:00
val := schema . NewStructValidator ( )
keys , _ , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
require . Len ( t , val . Warnings ( ) , 1 )
2023-05-07 06:39:17 +00:00
assert . Len ( t , val . Errors ( ) , 1 )
2021-08-03 09:55:21 +00:00
assert . EqualError ( t , val . Warnings ( ) [ 0 ] , fmt . Sprintf ( "configuration environment variable not expected: %sSTORAGE_MYSQL" , DefaultEnvPrefix ) )
2023-05-07 06:39:17 +00:00
assert . EqualError ( t , val . Errors ( ) [ 0 ] , "error occurred during unmarshalling configuration: 1 error(s) decoding:\n\n* error decoding 'authentication_backend.ldap.address': could not decode 'an env authentication backend ldap password' to a *schema.AddressLDAP: could not parse string 'an env authentication backend ldap password' as address: expected format is [<scheme>://]<hostname>[:<port>]: parse \"ldaps://an env authentication backend ldap password\": invalid character \" \" in host name" )
2021-08-03 09:55:21 +00:00
}
func TestShouldValidateAndRaiseErrorsOnNormalConfigurationAndSecret ( t * testing . T ) {
2022-03-03 11:20:43 +00:00
testSetEnv ( t , "SESSION_SECRET" , "an env session secret" )
testSetEnv ( t , "SESSION_SECRET_FILE" , "./test_resources/example_secret" )
testSetEnv ( t , "STORAGE_MYSQL_PASSWORD" , "an env storage mysql password" )
testSetEnv ( t , "JWT_SECRET_FILE" , "./test_resources/example_secret" )
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_PASSWORD" , "an env authentication backend ldap password" )
testSetEnv ( t , "STORAGE_ENCRYPTION_KEY" , "a_very_bad_encryption_key" )
2021-08-03 09:55:21 +00:00
val := schema . NewStructValidator ( )
_ , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
require . Len ( t , val . Errors ( ) , 1 )
assert . Len ( t , val . Warnings ( ) , 0 )
assert . EqualError ( t , val . Errors ( ) [ 0 ] , "secrets: error loading secret into key 'session.secret': it's already defined in other configuration sources" )
assert . Equal ( t , "example_secret value" , config . JWTSecret )
assert . Equal ( t , "example_secret value" , config . Session . Secret )
assert . Equal ( t , "an env storage mysql password" , config . Storage . MySQL . Password )
assert . Equal ( t , "an env authentication backend ldap password" , config . AuthenticationBackend . LDAP . Password )
2021-11-25 01:56:58 +00:00
assert . Equal ( t , "a_very_bad_encryption_key" , config . Storage . EncryptionKey )
2021-08-03 09:55:21 +00:00
}
func TestShouldRaiseIOErrOnUnreadableFile ( t * testing . T ) {
if runtime . GOOS == constWindows {
t . Skip ( "skipping test due to being on windows" )
}
2022-12-04 09:57:28 +00:00
dir := t . TempDir ( )
2021-08-03 09:55:21 +00:00
assert . NoError ( t , os . WriteFile ( filepath . Join ( dir , "myconf.yml" ) , [ ] byte ( "server:\n port: 9091\n" ) , 0000 ) )
cfg := filepath . Join ( dir , "myconf.yml" )
val := schema . NewStructValidator ( )
2022-12-22 06:34:20 +00:00
_ , _ , err := Load ( val , NewFileSource ( cfg ) )
2021-08-03 09:55:21 +00:00
assert . NoError ( t , err )
require . Len ( t , val . Errors ( ) , 1 )
assert . Len ( t , val . Warnings ( ) , 0 )
2022-12-22 06:34:20 +00:00
assert . EqualError ( t , val . Errors ( ) [ 0 ] , fmt . Sprintf ( "failed to load configuration from file path(%s) source: open %s: permission denied" , cfg , cfg ) )
2021-08-03 09:55:21 +00:00
}
func TestShouldValidateConfigurationWithEnvSecrets ( t * testing . T ) {
2022-03-03 11:20:43 +00:00
testSetEnv ( t , "SESSION_SECRET_FILE" , "./test_resources/example_secret" )
testSetEnv ( t , "STORAGE_MYSQL_PASSWORD_FILE" , "./test_resources/example_secret" )
testSetEnv ( t , "JWT_SECRET_FILE" , "./test_resources/example_secret" )
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE" , "./test_resources/example_secret" )
testSetEnv ( t , "STORAGE_ENCRYPTION_KEY_FILE" , "./test_resources/example_secret" )
2021-08-03 09:55:21 +00:00
val := schema . NewStructValidator ( )
_ , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
assert . Equal ( t , "example_secret value" , config . JWTSecret )
assert . Equal ( t , "example_secret value" , config . Session . Secret )
assert . Equal ( t , "example_secret value" , config . AuthenticationBackend . LDAP . Password )
assert . Equal ( t , "example_secret value" , config . Storage . MySQL . Password )
2021-11-25 01:56:58 +00:00
assert . Equal ( t , "example_secret value" , config . Storage . EncryptionKey )
2021-08-03 09:55:21 +00:00
}
2022-04-07 00:58:51 +00:00
func TestShouldLoadURLList ( t * testing . T ) {
val := schema . NewStructValidator ( )
keys , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config_oidc.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
require . Len ( t , config . IdentityProviders . OIDC . CORS . AllowedOrigins , 2 )
assert . Equal ( t , "https://google.com" , config . IdentityProviders . OIDC . CORS . AllowedOrigins [ 0 ] . String ( ) )
assert . Equal ( t , "https://example.com" , config . IdentityProviders . OIDC . CORS . AllowedOrigins [ 1 ] . String ( ) )
}
2023-04-19 04:24:05 +00:00
/ *
func TestShouldLoadNewOIDCConfig ( t * testing . T ) {
val := schema . NewStructValidator ( )
_ , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config_oidc_modern.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
val . Clear ( )
validator . ValidateIdentityProviders ( & config . IdentityProviders , val )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , config . IdentityProviders . OIDC . IssuerJWKS . Keys , 2 )
assert . Equal ( t , "keya" , config . IdentityProviders . OIDC . IssuerJWKS . DefaultKeyID )
assert . Equal ( t , oidc . KeyUseSignature , config . IdentityProviders . OIDC . IssuerJWKS . Keys [ "keya" ] . Use )
assert . Equal ( t , oidc . SigningAlgRSAUsingSHA256 , config . IdentityProviders . OIDC . IssuerJWKS . Keys [ "keya" ] . Algorithm )
assert . Equal ( t , oidc . KeyUseSignature , config . IdentityProviders . OIDC . IssuerJWKS . Keys [ "ec521" ] . Use )
assert . Equal ( t , oidc . SigningAlgECDSAUsingP521AndSHA512 , config . IdentityProviders . OIDC . IssuerJWKS . Keys [ "ec521" ] . Algorithm )
assert . Contains ( t , config . IdentityProviders . OIDC . Discovery . RegisteredJWKSigningAlgs , oidc . SigningAlgRSAUsingSHA256 )
assert . Contains ( t , config . IdentityProviders . OIDC . Discovery . RegisteredJWKSigningAlgs , oidc . SigningAlgECDSAUsingP521AndSHA512 )
} .
* /
2022-10-20 02:16:36 +00:00
func TestShouldConfigureConsent ( t * testing . T ) {
val := schema . NewStructValidator ( )
keys , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config_oidc.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
require . Len ( t , config . IdentityProviders . OIDC . Clients , 1 )
assert . Equal ( t , config . IdentityProviders . OIDC . Clients [ 0 ] . ConsentMode , "explicit" )
}
2021-08-03 09:55:21 +00:00
func TestShouldValidateAndRaiseErrorsOnBadConfiguration ( t * testing . T ) {
2022-03-03 11:20:43 +00:00
testSetEnv ( t , "SESSION_SECRET" , "abc" )
testSetEnv ( t , "STORAGE_MYSQL_PASSWORD" , "abc" )
testSetEnv ( t , "JWT_SECRET" , "abc" )
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_PASSWORD" , "abc" )
2021-08-03 09:55:21 +00:00
val := schema . NewStructValidator ( )
2022-06-28 03:15:50 +00:00
keys , c , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config_bad_keys.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
2021-08-03 09:55:21 +00:00
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
2022-06-28 03:15:50 +00:00
require . Len ( t , val . Errors ( ) , 1 )
require . Len ( t , val . Warnings ( ) , 1 )
2021-08-03 09:55:21 +00:00
assert . EqualError ( t , val . Errors ( ) [ 0 ] , "configuration key not expected: loggy_file" )
2022-06-28 03:15:50 +00:00
assert . EqualError ( t , val . Warnings ( ) [ 0 ] , "configuration key 'logs_level' is deprecated in 4.7.0 and has been replaced by 'log.level': this has been automatically mapped for you but you will need to adjust your configuration to remove this message" )
assert . Equal ( t , "debug" , c . Log . Level )
2021-08-03 09:55:21 +00:00
}
2023-05-07 06:39:17 +00:00
func TestShouldValidateDeprecatedEnvNames ( t * testing . T ) {
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_URL" , "ldap://from-env" )
val := schema . NewStructValidator ( )
keys , c , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
assert . Len ( t , val . Errors ( ) , 0 )
require . Len ( t , val . Warnings ( ) , 1 )
assert . EqualError ( t , val . Warnings ( ) [ 0 ] , "configuration key 'authentication_backend.ldap.url' is deprecated in 4.38.0 and has been replaced by 'authentication_backend.ldap.address': this has not been automatically mapped for you because the replacement key also exists and you will need to adjust your configuration to remove this message" )
assert . Equal ( t , "ldap://127.0.0.1:389" , c . AuthenticationBackend . LDAP . Address . String ( ) )
}
func TestShouldValidateDeprecatedEnvNamesWithDeprecatedKeys ( t * testing . T ) {
testSetEnv ( t , "AUTHENTICATION_BACKEND_LDAP_URL" , "ldap://from-env" )
val := schema . NewStructValidator ( )
keys , c , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.deprecated.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
assert . Len ( t , val . Errors ( ) , 0 )
warnings := val . Warnings ( )
require . Len ( t , warnings , 3 )
sort . Sort ( utils . ErrSliceSortAlphabetical ( warnings ) )
assert . EqualError ( t , warnings [ 0 ] , "configuration key 'authentication_backend.ldap.url' is deprecated in 4.38.0 and has been replaced by 'authentication_backend.ldap.address': this has been automatically mapped for you but you will need to adjust your configuration to remove this message" )
assert . EqualError ( t , warnings [ 1 ] , "configuration key 'storage.mysql.host' is deprecated in 4.38.0 and has been replaced by 'storage.mysql.address' when combined with the 'storage.mysql.port' in the format of '[tcp://]<hostname>[:<port>]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message" )
assert . EqualError ( t , warnings [ 2 ] , "configuration key 'storage.mysql.port' is deprecated in 4.38.0 and has been replaced by 'storage.mysql.address' when combined with the 'storage.mysql.host' in the format of '[tcp://]<hostname>[:<port>]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message" )
assert . Equal ( t , "ldap://from-env:389" , c . AuthenticationBackend . LDAP . Address . String ( ) )
}
func TestShouldValidateDeprecatedEnvNamesWithDeprecatedKeysAlt ( t * testing . T ) {
val := schema . NewStructValidator ( )
keys , c , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.deprecated.alt.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
assert . Len ( t , val . Errors ( ) , 0 )
warnings := val . Warnings ( )
require . Len ( t , warnings , 3 )
sort . Sort ( utils . ErrSliceSortAlphabetical ( warnings ) )
assert . EqualError ( t , warnings [ 0 ] , "configuration key 'authentication_backend.ldap.url' is deprecated in 4.38.0 and has been replaced by 'authentication_backend.ldap.address': this has been automatically mapped for you but you will need to adjust your configuration to remove this message" )
assert . EqualError ( t , warnings [ 1 ] , "configuration key 'storage.postgres.host' is deprecated in 4.38.0 and has been replaced by 'storage.postgres.address' when combined with the 'storage.postgres.port' in the format of '[tcp://]<hostname>[:<port>]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message" )
assert . EqualError ( t , warnings [ 2 ] , "configuration key 'storage.postgres.port' is deprecated in 4.38.0 and has been replaced by 'storage.postgres.address' when combined with the 'storage.postgres.host' in the format of '[tcp://]<hostname>[:<port>]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message" )
val . Clear ( )
validator . ValidateConfiguration ( c , val )
require . NotNil ( t , c . Storage . PostgreSQL . Address )
assert . Equal ( t , "tcp://127.0.0.1:5432" , c . Storage . PostgreSQL . Address . String ( ) )
}
2021-11-30 11:15:21 +00:00
func TestShouldRaiseErrOnInvalidNotifierSMTPSender ( t * testing . T ) {
val := schema . NewStructValidator ( )
keys , _ , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config_smtp_sender_invalid.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
require . Len ( t , val . Errors ( ) , 1 )
assert . Len ( t , val . Warnings ( ) , 0 )
2022-04-03 12:44:52 +00:00
assert . EqualError ( t , val . Errors ( ) [ 0 ] , "error occurred during unmarshalling configuration: 1 error(s) decoding:\n\n* error decoding 'notifier.smtp.sender': could not decode 'admin' to a mail.Address (RFC5322): mail: missing '@' or angle-addr" )
2021-11-30 11:15:21 +00:00
}
func TestShouldHandleErrInvalidatorWhenSMTPSenderBlank ( t * testing . T ) {
val := schema . NewStructValidator ( )
keys , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config_smtp_sender_blank.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
assert . Equal ( t , "" , config . Notifier . SMTP . Sender . Name )
assert . Equal ( t , "" , config . Notifier . SMTP . Sender . Address )
2022-01-15 02:01:40 +00:00
2022-04-15 23:34:26 +00:00
validator . ValidateNotifier ( & config . Notifier , val )
2022-01-15 02:01:40 +00:00
require . Len ( t , val . Errors ( ) , 1 )
assert . Len ( t , val . Warnings ( ) , 0 )
2022-02-28 03:15:01 +00:00
assert . EqualError ( t , val . Errors ( ) [ 0 ] , "notifier: smtp: option 'sender' is required" )
2022-01-15 02:01:40 +00:00
}
func TestShouldDecodeSMTPSenderWithoutName ( t * testing . T ) {
val := schema . NewStructValidator ( )
keys , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
assert . Equal ( t , "" , config . Notifier . SMTP . Sender . Name )
assert . Equal ( t , "admin@example.com" , config . Notifier . SMTP . Sender . Address )
}
func TestShouldDecodeSMTPSenderWithName ( t * testing . T ) {
val := schema . NewStructValidator ( )
keys , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config_alt.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
assert . Equal ( t , "Admin" , config . Notifier . SMTP . Sender . Name )
assert . Equal ( t , "admin@example.com" , config . Notifier . SMTP . Sender . Address )
2023-01-12 10:57:44 +00:00
assert . Equal ( t , schema . RememberMeDisabled , config . Session . RememberMe )
2021-11-30 11:15:21 +00:00
}
2022-04-01 11:38:49 +00:00
func TestShouldParseRegex ( t * testing . T ) {
val := schema . NewStructValidator ( )
keys , config , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config_domain_regex.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
validator . ValidateRules ( config , val )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
assert . Len ( t , config . AccessControl . Rules [ 0 ] . DomainsRegex [ 0 ] . SubexpNames ( ) , 2 )
assert . Equal ( t , "" , config . AccessControl . Rules [ 0 ] . DomainsRegex [ 0 ] . SubexpNames ( ) [ 0 ] )
assert . Equal ( t , "" , config . AccessControl . Rules [ 0 ] . DomainsRegex [ 0 ] . SubexpNames ( ) [ 1 ] )
assert . Len ( t , config . AccessControl . Rules [ 1 ] . DomainsRegex [ 0 ] . SubexpNames ( ) , 2 )
assert . Equal ( t , "" , config . AccessControl . Rules [ 1 ] . DomainsRegex [ 0 ] . SubexpNames ( ) [ 0 ] )
assert . Equal ( t , "User" , config . AccessControl . Rules [ 1 ] . DomainsRegex [ 0 ] . SubexpNames ( ) [ 1 ] )
assert . Len ( t , config . AccessControl . Rules [ 2 ] . DomainsRegex [ 0 ] . SubexpNames ( ) , 3 )
assert . Equal ( t , "" , config . AccessControl . Rules [ 2 ] . DomainsRegex [ 0 ] . SubexpNames ( ) [ 0 ] )
assert . Equal ( t , "User" , config . AccessControl . Rules [ 2 ] . DomainsRegex [ 0 ] . SubexpNames ( ) [ 1 ] )
assert . Equal ( t , "Group" , config . AccessControl . Rules [ 2 ] . DomainsRegex [ 0 ] . SubexpNames ( ) [ 2 ] )
}
func TestShouldErrOnParseInvalidRegex ( t * testing . T ) {
val := schema . NewStructValidator ( )
keys , _ , err := Load ( val , NewDefaultSources ( [ ] string { "./test_resources/config_domain_bad_regex.yml" } , DefaultEnvPrefix , DefaultEnvDelimiter ) ... )
assert . NoError ( t , err )
validator . ValidateKeys ( keys , DefaultEnvPrefix , val )
require . Len ( t , val . Errors ( ) , 1 )
assert . Len ( t , val . Warnings ( ) , 0 )
2022-04-03 12:44:52 +00:00
assert . EqualError ( t , val . Errors ( ) [ 0 ] , "error occurred during unmarshalling configuration: 1 error(s) decoding:\n\n* error decoding 'access_control.rules[0].domain_regex[0]': could not decode '^\\K(public|public2).example.com$' to a regexp.Regexp: error parsing regexp: invalid escape sequence: `\\K`" )
2022-04-01 11:38:49 +00:00
}
2021-08-03 09:55:21 +00:00
func TestShouldNotReadConfigurationOnFSAccessDenied ( t * testing . T ) {
if runtime . GOOS == constWindows {
t . Skip ( "skipping test due to being on windows" )
}
2022-12-04 09:57:28 +00:00
dir := t . TempDir ( )
2021-08-03 09:55:21 +00:00
cfg := filepath . Join ( dir , "config.yml" )
assert . NoError ( t , testCreateFile ( filepath . Join ( dir , "config.yml" ) , "port: 9091\n" , 0000 ) )
val := schema . NewStructValidator ( )
2022-12-22 06:34:20 +00:00
_ , _ , err := Load ( val , NewFileSource ( cfg ) )
2021-08-03 09:55:21 +00:00
assert . NoError ( t , err )
require . Len ( t , val . Errors ( ) , 1 )
2022-12-22 06:34:20 +00:00
assert . EqualError ( t , val . Errors ( ) [ 0 ] , fmt . Sprintf ( "failed to load configuration from file path(%s) source: open %s: permission denied" , cfg , cfg ) )
2021-08-03 09:55:21 +00:00
}
2022-12-22 06:34:20 +00:00
func TestShouldLoadDirectoryConfiguration ( t * testing . T ) {
2022-12-04 09:57:28 +00:00
dir := t . TempDir ( )
2021-08-03 09:55:21 +00:00
2023-04-13 11:15:28 +00:00
cfg := filepath . Join ( dir , "myconf.yml" )
assert . NoError ( t , testCreateFile ( cfg , "server:\n port: 9091\n" , 0700 ) )
2021-08-03 09:55:21 +00:00
val := schema . NewStructValidator ( )
2022-12-22 06:34:20 +00:00
_ , _ , err := Load ( val , NewFileSource ( dir ) )
2021-08-03 09:55:21 +00:00
assert . NoError ( t , err )
2022-12-22 06:34:20 +00:00
assert . Len ( t , val . Errors ( ) , 0 )
2023-05-07 05:48:26 +00:00
require . Len ( t , val . Warnings ( ) , 1 )
2023-05-07 06:39:17 +00:00
assert . EqualError ( t , val . Warnings ( ) [ 0 ] , "configuration key 'server.port' is deprecated in 4.38.0 and has been replaced by 'server.address' when combined with the 'server.host' in the format of '[tcp://]<hostname>[:<port>]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message" )
2021-08-03 09:55:21 +00:00
}
2022-03-03 11:20:43 +00:00
func testSetEnv ( t * testing . T , key , value string ) {
2022-12-25 20:16:05 +00:00
t . Setenv ( DefaultEnvPrefix + key , value )
2021-08-03 09:55:21 +00:00
}
func testCreateFile ( path , value string , perm os . FileMode ) ( err error ) {
return os . WriteFile ( path , [ ] byte ( value ) , perm )
}
2023-04-13 11:15:28 +00:00
func TestShouldErrorOnNoPath ( t * testing . T ) {
val := schema . NewStructValidator ( )
_ , _ , err := Load ( val , NewFileSource ( "" ) )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 1 )
assert . ErrorContains ( t , val . Errors ( ) [ 0 ] , "invalid file path source configuration" )
}
func TestShouldErrorOnInvalidPath ( t * testing . T ) {
dir := t . TempDir ( )
cfg := filepath . Join ( dir , "invalid-folder/config" )
val := schema . NewStructValidator ( )
_ , _ , err := Load ( val , NewFileSource ( cfg ) )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 1 )
assert . ErrorContains ( t , val . Errors ( ) [ 0 ] , fmt . Sprintf ( "stat %s: no such file or directory" , cfg ) )
}
func TestShouldErrorOnDirFSPermissionDenied ( t * testing . T ) {
if runtime . GOOS == constWindows {
t . Skip ( "skipping test due to being on windows" )
}
dir := t . TempDir ( )
err := os . Chmod ( dir , 0200 )
assert . NoError ( t , err )
val := schema . NewStructValidator ( )
_ , _ , err = Load ( val , NewFileSource ( dir ) )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 1 )
assert . ErrorContains ( t , val . Errors ( ) [ 0 ] , fmt . Sprintf ( "open %s: permission denied" , dir ) )
}
func TestShouldSkipDirOnLoad ( t * testing . T ) {
dir := t . TempDir ( )
path := filepath . Join ( dir , "some-dir" )
err := os . Mkdir ( path , 0700 )
assert . NoError ( t , err )
val := schema . NewStructValidator ( )
_ , _ , err = Load ( val , NewFileSource ( dir ) )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 0 )
assert . Len ( t , val . Warnings ( ) , 0 )
}
func TestShouldFailIfYmlIsInvalid ( t * testing . T ) {
dir := t . TempDir ( )
cfg := filepath . Join ( dir , "myconf.yml" )
assert . NoError ( t , testCreateFile ( cfg , "an invalid contend\n" , 0700 ) )
val := schema . NewStructValidator ( )
_ , _ , err := Load ( val , NewFileSource ( dir ) )
assert . NoError ( t , err )
assert . Len ( t , val . Errors ( ) , 1 )
assert . ErrorContains ( t , val . Errors ( ) [ 0 ] , "unmarshal errors" )
}