From 4577fce95ba410fb164959f18069420e622cb824 Mon Sep 17 00:00:00 2001 From: James Elliott Date: Tue, 30 May 2023 18:21:19 +1000 Subject: [PATCH] refactor: path from address (#5492) Signed-off-by: James Elliott --- cmd/authelia-scripts/cmd/gen.go | 2 +- config.template.yml | 18 +- .../en/configuration/miscellaneous/server.md | 43 +---- .../en/configuration/prologue/common.md | 7 +- .../en/configuration/telemetry/metrics.md | 4 +- docs/data/configkeys.json | 2 +- internal/configuration/config.template.yml | 18 +- internal/configuration/const.go | 2 + internal/configuration/deprecation.go | 45 ++++- internal/configuration/provider_test.go | 42 ++--- internal/configuration/schema/keys.go | 2 +- internal/configuration/schema/server.go | 6 +- internal/configuration/schema/telemetry.go | 2 +- .../configuration/schema/types_address.go | 9 + .../test_resources/config.deprecated.alt.yml | 173 ------------------ .../test_resources/config.deprecated.yml | 162 +--------------- internal/configuration/validator/const.go | 5 +- internal/configuration/validator/server.go | 35 ++-- .../configuration/validator/server_test.go | 143 ++++++++------- internal/configuration/validator/telemetry.go | 4 + .../configuration/validator/telemetry_test.go | 8 +- internal/server/handlers.go | 8 +- internal/server/server.go | 10 +- internal/server/template.go | 4 + internal/suites/PathPrefix/configuration.yml | 3 +- 25 files changed, 233 insertions(+), 524 deletions(-) delete mode 100644 internal/configuration/test_resources/config.deprecated.alt.yml diff --git a/cmd/authelia-scripts/cmd/gen.go b/cmd/authelia-scripts/cmd/gen.go index be6a36a9e..329d00895 100644 --- a/cmd/authelia-scripts/cmd/gen.go +++ b/cmd/authelia-scripts/cmd/gen.go @@ -7,5 +7,5 @@ package cmd const ( - versionSwaggerUI = "4.18.3" + versionSwaggerUI = "4.19.0" ) diff --git a/config.template.yml b/config.template.yml index 4e8eb0580..61e010094 100644 --- a/config.template.yml +++ b/config.template.yml @@ -47,15 +47,12 @@ default_redirection_url: 'https://home.example.com/' server: ## The address for the Main server to listen on in the address common syntax. ## Formats: - ## - [://][:] - ## - [://][hostname]: + ## - [://][:][/] + ## - [://][hostname]:[/] ## Square brackets indicate optional portions of the format. Scheme must be 'tcp', 'tcp4', 'tcp6', or 'unix'. ## The default scheme is 'unix' if the address is an absolute path otherwise it's 'tcp'. The default port is '9091'. - address: 'tcp://:9091' - - ## Set the single level path Authelia listens on. - ## Must be alphanumeric chars and should not contain any slashes. - path: '' + ## If the path is specified this configures the router to handle both the `/` path and the configured path. + address: 'tcp://:9091/' ## Set the path on disk to Authelia assets. ## Useful to allow overriding of specific static assets. @@ -162,11 +159,12 @@ telemetry: ## The address for the Metrics server to listen on in the address common syntax. ## Formats: - ## - [://][:] - ## - [://][hostname]: + ## - [://][:][/] + ## - [://][hostname]:[/] ## Square brackets indicate optional portions of the format. Scheme must be 'tcp', 'tcp4', 'tcp6', or 'unix'. ## The default scheme is 'unix' if the address is an absolute path otherwise it's 'tcp'. The default port is '9959'. - address: 'tcp://:9959' + ## If the path is not specified it defaults to `/metrics`. + address: 'tcp://:9959/metrics' ## Metrics Server Buffers configuration. # buffers: diff --git a/docs/content/en/configuration/miscellaneous/server.md b/docs/content/en/configuration/miscellaneous/server.md index 865329991..366679d4f 100644 --- a/docs/content/en/configuration/miscellaneous/server.md +++ b/docs/content/en/configuration/miscellaneous/server.md @@ -21,8 +21,7 @@ aliases: ```yaml server: - address: 'tcp://:9091' - path: '' + address: 'tcp://:9091/' disable_healthcheck: false tls: key: '' @@ -59,19 +58,25 @@ server: ### address -{{< confkey type="address" default="tcp://:9091" required="no" >}} +{{< confkey type="address" default="tcp://:9091/" required="no" >}} *__Reference Note:__ This configuration option uses the [address common syntax](../prologue/common.md#address). Please see the [documentation](../prologue/common.md#address) on this format for more information.* Configures the listener address for the Main HTTP Server. The address itself is a listener and the scheme must either be -the `unix` scheme or one of the `tcp` schemes. +the `unix` scheme or one of the `tcp` schemes. It can configure the host, port, and path the listener responds to. If +the path is configured to anything other than `/` Authelia will handle requests for both `/` and the configured path. __Examples:__ ```yaml server: - address: tcp://127.0.0.1:9091 + address: tcp://127.0.0.1:9091/ +``` + +```yaml +server: + address: tcp://127.0.0.1:9091/subpath ``` ```yaml @@ -79,34 +84,6 @@ server: address: unix:///var/run/authelia.sock ``` -### path - -{{< confkey type="string " required="no" >}} - -Authelia by default is served from the root `/` location, either via its own domain or subdomain. - -Modifying this setting will allow you to serve Authelia out from a specified base path. Please note -that currently only a single level path is supported meaning slashes are not allowed, and only -alphanumeric characters are supported. - -__Example:__ - -```yaml -server: - path: "" -``` - -*Works for https://auth.example.com/, https://example.com/, etc*. - -__Example:__ - -```yaml -server: - path: authelia -``` - -*Works for https://auth.example.com/authelia/, https://example.com/authelia/, etc*. - ### asset_path {{< confkey type="string " required="no" >}} diff --git a/docs/content/en/configuration/prologue/common.md b/docs/content/en/configuration/prologue/common.md index f6762411d..49698424e 100644 --- a/docs/content/en/configuration/prologue/common.md +++ b/docs/content/en/configuration/prologue/common.md @@ -88,7 +88,7 @@ Refer to the individual documentation for an option for clarity. In this format are optional. The default for these when not provided varies. ```text -[://][:] +[://][:][/] ``` ##### Port @@ -99,7 +99,7 @@ hostname are optional. The default for the scheme when not provided varies, and available addresses when not provided. ```text -[://][hostname]: +[://][hostname]:[/] ``` ##### Unix Domain Socket @@ -131,8 +131,11 @@ Various examples for these formats. ```text 0.0.0.0 tcp://0.0.0.0 +tcp://0.0.0.0/subpath tcp://0.0.0.0:9091 +tcp://0.0.0.0:9091/subpath tcp://:9091 +tcp://:9091/subpath 0.0.0.0:9091 udp://0.0.0.0:123 diff --git a/docs/content/en/configuration/telemetry/metrics.md b/docs/content/en/configuration/telemetry/metrics.md index deb30d329..37b6c69ae 100644 --- a/docs/content/en/configuration/telemetry/metrics.md +++ b/docs/content/en/configuration/telemetry/metrics.md @@ -22,7 +22,7 @@ toc: true telemetry: metrics: enabled: false - address: 'tcp://:9959' + address: 'tcp://:9959/' buffers: read: 4096 write: 4096 @@ -44,7 +44,7 @@ Determines if the [Prometheus] HTTP Metrics Exporter is enabled. ### address -{{< confkey type="address" default="tcp://:9959" required="no" >}} +{{< confkey type="address" default="tcp://:9959/" required="no" >}} *__Reference Note:__ This configuration option uses the [address common syntax](../prologue/common.md#address). Please see the [documentation](../prologue/common.md#address) on this format for more information.* diff --git a/docs/data/configkeys.json b/docs/data/configkeys.json index 7c8f5bc0e..751cc1767 100644 --- a/docs/data/configkeys.json +++ b/docs/data/configkeys.json @@ -1 +1 @@ -[{"path":"theme","secret":false,"env":"AUTHELIA_THEME"},{"path":"certificates_directory","secret":false,"env":"AUTHELIA_CERTIFICATES_DIRECTORY"},{"path":"jwt_secret","secret":true,"env":"AUTHELIA_JWT_SECRET_FILE"},{"path":"default_redirection_url","secret":false,"env":"AUTHELIA_DEFAULT_REDIRECTION_URL"},{"path":"default_2fa_method","secret":false,"env":"AUTHELIA_DEFAULT_2FA_METHOD"},{"path":"log.level","secret":false,"env":"AUTHELIA_LOG_LEVEL"},{"path":"log.format","secret":false,"env":"AUTHELIA_LOG_FORMAT"},{"path":"log.file_path","secret":false,"env":"AUTHELIA_LOG_FILE_PATH"},{"path":"log.keep_stdout","secret":false,"env":"AUTHELIA_LOG_KEEP_STDOUT"},{"path":"identity_providers.oidc.hmac_secret","secret":true,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE"},{"path":"identity_providers.oidc.issuer_certificate_chain","secret":true,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_CERTIFICATE_CHAIN_FILE"},{"path":"identity_providers.oidc.issuer_private_key","secret":true,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY_FILE"},{"path":"identity_providers.oidc.access_token_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ACCESS_TOKEN_LIFESPAN"},{"path":"identity_providers.oidc.authorize_code_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_AUTHORIZE_CODE_LIFESPAN"},{"path":"identity_providers.oidc.id_token_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ID_TOKEN_LIFESPAN"},{"path":"identity_providers.oidc.refresh_token_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_REFRESH_TOKEN_LIFESPAN"},{"path":"identity_providers.oidc.enable_client_debug_messages","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ENABLE_CLIENT_DEBUG_MESSAGES"},{"path":"identity_providers.oidc.minimum_parameter_entropy","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_MINIMUM_PARAMETER_ENTROPY"},{"path":"identity_providers.oidc.enforce_pkce","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ENFORCE_PKCE"},{"path":"identity_providers.oidc.enable_pkce_plain_challenge","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ENABLE_PKCE_PLAIN_CHALLENGE"},{"path":"identity_providers.oidc.pushed_authorizations.enforce","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_PUSHED_AUTHORIZATIONS_ENFORCE"},{"path":"identity_providers.oidc.pushed_authorizations.context_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_PUSHED_AUTHORIZATIONS_CONTEXT_LIFESPAN"},{"path":"identity_providers.oidc.cors.allowed_origins_from_client_redirect_uris","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_CORS_ALLOWED_ORIGINS_FROM_CLIENT_REDIRECT_URIS"},{"path":"identity_providers.oidc","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC"},{"path":"authentication_backend.password_reset.disable","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_PASSWORD_RESET_DISABLE"},{"path":"authentication_backend.password_reset.custom_url","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_PASSWORD_RESET_CUSTOM_URL"},{"path":"authentication_backend.refresh_interval","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_REFRESH_INTERVAL"},{"path":"authentication_backend.file.path","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PATH"},{"path":"authentication_backend.file.watch","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_WATCH"},{"path":"authentication_backend.file.password.algorithm","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ALGORITHM"},{"path":"authentication_backend.file.password.argon2.variant","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_VARIANT"},{"path":"authentication_backend.file.password.argon2.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_ITERATIONS"},{"path":"authentication_backend.file.password.argon2.memory","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_MEMORY"},{"path":"authentication_backend.file.password.argon2.parallelism","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_PARALLELISM"},{"path":"authentication_backend.file.password.argon2.key_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_KEY_LENGTH"},{"path":"authentication_backend.file.password.argon2.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_SALT_LENGTH"},{"path":"authentication_backend.file.password.sha2crypt.variant","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SHA2CRYPT_VARIANT"},{"path":"authentication_backend.file.password.sha2crypt.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SHA2CRYPT_ITERATIONS"},{"path":"authentication_backend.file.password.sha2crypt.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SHA2CRYPT_SALT_LENGTH"},{"path":"authentication_backend.file.password.pbkdf2.variant","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_PBKDF2_VARIANT"},{"path":"authentication_backend.file.password.pbkdf2.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_PBKDF2_ITERATIONS"},{"path":"authentication_backend.file.password.pbkdf2.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_PBKDF2_SALT_LENGTH"},{"path":"authentication_backend.file.password.bcrypt.variant","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_BCRYPT_VARIANT"},{"path":"authentication_backend.file.password.bcrypt.cost","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_BCRYPT_COST"},{"path":"authentication_backend.file.password.scrypt.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_ITERATIONS"},{"path":"authentication_backend.file.password.scrypt.block_size","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_BLOCK_SIZE"},{"path":"authentication_backend.file.password.scrypt.parallelism","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_PARALLELISM"},{"path":"authentication_backend.file.password.scrypt.key_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_KEY_LENGTH"},{"path":"authentication_backend.file.password.scrypt.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_SALT_LENGTH"},{"path":"authentication_backend.file.password.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ITERATIONS"},{"path":"authentication_backend.file.password.memory","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_MEMORY"},{"path":"authentication_backend.file.password.parallelism","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_PARALLELISM"},{"path":"authentication_backend.file.password.key_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_KEY_LENGTH"},{"path":"authentication_backend.file.password.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SALT_LENGTH"},{"path":"authentication_backend.file.search.email","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_SEARCH_EMAIL"},{"path":"authentication_backend.file.search.case_insensitive","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_SEARCH_CASE_INSENSITIVE"},{"path":"authentication_backend.ldap.address","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_ADDRESS"},{"path":"authentication_backend.ldap.implementation","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_IMPLEMENTATION"},{"path":"authentication_backend.ldap.timeout","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TIMEOUT"},{"path":"authentication_backend.ldap.start_tls","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_START_TLS"},{"path":"authentication_backend.ldap.tls.minimum_version","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_MINIMUM_VERSION"},{"path":"authentication_backend.ldap.tls.maximum_version","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_MAXIMUM_VERSION"},{"path":"authentication_backend.ldap.tls.skip_verify","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_SKIP_VERIFY"},{"path":"authentication_backend.ldap.tls.server_name","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_SERVER_NAME"},{"path":"authentication_backend.ldap.tls.private_key","secret":true,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_PRIVATE_KEY_FILE"},{"path":"authentication_backend.ldap.tls.certificate_chain","secret":true,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"authentication_backend.ldap.base_dn","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_BASE_DN"},{"path":"authentication_backend.ldap.additional_users_dn","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_ADDITIONAL_USERS_DN"},{"path":"authentication_backend.ldap.users_filter","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_USERS_FILTER"},{"path":"authentication_backend.ldap.additional_groups_dn","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_ADDITIONAL_GROUPS_DN"},{"path":"authentication_backend.ldap.groups_filter","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_GROUPS_FILTER"},{"path":"authentication_backend.ldap.group_name_attribute","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_GROUP_NAME_ATTRIBUTE"},{"path":"authentication_backend.ldap.username_attribute","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_USERNAME_ATTRIBUTE"},{"path":"authentication_backend.ldap.mail_attribute","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_MAIL_ATTRIBUTE"},{"path":"authentication_backend.ldap.display_name_attribute","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_DISPLAY_NAME_ATTRIBUTE"},{"path":"authentication_backend.ldap.permit_referrals","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PERMIT_REFERRALS"},{"path":"authentication_backend.ldap.permit_unauthenticated_bind","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PERMIT_UNAUTHENTICATED_BIND"},{"path":"authentication_backend.ldap.permit_feature_detection_failure","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PERMIT_FEATURE_DETECTION_FAILURE"},{"path":"authentication_backend.ldap.user","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_USER"},{"path":"authentication_backend.ldap.password","secret":true,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE"},{"path":"session.secret","secret":true,"env":"AUTHELIA_SESSION_SECRET_FILE"},{"path":"session.name","secret":false,"env":"AUTHELIA_SESSION_NAME"},{"path":"session.domain","secret":false,"env":"AUTHELIA_SESSION_DOMAIN"},{"path":"session.same_site","secret":false,"env":"AUTHELIA_SESSION_SAME_SITE"},{"path":"session.expiration","secret":false,"env":"AUTHELIA_SESSION_EXPIRATION"},{"path":"session.inactivity","secret":false,"env":"AUTHELIA_SESSION_INACTIVITY"},{"path":"session.remember_me","secret":false,"env":"AUTHELIA_SESSION_REMEMBER_ME"},{"path":"session","secret":false,"env":"AUTHELIA_SESSION"},{"path":"session.redis.host","secret":false,"env":"AUTHELIA_SESSION_REDIS_HOST"},{"path":"session.redis.port","secret":false,"env":"AUTHELIA_SESSION_REDIS_PORT"},{"path":"session.redis.username","secret":false,"env":"AUTHELIA_SESSION_REDIS_USERNAME"},{"path":"session.redis.password","secret":true,"env":"AUTHELIA_SESSION_REDIS_PASSWORD_FILE"},{"path":"session.redis.database_index","secret":false,"env":"AUTHELIA_SESSION_REDIS_DATABASE_INDEX"},{"path":"session.redis.maximum_active_connections","secret":false,"env":"AUTHELIA_SESSION_REDIS_MAXIMUM_ACTIVE_CONNECTIONS"},{"path":"session.redis.minimum_idle_connections","secret":false,"env":"AUTHELIA_SESSION_REDIS_MINIMUM_IDLE_CONNECTIONS"},{"path":"session.redis.tls.minimum_version","secret":false,"env":"AUTHELIA_SESSION_REDIS_TLS_MINIMUM_VERSION"},{"path":"session.redis.tls.maximum_version","secret":false,"env":"AUTHELIA_SESSION_REDIS_TLS_MAXIMUM_VERSION"},{"path":"session.redis.tls.skip_verify","secret":false,"env":"AUTHELIA_SESSION_REDIS_TLS_SKIP_VERIFY"},{"path":"session.redis.tls.server_name","secret":false,"env":"AUTHELIA_SESSION_REDIS_TLS_SERVER_NAME"},{"path":"session.redis.tls.private_key","secret":true,"env":"AUTHELIA_SESSION_REDIS_TLS_PRIVATE_KEY_FILE"},{"path":"session.redis.tls.certificate_chain","secret":true,"env":"AUTHELIA_SESSION_REDIS_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"session.redis.high_availability.sentinel_name","secret":false,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_NAME"},{"path":"session.redis.high_availability.sentinel_username","secret":false,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_USERNAME"},{"path":"session.redis.high_availability.sentinel_password","secret":true,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_PASSWORD_FILE"},{"path":"session.redis.high_availability.route_by_latency","secret":false,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_ROUTE_BY_LATENCY"},{"path":"session.redis.high_availability.route_randomly","secret":false,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_ROUTE_RANDOMLY"},{"path":"totp.disable","secret":false,"env":"AUTHELIA_TOTP_DISABLE"},{"path":"totp.issuer","secret":false,"env":"AUTHELIA_TOTP_ISSUER"},{"path":"totp.algorithm","secret":false,"env":"AUTHELIA_TOTP_ALGORITHM"},{"path":"totp.digits","secret":false,"env":"AUTHELIA_TOTP_DIGITS"},{"path":"totp.period","secret":false,"env":"AUTHELIA_TOTP_PERIOD"},{"path":"totp.skew","secret":false,"env":"AUTHELIA_TOTP_SKEW"},{"path":"totp.secret_size","secret":false,"env":"AUTHELIA_TOTP_SECRET_SIZE"},{"path":"duo_api.disable","secret":false,"env":"AUTHELIA_DUO_API_DISABLE"},{"path":"duo_api.hostname","secret":false,"env":"AUTHELIA_DUO_API_HOSTNAME"},{"path":"duo_api.integration_key","secret":true,"env":"AUTHELIA_DUO_API_INTEGRATION_KEY_FILE"},{"path":"duo_api.secret_key","secret":true,"env":"AUTHELIA_DUO_API_SECRET_KEY_FILE"},{"path":"duo_api.enable_self_enrollment","secret":false,"env":"AUTHELIA_DUO_API_ENABLE_SELF_ENROLLMENT"},{"path":"access_control.default_policy","secret":false,"env":"AUTHELIA_ACCESS_CONTROL_DEFAULT_POLICY"},{"path":"ntp.address","secret":false,"env":"AUTHELIA_NTP_ADDRESS"},{"path":"ntp.version","secret":false,"env":"AUTHELIA_NTP_VERSION"},{"path":"ntp.max_desync","secret":false,"env":"AUTHELIA_NTP_MAX_DESYNC"},{"path":"ntp.disable_startup_check","secret":false,"env":"AUTHELIA_NTP_DISABLE_STARTUP_CHECK"},{"path":"ntp.disable_failure","secret":false,"env":"AUTHELIA_NTP_DISABLE_FAILURE"},{"path":"regulation.max_retries","secret":false,"env":"AUTHELIA_REGULATION_MAX_RETRIES"},{"path":"regulation.find_time","secret":false,"env":"AUTHELIA_REGULATION_FIND_TIME"},{"path":"regulation.ban_time","secret":false,"env":"AUTHELIA_REGULATION_BAN_TIME"},{"path":"storage.local.path","secret":false,"env":"AUTHELIA_STORAGE_LOCAL_PATH"},{"path":"storage.mysql.address","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_ADDRESS"},{"path":"storage.mysql.database","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_DATABASE"},{"path":"storage.mysql.username","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_USERNAME"},{"path":"storage.mysql.password","secret":true,"env":"AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE"},{"path":"storage.mysql.timeout","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TIMEOUT"},{"path":"storage.mysql.host","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_HOST"},{"path":"storage.mysql.port","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_PORT"},{"path":"storage.mysql.tls.minimum_version","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TLS_MINIMUM_VERSION"},{"path":"storage.mysql.tls.maximum_version","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TLS_MAXIMUM_VERSION"},{"path":"storage.mysql.tls.skip_verify","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TLS_SKIP_VERIFY"},{"path":"storage.mysql.tls.server_name","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TLS_SERVER_NAME"},{"path":"storage.mysql.tls.private_key","secret":true,"env":"AUTHELIA_STORAGE_MYSQL_TLS_PRIVATE_KEY_FILE"},{"path":"storage.mysql.tls.certificate_chain","secret":true,"env":"AUTHELIA_STORAGE_MYSQL_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"storage.postgres.address","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_ADDRESS"},{"path":"storage.postgres.database","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_DATABASE"},{"path":"storage.postgres.username","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_USERNAME"},{"path":"storage.postgres.password","secret":true,"env":"AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE"},{"path":"storage.postgres.timeout","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TIMEOUT"},{"path":"storage.postgres.host","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_HOST"},{"path":"storage.postgres.port","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_PORT"},{"path":"storage.postgres.schema","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_SCHEMA"},{"path":"storage.postgres.tls.minimum_version","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_MINIMUM_VERSION"},{"path":"storage.postgres.tls.maximum_version","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_MAXIMUM_VERSION"},{"path":"storage.postgres.tls.skip_verify","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_SKIP_VERIFY"},{"path":"storage.postgres.tls.server_name","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_SERVER_NAME"},{"path":"storage.postgres.tls.private_key","secret":true,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_PRIVATE_KEY_FILE"},{"path":"storage.postgres.tls.certificate_chain","secret":true,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"storage.postgres.ssl.mode","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_SSL_MODE"},{"path":"storage.postgres.ssl.root_certificate","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_SSL_ROOT_CERTIFICATE"},{"path":"storage.postgres.ssl.certificate","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_SSL_CERTIFICATE"},{"path":"storage.postgres.ssl.key","secret":true,"env":"AUTHELIA_STORAGE_POSTGRES_SSL_KEY_FILE"},{"path":"storage.encryption_key","secret":true,"env":"AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE"},{"path":"notifier.disable_startup_check","secret":false,"env":"AUTHELIA_NOTIFIER_DISABLE_STARTUP_CHECK"},{"path":"notifier.filesystem.filename","secret":false,"env":"AUTHELIA_NOTIFIER_FILESYSTEM_FILENAME"},{"path":"notifier.smtp.address","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_ADDRESS"},{"path":"notifier.smtp.timeout","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TIMEOUT"},{"path":"notifier.smtp.username","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_USERNAME"},{"path":"notifier.smtp.password","secret":true,"env":"AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE"},{"path":"notifier.smtp.identifier","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_IDENTIFIER"},{"path":"notifier.smtp.sender","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_SENDER"},{"path":"notifier.smtp.subject","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_SUBJECT"},{"path":"notifier.smtp.startup_check_address","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_STARTUP_CHECK_ADDRESS"},{"path":"notifier.smtp.disable_require_tls","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_DISABLE_REQUIRE_TLS"},{"path":"notifier.smtp.disable_html_emails","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_DISABLE_HTML_EMAILS"},{"path":"notifier.smtp.disable_starttls","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_DISABLE_STARTTLS"},{"path":"notifier.smtp.tls.minimum_version","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_MINIMUM_VERSION"},{"path":"notifier.smtp.tls.maximum_version","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_MAXIMUM_VERSION"},{"path":"notifier.smtp.tls.skip_verify","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_SKIP_VERIFY"},{"path":"notifier.smtp.tls.server_name","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_SERVER_NAME"},{"path":"notifier.smtp.tls.private_key","secret":true,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_PRIVATE_KEY_FILE"},{"path":"notifier.smtp.tls.certificate_chain","secret":true,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"notifier.smtp.host","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_HOST"},{"path":"notifier.smtp.port","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_PORT"},{"path":"notifier.template_path","secret":false,"env":"AUTHELIA_NOTIFIER_TEMPLATE_PATH"},{"path":"server.address","secret":false,"env":"AUTHELIA_SERVER_ADDRESS"},{"path":"server.path","secret":false,"env":"AUTHELIA_SERVER_PATH"},{"path":"server.asset_path","secret":false,"env":"AUTHELIA_SERVER_ASSET_PATH"},{"path":"server.disable_healthcheck","secret":false,"env":"AUTHELIA_SERVER_DISABLE_HEALTHCHECK"},{"path":"server.tls.certificate","secret":false,"env":"AUTHELIA_SERVER_TLS_CERTIFICATE"},{"path":"server.tls.key","secret":true,"env":"AUTHELIA_SERVER_TLS_KEY_FILE"},{"path":"server.headers.csp_template","secret":false,"env":"AUTHELIA_SERVER_HEADERS_CSP_TEMPLATE"},{"path":"server.endpoints.enable_pprof","secret":false,"env":"AUTHELIA_SERVER_ENDPOINTS_ENABLE_PPROF"},{"path":"server.endpoints.enable_expvars","secret":false,"env":"AUTHELIA_SERVER_ENDPOINTS_ENABLE_EXPVARS"},{"path":"server.buffers.read","secret":false,"env":"AUTHELIA_SERVER_BUFFERS_READ"},{"path":"server.buffers.write","secret":false,"env":"AUTHELIA_SERVER_BUFFERS_WRITE"},{"path":"server.timeouts.read","secret":false,"env":"AUTHELIA_SERVER_TIMEOUTS_READ"},{"path":"server.timeouts.write","secret":false,"env":"AUTHELIA_SERVER_TIMEOUTS_WRITE"},{"path":"server.timeouts.idle","secret":false,"env":"AUTHELIA_SERVER_TIMEOUTS_IDLE"},{"path":"server.host","secret":false,"env":"AUTHELIA_SERVER_HOST"},{"path":"server.port","secret":false,"env":"AUTHELIA_SERVER_PORT"},{"path":"telemetry.metrics.enabled","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_ENABLED"},{"path":"telemetry.metrics.address","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_ADDRESS"},{"path":"telemetry.metrics.buffers.read","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_BUFFERS_READ"},{"path":"telemetry.metrics.buffers.write","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_BUFFERS_WRITE"},{"path":"telemetry.metrics.timeouts.read","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_TIMEOUTS_READ"},{"path":"telemetry.metrics.timeouts.write","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_TIMEOUTS_WRITE"},{"path":"telemetry.metrics.timeouts.idle","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_TIMEOUTS_IDLE"},{"path":"webauthn.disable","secret":false,"env":"AUTHELIA_WEBAUTHN_DISABLE"},{"path":"webauthn.display_name","secret":false,"env":"AUTHELIA_WEBAUTHN_DISPLAY_NAME"},{"path":"webauthn.attestation_conveyance_preference","secret":false,"env":"AUTHELIA_WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE"},{"path":"webauthn.user_verification","secret":false,"env":"AUTHELIA_WEBAUTHN_USER_VERIFICATION"},{"path":"webauthn.timeout","secret":false,"env":"AUTHELIA_WEBAUTHN_TIMEOUT"},{"path":"password_policy.standard.enabled","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_ENABLED"},{"path":"password_policy.standard.min_length","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_MIN_LENGTH"},{"path":"password_policy.standard.max_length","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_MAX_LENGTH"},{"path":"password_policy.standard.require_uppercase","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_REQUIRE_UPPERCASE"},{"path":"password_policy.standard.require_lowercase","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_REQUIRE_LOWERCASE"},{"path":"password_policy.standard.require_number","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_REQUIRE_NUMBER"},{"path":"password_policy.standard.require_special","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_REQUIRE_SPECIAL"},{"path":"password_policy.zxcvbn.enabled","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_ZXCVBN_ENABLED"},{"path":"password_policy.zxcvbn.min_score","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_ZXCVBN_MIN_SCORE"},{"path":"privacy_policy.enabled","secret":false,"env":"AUTHELIA_PRIVACY_POLICY_ENABLED"},{"path":"privacy_policy.require_user_acceptance","secret":false,"env":"AUTHELIA_PRIVACY_POLICY_REQUIRE_USER_ACCEPTANCE"},{"path":"privacy_policy.policy_url","secret":false,"env":"AUTHELIA_PRIVACY_POLICY_POLICY_URL"}] \ No newline at end of file +[{"path":"theme","secret":false,"env":"AUTHELIA_THEME"},{"path":"certificates_directory","secret":false,"env":"AUTHELIA_CERTIFICATES_DIRECTORY"},{"path":"jwt_secret","secret":true,"env":"AUTHELIA_JWT_SECRET_FILE"},{"path":"default_redirection_url","secret":false,"env":"AUTHELIA_DEFAULT_REDIRECTION_URL"},{"path":"default_2fa_method","secret":false,"env":"AUTHELIA_DEFAULT_2FA_METHOD"},{"path":"log.level","secret":false,"env":"AUTHELIA_LOG_LEVEL"},{"path":"log.format","secret":false,"env":"AUTHELIA_LOG_FORMAT"},{"path":"log.file_path","secret":false,"env":"AUTHELIA_LOG_FILE_PATH"},{"path":"log.keep_stdout","secret":false,"env":"AUTHELIA_LOG_KEEP_STDOUT"},{"path":"identity_providers.oidc.hmac_secret","secret":true,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE"},{"path":"identity_providers.oidc.issuer_certificate_chain","secret":true,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_CERTIFICATE_CHAIN_FILE"},{"path":"identity_providers.oidc.issuer_private_key","secret":true,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY_FILE"},{"path":"identity_providers.oidc.access_token_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ACCESS_TOKEN_LIFESPAN"},{"path":"identity_providers.oidc.authorize_code_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_AUTHORIZE_CODE_LIFESPAN"},{"path":"identity_providers.oidc.id_token_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ID_TOKEN_LIFESPAN"},{"path":"identity_providers.oidc.refresh_token_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_REFRESH_TOKEN_LIFESPAN"},{"path":"identity_providers.oidc.enable_client_debug_messages","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ENABLE_CLIENT_DEBUG_MESSAGES"},{"path":"identity_providers.oidc.minimum_parameter_entropy","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_MINIMUM_PARAMETER_ENTROPY"},{"path":"identity_providers.oidc.enforce_pkce","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ENFORCE_PKCE"},{"path":"identity_providers.oidc.enable_pkce_plain_challenge","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_ENABLE_PKCE_PLAIN_CHALLENGE"},{"path":"identity_providers.oidc.pushed_authorizations.enforce","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_PUSHED_AUTHORIZATIONS_ENFORCE"},{"path":"identity_providers.oidc.pushed_authorizations.context_lifespan","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_PUSHED_AUTHORIZATIONS_CONTEXT_LIFESPAN"},{"path":"identity_providers.oidc.cors.allowed_origins_from_client_redirect_uris","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC_CORS_ALLOWED_ORIGINS_FROM_CLIENT_REDIRECT_URIS"},{"path":"identity_providers.oidc","secret":false,"env":"AUTHELIA_IDENTITY_PROVIDERS_OIDC"},{"path":"authentication_backend.password_reset.disable","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_PASSWORD_RESET_DISABLE"},{"path":"authentication_backend.password_reset.custom_url","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_PASSWORD_RESET_CUSTOM_URL"},{"path":"authentication_backend.refresh_interval","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_REFRESH_INTERVAL"},{"path":"authentication_backend.file.path","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PATH"},{"path":"authentication_backend.file.watch","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_WATCH"},{"path":"authentication_backend.file.password.algorithm","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ALGORITHM"},{"path":"authentication_backend.file.password.argon2.variant","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_VARIANT"},{"path":"authentication_backend.file.password.argon2.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_ITERATIONS"},{"path":"authentication_backend.file.password.argon2.memory","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_MEMORY"},{"path":"authentication_backend.file.password.argon2.parallelism","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_PARALLELISM"},{"path":"authentication_backend.file.password.argon2.key_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_KEY_LENGTH"},{"path":"authentication_backend.file.password.argon2.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ARGON2_SALT_LENGTH"},{"path":"authentication_backend.file.password.sha2crypt.variant","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SHA2CRYPT_VARIANT"},{"path":"authentication_backend.file.password.sha2crypt.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SHA2CRYPT_ITERATIONS"},{"path":"authentication_backend.file.password.sha2crypt.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SHA2CRYPT_SALT_LENGTH"},{"path":"authentication_backend.file.password.pbkdf2.variant","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_PBKDF2_VARIANT"},{"path":"authentication_backend.file.password.pbkdf2.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_PBKDF2_ITERATIONS"},{"path":"authentication_backend.file.password.pbkdf2.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_PBKDF2_SALT_LENGTH"},{"path":"authentication_backend.file.password.bcrypt.variant","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_BCRYPT_VARIANT"},{"path":"authentication_backend.file.password.bcrypt.cost","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_BCRYPT_COST"},{"path":"authentication_backend.file.password.scrypt.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_ITERATIONS"},{"path":"authentication_backend.file.password.scrypt.block_size","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_BLOCK_SIZE"},{"path":"authentication_backend.file.password.scrypt.parallelism","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_PARALLELISM"},{"path":"authentication_backend.file.password.scrypt.key_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_KEY_LENGTH"},{"path":"authentication_backend.file.password.scrypt.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SCRYPT_SALT_LENGTH"},{"path":"authentication_backend.file.password.iterations","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_ITERATIONS"},{"path":"authentication_backend.file.password.memory","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_MEMORY"},{"path":"authentication_backend.file.password.parallelism","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_PARALLELISM"},{"path":"authentication_backend.file.password.key_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_KEY_LENGTH"},{"path":"authentication_backend.file.password.salt_length","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_PASSWORD_SALT_LENGTH"},{"path":"authentication_backend.file.search.email","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_SEARCH_EMAIL"},{"path":"authentication_backend.file.search.case_insensitive","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_FILE_SEARCH_CASE_INSENSITIVE"},{"path":"authentication_backend.ldap.address","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_ADDRESS"},{"path":"authentication_backend.ldap.implementation","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_IMPLEMENTATION"},{"path":"authentication_backend.ldap.timeout","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TIMEOUT"},{"path":"authentication_backend.ldap.start_tls","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_START_TLS"},{"path":"authentication_backend.ldap.tls.minimum_version","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_MINIMUM_VERSION"},{"path":"authentication_backend.ldap.tls.maximum_version","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_MAXIMUM_VERSION"},{"path":"authentication_backend.ldap.tls.skip_verify","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_SKIP_VERIFY"},{"path":"authentication_backend.ldap.tls.server_name","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_SERVER_NAME"},{"path":"authentication_backend.ldap.tls.private_key","secret":true,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_PRIVATE_KEY_FILE"},{"path":"authentication_backend.ldap.tls.certificate_chain","secret":true,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"authentication_backend.ldap.base_dn","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_BASE_DN"},{"path":"authentication_backend.ldap.additional_users_dn","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_ADDITIONAL_USERS_DN"},{"path":"authentication_backend.ldap.users_filter","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_USERS_FILTER"},{"path":"authentication_backend.ldap.additional_groups_dn","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_ADDITIONAL_GROUPS_DN"},{"path":"authentication_backend.ldap.groups_filter","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_GROUPS_FILTER"},{"path":"authentication_backend.ldap.group_name_attribute","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_GROUP_NAME_ATTRIBUTE"},{"path":"authentication_backend.ldap.username_attribute","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_USERNAME_ATTRIBUTE"},{"path":"authentication_backend.ldap.mail_attribute","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_MAIL_ATTRIBUTE"},{"path":"authentication_backend.ldap.display_name_attribute","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_DISPLAY_NAME_ATTRIBUTE"},{"path":"authentication_backend.ldap.permit_referrals","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PERMIT_REFERRALS"},{"path":"authentication_backend.ldap.permit_unauthenticated_bind","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PERMIT_UNAUTHENTICATED_BIND"},{"path":"authentication_backend.ldap.permit_feature_detection_failure","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PERMIT_FEATURE_DETECTION_FAILURE"},{"path":"authentication_backend.ldap.user","secret":false,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_USER"},{"path":"authentication_backend.ldap.password","secret":true,"env":"AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE"},{"path":"session.secret","secret":true,"env":"AUTHELIA_SESSION_SECRET_FILE"},{"path":"session.name","secret":false,"env":"AUTHELIA_SESSION_NAME"},{"path":"session.domain","secret":false,"env":"AUTHELIA_SESSION_DOMAIN"},{"path":"session.same_site","secret":false,"env":"AUTHELIA_SESSION_SAME_SITE"},{"path":"session.expiration","secret":false,"env":"AUTHELIA_SESSION_EXPIRATION"},{"path":"session.inactivity","secret":false,"env":"AUTHELIA_SESSION_INACTIVITY"},{"path":"session.remember_me","secret":false,"env":"AUTHELIA_SESSION_REMEMBER_ME"},{"path":"session","secret":false,"env":"AUTHELIA_SESSION"},{"path":"session.redis.host","secret":false,"env":"AUTHELIA_SESSION_REDIS_HOST"},{"path":"session.redis.port","secret":false,"env":"AUTHELIA_SESSION_REDIS_PORT"},{"path":"session.redis.username","secret":false,"env":"AUTHELIA_SESSION_REDIS_USERNAME"},{"path":"session.redis.password","secret":true,"env":"AUTHELIA_SESSION_REDIS_PASSWORD_FILE"},{"path":"session.redis.database_index","secret":false,"env":"AUTHELIA_SESSION_REDIS_DATABASE_INDEX"},{"path":"session.redis.maximum_active_connections","secret":false,"env":"AUTHELIA_SESSION_REDIS_MAXIMUM_ACTIVE_CONNECTIONS"},{"path":"session.redis.minimum_idle_connections","secret":false,"env":"AUTHELIA_SESSION_REDIS_MINIMUM_IDLE_CONNECTIONS"},{"path":"session.redis.tls.minimum_version","secret":false,"env":"AUTHELIA_SESSION_REDIS_TLS_MINIMUM_VERSION"},{"path":"session.redis.tls.maximum_version","secret":false,"env":"AUTHELIA_SESSION_REDIS_TLS_MAXIMUM_VERSION"},{"path":"session.redis.tls.skip_verify","secret":false,"env":"AUTHELIA_SESSION_REDIS_TLS_SKIP_VERIFY"},{"path":"session.redis.tls.server_name","secret":false,"env":"AUTHELIA_SESSION_REDIS_TLS_SERVER_NAME"},{"path":"session.redis.tls.private_key","secret":true,"env":"AUTHELIA_SESSION_REDIS_TLS_PRIVATE_KEY_FILE"},{"path":"session.redis.tls.certificate_chain","secret":true,"env":"AUTHELIA_SESSION_REDIS_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"session.redis.high_availability.sentinel_name","secret":false,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_NAME"},{"path":"session.redis.high_availability.sentinel_username","secret":false,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_USERNAME"},{"path":"session.redis.high_availability.sentinel_password","secret":true,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_SENTINEL_PASSWORD_FILE"},{"path":"session.redis.high_availability.route_by_latency","secret":false,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_ROUTE_BY_LATENCY"},{"path":"session.redis.high_availability.route_randomly","secret":false,"env":"AUTHELIA_SESSION_REDIS_HIGH_AVAILABILITY_ROUTE_RANDOMLY"},{"path":"totp.disable","secret":false,"env":"AUTHELIA_TOTP_DISABLE"},{"path":"totp.issuer","secret":false,"env":"AUTHELIA_TOTP_ISSUER"},{"path":"totp.algorithm","secret":false,"env":"AUTHELIA_TOTP_ALGORITHM"},{"path":"totp.digits","secret":false,"env":"AUTHELIA_TOTP_DIGITS"},{"path":"totp.period","secret":false,"env":"AUTHELIA_TOTP_PERIOD"},{"path":"totp.skew","secret":false,"env":"AUTHELIA_TOTP_SKEW"},{"path":"totp.secret_size","secret":false,"env":"AUTHELIA_TOTP_SECRET_SIZE"},{"path":"duo_api.disable","secret":false,"env":"AUTHELIA_DUO_API_DISABLE"},{"path":"duo_api.hostname","secret":false,"env":"AUTHELIA_DUO_API_HOSTNAME"},{"path":"duo_api.integration_key","secret":true,"env":"AUTHELIA_DUO_API_INTEGRATION_KEY_FILE"},{"path":"duo_api.secret_key","secret":true,"env":"AUTHELIA_DUO_API_SECRET_KEY_FILE"},{"path":"duo_api.enable_self_enrollment","secret":false,"env":"AUTHELIA_DUO_API_ENABLE_SELF_ENROLLMENT"},{"path":"access_control.default_policy","secret":false,"env":"AUTHELIA_ACCESS_CONTROL_DEFAULT_POLICY"},{"path":"ntp.address","secret":false,"env":"AUTHELIA_NTP_ADDRESS"},{"path":"ntp.version","secret":false,"env":"AUTHELIA_NTP_VERSION"},{"path":"ntp.max_desync","secret":false,"env":"AUTHELIA_NTP_MAX_DESYNC"},{"path":"ntp.disable_startup_check","secret":false,"env":"AUTHELIA_NTP_DISABLE_STARTUP_CHECK"},{"path":"ntp.disable_failure","secret":false,"env":"AUTHELIA_NTP_DISABLE_FAILURE"},{"path":"regulation.max_retries","secret":false,"env":"AUTHELIA_REGULATION_MAX_RETRIES"},{"path":"regulation.find_time","secret":false,"env":"AUTHELIA_REGULATION_FIND_TIME"},{"path":"regulation.ban_time","secret":false,"env":"AUTHELIA_REGULATION_BAN_TIME"},{"path":"storage.local.path","secret":false,"env":"AUTHELIA_STORAGE_LOCAL_PATH"},{"path":"storage.mysql.address","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_ADDRESS"},{"path":"storage.mysql.database","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_DATABASE"},{"path":"storage.mysql.username","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_USERNAME"},{"path":"storage.mysql.password","secret":true,"env":"AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE"},{"path":"storage.mysql.timeout","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TIMEOUT"},{"path":"storage.mysql.host","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_HOST"},{"path":"storage.mysql.port","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_PORT"},{"path":"storage.mysql.tls.minimum_version","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TLS_MINIMUM_VERSION"},{"path":"storage.mysql.tls.maximum_version","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TLS_MAXIMUM_VERSION"},{"path":"storage.mysql.tls.skip_verify","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TLS_SKIP_VERIFY"},{"path":"storage.mysql.tls.server_name","secret":false,"env":"AUTHELIA_STORAGE_MYSQL_TLS_SERVER_NAME"},{"path":"storage.mysql.tls.private_key","secret":true,"env":"AUTHELIA_STORAGE_MYSQL_TLS_PRIVATE_KEY_FILE"},{"path":"storage.mysql.tls.certificate_chain","secret":true,"env":"AUTHELIA_STORAGE_MYSQL_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"storage.postgres.address","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_ADDRESS"},{"path":"storage.postgres.database","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_DATABASE"},{"path":"storage.postgres.username","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_USERNAME"},{"path":"storage.postgres.password","secret":true,"env":"AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE"},{"path":"storage.postgres.timeout","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TIMEOUT"},{"path":"storage.postgres.host","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_HOST"},{"path":"storage.postgres.port","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_PORT"},{"path":"storage.postgres.schema","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_SCHEMA"},{"path":"storage.postgres.tls.minimum_version","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_MINIMUM_VERSION"},{"path":"storage.postgres.tls.maximum_version","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_MAXIMUM_VERSION"},{"path":"storage.postgres.tls.skip_verify","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_SKIP_VERIFY"},{"path":"storage.postgres.tls.server_name","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_SERVER_NAME"},{"path":"storage.postgres.tls.private_key","secret":true,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_PRIVATE_KEY_FILE"},{"path":"storage.postgres.tls.certificate_chain","secret":true,"env":"AUTHELIA_STORAGE_POSTGRES_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"storage.postgres.ssl.mode","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_SSL_MODE"},{"path":"storage.postgres.ssl.root_certificate","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_SSL_ROOT_CERTIFICATE"},{"path":"storage.postgres.ssl.certificate","secret":false,"env":"AUTHELIA_STORAGE_POSTGRES_SSL_CERTIFICATE"},{"path":"storage.postgres.ssl.key","secret":true,"env":"AUTHELIA_STORAGE_POSTGRES_SSL_KEY_FILE"},{"path":"storage.encryption_key","secret":true,"env":"AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE"},{"path":"notifier.disable_startup_check","secret":false,"env":"AUTHELIA_NOTIFIER_DISABLE_STARTUP_CHECK"},{"path":"notifier.filesystem.filename","secret":false,"env":"AUTHELIA_NOTIFIER_FILESYSTEM_FILENAME"},{"path":"notifier.smtp.address","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_ADDRESS"},{"path":"notifier.smtp.timeout","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TIMEOUT"},{"path":"notifier.smtp.username","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_USERNAME"},{"path":"notifier.smtp.password","secret":true,"env":"AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE"},{"path":"notifier.smtp.identifier","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_IDENTIFIER"},{"path":"notifier.smtp.sender","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_SENDER"},{"path":"notifier.smtp.subject","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_SUBJECT"},{"path":"notifier.smtp.startup_check_address","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_STARTUP_CHECK_ADDRESS"},{"path":"notifier.smtp.disable_require_tls","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_DISABLE_REQUIRE_TLS"},{"path":"notifier.smtp.disable_html_emails","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_DISABLE_HTML_EMAILS"},{"path":"notifier.smtp.disable_starttls","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_DISABLE_STARTTLS"},{"path":"notifier.smtp.tls.minimum_version","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_MINIMUM_VERSION"},{"path":"notifier.smtp.tls.maximum_version","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_MAXIMUM_VERSION"},{"path":"notifier.smtp.tls.skip_verify","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_SKIP_VERIFY"},{"path":"notifier.smtp.tls.server_name","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_SERVER_NAME"},{"path":"notifier.smtp.tls.private_key","secret":true,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_PRIVATE_KEY_FILE"},{"path":"notifier.smtp.tls.certificate_chain","secret":true,"env":"AUTHELIA_NOTIFIER_SMTP_TLS_CERTIFICATE_CHAIN_FILE"},{"path":"notifier.smtp.host","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_HOST"},{"path":"notifier.smtp.port","secret":false,"env":"AUTHELIA_NOTIFIER_SMTP_PORT"},{"path":"notifier.template_path","secret":false,"env":"AUTHELIA_NOTIFIER_TEMPLATE_PATH"},{"path":"server.address","secret":false,"env":"AUTHELIA_SERVER_ADDRESS"},{"path":"server.asset_path","secret":false,"env":"AUTHELIA_SERVER_ASSET_PATH"},{"path":"server.disable_healthcheck","secret":false,"env":"AUTHELIA_SERVER_DISABLE_HEALTHCHECK"},{"path":"server.tls.certificate","secret":false,"env":"AUTHELIA_SERVER_TLS_CERTIFICATE"},{"path":"server.tls.key","secret":true,"env":"AUTHELIA_SERVER_TLS_KEY_FILE"},{"path":"server.headers.csp_template","secret":false,"env":"AUTHELIA_SERVER_HEADERS_CSP_TEMPLATE"},{"path":"server.endpoints.enable_pprof","secret":false,"env":"AUTHELIA_SERVER_ENDPOINTS_ENABLE_PPROF"},{"path":"server.endpoints.enable_expvars","secret":false,"env":"AUTHELIA_SERVER_ENDPOINTS_ENABLE_EXPVARS"},{"path":"server.buffers.read","secret":false,"env":"AUTHELIA_SERVER_BUFFERS_READ"},{"path":"server.buffers.write","secret":false,"env":"AUTHELIA_SERVER_BUFFERS_WRITE"},{"path":"server.timeouts.read","secret":false,"env":"AUTHELIA_SERVER_TIMEOUTS_READ"},{"path":"server.timeouts.write","secret":false,"env":"AUTHELIA_SERVER_TIMEOUTS_WRITE"},{"path":"server.timeouts.idle","secret":false,"env":"AUTHELIA_SERVER_TIMEOUTS_IDLE"},{"path":"server.host","secret":false,"env":"AUTHELIA_SERVER_HOST"},{"path":"server.port","secret":false,"env":"AUTHELIA_SERVER_PORT"},{"path":"server.path","secret":false,"env":"AUTHELIA_SERVER_PATH"},{"path":"telemetry.metrics.enabled","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_ENABLED"},{"path":"telemetry.metrics.address","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_ADDRESS"},{"path":"telemetry.metrics.buffers.read","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_BUFFERS_READ"},{"path":"telemetry.metrics.buffers.write","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_BUFFERS_WRITE"},{"path":"telemetry.metrics.timeouts.read","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_TIMEOUTS_READ"},{"path":"telemetry.metrics.timeouts.write","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_TIMEOUTS_WRITE"},{"path":"telemetry.metrics.timeouts.idle","secret":false,"env":"AUTHELIA_TELEMETRY_METRICS_TIMEOUTS_IDLE"},{"path":"webauthn.disable","secret":false,"env":"AUTHELIA_WEBAUTHN_DISABLE"},{"path":"webauthn.display_name","secret":false,"env":"AUTHELIA_WEBAUTHN_DISPLAY_NAME"},{"path":"webauthn.attestation_conveyance_preference","secret":false,"env":"AUTHELIA_WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE"},{"path":"webauthn.user_verification","secret":false,"env":"AUTHELIA_WEBAUTHN_USER_VERIFICATION"},{"path":"webauthn.timeout","secret":false,"env":"AUTHELIA_WEBAUTHN_TIMEOUT"},{"path":"password_policy.standard.enabled","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_ENABLED"},{"path":"password_policy.standard.min_length","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_MIN_LENGTH"},{"path":"password_policy.standard.max_length","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_MAX_LENGTH"},{"path":"password_policy.standard.require_uppercase","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_REQUIRE_UPPERCASE"},{"path":"password_policy.standard.require_lowercase","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_REQUIRE_LOWERCASE"},{"path":"password_policy.standard.require_number","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_REQUIRE_NUMBER"},{"path":"password_policy.standard.require_special","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_STANDARD_REQUIRE_SPECIAL"},{"path":"password_policy.zxcvbn.enabled","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_ZXCVBN_ENABLED"},{"path":"password_policy.zxcvbn.min_score","secret":false,"env":"AUTHELIA_PASSWORD_POLICY_ZXCVBN_MIN_SCORE"},{"path":"privacy_policy.enabled","secret":false,"env":"AUTHELIA_PRIVACY_POLICY_ENABLED"},{"path":"privacy_policy.require_user_acceptance","secret":false,"env":"AUTHELIA_PRIVACY_POLICY_REQUIRE_USER_ACCEPTANCE"},{"path":"privacy_policy.policy_url","secret":false,"env":"AUTHELIA_PRIVACY_POLICY_POLICY_URL"}] \ No newline at end of file diff --git a/internal/configuration/config.template.yml b/internal/configuration/config.template.yml index 4e8eb0580..61e010094 100644 --- a/internal/configuration/config.template.yml +++ b/internal/configuration/config.template.yml @@ -47,15 +47,12 @@ default_redirection_url: 'https://home.example.com/' server: ## The address for the Main server to listen on in the address common syntax. ## Formats: - ## - [://][:] - ## - [://][hostname]: + ## - [://][:][/] + ## - [://][hostname]:[/] ## Square brackets indicate optional portions of the format. Scheme must be 'tcp', 'tcp4', 'tcp6', or 'unix'. ## The default scheme is 'unix' if the address is an absolute path otherwise it's 'tcp'. The default port is '9091'. - address: 'tcp://:9091' - - ## Set the single level path Authelia listens on. - ## Must be alphanumeric chars and should not contain any slashes. - path: '' + ## If the path is specified this configures the router to handle both the `/` path and the configured path. + address: 'tcp://:9091/' ## Set the path on disk to Authelia assets. ## Useful to allow overriding of specific static assets. @@ -162,11 +159,12 @@ telemetry: ## The address for the Metrics server to listen on in the address common syntax. ## Formats: - ## - [://][:] - ## - [://][hostname]: + ## - [://][:][/] + ## - [://][hostname]:[/] ## Square brackets indicate optional portions of the format. Scheme must be 'tcp', 'tcp4', 'tcp6', or 'unix'. ## The default scheme is 'unix' if the address is an absolute path otherwise it's 'tcp'. The default port is '9959'. - address: 'tcp://:9959' + ## If the path is not specified it defaults to `/metrics`. + address: 'tcp://:9959/metrics' ## Metrics Server Buffers configuration. # buffers: diff --git a/internal/configuration/const.go b/internal/configuration/const.go index 7ec14716c..26c023159 100644 --- a/internal/configuration/const.go +++ b/internal/configuration/const.go @@ -38,6 +38,8 @@ const ( errFmtDecodeHookCouldNotParse = "could not decode '%s' to a %s%s: %w" errFmtDecodeHookCouldNotParseBasic = "could not decode to a %s%s: %w" errFmtDecodeHookCouldNotParseEmptyValue = "could not decode an empty value to a %s%s: %w" + + errFmtSpecialRemappedKey = "configuration key '%s' is deprecated in %s and has been replaced by '%s' when combined with the '%s' in the format of '%s': this should be automatically mapped for you but you will need to adjust your configuration to remove this message" ) const ( diff --git a/internal/configuration/deprecation.go b/internal/configuration/deprecation.go index b36d61a61..eeaa84a2e 100644 --- a/internal/configuration/deprecation.go +++ b/internal/configuration/deprecation.go @@ -187,7 +187,7 @@ var deprecations = map[string]Deprecation{ Keep: true, MapFunc: nil, ErrFunc: func(d Deprecation, _ map[string]any, _ any, val *schema.StructValidator) { - val.PushWarning(fmt.Errorf("configuration key 'server.host' is deprecated in %s and has been replaced by 'server.address' when combined with the 'server.port' in the format of '[tcp://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message", d.Version.String())) + val.PushWarning(fmt.Errorf("configuration key '%s' is deprecated in %s and has been replaced by '%s' when combined with the 'server.port' and 'server.path' in the format of %s: this should be automatically mapped for you but you will need to adjust your configuration to remove this message", d.Key, d.Version.String(), d.NewKey, "'[tcp[(4|6)]://][:][/]' or 'tcp[(4|6)://][hostname]:[/]'")) }, }, "server.port": { @@ -198,7 +198,18 @@ var deprecations = map[string]Deprecation{ Keep: true, MapFunc: nil, ErrFunc: func(d Deprecation, _ map[string]any, _ any, val *schema.StructValidator) { - val.PushWarning(fmt.Errorf("configuration key 'server.port' is deprecated in %s and has been replaced by 'server.address' when combined with the 'server.host' in the format of '[tcp://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message", d.Version.String())) + val.PushWarning(fmt.Errorf("configuration key '%s' is deprecated in %s and has been replaced by '%s' when combined with the 'server.host' and 'server.path' in the format of %s: this should be automatically mapped for you but you will need to adjust your configuration to remove this message", d.Key, d.Version.String(), d.NewKey, "'[tcp[(4|6)]://][:][/]' or 'tcp[(4|6)://][hostname]:[/]'")) + }, + }, + "server.path": { + Version: model.SemanticVersion{Major: 4, Minor: 38}, + Key: "server.path", + NewKey: "server.address", + AutoMap: false, + Keep: true, + MapFunc: nil, + ErrFunc: func(d Deprecation, _ map[string]any, _ any, val *schema.StructValidator) { + val.PushWarning(fmt.Errorf("configuration key '%s' is deprecated in %s and has been replaced by '%s' when combined with the 'server.host' and 'server.port' in the format of %s: this should be automatically mapped for you but you will need to adjust your configuration to remove this message", d.Key, d.Version.String(), d.NewKey, "'[tcp[(4|6)]://][:][/]' or 'tcp[(4|6)://][hostname]:[/]'")) }, }, "storage.mysql.host": { @@ -209,7 +220,7 @@ var deprecations = map[string]Deprecation{ Keep: true, MapFunc: nil, ErrFunc: func(d Deprecation, _ map[string]any, _ any, val *schema.StructValidator) { - val.PushWarning(fmt.Errorf("configuration key 'storage.mysql.host' is deprecated in %s and has been replaced by 'storage.mysql.address' when combined with the 'storage.mysql.port' in the format of '[tcp://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message", d.Version.String())) + val.PushWarning(fmt.Errorf(errFmtSpecialRemappedKey, d.Key, d.Version.String(), d.NewKey, "storage.mysql.port", "[tcp://][:]")) }, }, "storage.mysql.port": { @@ -220,7 +231,7 @@ var deprecations = map[string]Deprecation{ Keep: true, MapFunc: nil, ErrFunc: func(d Deprecation, _ map[string]any, _ any, val *schema.StructValidator) { - val.PushWarning(fmt.Errorf("configuration key 'storage.mysql.port' is deprecated in %s and has been replaced by 'storage.mysql.address' when combined with the 'storage.mysql.host' in the format of '[tcp://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message", d.Version.String())) + val.PushWarning(fmt.Errorf(errFmtSpecialRemappedKey, d.Key, d.Version.String(), d.NewKey, "storage.mysql.host", "[tcp://][:]")) }, }, "storage.postgres.host": { @@ -231,7 +242,7 @@ var deprecations = map[string]Deprecation{ Keep: true, MapFunc: nil, ErrFunc: func(d Deprecation, _ map[string]any, _ any, val *schema.StructValidator) { - val.PushWarning(fmt.Errorf("configuration key 'storage.postgres.host' is deprecated in %s and has been replaced by 'storage.postgres.address' when combined with the 'storage.postgres.port' in the format of '[tcp://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message", d.Version.String())) + val.PushWarning(fmt.Errorf(errFmtSpecialRemappedKey, d.Key, d.Version.String(), d.NewKey, "storage.postgres.port", "[tcp://][:]")) }, }, "storage.postgres.port": { @@ -242,7 +253,29 @@ var deprecations = map[string]Deprecation{ Keep: true, MapFunc: nil, ErrFunc: func(d Deprecation, _ map[string]any, _ any, val *schema.StructValidator) { - val.PushWarning(fmt.Errorf("configuration key 'storage.postgres.port' is deprecated in %s and has been replaced by 'storage.postgres.address' when combined with the 'storage.postgres.host' in the format of '[tcp://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message", d.Version.String())) + val.PushWarning(fmt.Errorf(errFmtSpecialRemappedKey, d.Key, d.Version.String(), d.NewKey, "storage.postgres.host", "[tcp://][:]")) + }, + }, + "notifier.smtp.host": { + Version: model.SemanticVersion{Major: 4, Minor: 38}, + Key: "notifier.smtp.host", + NewKey: "notifier.smtp.address", + AutoMap: false, + Keep: true, + MapFunc: nil, + ErrFunc: func(d Deprecation, _ map[string]any, _ any, val *schema.StructValidator) { + val.PushWarning(fmt.Errorf(errFmtSpecialRemappedKey, d.Key, d.Version.String(), d.NewKey, "notifier.smtp.port", "[tcp://][:]")) + }, + }, + "notifier.smtp.port": { + Version: model.SemanticVersion{Major: 4, Minor: 38}, + Key: "notifier.smtp.port", + NewKey: "notifier.smtp.address", + AutoMap: false, + Keep: true, + MapFunc: nil, + ErrFunc: func(d Deprecation, _ map[string]any, _ any, val *schema.StructValidator) { + val.PushWarning(fmt.Errorf(errFmtSpecialRemappedKey, d.Key, d.Version.String(), d.NewKey, "notifier.smtp.host", "[tcp://][:]")) }, }, "authentication_backend.ldap.url": { diff --git a/internal/configuration/provider_test.go b/internal/configuration/provider_test.go index da90574db..1072a6956 100644 --- a/internal/configuration/provider_test.go +++ b/internal/configuration/provider_test.go @@ -314,44 +314,24 @@ func TestShouldValidateDeprecatedEnvNamesWithDeprecatedKeys(t *testing.T) { assert.Len(t, val.Errors(), 0) warnings := val.Warnings() - require.Len(t, warnings, 3) + require.Len(t, warnings, 10) 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://][:]': 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://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") + assert.EqualError(t, warnings[1], "configuration key 'notifier.smtp.host' is deprecated in 4.38.0 and has been replaced by 'notifier.smtp.address' when combined with the 'notifier.smtp.port' in the format of '[tcp://][:]': 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 'notifier.smtp.port' is deprecated in 4.38.0 and has been replaced by 'notifier.smtp.address' when combined with the 'notifier.smtp.host' in the format of '[tcp://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") + assert.EqualError(t, warnings[3], "configuration key 'server.host' is deprecated in 4.38.0 and has been replaced by 'server.address' when combined with the 'server.port' and 'server.path' in the format of '[tcp[(4|6)]://][:][/]' or 'tcp[(4|6)://][hostname]:[/]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") + assert.EqualError(t, warnings[4], "configuration key 'server.path' is deprecated in 4.38.0 and has been replaced by 'server.address' when combined with the 'server.host' and 'server.port' in the format of '[tcp[(4|6)]://][:][/]' or 'tcp[(4|6)://][hostname]:[/]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") + assert.EqualError(t, warnings[5], "configuration key 'server.port' is deprecated in 4.38.0 and has been replaced by 'server.address' when combined with the 'server.host' and 'server.path' in the format of '[tcp[(4|6)]://][:][/]' or 'tcp[(4|6)://][hostname]:[/]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") + assert.EqualError(t, warnings[6], "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://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") + assert.EqualError(t, warnings[7], "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://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") + assert.EqualError(t, warnings[8], "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://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") + assert.EqualError(t, warnings[9], "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://][:]': 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://][:]': 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://][:]': 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()) -} - func TestShouldRaiseErrOnInvalidNotifierSMTPSender(t *testing.T) { val := schema.NewStructValidator() keys, _, err := Load(val, NewDefaultSources([]string{"./test_resources/config_smtp_sender_invalid.yml"}, DefaultEnvPrefix, DefaultEnvDelimiter)...) @@ -495,7 +475,7 @@ func TestShouldLoadDirectoryConfiguration(t *testing.T) { assert.Len(t, val.Errors(), 0) require.Len(t, val.Warnings(), 1) - 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://][:]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") + 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' and 'server.path' in the format of '[tcp[(4|6)]://][:][/]' or 'tcp[(4|6)://][hostname]:[/]': this should be automatically mapped for you but you will need to adjust your configuration to remove this message") } func testSetEnv(t *testing.T, key, value string) { diff --git a/internal/configuration/schema/keys.go b/internal/configuration/schema/keys.go index e2ee63916..c4c0054e7 100644 --- a/internal/configuration/schema/keys.go +++ b/internal/configuration/schema/keys.go @@ -259,7 +259,6 @@ var Keys = []string{ "notifier.smtp.port", "notifier.template_path", "server.address", - "server.path", "server.asset_path", "server.disable_healthcheck", "server.tls.certificate", @@ -279,6 +278,7 @@ var Keys = []string{ "server.timeouts.idle", "server.host", "server.port", + "server.path", "telemetry.metrics.enabled", "telemetry.metrics.address", "telemetry.metrics.buffers.read", diff --git a/internal/configuration/schema/server.go b/internal/configuration/schema/server.go index 65ac03099..bca2a0b9d 100644 --- a/internal/configuration/schema/server.go +++ b/internal/configuration/schema/server.go @@ -8,7 +8,6 @@ import ( // ServerConfiguration represents the configuration of the http server. type ServerConfiguration struct { Address *AddressTCP `koanf:"address"` - Path string `koanf:"path"` AssetPath string `koanf:"asset_path"` DisableHealthcheck bool `koanf:"disable_healthcheck"` @@ -24,6 +23,9 @@ type ServerConfiguration struct { // Deprecated: use address instead. Port int `koanf:"port"` + + // Deprecated: use address instead. + Path string `koanf:"path"` } // ServerEndpoints is the endpoints configuration for the HTTP server. @@ -60,7 +62,7 @@ type ServerHeaders struct { // DefaultServerConfiguration represents the default values of the ServerConfiguration. var DefaultServerConfiguration = ServerConfiguration{ - Address: &AddressTCP{Address{true, false, -1, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: ":9091"}}}, + Address: &AddressTCP{Address{true, false, -1, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: ":9091", Path: "/"}}}, Buffers: ServerBuffers{ Read: 4096, Write: 4096, diff --git a/internal/configuration/schema/telemetry.go b/internal/configuration/schema/telemetry.go index 10f804f4d..06160c252 100644 --- a/internal/configuration/schema/telemetry.go +++ b/internal/configuration/schema/telemetry.go @@ -21,7 +21,7 @@ type TelemetryMetricsConfig struct { // DefaultTelemetryConfig is the default telemetry configuration. var DefaultTelemetryConfig = TelemetryConfig{ Metrics: TelemetryMetricsConfig{ - Address: &AddressTCP{Address{true, false, -1, 9959, &url.URL{Scheme: AddressSchemeTCP, Host: ":9959"}}}, + Address: &AddressTCP{Address{true, false, -1, 9959, &url.URL{Scheme: AddressSchemeTCP, Host: ":9959", Path: "/metrics"}}}, Buffers: ServerBuffers{ Read: 4096, Write: 4096, diff --git a/internal/configuration/schema/types_address.go b/internal/configuration/schema/types_address.go index a68bad701..702133382 100644 --- a/internal/configuration/schema/types_address.go +++ b/internal/configuration/schema/types_address.go @@ -336,6 +336,15 @@ func (a *Address) Path() string { return a.url.Path } +// SetPath sets the path. +func (a *Address) SetPath(path string) { + if !a.valid || a.url == nil { + return + } + + a.url.Path = path +} + // SocketHostname returns the correct hostname for a socket connection. func (a *Address) SocketHostname() string { if !a.valid || a.url == nil { diff --git a/internal/configuration/test_resources/config.deprecated.alt.yml b/internal/configuration/test_resources/config.deprecated.alt.yml deleted file mode 100644 index 9ea5f9cd6..000000000 --- a/internal/configuration/test_resources/config.deprecated.alt.yml +++ /dev/null @@ -1,173 +0,0 @@ ---- -default_redirection_url: https://home.example.com:8080/ - -server: - address: "tcp://127.0.0.1:9091" - endpoints: - authz: - forward-auth: - implementation: ForwardAuth - authn_strategies: - - name: HeaderProxyAuthorization - - name: CookieSession - ext-authz: - implementation: ExtAuthz - authn_strategies: - - name: HeaderProxyAuthorization - - name: CookieSession - auth-request: - implementation: AuthRequest - authn_strategies: - - name: HeaderAuthRequestProxyAuthorization - - name: CookieSession - legacy: - implementation: Legacy - -log: - level: debug - -totp: - issuer: authelia.com - -duo_api: - hostname: api-123456789.example.com - integration_key: ABCDEF - -authentication_backend: - ldap: - url: 'ldap://127.0.0.1' - tls: - private_key: | - -----BEGIN RSA PRIVATE KEY----- - MIIEpAIBAAKCAQEA6z1LOg1ZCqb0lytXWZ+MRBpMHEXOoTOLYgfZXt1IYyE3Z758 - cyalk0NYQhY5cZDsXPYWPvAHiPMUxutWkoxFwby56S+AbIMa3/Is+ILrHRJs8Exn - ZkpyrYFxPX12app2kErdmAkHSx0Z5/kuXiz96PHs8S8/ZbyZolLHzdfLtSzjvRm5 - Zue5iFzsf19NJz5CIBfv8g5lRwtE8wNJoRSpn1xq7fqfuA0weDNFPzjlNWRLy6aa - rK7qJexRkmkCs4sLgyl+9NODYJpvmN8E1yhyC27E0joI6rBFVW7Ihv+cSPCdDzGp - EWe81x3AeqAa3mjVqkiq4u4Z2i8JDgBaPboqJwIDAQABAoIBAAFdLZ58jVOefDSU - L8F5R1rtvBs93GDa56f926jNJ6pLewLC+/2+757W+SAI+PRLntM7Kg3bXm/Q2QH+ - Q1Y+MflZmspbWCdI61L5GIGoYKyeers59i+FpvySj5GHtLQRiTZ0+Kv1AXHSDWBm - 9XneUOqU3IbZe0ifu1RRno72/VtjkGXbW8Mkkw+ohyGbIeTx/0/JQ6sSNZTT3Vk7 - 8i4IXptq3HSF0/vqZuah8rShoeNq72pD1YLM9YPdL5by1QkDLnqATDiCpLBTCaNV - I8sqYEun+HYbQzBj8ZACG2JVZpEEidONWQHw5BPWO95DSZYrVnEkuCqeH+u5vYt7 - CHuJ3AECgYEA+W3v5z+j91w1VPHS0VB3SCDMouycAMIUnJPAbt+0LPP0scUFsBGE - hPAKddC54pmMZRQ2KIwBKiyWfCrJ8Xz8Yogn7fJgmwTHidJBr2WQpIEkNGlK3Dzi - jXL2sh0yC7sHvn0DqiQ79l/e7yRbSnv2wrTJEczOOH2haD7/tBRyCYECgYEA8W+q - E9YyGvEltnPFaOxofNZ8LHVcZSsQI5b6fc0iE7fjxFqeXPXEwGSOTwqQLQRiHn9b - CfPmIG4Vhyq0otVmlPvUnfBZ2OK+tl5X2/mQFO3ROMdvpi0KYa994uqfJdSTaqLn - jjoKFB906UFHnDQDLZUNiV1WwnkTglgLc+xrd6cCgYEAqqthyv6NyBTM3Tm2gcio - Ra9Dtntl51LlXZnvwy3IkDXBCd6BHM9vuLKyxZiziGx+Vy90O1xI872cnot8sINQ - Am+dur/tAEVN72zxyv0Y8qb2yfH96iKy9gxi5s75TnOEQgAygLnYWaWR2lorKRUX - bHTdXBOiS58S0UzCFEslGIECgYBqkO4SKWYeTDhoKvuEj2yjRYyzlu28XeCWxOo1 - otiauX0YSyNBRt2cSgYiTzhKFng0m+QUJYp63/wymB/5C5Zmxi0XtWIDADpLhqLj - HmmBQ2Mo26alQ5YkffBju0mZyhVzaQop1eZi8WuKFV1FThPlB7hc3E0SM5zv2Grd - tQnOWwKBgQC40yZY0PcjuILhy+sIc0Wvh7LUA7taSdTye149kRvbvsCDN7Jh75lM - USjhLXY0Nld2zBm9r8wMb81mXH29uvD+tDqqsICvyuKlA/tyzXR+QTr7dCVKVwu0 - 1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw== - -----END RSA PRIVATE KEY----- - base_dn: dc=example,dc=com - username_attribute: uid - additional_users_dn: ou=users - users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user)) - additional_groups_dn: ou=groups - groups_filter: (&(member={dn})(objectClass=groupOfNames)) - group_name_attribute: cn - mail_attribute: mail - user: cn=admin,dc=example,dc=com - -access_control: - default_policy: deny - - rules: - # Rules applied to everyone - - domain: public.example.com - policy: bypass - - - domain: secure.example.com - policy: one_factor - # Network based rule, if not provided any network matches. - networks: - - 192.168.1.0/24 - - domain: secure.example.com - policy: two_factor - - - domain: [singlefactor.example.com, onefactor.example.com] - policy: one_factor - - # Rules applied to 'admins' group - - domain: "mx2.mail.example.com" - subject: "group:admins" - policy: deny - - domain: "*.example.com" - subject: "group:admins" - policy: two_factor - - # Rules applied to 'dev' group - - domain: dev.example.com - resources: - - "^/groups/dev/.*$" - subject: "group:dev" - policy: two_factor - - # Rules applied to user 'john' - - domain: dev.example.com - resources: - - "^/users/john/.*$" - subject: "user:john" - policy: two_factor - - # Rules applied to 'dev' group and user 'john' - - domain: dev.example.com - resources: - - "^/deny-all.*$" - subject: ["group:dev", "user:john"] - policy: deny - - # Rules applied to user 'harry' - - domain: dev.example.com - resources: - - "^/users/harry/.*$" - subject: "user:harry" - policy: two_factor - - # Rules applied to user 'bob' - - domain: "*.mail.example.com" - subject: "user:bob" - policy: two_factor - - domain: "dev.example.com" - resources: - - "^/users/bob/.*$" - subject: "user:bob" - policy: two_factor - -session: - name: authelia_session - expiration: 3600000 # 1 hour - inactivity: 300000 # 5 minutes - domain: example.com - redis: - host: 127.0.0.1 - port: 6379 - high_availability: - sentinel_name: test - -regulation: - max_retries: 3 - find_time: 120 - ban_time: 300 - -storage: - postgres: - host: 127.0.0.1 - port: 5432 - database: authelia - username: authelia - -notifier: - smtp: - username: test - host: 127.0.0.1 - port: 1025 - sender: admin@example.com - disable_require_tls: true -... diff --git a/internal/configuration/test_resources/config.deprecated.yml b/internal/configuration/test_resources/config.deprecated.yml index 24a577b4f..c967ac936 100644 --- a/internal/configuration/test_resources/config.deprecated.yml +++ b/internal/configuration/test_resources/config.deprecated.yml @@ -1,173 +1,23 @@ --- -default_redirection_url: https://home.example.com:8080/ - server: - address: "tcp://127.0.0.1:9091" - endpoints: - authz: - forward-auth: - implementation: ForwardAuth - authn_strategies: - - name: HeaderProxyAuthorization - - name: CookieSession - ext-authz: - implementation: ExtAuthz - authn_strategies: - - name: HeaderProxyAuthorization - - name: CookieSession - auth-request: - implementation: AuthRequest - authn_strategies: - - name: HeaderAuthRequestProxyAuthorization - - name: CookieSession - legacy: - implementation: Legacy - -log: - level: debug - -totp: - issuer: authelia.com - -duo_api: - hostname: api-123456789.example.com - integration_key: ABCDEF + host: '0.0.0.0' + port: 9091 + path: "auth" authentication_backend: ldap: url: 'ldap://127.0.0.1' - tls: - private_key: | - -----BEGIN RSA PRIVATE KEY----- - MIIEpAIBAAKCAQEA6z1LOg1ZCqb0lytXWZ+MRBpMHEXOoTOLYgfZXt1IYyE3Z758 - cyalk0NYQhY5cZDsXPYWPvAHiPMUxutWkoxFwby56S+AbIMa3/Is+ILrHRJs8Exn - ZkpyrYFxPX12app2kErdmAkHSx0Z5/kuXiz96PHs8S8/ZbyZolLHzdfLtSzjvRm5 - Zue5iFzsf19NJz5CIBfv8g5lRwtE8wNJoRSpn1xq7fqfuA0weDNFPzjlNWRLy6aa - rK7qJexRkmkCs4sLgyl+9NODYJpvmN8E1yhyC27E0joI6rBFVW7Ihv+cSPCdDzGp - EWe81x3AeqAa3mjVqkiq4u4Z2i8JDgBaPboqJwIDAQABAoIBAAFdLZ58jVOefDSU - L8F5R1rtvBs93GDa56f926jNJ6pLewLC+/2+757W+SAI+PRLntM7Kg3bXm/Q2QH+ - Q1Y+MflZmspbWCdI61L5GIGoYKyeers59i+FpvySj5GHtLQRiTZ0+Kv1AXHSDWBm - 9XneUOqU3IbZe0ifu1RRno72/VtjkGXbW8Mkkw+ohyGbIeTx/0/JQ6sSNZTT3Vk7 - 8i4IXptq3HSF0/vqZuah8rShoeNq72pD1YLM9YPdL5by1QkDLnqATDiCpLBTCaNV - I8sqYEun+HYbQzBj8ZACG2JVZpEEidONWQHw5BPWO95DSZYrVnEkuCqeH+u5vYt7 - CHuJ3AECgYEA+W3v5z+j91w1VPHS0VB3SCDMouycAMIUnJPAbt+0LPP0scUFsBGE - hPAKddC54pmMZRQ2KIwBKiyWfCrJ8Xz8Yogn7fJgmwTHidJBr2WQpIEkNGlK3Dzi - jXL2sh0yC7sHvn0DqiQ79l/e7yRbSnv2wrTJEczOOH2haD7/tBRyCYECgYEA8W+q - E9YyGvEltnPFaOxofNZ8LHVcZSsQI5b6fc0iE7fjxFqeXPXEwGSOTwqQLQRiHn9b - CfPmIG4Vhyq0otVmlPvUnfBZ2OK+tl5X2/mQFO3ROMdvpi0KYa994uqfJdSTaqLn - jjoKFB906UFHnDQDLZUNiV1WwnkTglgLc+xrd6cCgYEAqqthyv6NyBTM3Tm2gcio - Ra9Dtntl51LlXZnvwy3IkDXBCd6BHM9vuLKyxZiziGx+Vy90O1xI872cnot8sINQ - Am+dur/tAEVN72zxyv0Y8qb2yfH96iKy9gxi5s75TnOEQgAygLnYWaWR2lorKRUX - bHTdXBOiS58S0UzCFEslGIECgYBqkO4SKWYeTDhoKvuEj2yjRYyzlu28XeCWxOo1 - otiauX0YSyNBRt2cSgYiTzhKFng0m+QUJYp63/wymB/5C5Zmxi0XtWIDADpLhqLj - HmmBQ2Mo26alQ5YkffBju0mZyhVzaQop1eZi8WuKFV1FThPlB7hc3E0SM5zv2Grd - tQnOWwKBgQC40yZY0PcjuILhy+sIc0Wvh7LUA7taSdTye149kRvbvsCDN7Jh75lM - USjhLXY0Nld2zBm9r8wMb81mXH29uvD+tDqqsICvyuKlA/tyzXR+QTr7dCVKVwu0 - 1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw== - -----END RSA PRIVATE KEY----- - base_dn: dc=example,dc=com - username_attribute: uid - additional_users_dn: ou=users - users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user)) - additional_groups_dn: ou=groups - groups_filter: (&(member={dn})(objectClass=groupOfNames)) - group_name_attribute: cn - mail_attribute: mail - user: cn=admin,dc=example,dc=com - -access_control: - default_policy: deny - - rules: - # Rules applied to everyone - - domain: public.example.com - policy: bypass - - - domain: secure.example.com - policy: one_factor - # Network based rule, if not provided any network matches. - networks: - - 192.168.1.0/24 - - domain: secure.example.com - policy: two_factor - - - domain: [singlefactor.example.com, onefactor.example.com] - policy: one_factor - - # Rules applied to 'admins' group - - domain: "mx2.mail.example.com" - subject: "group:admins" - policy: deny - - domain: "*.example.com" - subject: "group:admins" - policy: two_factor - - # Rules applied to 'dev' group - - domain: dev.example.com - resources: - - "^/groups/dev/.*$" - subject: "group:dev" - policy: two_factor - - # Rules applied to user 'john' - - domain: dev.example.com - resources: - - "^/users/john/.*$" - subject: "user:john" - policy: two_factor - - # Rules applied to 'dev' group and user 'john' - - domain: dev.example.com - resources: - - "^/deny-all.*$" - subject: ["group:dev", "user:john"] - policy: deny - - # Rules applied to user 'harry' - - domain: dev.example.com - resources: - - "^/users/harry/.*$" - subject: "user:harry" - policy: two_factor - - # Rules applied to user 'bob' - - domain: "*.mail.example.com" - subject: "user:bob" - policy: two_factor - - domain: "dev.example.com" - resources: - - "^/users/bob/.*$" - subject: "user:bob" - policy: two_factor - -session: - name: authelia_session - expiration: 3600000 # 1 hour - inactivity: 300000 # 5 minutes - domain: example.com - redis: - host: 127.0.0.1 - port: 6379 - high_availability: - sentinel_name: test - -regulation: - max_retries: 3 - find_time: 120 - ban_time: 300 storage: mysql: host: 127.0.0.1 port: 3306 - database: authelia - username: authelia + postgres: + host: 127.0.0.1 + port: 5432 notifier: smtp: - username: test host: 127.0.0.1 port: 1025 - sender: admin@example.com - disable_require_tls: true ... diff --git a/internal/configuration/validator/const.go b/internal/configuration/validator/const.go index a9e934f2f..4da34125c 100644 --- a/internal/configuration/validator/const.go +++ b/internal/configuration/validator/const.go @@ -323,8 +323,9 @@ const ( errFmtServerAddressLegacyAndModern = "server: option 'host' and 'port' can't be configured at the same time as 'address'" errFmtServerAddress = "server: option 'address' with value '%s' is invalid: %w" - errFmtServerPathNoForwardSlashes = "server: option 'path' must not contain any forward slashes" - errFmtServerPathAlphaNum = "server: option 'path' must only contain alpha numeric characters" + errFmtServerPathNoForwardSlashes = "server: option 'path' must not contain any forward slashes" + errFmtServerPathNotEndForwardSlash = "server: option 'address' must not and with a forward slash but it's configured as '%s'" + errFmtServerPathAlphaNum = "server: option 'path' must only contain alpha numeric characters" errFmtServerEndpointsAuthzImplementation = "server: endpoints: authz: %s: option 'implementation' must be one of %s but it's configured as '%s'" errFmtServerEndpointsAuthzStrategy = "server: endpoints: authz: %s: authn_strategies: option 'name' must be one of %s but it's configured as '%s'" diff --git a/internal/configuration/validator/server.go b/internal/configuration/validator/server.go index 3dcfc7533..a4f69cf46 100644 --- a/internal/configuration/validator/server.go +++ b/internal/configuration/validator/server.go @@ -59,17 +59,6 @@ func ValidateServer(config *schema.Configuration, validator *schema.StructValida ValidateServerAddress(config, validator) ValidateServerTLS(config, validator) - switch { - case strings.Contains(config.Server.Path, "/"): - validator.Push(fmt.Errorf(errFmtServerPathNoForwardSlashes)) - case !utils.IsStringAlphaNumeric(config.Server.Path): - validator.Push(fmt.Errorf(errFmtServerPathAlphaNum)) - case config.Server.Path == "": // Don't do anything if it's blank. - break - default: - config.Server.Path = path.Clean("/" + config.Server.Path) - } - if config.Server.Buffers.Read <= 0 { config.Server.Buffers.Read = schema.DefaultServerConfiguration.Buffers.Read } @@ -96,11 +85,12 @@ func ValidateServer(config *schema.Configuration, validator *schema.StructValida // ValidateServerAddress checks the configured server address is correct. func ValidateServerAddress(config *schema.Configuration, validator *schema.StructValidator) { if config.Server.Address == nil { - if config.Server.Host == "" && config.Server.Port == 0 { //nolint:staticcheck + if config.Server.Host == "" && config.Server.Port == 0 && config.Server.Path == "" { //nolint:staticcheck config.Server.Address = schema.DefaultServerConfiguration.Address } else { - host := config.Server.Host //nolint:staticcheck - port := config.Server.Port //nolint:staticcheck + host := config.Server.Host //nolint:staticcheck + port := config.Server.Port //nolint:staticcheck + subpath := config.Server.Path //nolint:staticcheck if host == "" { host = schema.DefaultServerConfiguration.Address.Hostname() @@ -110,7 +100,20 @@ func ValidateServerAddress(config *schema.Configuration, validator *schema.Struc port = schema.DefaultServerConfiguration.Address.Port() } + switch { + case strings.Contains(subpath, "/"): + validator.Push(fmt.Errorf(errFmtServerPathNoForwardSlashes)) + case !utils.IsStringAlphaNumeric(config.Server.Path): //nolint:staticcheck + validator.Push(fmt.Errorf(errFmtServerPathAlphaNum)) + case subpath == "": + subpath = schema.DefaultServerConfiguration.Address.Path() + default: + subpath = path.Clean("/" + config.Server.Path) //nolint:staticcheck + } + config.Server.Address = &schema.AddressTCP{Address: schema.NewAddressFromNetworkValues(schema.AddressSchemeTCP, host, port)} + + config.Server.Address.SetPath(subpath) } } else { if config.Server.Host != "" || config.Server.Port != 0 { //nolint:staticcheck @@ -123,6 +126,10 @@ func ValidateServerAddress(config *schema.Configuration, validator *schema.Struc validator.Push(fmt.Errorf(errFmtServerAddress, config.Server.Address.String(), err)) } } + + if path := config.Server.Address.Path(); path != "/" && strings.HasSuffix(path, "/") { + validator.Push(fmt.Errorf(errFmtServerPathNotEndForwardSlash, path)) + } } // ValidateServerEndpoints configures the default endpoints and checks the configuration of custom endpoints. diff --git a/internal/configuration/validator/server_test.go b/internal/configuration/validator/server_test.go index 7ba5f55cf..191411c1c 100644 --- a/internal/configuration/validator/server_test.go +++ b/internal/configuration/validator/server_test.go @@ -23,66 +23,97 @@ func TestShouldSetDefaultServerValues(t *testing.T) { assert.Len(t, validator.Errors(), 0) assert.Len(t, validator.Warnings(), 0) - assert.Equal(t, "", config.Server.Host) //nolint:staticcheck - assert.Equal(t, 0, config.Server.Port) //nolint:staticcheck assert.Equal(t, schema.DefaultServerConfiguration.Address, config.Server.Address) assert.Equal(t, schema.DefaultServerConfiguration.Buffers.Read, config.Server.Buffers.Read) assert.Equal(t, schema.DefaultServerConfiguration.Buffers.Write, config.Server.Buffers.Write) assert.Equal(t, schema.DefaultServerConfiguration.TLS.Key, config.Server.TLS.Key) assert.Equal(t, schema.DefaultServerConfiguration.TLS.Certificate, config.Server.TLS.Certificate) - assert.Equal(t, schema.DefaultServerConfiguration.Path, config.Server.Path) assert.Equal(t, schema.DefaultServerConfiguration.Endpoints.EnableExpvars, config.Server.Endpoints.EnableExpvars) assert.Equal(t, schema.DefaultServerConfiguration.Endpoints.EnablePprof, config.Server.Endpoints.EnablePprof) assert.Equal(t, schema.DefaultServerConfiguration.Endpoints.Authz, config.Server.Endpoints.Authz) + + assert.Equal(t, "", config.Server.Host) //nolint:staticcheck + assert.Equal(t, 0, config.Server.Port) //nolint:staticcheck + assert.Equal(t, "", config.Server.Path) //nolint:staticcheck } func TestShouldSetDefaultServerValuesWithLegacyAddress(t *testing.T) { - validator := schema.NewStructValidator() - config := &schema.Configuration{ - Server: schema.ServerConfiguration{ - Host: "abc", - Port: 123, + testCases := []struct { + name string + have schema.ServerConfiguration + expected schema.Address + }{ + { + "ShouldParseAll", + schema.ServerConfiguration{ + Host: "abc", + Port: 123, + Path: "subpath", + }, + MustParseAddress("tcp://abc:123/subpath"), + }, + { + "ShouldParseHostAndPort", + schema.ServerConfiguration{ + Host: "abc", + Port: 123, + }, + MustParseAddress("tcp://abc:123/"), + }, + { + "ShouldParseHostAndPath", + schema.ServerConfiguration{ + Host: "abc", + Path: "subpath", + }, + MustParseAddress("tcp://abc:9091/subpath"), + }, + { + "ShouldParsePortAndPath", + schema.ServerConfiguration{ + Port: 123, + Path: "subpath", + }, + MustParseAddress("tcp://:123/subpath"), + }, + { + "ShouldParseHost", + schema.ServerConfiguration{ + Host: "abc", + }, + MustParseAddress("tcp://abc:9091/"), + }, + { + "ShouldParsePort", + schema.ServerConfiguration{ + Port: 123, + }, + MustParseAddress("tcp://:123/"), + }, + { + "ShouldParsePath", + schema.ServerConfiguration{ + Path: "subpath", + }, + MustParseAddress("tcp://:9091/subpath"), }, } - ValidateServer(config, validator) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + validator := schema.NewStructValidator() + config := &schema.Configuration{ + Server: tc.have, + } - assert.Len(t, validator.Errors(), 0) - assert.Len(t, validator.Warnings(), 0) + ValidateServer(config, validator) - assert.Equal(t, "abc", config.Server.Host) //nolint:staticcheck - assert.Equal(t, 123, config.Server.Port) //nolint:staticcheck - assert.Equal(t, &schema.AddressTCP{Address: MustParseAddress("tcp://abc:123")}, config.Server.Address) + assert.Len(t, validator.Errors(), 0) + assert.Len(t, validator.Warnings(), 0) - config = &schema.Configuration{ - Server: schema.ServerConfiguration{ - Host: "abc", - }, + assert.Equal(t, &schema.AddressTCP{Address: tc.expected}, config.Server.Address) + }) } - - ValidateServer(config, validator) - - assert.Len(t, validator.Errors(), 0) - assert.Len(t, validator.Warnings(), 0) - - assert.Equal(t, "abc", config.Server.Host) //nolint:staticcheck - assert.Equal(t, 0, config.Server.Port) //nolint:staticcheck - assert.Equal(t, &schema.AddressTCP{Address: MustParseAddress("tcp://abc:9091")}, config.Server.Address) - - config = &schema.Configuration{ - Server: schema.ServerConfiguration{ - Port: 123, - }, - } - - ValidateServer(config, validator) - - assert.Len(t, validator.Errors(), 0) - assert.Len(t, validator.Warnings(), 0) - - assert.Equal(t, "", config.Server.Host) //nolint:staticcheck - assert.Equal(t, 123, config.Server.Port) //nolint:staticcheck - assert.Equal(t, &schema.AddressTCP{Address: MustParseAddress("tcp://:123")}, config.Server.Address) } func TestShouldSetDefaultConfig(t *testing.T) { @@ -98,20 +129,20 @@ func TestShouldSetDefaultConfig(t *testing.T) { assert.Equal(t, schema.DefaultServerConfiguration.Buffers.Write, config.Server.Buffers.Write) } -func TestShouldParsePathCorrectly(t *testing.T) { - validator := schema.NewStructValidator() +func TestValidateSeverAddress(t *testing.T) { config := &schema.Configuration{ Server: schema.ServerConfiguration{ - Path: "apple", + Address: &schema.AddressTCP{Address: MustParseAddress("tcp://:9091/path/")}, }, } + validator := schema.NewStructValidator() ValidateServer(config, validator) - assert.Len(t, validator.Errors(), 0) + require.Len(t, validator.Errors(), 1) assert.Len(t, validator.Warnings(), 0) - assert.Equal(t, "/apple", config.Server.Path) + assert.EqualError(t, validator.Errors()[0], "server: option 'address' must not and with a forward slash but it's configured as '/path/'") } func TestValidateServerShouldCorrectlyIdentifyValidAddressSchemes(t *testing.T) { @@ -236,7 +267,7 @@ func TestShouldValidateAndUpdateAddress(t *testing.T) { ValidateServer(&config, validator) require.Len(t, validator.Errors(), 0) - assert.Equal(t, "tcp://:9091", config.Server.Address.String()) + assert.Equal(t, "tcp://:9091/", config.Server.Address.String()) } func TestShouldRaiseErrorOnLegacyAndModernValues(t *testing.T) { @@ -251,22 +282,6 @@ func TestShouldRaiseErrorOnLegacyAndModernValues(t *testing.T) { assert.EqualError(t, validator.Errors()[0], "server: option 'host' and 'port' can't be configured at the same time as 'address'") } -func TestShouldValidateAndUpdateAddressWithOldValues(t *testing.T) { - validator := schema.NewStructValidator() - config := newDefaultConfig() - config.Server.Address = nil - config.Server.Host = local25 //nolint:staticcheck - config.Server.Port = 9999 //nolint:staticcheck - - ValidateServer(&config, validator) - - assert.Len(t, validator.Errors(), 0) - assert.Len(t, validator.Warnings(), 0) - - require.NotNil(t, config.Server.Address) - assert.Equal(t, "tcp://127.0.0.25:9999", config.Server.Address.String()) -} - func TestShouldRaiseErrorWhenTLSCertWithoutKeyIsProvided(t *testing.T) { validator := schema.NewStructValidator() config := newDefaultConfig() diff --git a/internal/configuration/validator/telemetry.go b/internal/configuration/validator/telemetry.go index 39c49273d..81885b27e 100644 --- a/internal/configuration/validator/telemetry.go +++ b/internal/configuration/validator/telemetry.go @@ -20,6 +20,10 @@ func ValidateTelemetry(config *schema.Configuration, validator *schema.StructVal config.Telemetry.Metrics.Address.SetPort(schema.DefaultTelemetryConfig.Metrics.Address.Port()) } + if config.Telemetry.Metrics.Address.Path() == "" { + config.Telemetry.Metrics.Address.SetPath(schema.DefaultTelemetryConfig.Metrics.Address.Path()) + } + if config.Telemetry.Metrics.Buffers.Read <= 0 { config.Telemetry.Metrics.Buffers.Read = schema.DefaultTelemetryConfig.Metrics.Buffers.Read } diff --git a/internal/configuration/validator/telemetry_test.go b/internal/configuration/validator/telemetry_test.go index e75ca5ca1..59bbd7513 100644 --- a/internal/configuration/validator/telemetry_test.go +++ b/internal/configuration/validator/telemetry_test.go @@ -38,7 +38,7 @@ func TestValidateTelemetry(t *testing.T) { &schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://0.0.0.0")}}}, &schema.Configuration{Telemetry: schema.TelemetryConfig{ Metrics: schema.TelemetryMetricsConfig{ - Address: &schema.AddressTCP{Address: schema.NewAddressFromNetworkValues(schema.AddressSchemeTCP, "0.0.0.0", schema.DefaultTelemetryConfig.Metrics.Address.Port())}, + Address: mustParseAddress("tcp://0.0.0.0:9959/metrics"), Buffers: schema.ServerBuffers{ Read: 4096, Write: 4096, @@ -55,7 +55,7 @@ func TestValidateTelemetry(t *testing.T) { }, { "ShouldSetDefaultPortAlt", - &schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://:0")}}}, + &schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://:0/metrics")}}}, &schema.Configuration{Telemetry: schema.DefaultTelemetryConfig}, nil, nil, @@ -63,14 +63,14 @@ func TestValidateTelemetry(t *testing.T) { { "ShouldSetDefaultPortWithCustomIP", &schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://127.0.0.1")}}}, - &schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://127.0.0.1:9959")}}}, + &schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("tcp://127.0.0.1:9959/metrics")}}}, nil, nil, }, { "ShouldNotValidateUDP", &schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("udp://0.0.0.0")}}}, - &schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("udp://0.0.0.0:9959")}}}, + &schema.Configuration{Telemetry: schema.TelemetryConfig{Metrics: schema.TelemetryMetricsConfig{Address: mustParseAddress("udp://0.0.0.0:9959/metrics")}}}, nil, []string{"telemetry: metrics: option 'address' with value 'udp://0.0.0.0:0' is invalid: scheme must be one of 'tcp', 'tcp4', 'tcp6', or 'unix' but is configured as 'udp'"}, }, diff --git a/internal/server/handlers.go b/internal/server/handlers.go index 402761edc..cc7674067 100644 --- a/internal/server/handlers.go +++ b/internal/server/handlers.go @@ -395,8 +395,8 @@ func handleRouter(config *schema.Configuration, providers middlewares.Providers) r.NotFound = handleNotFound(bridge(serveIndexHandler)) handler := middlewares.LogRequest(r.Handler) - if config.Server.Path != "" { - handler = middlewares.StripPath(config.Server.Path)(handler) + if config.Server.Address.Path() != "/" { + handler = middlewares.StripPath(config.Server.Address.Path())(handler) } handler = middlewares.Wrap(middlewares.NewMetricsRequest(providers.Metrics), handler) @@ -404,10 +404,10 @@ func handleRouter(config *schema.Configuration, providers middlewares.Providers) return handler } -func handleMetrics() fasthttp.RequestHandler { +func handleMetrics(path string) fasthttp.RequestHandler { r := router.New() - r.GET("/metrics", fasthttpadaptor.NewFastHTTPHandler(promhttp.Handler())) + r.GET(path, fasthttpadaptor.NewFastHTTPHandler(promhttp.Handler())) r.HandleMethodNotAllowed = true r.MethodNotAllowed = handlers.Status(fasthttp.StatusMethodNotAllowed) diff --git a/internal/server/server.go b/internal/server/server.go index 59d2d5d92..f76e6cfc3 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -71,14 +71,14 @@ func CreateDefaultServer(config *schema.Configuration, providers middlewares.Pro } if err = writeHealthCheckEnv(config.Server.DisableHealthcheck, connectionScheme, config.Server.Address.Hostname(), - config.Server.Path, config.Server.Address.Port()); err != nil { + config.Server.Address.Path(), config.Server.Address.Port()); err != nil { return nil, nil, nil, false, fmt.Errorf("unable to configure healthcheck: %w", err) } paths = []string{"/"} - if config.Server.Path != "" { - paths = append(paths, config.Server.Path) + if config.Server.Address.Path() != "/" { + paths = append(paths, config.Server.Address.Path()) } return server, listener, paths, isTLS, nil @@ -93,7 +93,7 @@ func CreateMetricsServer(config *schema.Configuration, providers middlewares.Pro server = &fasthttp.Server{ ErrorHandler: handleError(), NoDefaultServerHeader: true, - Handler: handleMetrics(), + Handler: handleMetrics(config.Telemetry.Metrics.Address.Path()), ReadBufferSize: config.Telemetry.Metrics.Buffers.Read, WriteBufferSize: config.Telemetry.Metrics.Buffers.Write, ReadTimeout: config.Telemetry.Metrics.Timeouts.Read, @@ -106,5 +106,5 @@ func CreateMetricsServer(config *schema.Configuration, providers middlewares.Pro return nil, nil, nil, false, fmt.Errorf("error occurred while attempting to initialize metrics telemetry server listener for address '%s': %w", config.Telemetry.Metrics.Address.String(), err) } - return server, listener, []string{"/metrics"}, false, nil + return server, listener, []string{config.Telemetry.Metrics.Address.Path()}, false, nil } diff --git a/internal/server/template.go b/internal/server/template.go index 91fcd2a80..869e8e7a7 100644 --- a/internal/server/template.go +++ b/internal/server/template.go @@ -256,6 +256,10 @@ func writeHealthCheckEnv(disabled bool, scheme, host, path string, port int) (er host = "[" + host + "]" } + if path == "/" { + path = "" + } + _, err = file.WriteString(fmt.Sprintf(healthCheckEnv, scheme, host, port, path)) return err diff --git a/internal/suites/PathPrefix/configuration.yml b/internal/suites/PathPrefix/configuration.yml index 441b88b20..8ac45c7c7 100644 --- a/internal/suites/PathPrefix/configuration.yml +++ b/internal/suites/PathPrefix/configuration.yml @@ -6,8 +6,7 @@ jwt_secret: unsecure_secret server: - address: 'tcp://:9091' - path: 'auth' + address: 'tcp://:9091/auth' tls: certificate: /pki/public.backend.crt key: /pki/private.backend.pem