feat(configuration): add error and warn log levels (#2050)
This is so levels like warn and error can be used to exclude info or warn messages. Additionally there is a reasonable refactoring of logging moving the log config options to the logging key because there are a significant number of log options now. This also decouples the expvars and pprof handlers from the log level, and they are now configured by server.enable_expvars and server.enable_pprof at any logging level.pull/1944/head^2
parent
4cfda7eece
commit
cef35fadcd
|
@ -52,11 +52,17 @@ func startServer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := logging.InitializeLogger(config.LogFormat, config.LogFilePath, config.LogKeepStdout); err != nil {
|
if err := logging.InitializeLogger(config.Logging.Format, config.Logging.FilePath, config.Logging.KeepStdout); err != nil {
|
||||||
logger.Fatalf("Cannot initialize logger: %v", err)
|
logger.Fatalf("Cannot initialize logger: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch config.LogLevel {
|
switch config.Logging.Level {
|
||||||
|
case "error":
|
||||||
|
logger.Info("Logging severity set to error")
|
||||||
|
logging.SetLevel(logrus.ErrorLevel)
|
||||||
|
case "warn":
|
||||||
|
logger.Info("Logging severity set to warn")
|
||||||
|
logging.SetLevel(logrus.WarnLevel)
|
||||||
case "info":
|
case "info":
|
||||||
logger.Info("Logging severity set to info")
|
logger.Info("Logging severity set to info")
|
||||||
logging.SetLevel(logrus.InfoLevel)
|
logging.SetLevel(logrus.InfoLevel)
|
||||||
|
|
|
@ -34,17 +34,24 @@ server:
|
||||||
## Must be alphanumeric chars and should not contain any slashes.
|
## Must be alphanumeric chars and should not contain any slashes.
|
||||||
path: ""
|
path: ""
|
||||||
|
|
||||||
|
## Enables the pprof endpoint.
|
||||||
|
enable_pprof: false
|
||||||
|
|
||||||
|
## Enables the expvars endpoint.
|
||||||
|
enable_expvars: false
|
||||||
|
|
||||||
## Level of verbosity for logs: info, debug, trace.
|
## Level of verbosity for logs: info, debug, trace.
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
## Format the logs are written as: json, text.
|
## Format the logs are written as: json, text.
|
||||||
# log_format: json
|
# format: json
|
||||||
|
|
||||||
## File path where the logs will be written. If not set logs are written to stdout.
|
## File path where the logs will be written. If not set logs are written to stdout.
|
||||||
# log_file_path: /config/authelia.log
|
# file_path: /config/authelia.log
|
||||||
|
|
||||||
## Whether to also log to stdout when a log_file_path is defined.
|
## Whether to also log to stdout when a log_file_path is defined.
|
||||||
# log_keep_stdout: false
|
# keep_stdout: false
|
||||||
|
|
||||||
## The secret used to generate JWT tokens when validating user identity by email confirmation. JWT Secret can also be
|
## The secret used to generate JWT tokens when validating user identity by email confirmation. JWT Secret can also be
|
||||||
## set using a secret: https://www.authelia.com/docs/configuration/secrets.html
|
## set using a secret: https://www.authelia.com/docs/configuration/secrets.html
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Identity Providers
|
title: Identity Providers
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 12
|
nav_order: 3
|
||||||
has_children: true
|
has_children: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
---
|
||||||
|
layout: default
|
||||||
|
title: Logging
|
||||||
|
parent: Configuration
|
||||||
|
nav_order: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
|
||||||
|
The logging section tunes the logging settings.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
logging:
|
||||||
|
level: info
|
||||||
|
format: text
|
||||||
|
file_path: ""
|
||||||
|
keep_stdout: false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
### level
|
||||||
|
<div markdown="1">
|
||||||
|
type: string
|
||||||
|
{: .label .label-config .label-purple }
|
||||||
|
default: info
|
||||||
|
{: .label .label-config .label-blue }
|
||||||
|
required: no
|
||||||
|
{: .label .label-config .label-green }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Defines the level of logs used by Authelia. This level can be set to `trace`, `debug`, `info`, `warn`, or `error`. When
|
||||||
|
setting level to `trace`, you will generate a large amount of log entries and expose the `/debug/vars` and
|
||||||
|
`/debug/pprof/` endpoints which should not be enabled in production.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
logging:
|
||||||
|
level: debug
|
||||||
|
```
|
||||||
|
|
||||||
|
### format
|
||||||
|
<div markdown="1">
|
||||||
|
type: string
|
||||||
|
{: .label .label-config .label-purple }
|
||||||
|
default: text
|
||||||
|
{: .label .label-config .label-blue }
|
||||||
|
required: no
|
||||||
|
{: .label .label-config .label-green }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Defines the format of the logs written by Authelia. This format can be set to `json` or `text`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
logging:
|
||||||
|
format: json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### JSON format
|
||||||
|
```
|
||||||
|
{"level":"info","msg":"Logging severity set to info","time":"2020-01-01T00:00:00+11:00"}
|
||||||
|
{"level":"info","msg":"Authelia is listening for non-TLS connections on 0.0.0.0:9091","time":"2020-01-01T00:00:00+11:00"}
|
||||||
|
```
|
||||||
|
#### Text format
|
||||||
|
```
|
||||||
|
time="2020-01-01T00:00:00+11:00" level=info msg="Logging severity set to info"
|
||||||
|
time="2020-01-01T00:00:00+11:00" level=info msg="Authelia is listening for non-TLS connections on 0.0.0.0:9091"
|
||||||
|
```
|
||||||
|
|
||||||
|
### file_path
|
||||||
|
<div markdown="1">
|
||||||
|
type: string (path)
|
||||||
|
{: .label .label-config .label-purple }
|
||||||
|
default: ""
|
||||||
|
{: .label .label-config .label-blue }
|
||||||
|
required: no
|
||||||
|
{: .label .label-config .label-green }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Logs can be stored in a file when file path is provided. Otherwise logs are written to standard output. When setting the
|
||||||
|
level to `debug` or `trace` this will generate large amount of log entries. Administrators will need to ensure that
|
||||||
|
they rotate and/or truncate the logs over time to prevent significant long-term disk usage.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
logging:
|
||||||
|
file_path: /config/authelia.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### keep_stdout
|
||||||
|
<div markdown="1">
|
||||||
|
type: boolean
|
||||||
|
{: .label .label-config .label-purple }
|
||||||
|
default: false
|
||||||
|
{: .label .label-config .label-blue }
|
||||||
|
required: no
|
||||||
|
{: .label .label-config .label-green }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Overrides the behaviour to redirect logging only to the `file_path`. If set to `true` logs will be written to both
|
||||||
|
standard output, and the defined logging location.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
logging:
|
||||||
|
keep_stdout: true
|
||||||
|
```
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Miscellaneous
|
title: Miscellaneous
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 3
|
nav_order: 5
|
||||||
---
|
---
|
||||||
|
|
||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
|
@ -93,88 +93,6 @@ key or the CA public key which signed them (don't add the private key).
|
||||||
certificates_directory: /config/certs/
|
certificates_directory: /config/certs/
|
||||||
```
|
```
|
||||||
|
|
||||||
## Logging
|
|
||||||
|
|
||||||
### log_level
|
|
||||||
<div markdown="1">
|
|
||||||
type: string
|
|
||||||
{: .label .label-config .label-purple }
|
|
||||||
default: info
|
|
||||||
{: .label .label-config .label-blue }
|
|
||||||
required: no
|
|
||||||
{: .label .label-config .label-green }
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Defines the level of logs used by Authelia. This level can be set to `trace`, `debug` or `info`. When setting log_level
|
|
||||||
to `trace`, you will generate a large amount of log entries and expose the `/debug/vars` and `/debug/pprof/` endpoints
|
|
||||||
which should not be enabled in production.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
log_level: debug
|
|
||||||
```
|
|
||||||
|
|
||||||
### log_format
|
|
||||||
<div markdown="1">
|
|
||||||
type: string
|
|
||||||
{: .label .label-config .label-purple }
|
|
||||||
default: text
|
|
||||||
{: .label .label-config .label-blue }
|
|
||||||
required: no
|
|
||||||
{: .label .label-config .label-green }
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Defines the format of the logs written by Authelia. This format can be set to `json` or `text`.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
log_format: json
|
|
||||||
```
|
|
||||||
|
|
||||||
#### JSON format
|
|
||||||
```
|
|
||||||
{"level":"info","msg":"Logging severity set to info","time":"2020-01-01T00:00:00+11:00"}
|
|
||||||
{"level":"info","msg":"Authelia is listening for non-TLS connections on 0.0.0.0:9091","time":"2020-01-01T00:00:00+11:00"}
|
|
||||||
```
|
|
||||||
#### Text format
|
|
||||||
```
|
|
||||||
time="2020-01-01T00:00:00+11:00" level=info msg="Logging severity set to info"
|
|
||||||
time="2020-01-01T00:00:00+11:00" level=info msg="Authelia is listening for non-TLS connections on 0.0.0.0:9091"
|
|
||||||
```
|
|
||||||
|
|
||||||
### log_file_path
|
|
||||||
<div markdown="1">
|
|
||||||
type: string (path)
|
|
||||||
{: .label .label-config .label-purple }
|
|
||||||
default: ""
|
|
||||||
{: .label .label-config .label-blue }
|
|
||||||
required: no
|
|
||||||
{: .label .label-config .label-green }
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Logs can be stored in a file when file path is provided. Otherwise logs are written to standard output. When setting the
|
|
||||||
log_level to `debug` or `trace` this will generate large amount of log entries. Administrators will need to ensure that
|
|
||||||
they rotate and/or truncate the logs over time to prevent significant long-term disk usage.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
log_file_path: /config/authelia.log
|
|
||||||
```
|
|
||||||
|
|
||||||
### log_keep_stdout
|
|
||||||
<div markdown="1">
|
|
||||||
type: boolean
|
|
||||||
{: .label .label-config .label-purple }
|
|
||||||
default: false
|
|
||||||
{: .label .label-config .label-blue }
|
|
||||||
required: no
|
|
||||||
{: .label .label-config .label-green }
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Overrides the behaviour to redirect logging only to the `log_file_path`. If set to `true` logs will be written to both
|
|
||||||
standard output, and the defined logging location.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
log_keep_stdout: true
|
|
||||||
```
|
|
||||||
|
|
||||||
## jwt_secret
|
## jwt_secret
|
||||||
<div markdown="1">
|
<div markdown="1">
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Notifier
|
title: Notifier
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 6
|
nav_order: 8
|
||||||
has_children: true
|
has_children: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Time-based One-Time Password
|
title: Time-based One-Time Password
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 4
|
nav_order: 6
|
||||||
---
|
---
|
||||||
|
|
||||||
# Time-based One-Time Password
|
# Time-based One-Time Password
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Regulation
|
title: Regulation
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 5
|
nav_order: 7
|
||||||
---
|
---
|
||||||
|
|
||||||
# Regulation
|
# Regulation
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Secrets
|
title: Secrets
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 6
|
nav_order: 8
|
||||||
---
|
---
|
||||||
|
|
||||||
# Secrets
|
# Secrets
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Server
|
title: Server
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 7
|
nav_order: 9
|
||||||
---
|
---
|
||||||
|
|
||||||
# Server
|
# Server
|
||||||
|
@ -16,6 +16,8 @@ server:
|
||||||
read_buffer_size: 4096
|
read_buffer_size: 4096
|
||||||
write_buffer_size: 4096
|
write_buffer_size: 4096
|
||||||
path: ""
|
path: ""
|
||||||
|
enable_pprof: false
|
||||||
|
enable_expvars: false
|
||||||
```
|
```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
@ -72,6 +74,31 @@ server:
|
||||||
path: authelia
|
path: authelia
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### enable_pprof
|
||||||
|
<div markdown="1">
|
||||||
|
type: boolean
|
||||||
|
{: .label .label-config .label-purple }
|
||||||
|
default: false
|
||||||
|
{: .label .label-config .label-blue }
|
||||||
|
required: no
|
||||||
|
{: .label .label-config .label-green }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Enables the go pprof endpoints.
|
||||||
|
|
||||||
|
### enable_expvars
|
||||||
|
<div markdown="1">
|
||||||
|
type: boolean
|
||||||
|
{: .label .label-config .label-purple }
|
||||||
|
default: false
|
||||||
|
{: .label .label-config .label-blue }
|
||||||
|
required: no
|
||||||
|
{: .label .label-config .label-green }
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Enables the go expvars endpoints.
|
||||||
|
|
||||||
|
|
||||||
## Additional Notes
|
## Additional Notes
|
||||||
|
|
||||||
### Buffer Sizes
|
### Buffer Sizes
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Session
|
title: Session
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 8
|
nav_order: 10
|
||||||
has_children: true
|
has_children: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Storage backends
|
title: Storage backends
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 10
|
nav_order: 12
|
||||||
has_children: true
|
has_children: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
layout: default
|
layout: default
|
||||||
title: Theme
|
title: Theme
|
||||||
parent: Configuration
|
parent: Configuration
|
||||||
nav_order: 11
|
nav_order: 13
|
||||||
---
|
---
|
||||||
|
|
||||||
# Theme
|
# Theme
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
host: 0.0.0.0
|
host: 0.0.0.0
|
||||||
port: 9091
|
port: 9091
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
# This secret can also be set using the env variables AUTHELIA_JWT_SECRET_FILE
|
# This secret can also be set using the env variables AUTHELIA_JWT_SECRET_FILE
|
||||||
jwt_secret: a_very_important_secret
|
jwt_secret: a_very_important_secret
|
||||||
default_redirection_url: https://public.example.com
|
default_redirection_url: https://public.example.com
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
host: 0.0.0.0
|
host: 0.0.0.0
|
||||||
port: 9091
|
port: 9091
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
jwt_secret: a_very_important_secret
|
jwt_secret: a_very_important_secret
|
||||||
default_redirection_url: https://public.example.com
|
default_redirection_url: https://public.example.com
|
||||||
totp:
|
totp:
|
||||||
|
|
|
@ -34,17 +34,24 @@ server:
|
||||||
## Must be alphanumeric chars and should not contain any slashes.
|
## Must be alphanumeric chars and should not contain any slashes.
|
||||||
path: ""
|
path: ""
|
||||||
|
|
||||||
|
## Enables the pprof endpoint.
|
||||||
|
enable_pprof: false
|
||||||
|
|
||||||
|
## Enables the expvars endpoint.
|
||||||
|
enable_expvars: false
|
||||||
|
|
||||||
## Level of verbosity for logs: info, debug, trace.
|
## Level of verbosity for logs: info, debug, trace.
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
## Format the logs are written as: json, text.
|
## Format the logs are written as: json, text.
|
||||||
# log_format: json
|
# format: json
|
||||||
|
|
||||||
## File path where the logs will be written. If not set logs are written to stdout.
|
## File path where the logs will be written. If not set logs are written to stdout.
|
||||||
# log_file_path: /config/authelia.log
|
# file_path: /config/authelia.log
|
||||||
|
|
||||||
## Whether to also log to stdout when a log_file_path is defined.
|
## Whether to also log to stdout when a log_file_path is defined.
|
||||||
# log_keep_stdout: false
|
# keep_stdout: false
|
||||||
|
|
||||||
## The secret used to generate JWT tokens when validating user identity by email confirmation. JWT Secret can also be
|
## The secret used to generate JWT tokens when validating user identity by email confirmation. JWT Secret can also be
|
||||||
## set using a secret: https://www.authelia.com/docs/configuration/secrets.html
|
## set using a secret: https://www.authelia.com/docs/configuration/secrets.html
|
||||||
|
|
|
@ -164,7 +164,7 @@ func TestShouldErrorParseBadConfigFile(t *testing.T) {
|
||||||
|
|
||||||
require.Len(t, errors, 1)
|
require.Len(t, errors, 1)
|
||||||
|
|
||||||
require.EqualError(t, errors[0], "Error malformed yaml: line 24: did not find expected alphabetic or numeric character")
|
require.EqualError(t, errors[0], "Error malformed yaml: line 25: did not find expected alphabetic or numeric character")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldParseConfigFile(t *testing.T) {
|
func TestShouldParseConfigFile(t *testing.T) {
|
||||||
|
@ -185,7 +185,7 @@ func TestShouldParseConfigFile(t *testing.T) {
|
||||||
require.Len(t, errors, 0)
|
require.Len(t, errors, 0)
|
||||||
|
|
||||||
assert.Equal(t, 9091, config.Port)
|
assert.Equal(t, 9091, config.Port)
|
||||||
assert.Equal(t, "debug", config.LogLevel)
|
assert.Equal(t, "debug", config.Logging.Level)
|
||||||
assert.Equal(t, "https://home.example.com:8080/", config.DefaultRedirectionURL)
|
assert.Equal(t, "https://home.example.com:8080/", config.DefaultRedirectionURL)
|
||||||
assert.Equal(t, "authelia.com", config.TOTP.Issuer)
|
assert.Equal(t, "authelia.com", config.TOTP.Issuer)
|
||||||
assert.Equal(t, "secret_from_env", config.JWTSecret)
|
assert.Equal(t, "secret_from_env", config.JWTSecret)
|
||||||
|
@ -221,7 +221,7 @@ func TestShouldParseAltConfigFile(t *testing.T) {
|
||||||
require.Len(t, errors, 0)
|
require.Len(t, errors, 0)
|
||||||
|
|
||||||
assert.Equal(t, 9091, config.Port)
|
assert.Equal(t, 9091, config.Port)
|
||||||
assert.Equal(t, "debug", config.LogLevel)
|
assert.Equal(t, "debug", config.Logging.Level)
|
||||||
assert.Equal(t, "https://home.example.com:8080/", config.DefaultRedirectionURL)
|
assert.Equal(t, "https://home.example.com:8080/", config.DefaultRedirectionURL)
|
||||||
assert.Equal(t, "authelia.com", config.TOTP.Issuer)
|
assert.Equal(t, "authelia.com", config.TOTP.Issuer)
|
||||||
assert.Equal(t, "secret_from_env", config.JWTSecret)
|
assert.Equal(t, "secret_from_env", config.JWTSecret)
|
||||||
|
@ -253,7 +253,7 @@ func TestShouldNotParseConfigFileWithOldOrUnexpectedKeys(t *testing.T) {
|
||||||
return errors[i].Error() < errors[j].Error()
|
return errors[i].Error() < errors[j].Error()
|
||||||
})
|
})
|
||||||
assert.EqualError(t, errors[0], "config key not expected: loggy_file")
|
assert.EqualError(t, errors[0], "config key not expected: loggy_file")
|
||||||
assert.EqualError(t, errors[1], "invalid configuration key 'logs_level' was replaced by 'log_level'")
|
assert.EqualError(t, errors[1], "invalid configuration key 'logs_level' was replaced by 'logging.level'")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldValidateConfigurationTemplate(t *testing.T) {
|
func TestShouldValidateConfigurationTemplate(t *testing.T) {
|
||||||
|
|
|
@ -8,13 +8,16 @@ type Configuration struct {
|
||||||
TLSCert string `mapstructure:"tls_cert"`
|
TLSCert string `mapstructure:"tls_cert"`
|
||||||
TLSKey string `mapstructure:"tls_key"`
|
TLSKey string `mapstructure:"tls_key"`
|
||||||
CertificatesDirectory string `mapstructure:"certificates_directory"`
|
CertificatesDirectory string `mapstructure:"certificates_directory"`
|
||||||
LogLevel string `mapstructure:"log_level"`
|
|
||||||
LogFormat string `mapstructure:"log_format"`
|
|
||||||
LogFilePath string `mapstructure:"log_file_path"`
|
|
||||||
LogKeepStdout bool `mapstructure:"log_keep_stdout"`
|
|
||||||
JWTSecret string `mapstructure:"jwt_secret"`
|
JWTSecret string `mapstructure:"jwt_secret"`
|
||||||
DefaultRedirectionURL string `mapstructure:"default_redirection_url"`
|
DefaultRedirectionURL string `mapstructure:"default_redirection_url"`
|
||||||
|
|
||||||
|
// TODO: DEPRECATED START. Remove in 4.33.0.
|
||||||
|
LogLevel string `mapstructure:"log_level"`
|
||||||
|
LogFormat string `mapstructure:"log_format"`
|
||||||
|
LogFilePath string `mapstructure:"log_file_path"`
|
||||||
|
// TODO: DEPRECATED END. Remove in 4.33.0.
|
||||||
|
|
||||||
|
Logging LoggingConfiguration `mapstructure:"logging"`
|
||||||
IdentityProviders IdentityProvidersConfiguration `mapstructure:"identity_providers"`
|
IdentityProviders IdentityProvidersConfiguration `mapstructure:"identity_providers"`
|
||||||
AuthenticationBackend AuthenticationBackendConfiguration `mapstructure:"authentication_backend"`
|
AuthenticationBackend AuthenticationBackendConfiguration `mapstructure:"authentication_backend"`
|
||||||
Session SessionConfiguration `mapstructure:"session"`
|
Session SessionConfiguration `mapstructure:"session"`
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package schema
|
||||||
|
|
||||||
|
// LoggingConfiguration represents the logging configuration.
|
||||||
|
type LoggingConfiguration struct {
|
||||||
|
Level string `mapstructure:"level"`
|
||||||
|
Format string `mapstructure:"format"`
|
||||||
|
FilePath string `mapstructure:"file_path"`
|
||||||
|
KeepStdout bool `mapstructure:"keep_stdout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultLoggingConfiguration is the default logging configuration.
|
||||||
|
var DefaultLoggingConfiguration = LoggingConfiguration{
|
||||||
|
Level: "info",
|
||||||
|
Format: "text",
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ type ServerConfiguration struct {
|
||||||
Path string `mapstructure:"path"`
|
Path string `mapstructure:"path"`
|
||||||
ReadBufferSize int `mapstructure:"read_buffer_size"`
|
ReadBufferSize int `mapstructure:"read_buffer_size"`
|
||||||
WriteBufferSize int `mapstructure:"write_buffer_size"`
|
WriteBufferSize int `mapstructure:"write_buffer_size"`
|
||||||
|
EnablePprof bool `mapstructure:"enable_endpoint_pprof"`
|
||||||
|
EnableExpvars bool `mapstructure:"enable_endpoint_expvars"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultServerConfiguration represents the default values of the ServerConfiguration.
|
// DefaultServerConfiguration represents the default values of the ServerConfiguration.
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
port: 9091
|
port: 9091
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
totp:
|
totp:
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
port: 9091
|
port: 9091
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
totp:
|
totp:
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
---
|
---
|
||||||
host: 0.0.0.0
|
host: 0.0.0.0
|
||||||
port: 9091
|
port: 9091
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: RUtG9TnbXrOl1XLLmDgySw1DGgx9QcrtepIf1uDDBlBVKFZxkVBruYKBi32PvaU
|
jwt_secret: RUtG9TnbXrOl1XLLmDgySw1DGgx9QcrtepIf1uDDBlBVKFZxkVBruYKBi32PvaU
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@ host: 127.0.0.1
|
||||||
port: 9091
|
port: 9091
|
||||||
jwt_secret: secret_from_config
|
jwt_secret: secret_from_config
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
totp:
|
totp:
|
||||||
|
|
|
@ -50,7 +50,11 @@ func IsNetworkValid(network string) (isValid bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateAccessControl validates access control configuration.
|
// ValidateAccessControl validates access control configuration.
|
||||||
func ValidateAccessControl(configuration schema.AccessControlConfiguration, validator *schema.StructValidator) {
|
func ValidateAccessControl(configuration *schema.AccessControlConfiguration, validator *schema.StructValidator) {
|
||||||
|
if configuration.DefaultPolicy == "" {
|
||||||
|
configuration.DefaultPolicy = denyPolicy
|
||||||
|
}
|
||||||
|
|
||||||
if !IsPolicyValid(configuration.DefaultPolicy) {
|
if !IsPolicyValid(configuration.DefaultPolicy) {
|
||||||
validator.Push(fmt.Errorf("'default_policy' must either be 'deny', 'two_factor', 'one_factor' or 'bypass'"))
|
validator.Push(fmt.Errorf("'default_policy' must either be 'deny', 'two_factor', 'one_factor' or 'bypass'"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ func (suite *AccessControl) SetupTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *AccessControl) TestShouldValidateCompleteConfiguration() {
|
func (suite *AccessControl) TestShouldValidateCompleteConfiguration() {
|
||||||
ValidateAccessControl(suite.configuration, suite.validator)
|
ValidateAccessControl(&suite.configuration, suite.validator)
|
||||||
|
|
||||||
suite.Assert().False(suite.validator.HasWarnings())
|
suite.Assert().False(suite.validator.HasWarnings())
|
||||||
suite.Assert().False(suite.validator.HasErrors())
|
suite.Assert().False(suite.validator.HasErrors())
|
||||||
|
@ -33,7 +33,7 @@ func (suite *AccessControl) TestShouldValidateCompleteConfiguration() {
|
||||||
func (suite *AccessControl) TestShouldRaiseErrorInvalidDefaultPolicy() {
|
func (suite *AccessControl) TestShouldRaiseErrorInvalidDefaultPolicy() {
|
||||||
suite.configuration.DefaultPolicy = testInvalidPolicy
|
suite.configuration.DefaultPolicy = testInvalidPolicy
|
||||||
|
|
||||||
ValidateAccessControl(suite.configuration, suite.validator)
|
ValidateAccessControl(&suite.configuration, suite.validator)
|
||||||
|
|
||||||
suite.Assert().False(suite.validator.HasWarnings())
|
suite.Assert().False(suite.validator.HasWarnings())
|
||||||
suite.Require().Len(suite.validator.Errors(), 1)
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
@ -49,7 +49,7 @@ func (suite *AccessControl) TestShouldRaiseErrorInvalidNetworkGroupNetwork() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateAccessControl(suite.configuration, suite.validator)
|
ValidateAccessControl(&suite.configuration, suite.validator)
|
||||||
|
|
||||||
suite.Assert().False(suite.validator.HasWarnings())
|
suite.Assert().False(suite.validator.HasWarnings())
|
||||||
suite.Require().Len(suite.validator.Errors(), 1)
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultPort = 9091
|
var defaultPort = 9091
|
||||||
var defaultLogLevel = "info"
|
|
||||||
|
|
||||||
// ValidateConfiguration and adapt the configuration read from file.
|
// ValidateConfiguration and adapt the configuration read from file.
|
||||||
//nolint:gocyclo // This function is likely to always have lots of if/else statements, as long as we keep the flow clean it should be understandable.
|
//nolint:gocyclo // This function is likely to always have lots of if/else statements, as long as we keep the flow clean it should be understandable.
|
||||||
|
@ -37,10 +36,6 @@ func ValidateConfiguration(configuration *schema.Configuration, validator *schem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if configuration.LogLevel == "" {
|
|
||||||
configuration.LogLevel = defaultLogLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
if configuration.JWTSecret == "" {
|
if configuration.JWTSecret == "" {
|
||||||
validator.Push(fmt.Errorf("Provide a JWT secret using \"jwt_secret\" key"))
|
validator.Push(fmt.Errorf("Provide a JWT secret using \"jwt_secret\" key"))
|
||||||
}
|
}
|
||||||
|
@ -52,25 +47,19 @@ func ValidateConfiguration(configuration *schema.Configuration, validator *schem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if configuration.Theme == "" {
|
|
||||||
configuration.Theme = "light"
|
|
||||||
}
|
|
||||||
|
|
||||||
ValidateTheme(configuration, validator)
|
ValidateTheme(configuration, validator)
|
||||||
|
|
||||||
if configuration.TOTP == nil {
|
if configuration.TOTP == nil {
|
||||||
configuration.TOTP = &schema.DefaultTOTPConfiguration
|
configuration.TOTP = &schema.DefaultTOTPConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValidateLogging(configuration, validator)
|
||||||
|
|
||||||
ValidateTOTP(configuration.TOTP, validator)
|
ValidateTOTP(configuration.TOTP, validator)
|
||||||
|
|
||||||
ValidateAuthenticationBackend(&configuration.AuthenticationBackend, validator)
|
ValidateAuthenticationBackend(&configuration.AuthenticationBackend, validator)
|
||||||
|
|
||||||
if configuration.AccessControl.DefaultPolicy == "" {
|
ValidateAccessControl(&configuration.AccessControl, validator)
|
||||||
configuration.AccessControl.DefaultPolicy = denyPolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
ValidateAccessControl(configuration.AccessControl, validator)
|
|
||||||
|
|
||||||
ValidateRules(configuration.AccessControl, validator)
|
ValidateRules(configuration.AccessControl, validator)
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ func newDefaultConfig() schema.Configuration {
|
||||||
config := schema.Configuration{}
|
config := schema.Configuration{}
|
||||||
config.Host = "127.0.0.1"
|
config.Host = "127.0.0.1"
|
||||||
config.Port = 9090
|
config.Port = 9090
|
||||||
config.LogLevel = "info"
|
config.Logging.Level = "info"
|
||||||
config.LogFormat = "text"
|
config.Logging.Format = "text"
|
||||||
config.JWTSecret = testJWTSecret
|
config.JWTSecret = testJWTSecret
|
||||||
config.AuthenticationBackend.File = &schema.FileAuthenticationBackendConfiguration{
|
config.AuthenticationBackend.File = &schema.FileAuthenticationBackendConfiguration{
|
||||||
Path: "/a/path",
|
Path: "/a/path",
|
||||||
|
@ -48,7 +48,7 @@ func TestShouldNotUpdateConfig(t *testing.T) {
|
||||||
|
|
||||||
require.Len(t, validator.Errors(), 0)
|
require.Len(t, validator.Errors(), 0)
|
||||||
assert.Equal(t, 9090, config.Port)
|
assert.Equal(t, 9090, config.Port)
|
||||||
assert.Equal(t, "info", config.LogLevel)
|
assert.Equal(t, "info", config.Logging.Level)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldValidateAndUpdatePort(t *testing.T) {
|
func TestShouldValidateAndUpdatePort(t *testing.T) {
|
||||||
|
@ -73,17 +73,6 @@ func TestShouldValidateAndUpdateHost(t *testing.T) {
|
||||||
assert.Equal(t, "0.0.0.0", config.Host)
|
assert.Equal(t, "0.0.0.0", config.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldValidateAndUpdateLogsLevel(t *testing.T) {
|
|
||||||
validator := schema.NewStructValidator()
|
|
||||||
config := newDefaultConfig()
|
|
||||||
config.LogLevel = ""
|
|
||||||
|
|
||||||
ValidateConfiguration(&config, validator)
|
|
||||||
|
|
||||||
require.Len(t, validator.Errors(), 0)
|
|
||||||
assert.Equal(t, "info", config.LogLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldEnsureNotifierConfigIsProvided(t *testing.T) {
|
func TestShouldEnsureNotifierConfigIsProvided(t *testing.T) {
|
||||||
validator := schema.NewStructValidator()
|
validator := schema.NewStructValidator()
|
||||||
config := newDefaultConfig()
|
config := newDefaultConfig()
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
package validator
|
package validator
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
errFmtDeprecatedConfigurationKey = "[DEPRECATED] The %s configuration option is deprecated and will be " +
|
||||||
|
"removed in %s, please use %s instead"
|
||||||
|
errFmtReplacedConfigurationKey = "invalid configuration key '%s' was replaced by '%s'"
|
||||||
|
|
||||||
|
errFmtLoggingLevelInvalid = "the log level '%s' is invalid, must be one of: %s"
|
||||||
|
|
||||||
errFmtSessionSecretRedisProvider = "The session secret must be set when using the %s session provider"
|
errFmtSessionSecretRedisProvider = "The session secret must be set when using the %s session provider"
|
||||||
errFmtSessionRedisPortRange = "The port must be between 1 and 65535 for the %s session provider"
|
errFmtSessionRedisPortRange = "The port must be between 1 and 65535 for the %s session provider"
|
||||||
errFmtSessionRedisHostRequired = "The host must be provided when using the %s session provider"
|
errFmtSessionRedisHostRequired = "The host must be provided when using the %s session provider"
|
||||||
errFmtSessionRedisHostOrNodesRequired = "Either the host or a node must be provided when using the %s session provider"
|
errFmtSessionRedisHostOrNodesRequired = "Either the host or a node must be provided when using the %s session provider"
|
||||||
errFmtReplacedConfigurationKey = "invalid configuration key '%s' was replaced by '%s'"
|
|
||||||
|
|
||||||
errOAuthOIDCServerClientRedirectURIFmt = "OIDC Server Client redirect URI %s has an invalid scheme %s, should be http or https"
|
errOAuthOIDCServerClientRedirectURIFmt = "OIDC Server Client redirect URI %s has an invalid scheme %s, should be http or https"
|
||||||
errOAuthOIDCServerClientRedirectURICantBeParsedFmt = "OIDC Client with ID '%s' has an invalid redirect URI '%s' could not be parsed: %v"
|
errOAuthOIDCServerClientRedirectURICantBeParsedFmt = "OIDC Client with ID '%s' has an invalid redirect URI '%s' could not be parsed: %v"
|
||||||
|
@ -43,6 +48,7 @@ const (
|
||||||
"https://www.authelia.com/docs/configuration/access-control.html#combining-subjects-and-the-bypass-policy"
|
"https://www.authelia.com/docs/configuration/access-control.html#combining-subjects-and-the-bypass-policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var validLoggingLevels = []string{"trace", "debug", "info", "warn", "error"}
|
||||||
var validRequestMethods = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "TRACE", "CONNECT", "OPTIONS"}
|
var validRequestMethods = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "TRACE", "CONNECT", "OPTIONS"}
|
||||||
|
|
||||||
// SecretNames contains a map of secret names.
|
// SecretNames contains a map of secret names.
|
||||||
|
@ -66,19 +72,30 @@ var validKeys = []string{
|
||||||
// Root Keys.
|
// Root Keys.
|
||||||
"host",
|
"host",
|
||||||
"port",
|
"port",
|
||||||
"log_level",
|
|
||||||
"log_format",
|
|
||||||
"log_file_path",
|
|
||||||
"default_redirection_url",
|
"default_redirection_url",
|
||||||
"theme",
|
"theme",
|
||||||
"tls_key",
|
"tls_key",
|
||||||
"tls_cert",
|
"tls_cert",
|
||||||
"certificates_directory",
|
"certificates_directory",
|
||||||
|
|
||||||
|
// Logging keys.
|
||||||
|
"logging.level",
|
||||||
|
"logging.format",
|
||||||
|
"logging.file_path",
|
||||||
|
"logging.keep_stdout",
|
||||||
|
|
||||||
|
// TODO: DEPRECATED START. Remove in 4.33.0.
|
||||||
|
"log_level",
|
||||||
|
"log_format",
|
||||||
|
"log_file_path",
|
||||||
|
// TODO: DEPRECATED END. Remove in 4.33.0.
|
||||||
|
|
||||||
// Server Keys.
|
// Server Keys.
|
||||||
"server.read_buffer_size",
|
"server.read_buffer_size",
|
||||||
"server.write_buffer_size",
|
"server.write_buffer_size",
|
||||||
"server.path",
|
"server.path",
|
||||||
|
"server.enable_pprof",
|
||||||
|
"server.enable_expvars",
|
||||||
|
|
||||||
// TOTP Keys.
|
// TOTP Keys.
|
||||||
"totp.issuer",
|
"totp.issuer",
|
||||||
|
@ -200,8 +217,8 @@ var replacedKeys = map[string]string{
|
||||||
"authentication_backend.ldap.skip_verify": "authentication_backend.ldap.tls.skip_verify",
|
"authentication_backend.ldap.skip_verify": "authentication_backend.ldap.tls.skip_verify",
|
||||||
"authentication_backend.ldap.minimum_tls_version": "authentication_backend.ldap.tls.minimum_version",
|
"authentication_backend.ldap.minimum_tls_version": "authentication_backend.ldap.tls.minimum_version",
|
||||||
"notifier.smtp.disable_verify_cert": "notifier.smtp.tls.skip_verify",
|
"notifier.smtp.disable_verify_cert": "notifier.smtp.tls.skip_verify",
|
||||||
"logs_file_path": "log_file",
|
"logs_file_path": "logging.file_path",
|
||||||
"logs_level": "log_level",
|
"logs_level": "logging.level",
|
||||||
}
|
}
|
||||||
|
|
||||||
var specificErrorKeys = map[string]string{
|
var specificErrorKeys = map[string]string{
|
||||||
|
|
|
@ -106,8 +106,8 @@ func TestReplacedErrors(t *testing.T) {
|
||||||
assert.EqualError(t, errs[0], fmt.Sprintf(errFmtReplacedConfigurationKey, "authentication_backend.ldap.skip_verify", "authentication_backend.ldap.tls.skip_verify"))
|
assert.EqualError(t, errs[0], fmt.Sprintf(errFmtReplacedConfigurationKey, "authentication_backend.ldap.skip_verify", "authentication_backend.ldap.tls.skip_verify"))
|
||||||
assert.EqualError(t, errs[1], fmt.Sprintf(errFmtReplacedConfigurationKey, "authentication_backend.ldap.minimum_tls_version", "authentication_backend.ldap.tls.minimum_version"))
|
assert.EqualError(t, errs[1], fmt.Sprintf(errFmtReplacedConfigurationKey, "authentication_backend.ldap.minimum_tls_version", "authentication_backend.ldap.tls.minimum_version"))
|
||||||
assert.EqualError(t, errs[2], fmt.Sprintf(errFmtReplacedConfigurationKey, "notifier.smtp.disable_verify_cert", "notifier.smtp.tls.skip_verify"))
|
assert.EqualError(t, errs[2], fmt.Sprintf(errFmtReplacedConfigurationKey, "notifier.smtp.disable_verify_cert", "notifier.smtp.tls.skip_verify"))
|
||||||
assert.EqualError(t, errs[3], fmt.Sprintf(errFmtReplacedConfigurationKey, "logs_file_path", "log_file"))
|
assert.EqualError(t, errs[3], fmt.Sprintf(errFmtReplacedConfigurationKey, "logs_file_path", "logging.file_path"))
|
||||||
assert.EqualError(t, errs[4], fmt.Sprintf(errFmtReplacedConfigurationKey, "logs_level", "log_level"))
|
assert.EqualError(t, errs[4], fmt.Sprintf(errFmtReplacedConfigurationKey, "logs_level", "logging.level"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSecretKeysDontRaiseErrors(t *testing.T) {
|
func TestSecretKeysDontRaiseErrors(t *testing.T) {
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/authelia/authelia/internal/configuration/schema"
|
||||||
|
"github.com/authelia/authelia/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateLogging validates the logging configuration.
|
||||||
|
func ValidateLogging(configuration *schema.Configuration, validator *schema.StructValidator) {
|
||||||
|
applyDeprecatedLoggingConfiguration(configuration, validator) // TODO: DEPRECATED LINE. Remove in 4.33.0.
|
||||||
|
|
||||||
|
if configuration.Logging.Level == "" {
|
||||||
|
configuration.Logging.Level = schema.DefaultLoggingConfiguration.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
if configuration.Logging.Format == "" {
|
||||||
|
configuration.Logging.Format = schema.DefaultLoggingConfiguration.Format
|
||||||
|
}
|
||||||
|
|
||||||
|
if !utils.IsStringInSlice(configuration.Logging.Level, validLoggingLevels) {
|
||||||
|
validator.Push(fmt.Errorf(errFmtLoggingLevelInvalid, configuration.Logging.Level, strings.Join(validLoggingLevels, ", ")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: DEPRECATED FUNCTION. Remove in 4.33.0.
|
||||||
|
func applyDeprecatedLoggingConfiguration(configuration *schema.Configuration, validator *schema.StructValidator) {
|
||||||
|
if configuration.LogLevel != "" {
|
||||||
|
validator.PushWarning(fmt.Errorf(errFmtDeprecatedConfigurationKey, "log_level", "4.33.0", "logging.level"))
|
||||||
|
|
||||||
|
if configuration.Logging.Level == "" {
|
||||||
|
configuration.Logging.Level = configuration.LogLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if configuration.LogFormat != "" {
|
||||||
|
validator.PushWarning(fmt.Errorf(errFmtDeprecatedConfigurationKey, "log_format", "4.33.0", "logging.format"))
|
||||||
|
|
||||||
|
if configuration.Logging.Format == "" {
|
||||||
|
configuration.Logging.Format = configuration.LogFormat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if configuration.LogFilePath != "" {
|
||||||
|
validator.PushWarning(fmt.Errorf(errFmtDeprecatedConfigurationKey, "log_file_path", "4.33.0", "logging.file_path"))
|
||||||
|
|
||||||
|
if configuration.Logging.FilePath == "" {
|
||||||
|
configuration.Logging.FilePath = configuration.LogFilePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/authelia/authelia/internal/configuration/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestShouldSetDefaultLoggingValues(t *testing.T) {
|
||||||
|
config := &schema.Configuration{}
|
||||||
|
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
|
||||||
|
ValidateLogging(config, validator)
|
||||||
|
|
||||||
|
assert.Len(t, validator.Warnings(), 0)
|
||||||
|
assert.Len(t, validator.Errors(), 0)
|
||||||
|
|
||||||
|
require.NotNil(t, config.Logging.KeepStdout)
|
||||||
|
|
||||||
|
assert.Equal(t, "", config.LogLevel)
|
||||||
|
assert.Equal(t, "", config.LogFormat)
|
||||||
|
assert.Equal(t, "", config.LogFilePath)
|
||||||
|
|
||||||
|
assert.Equal(t, "info", config.Logging.Level)
|
||||||
|
assert.Equal(t, "text", config.Logging.Format)
|
||||||
|
assert.Equal(t, "", config.Logging.FilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldRaiseErrorOnInvalidLoggingLevel(t *testing.T) {
|
||||||
|
config := &schema.Configuration{
|
||||||
|
Logging: schema.LoggingConfiguration{
|
||||||
|
Level: "TRACE",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
|
||||||
|
ValidateLogging(config, validator)
|
||||||
|
|
||||||
|
assert.Len(t, validator.Warnings(), 0)
|
||||||
|
require.Len(t, validator.Errors(), 1)
|
||||||
|
|
||||||
|
assert.EqualError(t, validator.Errors()[0], "the log level 'TRACE' is invalid, must be one of: trace, debug, info, warn, error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: DEPRECATED TEST. Remove in 4.33.0.
|
||||||
|
func TestShouldMigrateDeprecatedLoggingConfig(t *testing.T) {
|
||||||
|
config := &schema.Configuration{
|
||||||
|
LogLevel: "trace",
|
||||||
|
LogFormat: "json",
|
||||||
|
LogFilePath: "/a/b/c",
|
||||||
|
}
|
||||||
|
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
|
||||||
|
ValidateLogging(config, validator)
|
||||||
|
|
||||||
|
assert.Len(t, validator.Errors(), 0)
|
||||||
|
require.Len(t, validator.Warnings(), 3)
|
||||||
|
|
||||||
|
require.NotNil(t, config.Logging.KeepStdout)
|
||||||
|
|
||||||
|
assert.Equal(t, "trace", config.LogLevel)
|
||||||
|
assert.Equal(t, "json", config.LogFormat)
|
||||||
|
assert.Equal(t, "/a/b/c", config.LogFilePath)
|
||||||
|
|
||||||
|
assert.Equal(t, "trace", config.Logging.Level)
|
||||||
|
assert.Equal(t, "json", config.Logging.Format)
|
||||||
|
assert.Equal(t, "/a/b/c", config.Logging.FilePath)
|
||||||
|
|
||||||
|
assert.EqualError(t, validator.Warnings()[0], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_level", "4.33.0", "logging.level"))
|
||||||
|
assert.EqualError(t, validator.Warnings()[1], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_format", "4.33.0", "logging.format"))
|
||||||
|
assert.EqualError(t, validator.Warnings()[2], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_file_path", "4.33.0", "logging.file_path"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldRaiseErrorsAndNotOverwriteConfigurationWhenUsingDeprecatedLoggingConfig(t *testing.T) {
|
||||||
|
config := &schema.Configuration{
|
||||||
|
Logging: schema.LoggingConfiguration{
|
||||||
|
Level: "info",
|
||||||
|
Format: "text",
|
||||||
|
FilePath: "/x/y/z",
|
||||||
|
KeepStdout: true,
|
||||||
|
},
|
||||||
|
LogLevel: "debug",
|
||||||
|
LogFormat: "json",
|
||||||
|
LogFilePath: "/a/b/c",
|
||||||
|
}
|
||||||
|
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
|
||||||
|
ValidateLogging(config, validator)
|
||||||
|
|
||||||
|
require.NotNil(t, config.Logging.KeepStdout)
|
||||||
|
|
||||||
|
assert.Equal(t, "info", config.Logging.Level)
|
||||||
|
assert.Equal(t, "text", config.Logging.Format)
|
||||||
|
assert.True(t, config.Logging.KeepStdout)
|
||||||
|
assert.Equal(t, "/x/y/z", config.Logging.FilePath)
|
||||||
|
|
||||||
|
assert.Len(t, validator.Errors(), 0)
|
||||||
|
require.Len(t, validator.Warnings(), 3)
|
||||||
|
|
||||||
|
assert.EqualError(t, validator.Warnings()[0], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_level", "4.33.0", "logging.level"))
|
||||||
|
assert.EqualError(t, validator.Warnings()[1], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_format", "4.33.0", "logging.format"))
|
||||||
|
assert.EqualError(t, validator.Warnings()[2], fmt.Sprintf(errFmtDeprecatedConfigurationKey, "log_file_path", "4.33.0", "logging.file_path"))
|
||||||
|
}
|
|
@ -9,6 +9,10 @@ import (
|
||||||
|
|
||||||
// ValidateTheme validates and update Theme configuration.
|
// ValidateTheme validates and update Theme configuration.
|
||||||
func ValidateTheme(configuration *schema.Configuration, validator *schema.StructValidator) {
|
func ValidateTheme(configuration *schema.Configuration, validator *schema.StructValidator) {
|
||||||
|
if configuration.Theme == "" {
|
||||||
|
configuration.Theme = "light"
|
||||||
|
}
|
||||||
|
|
||||||
validThemes := regexp.MustCompile("light|dark|grey")
|
validThemes := regexp.MustCompile("light|dark|grey")
|
||||||
if !validThemes.MatchString(configuration.Theme) {
|
if !validThemes.MatchString(configuration.Theme) {
|
||||||
validator.Push(fmt.Errorf("Theme: %s is not valid, valid themes are: \"light\", \"dark\" or \"grey\"", configuration.Theme))
|
validator.Push(fmt.Errorf("Theme: %s is not valid, valid themes are: \"light\", \"dark\" or \"grey\"", configuration.Theme))
|
||||||
|
|
|
@ -339,7 +339,7 @@ func verifySessionHasUpToDateProfile(ctx *middlewares.AutheliaCtx, targetURL *ur
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.Logger.Debugf("Updated profile detected for %s.", userSession.Username)
|
ctx.Logger.Debugf("Updated profile detected for %s.", userSession.Username)
|
||||||
if ctx.Configuration.LogLevel == "trace" {
|
if ctx.Configuration.Logging.Level == "trace" {
|
||||||
generateVerifySessionHasUpToDateProfileTraceLogs(ctx, userSession, details)
|
generateVerifySessionHasUpToDateProfileTraceLogs(ctx, userSession, details)
|
||||||
}
|
}
|
||||||
userSession.Emails = details.Emails
|
userSession.Emails = details.Emails
|
||||||
|
|
|
@ -127,9 +127,11 @@ func registerRoutes(configuration schema.Configuration, providers middlewares.Pr
|
||||||
middlewares.RequireFirstFactor(handlers.SecondFactorDuoPost(duoAPI))))
|
middlewares.RequireFirstFactor(handlers.SecondFactorDuoPost(duoAPI))))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If trace is set, enable pprofhandler and expvarhandler.
|
if configuration.Server.EnablePprof {
|
||||||
if configuration.LogLevel == "trace" {
|
|
||||||
r.GET("/debug/pprof/{name?}", pprofhandler.PprofHandler)
|
r.GET("/debug/pprof/{name?}", pprofhandler.PprofHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
if configuration.Server.EnableExpvars {
|
||||||
r.GET("/debug/vars", expvarhandler.ExpvarHandler)
|
r.GET("/debug/vars", expvarhandler.ExpvarHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@ tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
theme: grey
|
theme: grey
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: trace
|
logging:
|
||||||
|
level: trace
|
||||||
|
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@ tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
theme: dark
|
theme: dark
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_password
|
jwt_secret: unsecure_password
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,8 @@ tls_key: /config/ssl/key.pem
|
||||||
server:
|
server:
|
||||||
path: auth
|
path: auth
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
default_redirection_url: https://home.example.com:8080/
|
default_redirection_url: https://home.example.com:8080/
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
authentication_backend:
|
authentication_backend:
|
||||||
file:
|
file:
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 9091
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
jwt_secret: unsecure_secret
|
jwt_secret: unsecure_secret
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ port: 443
|
||||||
tls_cert: /config/ssl/cert.pem
|
tls_cert: /config/ssl/cert.pem
|
||||||
tls_key: /config/ssl/key.pem
|
tls_key: /config/ssl/key.pem
|
||||||
|
|
||||||
log_level: debug
|
logging:
|
||||||
|
level: debug
|
||||||
|
|
||||||
default_redirection_url: https://home.example.com:8080
|
default_redirection_url: https://home.example.com:8080
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@ func IsStringAlphaNumeric(input string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsStringInSlice checks if a single string is in a slice of strings.
|
// IsStringInSlice checks if a single string is in a slice of strings.
|
||||||
func IsStringInSlice(a string, slice []string) (inSlice bool) {
|
func IsStringInSlice(needle string, haystack []string) (inSlice bool) {
|
||||||
for _, b := range slice {
|
for _, b := range haystack {
|
||||||
if b == a {
|
if b == needle {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,9 @@ func IsStringInSlice(a string, slice []string) (inSlice bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsStringInSliceFold checks if a single string is in a slice of strings but uses strings.EqualFold to compare them.
|
// IsStringInSliceFold checks if a single string is in a slice of strings but uses strings.EqualFold to compare them.
|
||||||
func IsStringInSliceFold(a string, slice []string) (inSlice bool) {
|
func IsStringInSliceFold(needle string, haystack []string) (inSlice bool) {
|
||||||
for _, b := range slice {
|
for _, b := range haystack {
|
||||||
if strings.EqualFold(b, a) {
|
if strings.EqualFold(b, needle) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,9 @@ func IsStringInSliceFold(a string, slice []string) (inSlice bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsStringInSliceContains checks if a single string is in an array of strings.
|
// IsStringInSliceContains checks if a single string is in an array of strings.
|
||||||
func IsStringInSliceContains(a string, list []string) (inSlice bool) {
|
func IsStringInSliceContains(needle string, haystack []string) (inSlice bool) {
|
||||||
for _, b := range list {
|
for _, b := range haystack {
|
||||||
if strings.Contains(a, b) {
|
if strings.Contains(needle, b) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue