diff --git a/config.template.yml b/config.template.yml index 9a8bf7760..7311acd7e 100644 --- a/config.template.yml +++ b/config.template.yml @@ -361,6 +361,9 @@ notifier: host: 127.0.0.1 port: 1025 sender: admin@example.com + # Subject configuration of the emails sent. + # {title} is replaced by the text from the notifier + subject: "[Authelia] {title}" ## disable_require_tls: false ## disable_verify_cert: false ## trusted_cert: "" diff --git a/docs/configuration/notifier/smtp.md b/docs/configuration/notifier/smtp.md index 01c6f8f72..1fe17008a 100644 --- a/docs/configuration/notifier/smtp.md +++ b/docs/configuration/notifier/smtp.md @@ -12,7 +12,16 @@ nav_order: 2 It can be configured as described below. ```yaml +# Configuration of the notification system. +# +# Notifications are sent to users when they require a password reset, a u2f +# registration or a TOTP registration. +# Use only an available configuration: filesystem, smtp notifier: + # For testing purpose, notifications can be sent in a file + ## filesystem: + ## filename: /tmp/authelia/notification.txt + # Use a SMTP server for sending notifications. Authelia uses PLAIN or LOGIN method to authenticate. # [Security] By default Authelia will: # - force all SMTP connections over TLS including unauthenticated connections @@ -31,6 +40,9 @@ notifier: host: 127.0.0.1 port: 1025 sender: admin@example.com + # Subject configuration of the emails sent. + # {title} is replaced by the text from the notifier + subject: "[Authelia] {title}" ## disable_require_tls: false ## disable_verify_cert: false ## trusted_cert: "" @@ -50,4 +62,4 @@ notifier: sender: admin@example.com host: smtp.gmail.com port: 587 -``` \ No newline at end of file +``` diff --git a/internal/configuration/schema/notifier.go b/internal/configuration/schema/notifier.go index ce2db6f73..4b79874db 100644 --- a/internal/configuration/schema/notifier.go +++ b/internal/configuration/schema/notifier.go @@ -10,6 +10,7 @@ type SMTPNotifierConfiguration struct { Username string `mapstructure:"username"` Password string `mapstructure:"password"` Sender string `mapstructure:"sender"` + Subject string `mapstructure:"subject"` Host string `mapstructure:"host"` Port int `mapstructure:"port"` TrustedCert string `mapstructure:"trusted_cert"` @@ -22,3 +23,7 @@ type NotifierConfiguration struct { FileSystem *FileSystemNotifierConfiguration `mapstructure:"filesystem"` SMTP *SMTPNotifierConfiguration `mapstructure:"smtp"` } + +var DefaultSMTPNotifierConfiguration = SMTPNotifierConfiguration{ + Subject: "[Authelia] {title}", +} diff --git a/internal/configuration/validator/notifier.go b/internal/configuration/validator/notifier.go index 478d60eba..68783475a 100644 --- a/internal/configuration/validator/notifier.go +++ b/internal/configuration/validator/notifier.go @@ -37,6 +37,10 @@ func ValidateNotifier(configuration *schema.NotifierConfiguration, validator *sc if configuration.SMTP.Sender == "" { validator.Push(fmt.Errorf("Sender of SMTP notifier must be provided")) } + + if configuration.SMTP.Subject == "" { + configuration.SMTP.Subject = schema.DefaultSMTPNotifierConfiguration.Subject + } return } } diff --git a/internal/handlers/handler_register_totp.go b/internal/handlers/handler_register_totp.go index 97c850a90..8fa3288a0 100644 --- a/internal/handlers/handler_register_totp.go +++ b/internal/handlers/handler_register_totp.go @@ -29,7 +29,6 @@ func isTokenUserValidFor2FARegistration(ctx *middlewares.AutheliaCtx, username s // SecondFactorTOTPIdentityStart the handler for initiating the identity validation. var SecondFactorTOTPIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ - MailSubject: "[Authelia] Register your mobile", MailTitle: "Register your mobile", MailButtonContent: "Register", TargetEndpoint: "/one-time-password/register", diff --git a/internal/handlers/handler_register_u2f_step1.go b/internal/handlers/handler_register_u2f_step1.go index 29c4ab051..9ce5d8eb6 100644 --- a/internal/handlers/handler_register_u2f_step1.go +++ b/internal/handlers/handler_register_u2f_step1.go @@ -16,7 +16,6 @@ var u2fConfig = &u2f.Config{ // SecondFactorU2FIdentityStart the handler for initiating the identity validation. var SecondFactorU2FIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ - MailSubject: "[Authelia] Register your key", MailTitle: "Register your key", MailButtonContent: "Register", TargetEndpoint: "/security-key/register", diff --git a/internal/handlers/handler_reset_password_step1.go b/internal/handlers/handler_reset_password_step1.go index da70942f3..697dff864 100644 --- a/internal/handlers/handler_reset_password_step1.go +++ b/internal/handlers/handler_reset_password_step1.go @@ -35,7 +35,6 @@ func identityRetrieverFromStorage(ctx *middlewares.AutheliaCtx) (*session.Identi // ResetPasswordIdentityStart the handler for initiating the identity validation for resetting a password. // We need to ensure the attacker cannot perform user enumeration by always replying with 200 whatever what happens in backend. var ResetPasswordIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ - MailSubject: "[Authelia] Reset your password", MailTitle: "Reset your password", MailButtonContent: "Reset", TargetEndpoint: "/reset-password/step2", diff --git a/internal/middlewares/identity_verification.go b/internal/middlewares/identity_verification.go index 09dfa788f..c56cd7f86 100644 --- a/internal/middlewares/identity_verification.go +++ b/internal/middlewares/identity_verification.go @@ -78,7 +78,7 @@ func IdentityVerificationStart(args IdentityVerificationStartArgs) RequestHandle ctx.Logger.Debugf("Sending an email to user %s (%s) to confirm identity for registering a device.", identity.Username, identity.Email) - err = ctx.Providers.Notifier.Send(identity.Email, args.MailSubject, buf.String()) + err = ctx.Providers.Notifier.Send(identity.Email, args.MailTitle, buf.String()) if err != nil { ctx.Error(err, operationFailedMessage) diff --git a/internal/middlewares/identity_verification_test.go b/internal/middlewares/identity_verification_test.go index b0a85bbda..e1a17dbc0 100644 --- a/internal/middlewares/identity_verification_test.go +++ b/internal/middlewares/identity_verification_test.go @@ -19,7 +19,6 @@ func newArgs(retriever func(ctx *middlewares.AutheliaCtx) (*session.Identity, er return middlewares.IdentityVerificationStartArgs{ ActionClaim: "Claim", MailButtonContent: "Register", - MailSubject: "Subject", MailTitle: "Title", TargetEndpoint: "/target", IdentityRetrieverFunc: retriever, @@ -77,7 +76,7 @@ func TestShouldFailSendingAnEmail(t *testing.T) { Return(nil) mock.NotifierMock.EXPECT(). - Send(gomock.Eq("john@example.com"), gomock.Eq("Subject"), gomock.Any()). + Send(gomock.Eq("john@example.com"), gomock.Eq("Title"), gomock.Any()). Return(fmt.Errorf("no notif")) args := newArgs(defaultRetriever) @@ -136,7 +135,7 @@ func TestShouldSucceedIdentityVerificationStartProcess(t *testing.T) { Return(nil) mock.NotifierMock.EXPECT(). - Send(gomock.Eq("john@example.com"), gomock.Eq("Subject"), gomock.Any()). + Send(gomock.Eq("john@example.com"), gomock.Eq("Title"), gomock.Any()). Return(nil) args := newArgs(defaultRetriever) diff --git a/internal/middlewares/types.go b/internal/middlewares/types.go index 525588221..06658c904 100644 --- a/internal/middlewares/types.go +++ b/internal/middlewares/types.go @@ -47,7 +47,6 @@ type Middleware = func(RequestHandler) RequestHandler // of the identity verification process. type IdentityVerificationStartArgs struct { // Email template needs a subject, a title and the content of the button. - MailSubject string MailTitle string MailButtonContent string diff --git a/internal/notification/smtp_notifier.go b/internal/notification/smtp_notifier.go index c9006c28f..65ee2acba 100644 --- a/internal/notification/smtp_notifier.go +++ b/internal/notification/smtp_notifier.go @@ -26,6 +26,7 @@ type SMTPNotifier struct { disableVerifyCert bool disableRequireTLS bool address string + subject string client *smtp.Client tlsConfig *tls.Config } @@ -42,6 +43,7 @@ func NewSMTPNotifier(configuration schema.SMTPNotifierConfiguration) *SMTPNotifi disableVerifyCert: configuration.DisableVerifyCert, disableRequireTLS: configuration.DisableRequireTLS, address: fmt.Sprintf("%s:%d", configuration.Host, configuration.Port), + subject: configuration.Subject, } notifier.initializeTLSConfig() return notifier @@ -231,7 +233,8 @@ func (n *SMTPNotifier) cleanup() { } // Send an email -func (n *SMTPNotifier) Send(recipient, subject, body string) error { +func (n *SMTPNotifier) Send(recipient, title, body string) error { + subject := strings.ReplaceAll(n.subject, "{title}", title) if err := n.dial(); err != nil { return err }