From ea86b6252718059e120445afc5eacaf784d3608d Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Tue, 21 Jan 2020 21:15:40 +0100 Subject: [PATCH] Add validation for notifier configuration. --- internal/configuration/schema/notifier.go | 9 -- .../configuration/validator/configuration.go | 6 + .../validator/configuration_test.go | 28 +++- internal/configuration/validator/notifier.go | 40 ++++++ .../configuration/validator/notifier_test.go | 120 ++++++++++++++++++ 5 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 internal/configuration/validator/notifier.go create mode 100644 internal/configuration/validator/notifier_test.go diff --git a/internal/configuration/schema/notifier.go b/internal/configuration/schema/notifier.go index 855e3ee0..e82cabbe 100644 --- a/internal/configuration/schema/notifier.go +++ b/internal/configuration/schema/notifier.go @@ -5,14 +5,6 @@ type FileSystemNotifierConfiguration struct { Filename string `yaml:"filename"` } -// EmailNotifierConfiguration represents the configuration of the email service notifier (like GMAIL API). -type EmailNotifierConfiguration struct { - Username string `yaml:"username"` - Password string `yaml:"password"` - Sender string `yaml:"sender"` - Service string `yaml:"service"` -} - // SMTPNotifierConfiguration represents the configuration of the SMTP server to send emails with. type SMTPNotifierConfiguration struct { Username string `yaml:"username"` @@ -28,6 +20,5 @@ type SMTPNotifierConfiguration struct { // NotifierConfiguration represents the configuration of the notifier to use when sending notifications to users. type NotifierConfiguration struct { FileSystem *FileSystemNotifierConfiguration `yaml:"filesystem"` - Email *EmailNotifierConfiguration `yaml:"email"` SMTP *SMTPNotifierConfiguration `yaml:"smtp"` } diff --git a/internal/configuration/validator/configuration.go b/internal/configuration/validator/configuration.go index b4b45c5a..9b048023 100644 --- a/internal/configuration/validator/configuration.go +++ b/internal/configuration/validator/configuration.go @@ -35,5 +35,11 @@ func Validate(configuration *schema.Configuration, validator *schema.StructValid ValidateTOTP(configuration.TOTP, validator) } + if configuration.Notifier == nil { + validator.Push(fmt.Errorf("A notifier configuration must be provided")) + } else { + ValidateNotifier(configuration.Notifier, validator) + } + ValidateSQLStorage(configuration.Storage, validator) } diff --git a/internal/configuration/validator/configuration_test.go b/internal/configuration/validator/configuration_test.go index 22630c72..70561fe9 100644 --- a/internal/configuration/validator/configuration_test.go +++ b/internal/configuration/validator/configuration_test.go @@ -5,6 +5,7 @@ import ( "github.com/authelia/authelia/internal/configuration/schema" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func newDefaultConfig() schema.Configuration { @@ -25,6 +26,11 @@ func newDefaultConfig() schema.Configuration { Path: "abc", }, } + config.Notifier = &schema.NotifierConfiguration{ + FileSystem: &schema.FileSystemNotifierConfiguration{ + Filename: "/tmp/file", + }, + } return config } @@ -34,7 +40,7 @@ func TestShouldNotUpdateConfig(t *testing.T) { Validate(&config, validator) - assert.Len(t, validator.Errors(), 0) + require.Len(t, validator.Errors(), 0) assert.Equal(t, 9090, config.Port) assert.Equal(t, "info", config.LogsLevel) } @@ -46,7 +52,7 @@ func TestShouldValidateAndUpdatePort(t *testing.T) { Validate(&config, validator) - assert.Len(t, validator.Errors(), 0) + require.Len(t, validator.Errors(), 0) assert.Equal(t, 8080, config.Port) } @@ -57,7 +63,7 @@ func TestShouldValidateAndUpdateHost(t *testing.T) { Validate(&config, validator) - assert.Len(t, validator.Errors(), 0) + require.Len(t, validator.Errors(), 0) assert.Equal(t, "0.0.0.0", config.Host) } @@ -68,6 +74,20 @@ func TestShouldValidateAndUpdateLogsLevel(t *testing.T) { Validate(&config, validator) - assert.Len(t, validator.Errors(), 0) + require.Len(t, validator.Errors(), 0) assert.Equal(t, "info", config.LogsLevel) } + +func TestShouldEnsureNotifierConfigIsProvided(t *testing.T) { + validator := schema.NewStructValidator() + config := newDefaultConfig() + + Validate(&config, validator) + require.Len(t, validator.Errors(), 0) + + config.Notifier = nil + + Validate(&config, validator) + require.Len(t, validator.Errors(), 1) + assert.EqualError(t, validator.Errors()[0], "A notifier configuration must be provided") +} diff --git a/internal/configuration/validator/notifier.go b/internal/configuration/validator/notifier.go new file mode 100644 index 00000000..22c0a473 --- /dev/null +++ b/internal/configuration/validator/notifier.go @@ -0,0 +1,40 @@ +package validator + +import "github.com/authelia/authelia/internal/configuration/schema" + +import "fmt" + +// ValidateSession validates and update session configuration. +func ValidateNotifier(configuration *schema.NotifierConfiguration, validator *schema.StructValidator) { + if configuration.SMTP == nil && configuration.FileSystem == nil { + validator.Push(fmt.Errorf("Notifier should be either `smtp` or `filesystem`")) + return + } + + if configuration.SMTP != nil && configuration.FileSystem != nil { + validator.Push(fmt.Errorf("Notifier should be either `smtp` or `filesystem`")) + return + } + + if configuration.FileSystem != nil { + if configuration.FileSystem.Filename == "" { + validator.Push(fmt.Errorf("Filename of filesystem notifier must not be empty")) + } + return + } + + if configuration.SMTP != nil { + if configuration.SMTP.Host == "" { + validator.Push(fmt.Errorf("Host of SMTP notifier must be provided")) + } + + if configuration.SMTP.Port == 0 { + validator.Push(fmt.Errorf("Port of SMTP notifier must be provided")) + } + + if configuration.SMTP.Sender == "" { + validator.Push(fmt.Errorf("Sender of SMTP notifier must be provided")) + } + return + } +} diff --git a/internal/configuration/validator/notifier_test.go b/internal/configuration/validator/notifier_test.go new file mode 100644 index 00000000..17a8c5bc --- /dev/null +++ b/internal/configuration/validator/notifier_test.go @@ -0,0 +1,120 @@ +package validator + +import ( + "testing" + + "github.com/authelia/authelia/internal/configuration/schema" + "github.com/stretchr/testify/suite" +) + +type NotifierSuite struct { + suite.Suite + + configuration schema.NotifierConfiguration +} + +func (s *NotifierSuite) SetupTest() { + s.configuration.SMTP = &schema.SMTPNotifierConfiguration{ + Username: "john", + Password: "password", + Sender: "admin@example.com", + Host: "example.com", + Port: 25, + } +} + +func (s *NotifierSuite) TestShouldEnsureAtLeastSMTPOrFilesystemIsProvided() { + validator := schema.NewStructValidator() + ValidateNotifier(&s.configuration, validator) + + errors := validator.Errors() + s.Require().Len(errors, 0) + + s.configuration.SMTP = nil + + ValidateNotifier(&s.configuration, validator) + + errors = validator.Errors() + s.Require().Len(errors, 1) + s.Assert().EqualError(errors[0], "Notifier should be either `smtp` or `filesystem`") +} + +func (s *NotifierSuite) TestShouldEnsureEitherSMTPOrFilesystemIsProvided() { + validator := schema.NewStructValidator() + ValidateNotifier(&s.configuration, validator) + + errors := validator.Errors() + s.Require().Len(errors, 0) + + s.configuration.FileSystem = &schema.FileSystemNotifierConfiguration{ + Filename: "test", + } + + ValidateNotifier(&s.configuration, validator) + + errors = validator.Errors() + s.Require().Len(errors, 1) + s.Assert().EqualError(errors[0], "Notifier should be either `smtp` or `filesystem`") +} + +func (s *NotifierSuite) TestShouldEnsureFilenameOfFilesystemNotifierIsProvided() { + validator := schema.NewStructValidator() + + s.configuration.SMTP = nil + s.configuration.FileSystem = &schema.FileSystemNotifierConfiguration{ + Filename: "test", + } + ValidateNotifier(&s.configuration, validator) + + errors := validator.Errors() + s.Require().Len(errors, 0) + + s.configuration.FileSystem.Filename = "" + + ValidateNotifier(&s.configuration, validator) + + errors = validator.Errors() + s.Require().Len(errors, 1) + s.Assert().EqualError(errors[0], "Filename of filesystem notifier must not be empty") +} + +func (s *NotifierSuite) TestShouldEnsureHostAndPortOfSMTPNotifierAreProvided() { + s.configuration.FileSystem = nil + validator := schema.NewStructValidator() + ValidateNotifier(&s.configuration, validator) + + errors := validator.Errors() + s.Require().Len(errors, 0) + + s.configuration.SMTP.Host = "" + s.configuration.SMTP.Port = 0 + + ValidateNotifier(&s.configuration, validator) + + errors = validator.Errors() + s.Require().Len(errors, 2) + s.Assert().EqualError(errors[0], "Host of SMTP notifier must be provided") + s.Assert().EqualError(errors[1], "Port of SMTP notifier must be provided") +} + +func (s *NotifierSuite) TestShouldEnsureSenderOfSMTPNotifierAreProvided() { + s.configuration.FileSystem = nil + + validator := schema.NewStructValidator() + ValidateNotifier(&s.configuration, validator) + + errors := validator.Errors() + s.Require().Len(errors, 0) + + s.configuration.SMTP.Sender = "" + + ValidateNotifier(&s.configuration, validator) + + errors = validator.Errors() + s.Require().Len(errors, 1) + s.Assert().EqualError(errors[0], "Sender of SMTP notifier must be provided") +} + +func TestNotifierSuite(t *testing.T) { + suite.Run(t, new(NotifierSuite)) +}