From 8aade7f40e00e7dc13cd32edcb105cc77ee0100b Mon Sep 17 00:00:00 2001 From: James Elliott Date: Sun, 5 Apr 2020 22:37:21 +1000 Subject: [PATCH] [MISC] Update durations to notation format and housekeeping (#824) * added regulation validator * made regulations find_time and ban_time values duration notation strings * added DefaultRegulationConfiguration for the validator * made session expiration and inactivity values duration notation strings * TOTP period does not need to be converted because adjustment should be discouraged * moved TOTP defaults to DefaultTOTPConfiguration and removed the consts * arranged the root config validator in configuration file order * adjusted tests for the changes * moved duration notation docs to root of configuration * added references to duration notation where applicable * project wide gofmt and goimports: * run gofmt * run goimports -local github.com/authelia/authelia -w on all files * Make jwt_secret error uniform and add tests * now at 100% coverage for internal/configuration/validator/configuration.go --- cmd/authelia-scripts/cmd_bootstrap.go | 3 +- cmd/authelia-scripts/cmd_build.go | 3 +- cmd/authelia-scripts/cmd_ci.go | 3 +- cmd/authelia-scripts/cmd_docker.go | 3 +- cmd/authelia-scripts/cmd_serve.go | 3 +- cmd/authelia-scripts/cmd_suites.go | 5 +- cmd/authelia-scripts/cmd_unittest.go | 6 ++- cmd/authelia-scripts/main.go | 5 +- cmd/authelia-suites/main.go | 5 +- cmd/authelia/main.go | 6 +-- config.template.yml | 12 +++-- docs/configuration/index.md | 24 +++++++++ docs/configuration/regulation.md | 13 +++-- docs/configuration/session.md | 33 +++--------- internal/authentication/file_user_provider.go | 3 +- .../authentication/file_user_provider_test.go | 3 +- .../ldap_connection_factory_mock.go | 3 +- internal/authentication/ldap_user_provider.go | 3 +- .../authentication/ldap_user_provider_test.go | 3 +- internal/authentication/password_hash.go | 3 +- internal/authentication/password_hash_test.go | 5 +- internal/commands/hash.go | 3 +- internal/commands/migration.go | 3 +- internal/commands/migration_local.go | 3 +- internal/commands/migration_mongo.go | 5 +- internal/configuration/reader.go | 3 +- internal/configuration/schema/regulation.go | 12 +++-- internal/configuration/schema/session.go | 8 +-- internal/configuration/schema/totp.go | 7 +++ .../validator/authentication_test.go | 3 +- .../configuration/validator/configuration.go | 40 ++++++++------- .../validator/configuration_test.go | 23 ++++++++- internal/configuration/validator/notifier.go | 6 ++- .../configuration/validator/notifier_test.go | 3 +- .../configuration/validator/regulation.go | 30 +++++++++++ .../validator/regulation_test.go | 45 ++++++++++++++++ internal/configuration/validator/session.go | 23 ++++----- .../configuration/validator/session_test.go | 35 ++++++++++--- .../configuration/validator/storage_test.go | 3 +- internal/configuration/validator/totp.go | 12 ++--- internal/configuration/validator/totp_test.go | 7 +-- internal/duo/duo.go | 2 +- internal/duo/types.go | 3 +- .../handlers/handler_configuration_test.go | 6 ++- .../handler_extended_configuration_test.go | 25 +++++---- internal/handlers/handler_firstfactor_test.go | 3 +- internal/handlers/handler_register_totp.go | 3 +- .../handlers/handler_register_u2f_step1.go | 3 +- .../handler_register_u2f_step1_test.go | 5 +- .../handlers/handler_register_u2f_step2.go | 3 +- internal/handlers/handler_sign_duo_test.go | 5 +- internal/handlers/handler_sign_totp_test.go | 5 +- internal/handlers/handler_sign_u2f_step1.go | 3 +- .../handlers/handler_sign_u2f_step1_test.go | 3 +- .../handlers/handler_sign_u2f_step2_test.go | 5 +- internal/handlers/handler_state_test.go | 3 +- internal/handlers/handler_user_info.go | 3 +- internal/handlers/handler_verify.go | 6 +-- internal/handlers/handler_verify_test.go | 51 +++++++++++++++---- internal/handlers/totp.go | 3 +- internal/handlers/totp_mock.go | 3 +- internal/handlers/types.go | 3 +- internal/handlers/u2f_mock.go | 3 +- internal/middlewares/authelia_context.go | 5 +- internal/middlewares/authelia_context_test.go | 7 +-- internal/middlewares/identity_verification.go | 3 +- .../middlewares/identity_verification_test.go | 7 +-- internal/middlewares/types.go | 7 +-- internal/mocks/mock_authelia_ctx.go | 14 ++--- internal/mocks/mock_duo_api.go | 3 +- internal/mocks/mock_user_provider.go | 3 +- internal/notification/notifier.go | 2 +- internal/notification/smtp_login_auth_test.go | 10 ++-- internal/notification/smtp_notifier.go | 3 +- internal/regulation/regulator.go | 16 ++++-- internal/regulation/regulator_test.go | 19 +++---- internal/server/server.go | 7 +-- internal/session/encrypting_serializer.go | 3 +- internal/session/mocks/mock_storer.go | 5 +- internal/session/provider.go | 14 ++++- internal/session/provider_config.go | 18 +++---- internal/session/provider_config_test.go | 14 +++-- internal/session/provider_test.go | 13 ++--- internal/session/types.go | 3 +- internal/storage/mysql_provider.go | 3 +- internal/storage/postgres_provider.go | 3 +- internal/storage/provider_mock.go | 6 ++- internal/storage/sqlite_provider.go | 3 +- internal/suites/docker.go | 3 +- internal/suites/environment.go | 3 +- internal/suites/suite_kubernetes.go | 3 +- internal/suites/suite_standalone_test.go | 3 +- internal/utils/time_test.go | 3 +- 93 files changed, 514 insertions(+), 262 deletions(-) create mode 100644 internal/configuration/validator/regulation.go create mode 100644 internal/configuration/validator/regulation_test.go diff --git a/cmd/authelia-scripts/cmd_bootstrap.go b/cmd/authelia-scripts/cmd_bootstrap.go index 6e9cbd3b0..11013d43b 100644 --- a/cmd/authelia-scripts/cmd_bootstrap.go +++ b/cmd/authelia-scripts/cmd_bootstrap.go @@ -8,8 +8,9 @@ import ( "os/exec" "strings" - "github.com/authelia/authelia/internal/utils" "github.com/spf13/cobra" + + "github.com/authelia/authelia/internal/utils" ) // HostEntry represents an entry in /etc/hosts diff --git a/cmd/authelia-scripts/cmd_build.go b/cmd/authelia-scripts/cmd_build.go index 7c984c292..981e48cc4 100644 --- a/cmd/authelia-scripts/cmd_build.go +++ b/cmd/authelia-scripts/cmd_build.go @@ -3,9 +3,10 @@ package main import ( "os" - "github.com/authelia/authelia/internal/utils" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/authelia/authelia/internal/utils" ) func buildAutheliaBinary() { diff --git a/cmd/authelia-scripts/cmd_ci.go b/cmd/authelia-scripts/cmd_ci.go index c09af3774..b409f9b8a 100644 --- a/cmd/authelia-scripts/cmd_ci.go +++ b/cmd/authelia-scripts/cmd_ci.go @@ -1,9 +1,10 @@ package main import ( - "github.com/authelia/authelia/internal/utils" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/authelia/authelia/internal/utils" ) const dockerPullCommandLine = "docker-compose -p authelia -f internal/suites/docker-compose.yml " + diff --git a/cmd/authelia-scripts/cmd_docker.go b/cmd/authelia-scripts/cmd_docker.go index 705ef5d4b..a23b01515 100644 --- a/cmd/authelia-scripts/cmd_docker.go +++ b/cmd/authelia-scripts/cmd_docker.go @@ -7,9 +7,10 @@ import ( "regexp" "strings" - "github.com/authelia/authelia/internal/utils" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/authelia/authelia/internal/utils" ) var arch string diff --git a/cmd/authelia-scripts/cmd_serve.go b/cmd/authelia-scripts/cmd_serve.go index bb4cf20cf..6adbc7cb2 100644 --- a/cmd/authelia-scripts/cmd_serve.go +++ b/cmd/authelia-scripts/cmd_serve.go @@ -3,9 +3,10 @@ package main import ( "os" - "github.com/authelia/authelia/internal/utils" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/authelia/authelia/internal/utils" ) // ServeCmd serve authelia with the provided configuration diff --git a/cmd/authelia-scripts/cmd_suites.go b/cmd/authelia-scripts/cmd_suites.go index eb097427d..eb79b1651 100644 --- a/cmd/authelia-scripts/cmd_suites.go +++ b/cmd/authelia-scripts/cmd_suites.go @@ -11,10 +11,11 @@ import ( "syscall" "time" - "github.com/authelia/authelia/internal/suites" - "github.com/authelia/authelia/internal/utils" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/authelia/authelia/internal/suites" + "github.com/authelia/authelia/internal/utils" ) // ErrNotAvailableSuite error raised when suite is not available. diff --git a/cmd/authelia-scripts/cmd_unittest.go b/cmd/authelia-scripts/cmd_unittest.go index b7db5e3e5..8e4e9ea45 100644 --- a/cmd/authelia-scripts/cmd_unittest.go +++ b/cmd/authelia-scripts/cmd_unittest.go @@ -1,10 +1,12 @@ package main import ( - "github.com/authelia/authelia/internal/utils" + "os" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "os" + + "github.com/authelia/authelia/internal/utils" ) // RunUnitTest run the unit tests diff --git a/cmd/authelia-scripts/main.go b/cmd/authelia-scripts/main.go index bfbc8faac..d4a537f89 100755 --- a/cmd/authelia-scripts/main.go +++ b/cmd/authelia-scripts/main.go @@ -3,10 +3,11 @@ package main import ( - "github.com/authelia/authelia/internal/commands" - "github.com/authelia/authelia/internal/utils" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/authelia/authelia/internal/commands" + "github.com/authelia/authelia/internal/utils" ) var logLevel string diff --git a/cmd/authelia-suites/main.go b/cmd/authelia-suites/main.go index 4a75aff42..648c04970 100644 --- a/cmd/authelia-suites/main.go +++ b/cmd/authelia-suites/main.go @@ -5,11 +5,12 @@ import ( "os" "path/filepath" - "github.com/authelia/authelia/internal/suites" - "github.com/authelia/authelia/internal/utils" "github.com/otiai10/copy" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/authelia/authelia/internal/suites" + "github.com/authelia/authelia/internal/utils" ) var tmpDirectory = "/tmp/authelia/suites/" diff --git a/cmd/authelia/main.go b/cmd/authelia/main.go index 2ed6592a8..8a0cb0ea7 100644 --- a/cmd/authelia/main.go +++ b/cmd/authelia/main.go @@ -6,6 +6,9 @@ import ( "log" "os" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/authelia/authelia/internal/authentication" "github.com/authelia/authelia/internal/authorization" "github.com/authelia/authelia/internal/commands" @@ -18,8 +21,6 @@ import ( "github.com/authelia/authelia/internal/session" "github.com/authelia/authelia/internal/storage" "github.com/authelia/authelia/internal/utils" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" ) var configPathFlag string @@ -50,7 +51,6 @@ func startServer() { case "debug": logging.Logger().Info("Logging severity set to debug") logging.SetLevel(logrus.DebugLevel) - break case "trace": logging.Logger().Info("Logging severity set to trace") logging.SetLevel(logrus.TraceLevel) diff --git a/config.template.yml b/config.template.yml index 800356185..9a8bf7760 100644 --- a/config.template.yml +++ b/config.template.yml @@ -262,14 +262,14 @@ session: secret: insecure_session_secret # The time in seconds before the cookie expires and session is reset. - expiration: 3600 # 1 hour + expiration: 1h # The inactivity time in seconds before the session is reset. - inactivity: 300 # 5 minutes + inactivity: 5m # The remember me duration. # Value of 0 disables remember me. - # Value is in seconds, or duration notation. See: https://docs.authelia.com/configuration/session.html#duration-notation + # Value is in seconds, or duration notation. See: https://docs.authelia.com/configuration/index.html#duration-notation-format # Longer periods are considered less secure because a stolen cookie will last longer giving attackers more time to spy # or attack. Currently the default is 1M or 1 month. remember_me_duration: 1M @@ -300,10 +300,12 @@ regulation: # The time range during which the user can attempt login before being banned. # The user is banned if the authentication failed 'max_retries' times in a 'find_time' seconds window. - find_time: 120 + # Find Time accepts duration notation. See: https://docs.authelia.com/configuration/index.html#duration-notation-format + find_time: 2m # The length of time before a banned user can login again. - ban_time: 300 + # Ban Time accepts duration notation. See: https://docs.authelia.com/configuration/index.html#duration-notation-format + ban_time: 5m # Configuration of the storage backend used to store data and secrets. # diff --git a/docs/configuration/index.md b/docs/configuration/index.md index db4dd6866..2207d3e38 100644 --- a/docs/configuration/index.md +++ b/docs/configuration/index.md @@ -14,3 +14,27 @@ When running **Authelia**, you can specify your configuration by passing the file path as shown below. $ authelia --config config.custom.yml + +## Duration Notation Format + +We have implemented a string based notation for configuration options that take a duration. This section describes its +usage. You can use this implementation in: session for expiration, inactivity, and remember_me_duration; and regulation +for ban_time, and find_time. This notation also supports just providing the number of seconds instead. + +The notation is comprised of a number which must be positive and not have leading zeros, followed by a letter +denoting the unit of time measurement. The table below describes the units of time and the associated letter. + +|Unit |Associated Letter| +|:-----:|:---------------:| +|Years |y | +|Months |M | +|Weeks |w | +|Days |d | +|Hours |h | +|Minutes|m | +|Seconds|s | + +Examples: +* 1 hour and 30 minutes: 90m +* 1 day: 1d +* 10 hours: 10h \ No newline at end of file diff --git a/docs/configuration/regulation.md b/docs/configuration/regulation.md index d2e5f7fdc..5dac36bd9 100644 --- a/docs/configuration/regulation.md +++ b/docs/configuration/regulation.md @@ -20,8 +20,15 @@ regulation: # The time range during which the user can attempt login before being banned. # The user is banned if the authentication failed `max_retries` times in a `find_time` seconds window. - find_time: 120 + # Find Time accepts duration notation. See: https://docs.authelia.com/configuration/index.html#duration-notation-format + find_time: 2m # The length of time before a banned user can sign in again. - ban_time: 300 -``` \ No newline at end of file + # Find Time accepts duration notation. See: https://docs.authelia.com/configuration/index.html#duration-notation-format + ban_time: 5m +``` + +### Duration Notation + +The configuration parameters find_time, and ban_time use duration notation. See the documentation +for [duration notation format](index.md#duration-notation-format) for more information. \ No newline at end of file diff --git a/docs/configuration/session.md b/docs/configuration/session.md index 1abc7f731..9d2a21f12 100644 --- a/docs/configuration/session.md +++ b/docs/configuration/session.md @@ -27,14 +27,14 @@ session: secret: unsecure_session_secret # The time in seconds before the cookie expires and session is reset. - expiration: 3600 # 1 hour + expiration: 1h # The inactivity time in seconds before the session is reset. - inactivity: 300 # 5 minutes + inactivity: 5m # The remember me duration. # Value of 0 disables remember me. - # Value is in seconds, or duration notation. See: https://docs.authelia.com/configuration/session.html#duration-notation + # Value is in seconds, or duration notation. See: https://docs.authelia.com/configuration/index.html#duration-notation-format # Longer periods are considered less secure because a stolen cookie will last longer giving attackers more time to spy # or attack. Currently the default is 1M or 1 month. remember_me_duration: 1M @@ -57,28 +57,7 @@ session: Configuration of this section has an impact on security. You should read notes in [security measures](../security/measures.md#session-security) for more information. -# Duration Notation +### Duration Notation -We have implemented a string based notation for configuration options that take a duration. This section describes its -usage. - -**NOTE:** At the time of this writing, only remember_me_duration uses this value type. But we plan to change expiration -and inactivity. - -The notation is comprised of a number which must be positive and not have leading zeros, followed by a letter -denoting the unit of time measurement. The table below describes the units of time and the associated letter. - -|Unit |Associated Letter| -|:-----:|:---------------:| -|Years |y | -|Months |M | -|Weeks |w | -|Days |d | -|Hours |h | -|Minutes|m | -|Seconds|s | - -Examples: -* 1 hour and 30 minutes: 90m -* 1 day: 1d -* 10 hours: 10h \ No newline at end of file +The configuration parameters expiration, inactivity, and remember_me_duration use duration notation. See the documentation +for [duration notation format](index.md#duration-notation-format) for more information. \ No newline at end of file diff --git a/internal/authentication/file_user_provider.go b/internal/authentication/file_user_provider.go index bfd59c96a..58fd82dab 100644 --- a/internal/authentication/file_user_provider.go +++ b/internal/authentication/file_user_provider.go @@ -8,8 +8,9 @@ import ( "sync" "github.com/asaskevich/govalidator" - "github.com/authelia/authelia/internal/configuration/schema" "gopkg.in/yaml.v2" + + "github.com/authelia/authelia/internal/configuration/schema" ) // FileUserProvider is a provider reading details from a file. diff --git a/internal/authentication/file_user_provider_test.go b/internal/authentication/file_user_provider_test.go index e6608922d..c5f3e7ce4 100644 --- a/internal/authentication/file_user_provider_test.go +++ b/internal/authentication/file_user_provider_test.go @@ -7,8 +7,9 @@ import ( "strings" "testing" - "github.com/authelia/authelia/internal/configuration/schema" "github.com/stretchr/testify/assert" + + "github.com/authelia/authelia/internal/configuration/schema" ) func WithDatabase(content []byte, f func(path string)) { diff --git a/internal/authentication/ldap_connection_factory_mock.go b/internal/authentication/ldap_connection_factory_mock.go index 46080a60b..5e48daa6c 100644 --- a/internal/authentication/ldap_connection_factory_mock.go +++ b/internal/authentication/ldap_connection_factory_mock.go @@ -6,9 +6,10 @@ package authentication import ( tls "crypto/tls" + reflect "reflect" + ldap_v3 "github.com/go-ldap/ldap/v3" gomock "github.com/golang/mock/gomock" - reflect "reflect" ) // MockLDAPConnection is a mock of LDAPConnection interface diff --git a/internal/authentication/ldap_user_provider.go b/internal/authentication/ldap_user_provider.go index 02d535277..1ece76562 100644 --- a/internal/authentication/ldap_user_provider.go +++ b/internal/authentication/ldap_user_provider.go @@ -6,9 +6,10 @@ import ( "net/url" "strings" + "github.com/go-ldap/ldap/v3" + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/logging" - "github.com/go-ldap/ldap/v3" ) // LDAPUserProvider is a provider using a LDAP or AD as a user database. diff --git a/internal/authentication/ldap_user_provider_test.go b/internal/authentication/ldap_user_provider_test.go index 034e53aac..b07e811fa 100644 --- a/internal/authentication/ldap_user_provider_test.go +++ b/internal/authentication/ldap_user_provider_test.go @@ -3,11 +3,12 @@ package authentication import ( "testing" - "github.com/authelia/authelia/internal/configuration/schema" "github.com/go-ldap/ldap/v3" gomock "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/authelia/authelia/internal/configuration/schema" ) func TestShouldCreateRawConnectionWhenSchemeIsLDAP(t *testing.T) { diff --git a/internal/authentication/password_hash.go b/internal/authentication/password_hash.go index 688f471f0..f7977bab5 100644 --- a/internal/authentication/password_hash.go +++ b/internal/authentication/password_hash.go @@ -6,8 +6,9 @@ import ( "strconv" "strings" - "github.com/authelia/authelia/internal/utils" "github.com/simia-tech/crypt" + + "github.com/authelia/authelia/internal/utils" ) // PasswordHash represents all characteristics of a password hash. diff --git a/internal/authentication/password_hash_test.go b/internal/authentication/password_hash_test.go index 4b08c8832..58434a73f 100644 --- a/internal/authentication/password_hash_test.go +++ b/internal/authentication/password_hash_test.go @@ -4,11 +4,12 @@ import ( "fmt" "testing" - "github.com/authelia/authelia/internal/configuration/schema" - "github.com/authelia/authelia/internal/utils" "github.com/simia-tech/crypt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/authelia/authelia/internal/configuration/schema" + "github.com/authelia/authelia/internal/utils" ) func TestShouldHashSHA512Password(t *testing.T) { diff --git a/internal/commands/hash.go b/internal/commands/hash.go index 0c27cbb67..e4a357a53 100644 --- a/internal/commands/hash.go +++ b/internal/commands/hash.go @@ -3,9 +3,10 @@ package commands import ( "fmt" + "github.com/spf13/cobra" + "github.com/authelia/authelia/internal/authentication" "github.com/authelia/authelia/internal/configuration/schema" - "github.com/spf13/cobra" ) func init() { diff --git a/internal/commands/migration.go b/internal/commands/migration.go index 751eb068d..6e0abe0d0 100644 --- a/internal/commands/migration.go +++ b/internal/commands/migration.go @@ -4,9 +4,10 @@ import ( "encoding/base64" "strings" + "github.com/spf13/cobra" + "github.com/authelia/authelia/internal/configuration" "github.com/authelia/authelia/internal/storage" - "github.com/spf13/cobra" ) var MigrateCmd *cobra.Command diff --git a/internal/commands/migration_local.go b/internal/commands/migration_local.go index 7f8d62e8b..cb355a00c 100644 --- a/internal/commands/migration_local.go +++ b/internal/commands/migration_local.go @@ -8,9 +8,10 @@ import ( "path" "time" + "github.com/spf13/cobra" + "github.com/authelia/authelia/internal/models" "github.com/authelia/authelia/internal/storage" - "github.com/spf13/cobra" ) var configurationPath string diff --git a/internal/commands/migration_mongo.go b/internal/commands/migration_mongo.go index 32994e7d1..f9805e9aa 100644 --- a/internal/commands/migration_mongo.go +++ b/internal/commands/migration_mongo.go @@ -5,12 +5,13 @@ import ( "log" "time" - "github.com/authelia/authelia/internal/models" - "github.com/authelia/authelia/internal/storage" "github.com/spf13/cobra" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/authelia/authelia/internal/models" + "github.com/authelia/authelia/internal/storage" ) var mongoURL string diff --git a/internal/configuration/reader.go b/internal/configuration/reader.go index 725bcfda3..176757b2e 100644 --- a/internal/configuration/reader.go +++ b/internal/configuration/reader.go @@ -4,9 +4,10 @@ import ( "fmt" "strings" + "github.com/spf13/viper" + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/configuration/validator" - "github.com/spf13/viper" ) func check(e error) { diff --git a/internal/configuration/schema/regulation.go b/internal/configuration/schema/regulation.go index d8d513f12..0c36a46b1 100644 --- a/internal/configuration/schema/regulation.go +++ b/internal/configuration/schema/regulation.go @@ -2,7 +2,13 @@ package schema // RegulationConfiguration represents the configuration related to regulation. type RegulationConfiguration struct { - MaxRetries int `mapstructure:"max_retries"` - FindTime int64 `mapstructure:"find_time"` - BanTime int64 `mapstructure:"ban_time"` + MaxRetries int `mapstructure:"max_retries"` + FindTime string `mapstructure:"find_time"` + BanTime string `mapstructure:"ban_time"` +} + +var DefaultRegulationConfiguration = RegulationConfiguration{ + MaxRetries: 3, + FindTime: "2m", + BanTime: "5m", } diff --git a/internal/configuration/schema/session.go b/internal/configuration/schema/session.go index 268dfef07..9ae2412bd 100644 --- a/internal/configuration/schema/session.go +++ b/internal/configuration/schema/session.go @@ -10,11 +10,10 @@ type RedisSessionConfiguration struct { // SessionConfiguration represents the configuration related to user sessions. type SessionConfiguration struct { - // TODO(james-d-elliott): Convert to duration notation (Both Expiration and Activity need to be strings, and default needs to be changed) Name string `mapstructure:"name"` Secret string `mapstructure:"secret"` - Expiration int64 `mapstructure:"expiration"` // Expiration in seconds - Inactivity int64 `mapstructure:"inactivity"` // Inactivity in seconds + Expiration string `mapstructure:"expiration"` + Inactivity string `mapstructure:"inactivity"` RememberMeDuration string `mapstructure:"remember_me_duration"` Domain string `mapstructure:"domain"` Redis *RedisSessionConfiguration `mapstructure:"redis"` @@ -23,6 +22,7 @@ type SessionConfiguration struct { // DefaultSessionConfiguration is the default session configuration var DefaultSessionConfiguration = SessionConfiguration{ Name: "authelia_session", - Expiration: 3600, + Expiration: "1h", + Inactivity: "5m", RememberMeDuration: "1M", } diff --git a/internal/configuration/schema/totp.go b/internal/configuration/schema/totp.go index 45c38d0f8..3b87464fe 100644 --- a/internal/configuration/schema/totp.go +++ b/internal/configuration/schema/totp.go @@ -6,3 +6,10 @@ type TOTPConfiguration struct { Period int `mapstructure:"period"` Skew *int `mapstructure:"skew"` } + +var defaultOtpSkew = 1 +var DefaultTOTPConfiguration = TOTPConfiguration{ + Issuer: "Authelia", + Period: 30, + Skew: &defaultOtpSkew, +} diff --git a/internal/configuration/validator/authentication_test.go b/internal/configuration/validator/authentication_test.go index fb535980a..e5bbd154f 100644 --- a/internal/configuration/validator/authentication_test.go +++ b/internal/configuration/validator/authentication_test.go @@ -3,10 +3,11 @@ package validator import ( "testing" - "github.com/authelia/authelia/internal/configuration/schema" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/configuration/schema" ) func TestShouldRaiseErrorsWhenNoBackendProvided(t *testing.T) { diff --git a/internal/configuration/validator/configuration.go b/internal/configuration/validator/configuration.go index e44b7d3d1..0ecc2ea9c 100644 --- a/internal/configuration/validator/configuration.go +++ b/internal/configuration/validator/configuration.go @@ -20,16 +20,20 @@ func Validate(configuration *schema.Configuration, validator *schema.StructValid configuration.Port = defaultPort } - if configuration.LogLevel == "" { - configuration.LogLevel = defaultLogLevel - } - if configuration.TLSKey != "" && configuration.TLSCert == "" { validator.Push(fmt.Errorf("No TLS certificate provided, please check the \"tls_cert\" which has been configured")) } else if configuration.TLSKey == "" && configuration.TLSCert != "" { validator.Push(fmt.Errorf("No TLS key provided, please check the \"tls_key\" which has been configured")) } + if configuration.LogLevel == "" { + configuration.LogLevel = defaultLogLevel + } + + if configuration.JWTSecret == "" { + validator.Push(fmt.Errorf("Provide a JWT secret using \"jwt_secret\" key")) + } + if configuration.DefaultRedirectionURL != "" { _, err := url.ParseRequestURI(configuration.DefaultRedirectionURL) if err != nil { @@ -37,27 +41,29 @@ func Validate(configuration *schema.Configuration, validator *schema.StructValid } } - if configuration.JWTSecret == "" { - validator.Push(fmt.Errorf("Provide a JWT secret using `jwt_secret` key")) - } - - ValidateAuthenticationBackend(&configuration.AuthenticationBackend, validator) - ValidateSession(&configuration.Session, validator) - if configuration.TOTP == nil { configuration.TOTP = &schema.TOTPConfiguration{} } ValidateTOTP(configuration.TOTP, validator) + ValidateAuthenticationBackend(&configuration.AuthenticationBackend, validator) + + if configuration.AccessControl.DefaultPolicy == "" { + configuration.AccessControl.DefaultPolicy = "deny" + } + + ValidateSession(&configuration.Session, validator) + + if configuration.Regulation == nil { + configuration.Regulation = &schema.RegulationConfiguration{} + } + ValidateRegulation(configuration.Regulation, validator) + + ValidateStorage(configuration.Storage, validator) + if configuration.Notifier == nil { validator.Push(fmt.Errorf("A notifier configuration must be provided")) } else { ValidateNotifier(configuration.Notifier, validator) } - - if configuration.AccessControl.DefaultPolicy == "" { - configuration.AccessControl.DefaultPolicy = "deny" - } - - ValidateStorage(configuration.Storage, validator) } diff --git a/internal/configuration/validator/configuration_test.go b/internal/configuration/validator/configuration_test.go index 83c6d6f59..c2e3eb321 100644 --- a/internal/configuration/validator/configuration_test.go +++ b/internal/configuration/validator/configuration_test.go @@ -3,9 +3,10 @@ package validator import ( "testing" - "github.com/authelia/authelia/internal/configuration/schema" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/authelia/authelia/internal/configuration/schema" ) func newDefaultConfig() schema.Configuration { @@ -129,3 +130,23 @@ func TestShouldNotRaiseErrorWhenBothTLSCertificateAndKeyAreProvided(t *testing.T Validate(&config, validator) require.Len(t, validator.Errors(), 0) } + +func TestShouldRaiseErrorWithUndefinedJWTSecretKey(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultConfig() + config.JWTSecret = "" + + Validate(&config, validator) + require.Len(t, validator.Errors(), 1) + assert.EqualError(t, validator.Errors()[0], "Provide a JWT secret using \"jwt_secret\" key") +} + +func TestShouldRaiseErrorWithBadDefaultRedirectionURL(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultConfig() + config.DefaultRedirectionURL = "abc" + + Validate(&config, validator) + require.Len(t, validator.Errors(), 1) + assert.EqualError(t, validator.Errors()[0], "Unable to parse default redirection url") +} diff --git a/internal/configuration/validator/notifier.go b/internal/configuration/validator/notifier.go index 22c0a473f..478d60eba 100644 --- a/internal/configuration/validator/notifier.go +++ b/internal/configuration/validator/notifier.go @@ -1,8 +1,10 @@ package validator -import "github.com/authelia/authelia/internal/configuration/schema" +import ( + "fmt" -import "fmt" + "github.com/authelia/authelia/internal/configuration/schema" +) // ValidateSession validates and update session configuration. func ValidateNotifier(configuration *schema.NotifierConfiguration, validator *schema.StructValidator) { diff --git a/internal/configuration/validator/notifier_test.go b/internal/configuration/validator/notifier_test.go index 17a8c5bcc..dcd6e4a14 100644 --- a/internal/configuration/validator/notifier_test.go +++ b/internal/configuration/validator/notifier_test.go @@ -3,8 +3,9 @@ package validator import ( "testing" - "github.com/authelia/authelia/internal/configuration/schema" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/configuration/schema" ) type NotifierSuite struct { diff --git a/internal/configuration/validator/regulation.go b/internal/configuration/validator/regulation.go new file mode 100644 index 000000000..54f91de30 --- /dev/null +++ b/internal/configuration/validator/regulation.go @@ -0,0 +1,30 @@ +package validator + +import ( + "errors" + "fmt" + + "github.com/authelia/authelia/internal/configuration/schema" + "github.com/authelia/authelia/internal/utils" +) + +// ValidateSession validates and update session configuration. +func ValidateRegulation(configuration *schema.RegulationConfiguration, validator *schema.StructValidator) { + if configuration.FindTime == "" { + configuration.FindTime = schema.DefaultRegulationConfiguration.FindTime // 2 min + } + if configuration.BanTime == "" { + configuration.BanTime = schema.DefaultRegulationConfiguration.BanTime // 5 min + } + findTime, err := utils.ParseDurationString(configuration.FindTime) + if err != nil { + validator.Push(errors.New(fmt.Sprintf("Error occurred parsing regulation find_time string: %s", err))) + } + banTime, err := utils.ParseDurationString(configuration.BanTime) + if err != nil { + validator.Push(errors.New(fmt.Sprintf("Error occurred parsing regulation ban_time string: %s", err))) + } + if findTime > banTime { + validator.Push(errors.New(fmt.Sprintf("find_time cannot be greater than ban_time"))) + } +} diff --git a/internal/configuration/validator/regulation_test.go b/internal/configuration/validator/regulation_test.go new file mode 100644 index 000000000..18915793b --- /dev/null +++ b/internal/configuration/validator/regulation_test.go @@ -0,0 +1,45 @@ +package validator + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/authelia/authelia/internal/configuration/schema" +) + +func newDefaultRegulationConfig() schema.RegulationConfiguration { + config := schema.RegulationConfiguration{} + return config +} + +func TestShouldSetDefaultRegulationBanTime(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultRegulationConfig() + + ValidateRegulation(&config, validator) + + assert.Len(t, validator.Errors(), 0) + assert.Equal(t, schema.DefaultRegulationConfiguration.BanTime, config.BanTime) +} + +func TestShouldSetDefaultRegulationFindTime(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultRegulationConfig() + + ValidateRegulation(&config, validator) + + assert.Len(t, validator.Errors(), 0) + assert.Equal(t, schema.DefaultRegulationConfiguration.FindTime, config.FindTime) +} + +func TestShouldRaiseErrorWhenFindTimeLessThanBanTime(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultRegulationConfig() + config.FindTime = "1m" + config.BanTime = "10s" + ValidateRegulation(&config, validator) + + assert.Len(t, validator.Errors(), 1) + assert.EqualError(t, validator.Errors()[0], "find_time cannot be greater than ban_time") +} diff --git a/internal/configuration/validator/session.go b/internal/configuration/validator/session.go index d78e917f4..89fc6df9c 100644 --- a/internal/configuration/validator/session.go +++ b/internal/configuration/validator/session.go @@ -3,6 +3,7 @@ package validator import ( "errors" "fmt" + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/utils" ) @@ -17,24 +18,22 @@ func ValidateSession(configuration *schema.SessionConfiguration, validator *sche validator.Push(errors.New("Set secret of the session object")) } - // TODO(james-d-elliott): Convert to duration notation - if configuration.Expiration == 0 { + if configuration.Expiration == "" { configuration.Expiration = schema.DefaultSessionConfiguration.Expiration // 1 hour - } else if configuration.Expiration < 1 { - validator.Push(errors.New("Set expiration of the session above 0")) + } else if _, err := utils.ParseDurationString(configuration.Expiration); err != nil { + validator.Push(errors.New(fmt.Sprintf("Error occurred parsing session expiration string: %s", err))) } - // TODO(james-d-elliott): Convert to duration notation - if configuration.Inactivity < 0 { - validator.Push(errors.New("Set inactivity of the session to 0 or above")) + if configuration.Inactivity == "" { + configuration.Inactivity = schema.DefaultSessionConfiguration.Inactivity // 5 min + } else if _, err := utils.ParseDurationString(configuration.Inactivity); err != nil { + validator.Push(errors.New(fmt.Sprintf("Error occurred parsing session inactivity string: %s", err))) } if configuration.RememberMeDuration == "" { - configuration.RememberMeDuration = schema.DefaultSessionConfiguration.RememberMeDuration - } else { - if _, err := utils.ParseDurationString(configuration.RememberMeDuration); err != nil { - validator.Push(errors.New(fmt.Sprintf("Error occurred parsing remember_me_duration string: %s", err))) - } + configuration.RememberMeDuration = schema.DefaultSessionConfiguration.RememberMeDuration // 1 month + } else if _, err := utils.ParseDurationString(configuration.RememberMeDuration); err != nil { + validator.Push(errors.New(fmt.Sprintf("Error occurred parsing session remember_me_duration string: %s", err))) } if configuration.Domain == "" { diff --git a/internal/configuration/validator/session_test.go b/internal/configuration/validator/session_test.go index 77f1ddddd..34829169a 100644 --- a/internal/configuration/validator/session_test.go +++ b/internal/configuration/validator/session_test.go @@ -3,8 +3,9 @@ package validator import ( "testing" - "github.com/authelia/authelia/internal/configuration/schema" "github.com/stretchr/testify/assert" + + "github.com/authelia/authelia/internal/configuration/schema" ) func newDefaultSessionConfig() schema.SessionConfiguration { @@ -21,7 +22,27 @@ func TestShouldSetDefaultSessionName(t *testing.T) { ValidateSession(&config, validator) assert.Len(t, validator.Errors(), 0) - assert.Equal(t, "authelia_session", config.Name) + assert.Equal(t, schema.DefaultSessionConfiguration.Name, config.Name) +} + +func TestShouldSetDefaultSessionInactivity(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultSessionConfig() + + ValidateSession(&config, validator) + + assert.Len(t, validator.Errors(), 0) + assert.Equal(t, schema.DefaultSessionConfiguration.Inactivity, config.Inactivity) +} + +func TestShouldSetDefaultSessionExpiration(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultSessionConfig() + + ValidateSession(&config, validator) + + assert.Len(t, validator.Errors(), 0) + assert.Equal(t, schema.DefaultSessionConfiguration.Expiration, config.Expiration) } func TestShouldRaiseErrorWhenRedisIsUsedAndPasswordNotSet(t *testing.T) { @@ -57,14 +78,14 @@ func TestShouldRaiseErrorWhenDomainNotSet(t *testing.T) { func TestShouldRaiseErrorWhenBadInactivityAndExpirationSet(t *testing.T) { validator := schema.NewStructValidator() config := newDefaultSessionConfig() - config.Inactivity = -1 - config.Expiration = -1 + config.Inactivity = "-1" + config.Expiration = "-1" ValidateSession(&config, validator) assert.Len(t, validator.Errors(), 2) - assert.EqualError(t, validator.Errors()[0], "Set expiration of the session above 0") - assert.EqualError(t, validator.Errors()[1], "Set inactivity of the session to 0 or above") + assert.EqualError(t, validator.Errors()[0], "Error occurred parsing session expiration string: could not convert the input string of -1 into a duration") + assert.EqualError(t, validator.Errors()[1], "Error occurred parsing session inactivity string: could not convert the input string of -1 into a duration") } func TestShouldRaiseErrorWhenBadRememberMeDurationSet(t *testing.T) { @@ -75,7 +96,7 @@ func TestShouldRaiseErrorWhenBadRememberMeDurationSet(t *testing.T) { ValidateSession(&config, validator) assert.Len(t, validator.Errors(), 1) - assert.EqualError(t, validator.Errors()[0], "Error occurred parsing remember_me_duration string: could not convert the input string of 1 year into a duration") + assert.EqualError(t, validator.Errors()[0], "Error occurred parsing session remember_me_duration string: could not convert the input string of 1 year into a duration") } func TestShouldSetDefaultRememberMeDuration(t *testing.T) { diff --git a/internal/configuration/validator/storage_test.go b/internal/configuration/validator/storage_test.go index 6091987b8..ba8183039 100644 --- a/internal/configuration/validator/storage_test.go +++ b/internal/configuration/validator/storage_test.go @@ -3,8 +3,9 @@ package validator import ( "testing" - "github.com/authelia/authelia/internal/configuration/schema" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/configuration/schema" ) type StorageSuite struct { diff --git a/internal/configuration/validator/totp.go b/internal/configuration/validator/totp.go index 5dfa9cf3c..68c94a44e 100644 --- a/internal/configuration/validator/totp.go +++ b/internal/configuration/validator/totp.go @@ -2,27 +2,23 @@ package validator import ( "fmt" + "github.com/authelia/authelia/internal/configuration/schema" ) -const defaultTOTPIssuer = "Authelia" -const DefaultTOTPPeriod = 30 -const DefaultTOTPSkew = 1 - // ValidateTOTP validates and update TOTP configuration. func ValidateTOTP(configuration *schema.TOTPConfiguration, validator *schema.StructValidator) { if configuration.Issuer == "" { - configuration.Issuer = defaultTOTPIssuer + configuration.Issuer = schema.DefaultTOTPConfiguration.Issuer } if configuration.Period == 0 { - configuration.Period = DefaultTOTPPeriod + configuration.Period = schema.DefaultTOTPConfiguration.Period } else if configuration.Period < 0 { validator.Push(fmt.Errorf("TOTP Period must be 1 or more")) } if configuration.Skew == nil { - var skew = DefaultTOTPSkew - configuration.Skew = &skew + configuration.Skew = schema.DefaultTOTPConfiguration.Skew } else if *configuration.Skew < 0 { validator.Push(fmt.Errorf("TOTP Skew must be 0 or more")) } diff --git a/internal/configuration/validator/totp_test.go b/internal/configuration/validator/totp_test.go index aae98c5b4..26d015577 100644 --- a/internal/configuration/validator/totp_test.go +++ b/internal/configuration/validator/totp_test.go @@ -3,9 +3,10 @@ package validator import ( "testing" - "github.com/authelia/authelia/internal/configuration/schema" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/authelia/authelia/internal/configuration/schema" ) func TestShouldSetDefaultTOTPValues(t *testing.T) { @@ -16,8 +17,8 @@ func TestShouldSetDefaultTOTPValues(t *testing.T) { require.Len(t, validator.Errors(), 0) assert.Equal(t, "Authelia", config.Issuer) - assert.Equal(t, DefaultTOTPSkew, *config.Skew) - assert.Equal(t, DefaultTOTPPeriod, config.Period) + assert.Equal(t, *schema.DefaultTOTPConfiguration.Skew, *config.Skew) + assert.Equal(t, schema.DefaultTOTPConfiguration.Period, config.Period) } func TestShouldRaiseErrorWhenInvalidTOTPMinimumValues(t *testing.T) { diff --git a/internal/duo/duo.go b/internal/duo/duo.go index 84a6f2595..3b4e147ed 100644 --- a/internal/duo/duo.go +++ b/internal/duo/duo.go @@ -4,7 +4,7 @@ import ( "encoding/json" "net/url" - "github.com/duosecurity/duo_api_golang" + duoapi "github.com/duosecurity/duo_api_golang" "github.com/authelia/authelia/internal/middlewares" ) diff --git a/internal/duo/types.go b/internal/duo/types.go index 0ba4bad62..17edc7e89 100644 --- a/internal/duo/types.go +++ b/internal/duo/types.go @@ -3,9 +3,10 @@ package duo import ( "net/url" + duoapi "github.com/duosecurity/duo_api_golang" + "github.com/authelia/authelia/internal/middlewares" ) -import "github.com/duosecurity/duo_api_golang" // API interface wrapping duo api library for testing purpose type API interface { diff --git a/internal/handlers/handler_configuration_test.go b/internal/handlers/handler_configuration_test.go index 9c0a4cf45..20d85deef 100644 --- a/internal/handlers/handler_configuration_test.go +++ b/internal/handlers/handler_configuration_test.go @@ -1,11 +1,13 @@ package handlers import ( + "testing" + + "github.com/stretchr/testify/suite" + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/mocks" "github.com/authelia/authelia/internal/session" - "github.com/stretchr/testify/suite" - "testing" ) type ConfigurationSuite struct { diff --git a/internal/handlers/handler_extended_configuration_test.go b/internal/handlers/handler_extended_configuration_test.go index 507e5d4fe..9f41b3ecf 100644 --- a/internal/handlers/handler_extended_configuration_test.go +++ b/internal/handlers/handler_extended_configuration_test.go @@ -3,12 +3,11 @@ package handlers import ( "testing" + "github.com/stretchr/testify/suite" + "github.com/authelia/authelia/internal/authorization" "github.com/authelia/authelia/internal/configuration/schema" - "github.com/authelia/authelia/internal/configuration/validator" "github.com/authelia/authelia/internal/mocks" - - "github.com/stretchr/testify/suite" ) type SecondFactorAvailableMethodsFixture struct { @@ -31,13 +30,13 @@ func (s *SecondFactorAvailableMethodsFixture) TearDownTest() { func (s *SecondFactorAvailableMethodsFixture) TestShouldServeDefaultMethods() { s.mock.Ctx.Configuration = schema.Configuration{ TOTP: &schema.TOTPConfiguration{ - Period: validator.DefaultTOTPPeriod, + Period: schema.DefaultTOTPConfiguration.Period, }, } expectedBody := ExtendedConfigurationBody{ AvailableMethods: []string{"totp", "u2f"}, SecondFactorEnabled: false, - TOTPPeriod: validator.DefaultTOTPPeriod, + TOTPPeriod: schema.DefaultTOTPConfiguration.Period, } ExtendedConfigurationGet(s.mock.Ctx) s.mock.Assert200OK(s.T(), expectedBody) @@ -47,13 +46,13 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldServeDefaultMethodsAndMo s.mock.Ctx.Configuration = schema.Configuration{ DuoAPI: &schema.DuoAPIConfiguration{}, TOTP: &schema.TOTPConfiguration{ - Period: validator.DefaultTOTPPeriod, + Period: schema.DefaultTOTPConfiguration.Period, }, } expectedBody := ExtendedConfigurationBody{ AvailableMethods: []string{"totp", "u2f", "mobile_push"}, SecondFactorEnabled: false, - TOTPPeriod: validator.DefaultTOTPPeriod, + TOTPPeriod: schema.DefaultTOTPConfiguration.Period, } ExtendedConfigurationGet(s.mock.Ctx) s.mock.Assert200OK(s.T(), expectedBody) @@ -62,7 +61,7 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldServeDefaultMethodsAndMo func (s *SecondFactorAvailableMethodsFixture) TestShouldCheckSecondFactorIsDisabledWhenNoRuleIsSetToTwoFactor() { s.mock.Ctx.Configuration = schema.Configuration{ TOTP: &schema.TOTPConfiguration{ - Period: validator.DefaultTOTPPeriod, + Period: schema.DefaultTOTPConfiguration.Period, }, } s.mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(schema.AccessControlConfiguration{ @@ -86,14 +85,14 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldCheckSecondFactorIsDisab s.mock.Assert200OK(s.T(), ExtendedConfigurationBody{ AvailableMethods: []string{"totp", "u2f"}, SecondFactorEnabled: false, - TOTPPeriod: validator.DefaultTOTPPeriod, + TOTPPeriod: schema.DefaultTOTPConfiguration.Period, }) } func (s *SecondFactorAvailableMethodsFixture) TestShouldCheckSecondFactorIsEnabledWhenDefaultPolicySetToTwoFactor() { s.mock.Ctx.Configuration = schema.Configuration{ TOTP: &schema.TOTPConfiguration{ - Period: validator.DefaultTOTPPeriod, + Period: schema.DefaultTOTPConfiguration.Period, }, } s.mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(schema.AccessControlConfiguration{ @@ -117,14 +116,14 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldCheckSecondFactorIsEnabl s.mock.Assert200OK(s.T(), ExtendedConfigurationBody{ AvailableMethods: []string{"totp", "u2f"}, SecondFactorEnabled: true, - TOTPPeriod: validator.DefaultTOTPPeriod, + TOTPPeriod: schema.DefaultTOTPConfiguration.Period, }) } func (s *SecondFactorAvailableMethodsFixture) TestShouldCheckSecondFactorIsEnabledWhenSomePolicySetToTwoFactor() { s.mock.Ctx.Configuration = schema.Configuration{ TOTP: &schema.TOTPConfiguration{ - Period: validator.DefaultTOTPPeriod, + Period: schema.DefaultTOTPConfiguration.Period, }, } s.mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(schema.AccessControlConfiguration{ @@ -148,7 +147,7 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldCheckSecondFactorIsEnabl s.mock.Assert200OK(s.T(), ExtendedConfigurationBody{ AvailableMethods: []string{"totp", "u2f"}, SecondFactorEnabled: true, - TOTPPeriod: validator.DefaultTOTPPeriod, + TOTPPeriod: schema.DefaultTOTPConfiguration.Period, }) } diff --git a/internal/handlers/handler_firstfactor_test.go b/internal/handlers/handler_firstfactor_test.go index 12265502e..e15bf13b3 100644 --- a/internal/handlers/handler_firstfactor_test.go +++ b/internal/handlers/handler_firstfactor_test.go @@ -9,11 +9,12 @@ import ( "github.com/authelia/authelia/internal/mocks" "github.com/authelia/authelia/internal/models" - "github.com/authelia/authelia/internal/authentication" "github.com/golang/mock/gomock" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/authentication" ) type FirstFactorSuite struct { diff --git a/internal/handlers/handler_register_totp.go b/internal/handlers/handler_register_totp.go index 9dee14652..97c850a90 100644 --- a/internal/handlers/handler_register_totp.go +++ b/internal/handlers/handler_register_totp.go @@ -3,9 +3,10 @@ package handlers import ( "fmt" + "github.com/pquerna/otp/totp" + "github.com/authelia/authelia/internal/middlewares" "github.com/authelia/authelia/internal/session" - "github.com/pquerna/otp/totp" ) // identityRetrieverFromSession retriever computing the identity from the cookie session. diff --git a/internal/handlers/handler_register_u2f_step1.go b/internal/handlers/handler_register_u2f_step1.go index ff114a9bc..29c4ab051 100644 --- a/internal/handlers/handler_register_u2f_step1.go +++ b/internal/handlers/handler_register_u2f_step1.go @@ -3,8 +3,9 @@ package handlers import ( "fmt" - "github.com/authelia/authelia/internal/middlewares" "github.com/tstranex/u2f" + + "github.com/authelia/authelia/internal/middlewares" ) var u2fConfig = &u2f.Config{ diff --git a/internal/handlers/handler_register_u2f_step1_test.go b/internal/handlers/handler_register_u2f_step1_test.go index 89bfa2a2e..d806518d5 100644 --- a/internal/handlers/handler_register_u2f_step1_test.go +++ b/internal/handlers/handler_register_u2f_step1_test.go @@ -5,12 +5,13 @@ import ( "testing" "time" - "github.com/authelia/authelia/internal/middlewares" - "github.com/authelia/authelia/internal/mocks" "github.com/dgrijalva/jwt-go" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/middlewares" + "github.com/authelia/authelia/internal/mocks" ) type HandlerRegisterU2FStep1Suite struct { diff --git a/internal/handlers/handler_register_u2f_step2.go b/internal/handlers/handler_register_u2f_step2.go index 3af2fc279..6d3856fdd 100644 --- a/internal/handlers/handler_register_u2f_step2.go +++ b/internal/handlers/handler_register_u2f_step2.go @@ -4,8 +4,9 @@ import ( "crypto/elliptic" "fmt" - "github.com/authelia/authelia/internal/middlewares" "github.com/tstranex/u2f" + + "github.com/authelia/authelia/internal/middlewares" ) // SecondFactorU2FRegister handler validating the client has successfully validated the challenge diff --git a/internal/handlers/handler_sign_duo_test.go b/internal/handlers/handler_sign_duo_test.go index 2d0629333..7b10d5483 100644 --- a/internal/handlers/handler_sign_duo_test.go +++ b/internal/handlers/handler_sign_duo_test.go @@ -7,11 +7,12 @@ import ( "regexp" "testing" - "github.com/authelia/authelia/internal/duo" - "github.com/authelia/authelia/internal/mocks" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/duo" + "github.com/authelia/authelia/internal/mocks" ) type SecondFactorDuoPostSuite struct { diff --git a/internal/handlers/handler_sign_totp_test.go b/internal/handlers/handler_sign_totp_test.go index baf8ae3d3..e5375c823 100644 --- a/internal/handlers/handler_sign_totp_test.go +++ b/internal/handlers/handler_sign_totp_test.go @@ -5,11 +5,12 @@ import ( "regexp" "testing" - "github.com/authelia/authelia/internal/mocks" - "github.com/authelia/authelia/internal/session" "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" "github.com/tstranex/u2f" + + "github.com/authelia/authelia/internal/mocks" + "github.com/authelia/authelia/internal/session" ) type HandlerSignTOTPSuite struct { diff --git a/internal/handlers/handler_sign_u2f_step1.go b/internal/handlers/handler_sign_u2f_step1.go index 950161325..abeb74b47 100644 --- a/internal/handlers/handler_sign_u2f_step1.go +++ b/internal/handlers/handler_sign_u2f_step1.go @@ -4,10 +4,11 @@ import ( "crypto/elliptic" "fmt" + "github.com/tstranex/u2f" + "github.com/authelia/authelia/internal/middlewares" "github.com/authelia/authelia/internal/session" "github.com/authelia/authelia/internal/storage" - "github.com/tstranex/u2f" ) // SecondFactorU2FSignGet handler for initiating a signing request. diff --git a/internal/handlers/handler_sign_u2f_step1_test.go b/internal/handlers/handler_sign_u2f_step1_test.go index 4b8ecf8fc..13ddf594e 100644 --- a/internal/handlers/handler_sign_u2f_step1_test.go +++ b/internal/handlers/handler_sign_u2f_step1_test.go @@ -3,9 +3,10 @@ package handlers import ( "testing" - "github.com/authelia/authelia/internal/mocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/mocks" ) type HandlerSignU2FStep1Suite struct { diff --git a/internal/handlers/handler_sign_u2f_step2_test.go b/internal/handlers/handler_sign_u2f_step2_test.go index 87a8fbdc9..2961d94b7 100644 --- a/internal/handlers/handler_sign_u2f_step2_test.go +++ b/internal/handlers/handler_sign_u2f_step2_test.go @@ -5,11 +5,12 @@ import ( "regexp" "testing" - "github.com/authelia/authelia/internal/mocks" - "github.com/authelia/authelia/internal/session" "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" "github.com/tstranex/u2f" + + "github.com/authelia/authelia/internal/mocks" + "github.com/authelia/authelia/internal/session" ) type HandlerSignU2FStep2Suite struct { diff --git a/internal/handlers/handler_state_test.go b/internal/handlers/handler_state_test.go index e69ccebc9..72198357c 100644 --- a/internal/handlers/handler_state_test.go +++ b/internal/handlers/handler_state_test.go @@ -6,9 +6,10 @@ import ( "github.com/authelia/authelia/internal/mocks" - "github.com/authelia/authelia/internal/authentication" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/authentication" ) type StateGetSuite struct { diff --git a/internal/handlers/handler_user_info.go b/internal/handlers/handler_user_info.go index e77914efc..d03de6a1e 100644 --- a/internal/handlers/handler_user_info.go +++ b/internal/handlers/handler_user_info.go @@ -5,11 +5,12 @@ import ( "strings" "sync" + "github.com/sirupsen/logrus" + "github.com/authelia/authelia/internal/authentication" "github.com/authelia/authelia/internal/middlewares" "github.com/authelia/authelia/internal/storage" "github.com/authelia/authelia/internal/utils" - "github.com/sirupsen/logrus" ) func loadInfo(username string, storageProvider storage.Provider, preferences *UserPreferences, logger *logrus.Entry) []error { diff --git a/internal/handlers/handler_verify.go b/internal/handlers/handler_verify.go index aafa2667d..acf54c511 100644 --- a/internal/handlers/handler_verify.go +++ b/internal/handlers/handler_verify.go @@ -8,10 +8,11 @@ import ( "strings" "time" + "github.com/valyala/fasthttp" + "github.com/authelia/authelia/internal/authentication" "github.com/authelia/authelia/internal/authorization" "github.com/authelia/authelia/internal/middlewares" - "github.com/valyala/fasthttp" ) func isURLUnderProtectedDomain(url *url.URL, domain string) bool { @@ -155,8 +156,7 @@ func setForwardedHeaders(headers *fasthttp.ResponseHeader, username string, grou // hasUserBeenInactiveLongEnough check whether the user has been inactive for too long. func hasUserBeenInactiveLongEnough(ctx *middlewares.AutheliaCtx) (bool, error) { - // TODO(james-d-elliott): Convert to duration notation - maxInactivityPeriod := ctx.Configuration.Session.Inactivity + maxInactivityPeriod := int64(ctx.Providers.SessionProvider.Inactivity.Seconds()) if maxInactivityPeriod == 0 { return false, nil } diff --git a/internal/handlers/handler_verify_test.go b/internal/handlers/handler_verify_test.go index f65dbbd0c..6bd8e23b5 100644 --- a/internal/handlers/handler_verify_test.go +++ b/internal/handlers/handler_verify_test.go @@ -7,14 +7,17 @@ import ( "testing" "time" - "github.com/authelia/authelia/internal/authentication" - "github.com/authelia/authelia/internal/authorization" - "github.com/authelia/authelia/internal/configuration/schema" - "github.com/authelia/authelia/internal/mocks" + "github.com/authelia/authelia/internal/session" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/authentication" + "github.com/authelia/authelia/internal/authorization" + "github.com/authelia/authelia/internal/configuration/schema" + "github.com/authelia/authelia/internal/mocks" ) // Test getOriginalURL @@ -469,8 +472,38 @@ func TestShouldDestroySessionWhenInactiveForTooLong(t *testing.T) { clock := mocks.TestingClock{} clock.Set(time.Now()) - // TODO(james-d-elliott): Convert to duration notation - mock.Ctx.Configuration.Session.Inactivity = 10 + mock.Ctx.Configuration.Session.Inactivity = "10" + // Reload the session provider since the configuration is indirect + mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session) + assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity) + + userSession := mock.Ctx.GetSession() + userSession.Username = "john" + userSession.AuthenticationLevel = authentication.TwoFactor + userSession.LastActivity = clock.Now().Add(-1 * time.Hour).Unix() + mock.Ctx.SaveSession(userSession) + + mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com") + + VerifyGet(mock.Ctx) + + // The session has been destroyed + newUserSession := mock.Ctx.GetSession() + assert.Equal(t, "", newUserSession.Username) + assert.Equal(t, authentication.NotAuthenticated, newUserSession.AuthenticationLevel) +} + +func TestShouldDestroySessionWhenInactiveForTooLongUsingDurationNotation(t *testing.T) { + mock := mocks.NewMockAutheliaCtx(t) + defer mock.Close() + + clock := mocks.TestingClock{} + clock.Set(time.Now()) + + mock.Ctx.Configuration.Session.Inactivity = "10s" + // Reload the session provider since the configuration is indirect + mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session) + assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity) userSession := mock.Ctx.GetSession() userSession.Username = "john" @@ -495,8 +528,7 @@ func TestShouldKeepSessionWhenUserCheckedRememberMeAndIsInactiveForTooLong(t *te clock := mocks.TestingClock{} clock.Set(time.Now()) - // TODO(james-d-elliott): Convert to duration notation - mock.Ctx.Configuration.Session.Inactivity = 10 + mock.Ctx.Configuration.Session.Inactivity = "10" userSession := mock.Ctx.GetSession() userSession.Username = "john" @@ -522,8 +554,7 @@ func TestShouldKeepSessionWhenInactivityTimeoutHasNotBeenExceeded(t *testing.T) clock := mocks.TestingClock{} clock.Set(time.Now()) - // TODO(james-d-elliott): Convert to duration notation - mock.Ctx.Configuration.Session.Inactivity = 10 + mock.Ctx.Configuration.Session.Inactivity = "10" userSession := mock.Ctx.GetSession() userSession.Username = "john" diff --git a/internal/handlers/totp.go b/internal/handlers/totp.go index 83476d4dd..f04aa6c35 100644 --- a/internal/handlers/totp.go +++ b/internal/handlers/totp.go @@ -1,9 +1,10 @@ package handlers import ( + "time" + "github.com/pquerna/otp" "github.com/pquerna/otp/totp" - "time" ) type TOTPVerifier interface { diff --git a/internal/handlers/totp_mock.go b/internal/handlers/totp_mock.go index 09d2641ea..1dad3fedf 100644 --- a/internal/handlers/totp_mock.go +++ b/internal/handlers/totp_mock.go @@ -5,8 +5,9 @@ package handlers import ( - gomock "github.com/golang/mock/gomock" reflect "reflect" + + gomock "github.com/golang/mock/gomock" ) // MockTOTPVerifier is a mock of TOTPVerifier interface diff --git a/internal/handlers/types.go b/internal/handlers/types.go index de030ac8d..f6b65b1c8 100644 --- a/internal/handlers/types.go +++ b/internal/handlers/types.go @@ -1,8 +1,9 @@ package handlers import ( - "github.com/authelia/authelia/internal/authentication" "github.com/tstranex/u2f" + + "github.com/authelia/authelia/internal/authentication" ) // MethodList is the list of available methods. diff --git a/internal/handlers/u2f_mock.go b/internal/handlers/u2f_mock.go index 3e9022710..151adff67 100644 --- a/internal/handlers/u2f_mock.go +++ b/internal/handlers/u2f_mock.go @@ -5,9 +5,10 @@ package handlers import ( + reflect "reflect" + gomock "github.com/golang/mock/gomock" u2f "github.com/tstranex/u2f" - reflect "reflect" ) // MockU2FVerifier is a mock of U2FVerifier interface diff --git a/internal/middlewares/authelia_context.go b/internal/middlewares/authelia_context.go index 8d97e2c59..06044c591 100644 --- a/internal/middlewares/authelia_context.go +++ b/internal/middlewares/authelia_context.go @@ -7,11 +7,12 @@ import ( "strings" "github.com/asaskevich/govalidator" + "github.com/sirupsen/logrus" + "github.com/valyala/fasthttp" + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/session" "github.com/authelia/authelia/internal/utils" - "github.com/sirupsen/logrus" - "github.com/valyala/fasthttp" ) // NewRequestLogger create a new request logger for the given request. diff --git a/internal/middlewares/authelia_context_test.go b/internal/middlewares/authelia_context_test.go index 919ab2567..425589874 100644 --- a/internal/middlewares/authelia_context_test.go +++ b/internal/middlewares/authelia_context_test.go @@ -5,12 +5,13 @@ import ( "github.com/authelia/authelia/internal/session" - "github.com/authelia/authelia/internal/configuration/schema" - "github.com/authelia/authelia/internal/middlewares" - "github.com/authelia/authelia/internal/mocks" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/valyala/fasthttp" + + "github.com/authelia/authelia/internal/configuration/schema" + "github.com/authelia/authelia/internal/middlewares" + "github.com/authelia/authelia/internal/mocks" ) func TestShouldCallNextWithAutheliaCtx(t *testing.T) { diff --git a/internal/middlewares/identity_verification.go b/internal/middlewares/identity_verification.go index 8410c6616..09dfa788f 100644 --- a/internal/middlewares/identity_verification.go +++ b/internal/middlewares/identity_verification.go @@ -6,8 +6,9 @@ import ( "fmt" "time" - "github.com/authelia/authelia/internal/templates" jwt "github.com/dgrijalva/jwt-go" + + "github.com/authelia/authelia/internal/templates" ) // IdentityVerificationStart the handler for initiating the identity validation process. diff --git a/internal/middlewares/identity_verification_test.go b/internal/middlewares/identity_verification_test.go index e5917e01b..b0a85bbda 100644 --- a/internal/middlewares/identity_verification_test.go +++ b/internal/middlewares/identity_verification_test.go @@ -5,13 +5,14 @@ import ( "testing" "time" - "github.com/authelia/authelia/internal/middlewares" - "github.com/authelia/authelia/internal/mocks" - "github.com/authelia/authelia/internal/session" jwt "github.com/dgrijalva/jwt-go" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/middlewares" + "github.com/authelia/authelia/internal/mocks" + "github.com/authelia/authelia/internal/session" ) func newArgs(retriever func(ctx *middlewares.AutheliaCtx) (*session.Identity, error)) middlewares.IdentityVerificationStartArgs { diff --git a/internal/middlewares/types.go b/internal/middlewares/types.go index 1078538a7..525588221 100644 --- a/internal/middlewares/types.go +++ b/internal/middlewares/types.go @@ -1,6 +1,10 @@ package middlewares import ( + jwt "github.com/dgrijalva/jwt-go" + "github.com/sirupsen/logrus" + "github.com/valyala/fasthttp" + "github.com/authelia/authelia/internal/authentication" "github.com/authelia/authelia/internal/authorization" "github.com/authelia/authelia/internal/configuration/schema" @@ -9,9 +13,6 @@ import ( "github.com/authelia/authelia/internal/session" "github.com/authelia/authelia/internal/storage" "github.com/authelia/authelia/internal/utils" - jwt "github.com/dgrijalva/jwt-go" - "github.com/sirupsen/logrus" - "github.com/valyala/fasthttp" ) // AutheliaCtx contains all server variables related to Authelia. diff --git a/internal/mocks/mock_authelia_ctx.go b/internal/mocks/mock_authelia_ctx.go index 2037a19b7..19f375591 100644 --- a/internal/mocks/mock_authelia_ctx.go +++ b/internal/mocks/mock_authelia_ctx.go @@ -6,19 +6,21 @@ import ( "testing" "time" - "github.com/authelia/authelia/internal/regulation" - "github.com/authelia/authelia/internal/storage" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/authelia/authelia/internal/regulation" + "github.com/authelia/authelia/internal/storage" + + "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/valyala/fasthttp" + "github.com/authelia/authelia/internal/authorization" "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/middlewares" "github.com/authelia/authelia/internal/session" - "github.com/golang/mock/gomock" - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" - "github.com/valyala/fasthttp" ) // MockAutheliaCtx a mock of AutheliaCtx diff --git a/internal/mocks/mock_duo_api.go b/internal/mocks/mock_duo_api.go index e4dff156d..d0c930403 100644 --- a/internal/mocks/mock_duo_api.go +++ b/internal/mocks/mock_duo_api.go @@ -8,9 +8,10 @@ import ( url "net/url" reflect "reflect" + gomock "github.com/golang/mock/gomock" + duo "github.com/authelia/authelia/internal/duo" "github.com/authelia/authelia/internal/middlewares" - gomock "github.com/golang/mock/gomock" ) // MockAPI is a mock of API interface diff --git a/internal/mocks/mock_user_provider.go b/internal/mocks/mock_user_provider.go index 73d589d56..0872de6bd 100644 --- a/internal/mocks/mock_user_provider.go +++ b/internal/mocks/mock_user_provider.go @@ -7,8 +7,9 @@ package mocks import ( reflect "reflect" - authentication "github.com/authelia/authelia/internal/authentication" gomock "github.com/golang/mock/gomock" + + authentication "github.com/authelia/authelia/internal/authentication" ) // MockUserProvider is a mock of UserProvider interface diff --git a/internal/notification/notifier.go b/internal/notification/notifier.go index 12c29e3f4..d829261d7 100644 --- a/internal/notification/notifier.go +++ b/internal/notification/notifier.go @@ -2,5 +2,5 @@ package notification // Notifier interface for sending the identity verification link. type Notifier interface { - Send(recipient, subject, body string) error + Send(recipient, subject, body string) error } diff --git a/internal/notification/smtp_login_auth_test.go b/internal/notification/smtp_login_auth_test.go index 6366cdae1..744f50edb 100644 --- a/internal/notification/smtp_login_auth_test.go +++ b/internal/notification/smtp_login_auth_test.go @@ -20,11 +20,11 @@ func TestFullLoginAuth(t *testing.T) { auth := newLoginAuth(username, password, "mail.authelia.com") proto, _, err := auth.Start(serverInfo) - assert.Equal(t,"LOGIN", proto) + assert.Equal(t, "LOGIN", proto) require.NoError(t, err) toServer, err := auth.Next([]byte("Username:"), true) - assert.Equal(t,[]byte(username), toServer) + assert.Equal(t, []byte(username), toServer) require.NoError(t, err) toServer, err = auth.Next([]byte("Password:"), true) @@ -32,7 +32,7 @@ func TestFullLoginAuth(t *testing.T) { require.NoError(t, err) toServer, err = auth.Next([]byte(nil), false) - assert.Equal(t,[]byte(nil), toServer) + assert.Equal(t, []byte(nil), toServer) require.NoError(t, err) toServer, err = auth.Next([]byte("test"), true) @@ -60,7 +60,7 @@ func TestTLSNotNeededForLocalhost(t *testing.T) { auth := newLoginAuth("john", "strongpw123", "localhost") proto, _, err := auth.Start(serverInfo) - assert.Equal(t,"LOGIN", proto) + assert.Equal(t, "LOGIN", proto) require.NoError(t, err) } @@ -73,4 +73,4 @@ func TestTLSNeededForNonLocalhost(t *testing.T) { auth := newLoginAuth("john", "strongpw123", "mail.authelia.com") _, _, err := auth.Start(serverInfo) assert.EqualError(t, err, "connection over plain-text") -} \ No newline at end of file +} diff --git a/internal/notification/smtp_notifier.go b/internal/notification/smtp_notifier.go index 7902ec2c3..c9006c28f 100644 --- a/internal/notification/smtp_notifier.go +++ b/internal/notification/smtp_notifier.go @@ -9,9 +9,10 @@ import ( "net/smtp" "strings" + log "github.com/sirupsen/logrus" + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/utils" - log "github.com/sirupsen/logrus" ) // SMTPNotifier a notifier to send emails to SMTP servers. diff --git a/internal/regulation/regulator.go b/internal/regulation/regulator.go index 5fc6ead18..7cf8bd506 100644 --- a/internal/regulation/regulator.go +++ b/internal/regulation/regulator.go @@ -15,14 +15,24 @@ func NewRegulator(configuration *schema.RegulationConfiguration, provider storag regulator := &Regulator{storageProvider: provider} regulator.clock = clock if configuration != nil { - if configuration.FindTime > configuration.BanTime { + findTime, err := utils.ParseDurationString(configuration.FindTime) + if err != nil { + panic(err) + } + banTime, err := utils.ParseDurationString(configuration.BanTime) + if err != nil { + panic(err) + } + + if findTime > banTime { panic(fmt.Errorf("find_time cannot be greater than ban_time")) } + // Set regulator enabled only if MaxRetries is not 0. regulator.enabled = configuration.MaxRetries > 0 regulator.maxRetries = configuration.MaxRetries - regulator.findTime = time.Duration(configuration.FindTime) * time.Second - regulator.banTime = time.Duration(configuration.BanTime) * time.Second + regulator.findTime = findTime + regulator.banTime = banTime } return regulator } diff --git a/internal/regulation/regulator_test.go b/internal/regulation/regulator_test.go index 3bc04e718..b9b4e9030 100644 --- a/internal/regulation/regulator_test.go +++ b/internal/regulation/regulator_test.go @@ -4,14 +4,15 @@ import ( "testing" "time" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/mocks" "github.com/authelia/authelia/internal/models" "github.com/authelia/authelia/internal/regulation" "github.com/authelia/authelia/internal/storage" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" ) type RegulatorSuite struct { @@ -29,8 +30,8 @@ func (s *RegulatorSuite) SetupTest() { s.configuration = schema.RegulationConfiguration{ MaxRetries: 3, - BanTime: 180, - FindTime: 30, + BanTime: "180", + FindTime: "30", } s.clock.Set(time.Now()) } @@ -282,8 +283,8 @@ func (s *RegulatorSuite) TestShouldHaveRegulatorDisabled() { // Check Disabled Functionality configuration := schema.RegulationConfiguration{ MaxRetries: 0, - FindTime: 180, - BanTime: 180, + FindTime: "180", + BanTime: "180", } regulator := regulation.NewRegulator(&configuration, s.storageMock, &s.clock) @@ -293,8 +294,8 @@ func (s *RegulatorSuite) TestShouldHaveRegulatorDisabled() { // Check Enabled Functionality configuration = schema.RegulationConfiguration{ MaxRetries: 1, - FindTime: 180, - BanTime: 180, + FindTime: "180", + BanTime: "180", } regulator = regulation.NewRegulator(&configuration, s.storageMock, &s.clock) diff --git a/internal/server/server.go b/internal/server/server.go index 4206dbf54..f9d4208e5 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -5,14 +5,15 @@ import ( "os" "path" + duoapi "github.com/duosecurity/duo_api_golang" + "github.com/fasthttp/router" + "github.com/valyala/fasthttp" + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/duo" "github.com/authelia/authelia/internal/handlers" "github.com/authelia/authelia/internal/logging" "github.com/authelia/authelia/internal/middlewares" - duoapi "github.com/duosecurity/duo_api_golang" - "github.com/fasthttp/router" - "github.com/valyala/fasthttp" ) // StartServer start Authelia server with the given configuration and providers. diff --git a/internal/session/encrypting_serializer.go b/internal/session/encrypting_serializer.go index 7117f37d4..18badf7d9 100644 --- a/internal/session/encrypting_serializer.go +++ b/internal/session/encrypting_serializer.go @@ -4,8 +4,9 @@ import ( "crypto/sha256" "fmt" - "github.com/authelia/authelia/internal/utils" "github.com/fasthttp/session" + + "github.com/authelia/authelia/internal/utils" ) // EncryptingSerializer a serializer encrypting the data with AES-GCM with 256-bit keys. diff --git a/internal/session/mocks/mock_storer.go b/internal/session/mocks/mock_storer.go index 416f31625..3bed91486 100644 --- a/internal/session/mocks/mock_storer.go +++ b/internal/session/mocks/mock_storer.go @@ -5,10 +5,11 @@ package mock_session import ( - session "github.com/fasthttp/session" - gomock "github.com/golang/mock/gomock" reflect "reflect" time "time" + + session "github.com/fasthttp/session" + gomock "github.com/golang/mock/gomock" ) // MockStorer is a mock of Storer interface diff --git a/internal/session/provider.go b/internal/session/provider.go index c321d6298..723ade4fe 100644 --- a/internal/session/provider.go +++ b/internal/session/provider.go @@ -2,18 +2,20 @@ package session import ( "encoding/json" - "github.com/authelia/authelia/internal/utils" "time" - "github.com/authelia/authelia/internal/configuration/schema" fasthttpsession "github.com/fasthttp/session" "github.com/valyala/fasthttp" + + "github.com/authelia/authelia/internal/configuration/schema" + "github.com/authelia/authelia/internal/utils" ) // Provider a session provider. type Provider struct { sessionHolder *fasthttpsession.Session RememberMe time.Duration + Inactivity time.Duration } // NewProvider instantiate a session provider given a configuration. @@ -22,11 +24,19 @@ func NewProvider(configuration schema.SessionConfiguration) *Provider { provider := new(Provider) provider.sessionHolder = fasthttpsession.New(providerConfig.config) + duration, err := utils.ParseDurationString(configuration.RememberMeDuration) if err != nil { panic(err) } provider.RememberMe = duration + + duration, err = utils.ParseDurationString(configuration.Inactivity) + if err != nil { + panic(err) + } + provider.Inactivity = duration + err = provider.sessionHolder.SetProvider(providerConfig.providerName, providerConfig.providerConfig) if err != nil { panic(err) diff --git a/internal/session/provider_config.go b/internal/session/provider_config.go index 8d176ad15..b8c91de31 100644 --- a/internal/session/provider_config.go +++ b/internal/session/provider_config.go @@ -1,14 +1,13 @@ package session import ( - "time" - - "github.com/valyala/fasthttp" - - "github.com/authelia/authelia/internal/configuration/schema" "github.com/fasthttp/session" "github.com/fasthttp/session/memory" "github.com/fasthttp/session/redis" + "github.com/valyala/fasthttp" + + "github.com/authelia/authelia/internal/configuration/schema" + "github.com/authelia/authelia/internal/utils" ) // NewProviderConfig creates a configuration for creating the session provider @@ -24,13 +23,8 @@ func NewProviderConfig(configuration schema.SessionConfiguration) ProviderConfig // Only serve the header over HTTPS. config.Secure = true - // TODO(james-d-elliott): Convert to duration notation - if configuration.Expiration > 0 { - config.Expires = time.Duration(configuration.Expiration) * time.Second - } else { - // If Expiration is 0 then cookie expiration is disabled. - config.Expires = 0 - } + // Ignore the error as it will be handled by validator + config.Expires, _ = utils.ParseDurationString(configuration.Expiration) // TODO(c.michaud): Make this configurable by giving the list of IPs that are trustable. config.IsSecureFunc = func(*fasthttp.RequestCtx) bool { diff --git a/internal/session/provider_config_test.go b/internal/session/provider_config_test.go index 1f1c7d863..dea94cac0 100644 --- a/internal/session/provider_config_test.go +++ b/internal/session/provider_config_test.go @@ -5,13 +5,14 @@ import ( "testing" "time" - "github.com/authelia/authelia/internal/configuration/schema" - "github.com/authelia/authelia/internal/utils" "github.com/fasthttp/session" "github.com/fasthttp/session/memory" "github.com/fasthttp/session/redis" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/authelia/authelia/internal/configuration/schema" + "github.com/authelia/authelia/internal/utils" ) func TestShouldCreateInMemorySessionProvider(t *testing.T) { @@ -19,8 +20,7 @@ func TestShouldCreateInMemorySessionProvider(t *testing.T) { configuration := schema.SessionConfiguration{} configuration.Domain = "example.com" configuration.Name = "my_session" - // TODO(james-d-elliott): Convert to duration notation - configuration.Expiration = 40 + configuration.Expiration = "40" providerConfig := NewProviderConfig(configuration) assert.Equal(t, "my_session", providerConfig.config.CookieName) @@ -38,8 +38,7 @@ func TestShouldCreateRedisSessionProvider(t *testing.T) { configuration := schema.SessionConfiguration{} configuration.Domain = "example.com" configuration.Name = "my_session" - // TODO(james-d-elliott): Convert to duration notation - configuration.Expiration = 40 + configuration.Expiration = "40" configuration.Redis = &schema.RedisSessionConfiguration{ Host: "redis.example.com", Port: 6379, @@ -68,8 +67,7 @@ func TestShouldSetDbNumber(t *testing.T) { configuration := schema.SessionConfiguration{} configuration.Domain = "example.com" configuration.Name = "my_session" - // TODO(james-d-elliott): Convert to duration notation - configuration.Expiration = 40 + configuration.Expiration = "40" configuration.Redis = &schema.RedisSessionConfiguration{ Host: "redis.example.com", Port: 6379, diff --git a/internal/session/provider_test.go b/internal/session/provider_test.go index c136d874d..d8c5248b5 100644 --- a/internal/session/provider_test.go +++ b/internal/session/provider_test.go @@ -3,13 +3,11 @@ package session import ( "testing" - "github.com/authelia/authelia/internal/authentication" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/valyala/fasthttp" + "github.com/authelia/authelia/internal/authentication" "github.com/authelia/authelia/internal/configuration/schema" ) @@ -18,8 +16,7 @@ func TestShouldInitializerSession(t *testing.T) { configuration := schema.SessionConfiguration{} configuration.Domain = "example.com" configuration.Name = "my_session" - // TODO(james-d-elliott): Convert to duration notation - configuration.Expiration = 40 + configuration.Expiration = "40" provider := NewProvider(configuration) session, err := provider.GetSession(ctx) @@ -33,8 +30,7 @@ func TestShouldUpdateSession(t *testing.T) { configuration := schema.SessionConfiguration{} configuration.Domain = "example.com" configuration.Name = "my_session" - // TODO(james-d-elliott): Convert to duration notation - configuration.Expiration = 40 + configuration.Expiration = "40" provider := NewProvider(configuration) session, _ := provider.GetSession(ctx) @@ -59,8 +55,7 @@ func TestShouldDestroySessionAndWipeSessionData(t *testing.T) { configuration := schema.SessionConfiguration{} configuration.Domain = "example.com" configuration.Name = "my_session" - // TODO(james-d-elliott): Convert to duration notation - configuration.Expiration = 40 + configuration.Expiration = "40" provider := NewProvider(configuration) session, err := provider.GetSession(ctx) diff --git a/internal/session/types.go b/internal/session/types.go index 3417808eb..a5e2a906d 100644 --- a/internal/session/types.go +++ b/internal/session/types.go @@ -1,9 +1,10 @@ package session import ( - "github.com/authelia/authelia/internal/authentication" "github.com/fasthttp/session" "github.com/tstranex/u2f" + + "github.com/authelia/authelia/internal/authentication" ) // ProviderConfig is the configuration used to create the session provider. diff --git a/internal/storage/mysql_provider.go b/internal/storage/mysql_provider.go index fa270e0c1..10a0f9771 100644 --- a/internal/storage/mysql_provider.go +++ b/internal/storage/mysql_provider.go @@ -4,9 +4,10 @@ import ( "database/sql" "fmt" + _ "github.com/go-sql-driver/mysql" // Load the MySQL Driver used in the connection string. + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/logging" - _ "github.com/go-sql-driver/mysql" // Load the MySQL Driver used in the connection string. ) // MySQLProvider is a MySQL provider diff --git a/internal/storage/postgres_provider.go b/internal/storage/postgres_provider.go index d19919086..0b246d3a3 100644 --- a/internal/storage/postgres_provider.go +++ b/internal/storage/postgres_provider.go @@ -5,9 +5,10 @@ import ( "fmt" "strings" + _ "github.com/lib/pq" // Load the PostgreSQL Driver used in the connection string. + "github.com/authelia/authelia/internal/configuration/schema" "github.com/authelia/authelia/internal/logging" - _ "github.com/lib/pq" // Load the PostgreSQL Driver used in the connection string. ) // PostgreSQLProvider is a Postrgres provider diff --git a/internal/storage/provider_mock.go b/internal/storage/provider_mock.go index 9126e4897..1d0c43b3c 100644 --- a/internal/storage/provider_mock.go +++ b/internal/storage/provider_mock.go @@ -5,10 +5,12 @@ package storage import ( - models "github.com/authelia/authelia/internal/models" - gomock "github.com/golang/mock/gomock" reflect "reflect" time "time" + + gomock "github.com/golang/mock/gomock" + + models "github.com/authelia/authelia/internal/models" ) // MockProvider is a mock of Provider interface diff --git a/internal/storage/sqlite_provider.go b/internal/storage/sqlite_provider.go index aa604d534..db8bfc739 100644 --- a/internal/storage/sqlite_provider.go +++ b/internal/storage/sqlite_provider.go @@ -4,8 +4,9 @@ import ( "database/sql" "fmt" - "github.com/authelia/authelia/internal/logging" _ "github.com/mattn/go-sqlite3" // Load the SQLite Driver used in the connection string. + + "github.com/authelia/authelia/internal/logging" ) // SQLiteProvider is a sqlite3 provider diff --git a/internal/suites/docker.go b/internal/suites/docker.go index 64879edc4..953565eab 100644 --- a/internal/suites/docker.go +++ b/internal/suites/docker.go @@ -6,8 +6,9 @@ import ( "os/exec" "strings" - "github.com/authelia/authelia/internal/utils" log "github.com/sirupsen/logrus" + + "github.com/authelia/authelia/internal/utils" ) // DockerEnvironment represent a docker environment diff --git a/internal/suites/environment.go b/internal/suites/environment.go index d59bc48e0..343a27688 100644 --- a/internal/suites/environment.go +++ b/internal/suites/environment.go @@ -5,8 +5,9 @@ import ( "strings" "time" - "github.com/authelia/authelia/internal/utils" log "github.com/sirupsen/logrus" + + "github.com/authelia/authelia/internal/utils" ) func waitUntilServiceLogDetected( diff --git a/internal/suites/suite_kubernetes.go b/internal/suites/suite_kubernetes.go index 57129e99c..a1302d5dc 100644 --- a/internal/suites/suite_kubernetes.go +++ b/internal/suites/suite_kubernetes.go @@ -5,8 +5,9 @@ import ( "os" "time" - "github.com/authelia/authelia/internal/utils" log "github.com/sirupsen/logrus" + + "github.com/authelia/authelia/internal/utils" ) var kubernetesSuiteName = "Kubernetes" diff --git a/internal/suites/suite_standalone_test.go b/internal/suites/suite_standalone_test.go index 1d6b36007..37e0dbfe0 100644 --- a/internal/suites/suite_standalone_test.go +++ b/internal/suites/suite_standalone_test.go @@ -10,9 +10,10 @@ import ( "testing" "time" - "github.com/authelia/authelia/internal/storage" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + + "github.com/authelia/authelia/internal/storage" ) type StandaloneWebDriverSuite struct { diff --git a/internal/utils/time_test.go b/internal/utils/time_test.go index a589d6d88..a4104720b 100644 --- a/internal/utils/time_test.go +++ b/internal/utils/time_test.go @@ -1,9 +1,10 @@ package utils import ( - "github.com/stretchr/testify/assert" "testing" "time" + + "github.com/stretchr/testify/assert" ) func TestShouldParseDurationString(t *testing.T) {