fix(notification): smtp auth not configured (#4647)

This fixes an issue introduced by the pending migration to the new SMTP library in 0bb657e where the auth mechanism is never defined. This only affects commits that are yet to be versioned.
pull/4645/head
James Elliott 2022-12-26 21:39:19 +11:00 committed by GitHub
parent 3ecb9f1d44
commit 7b8ed46537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 94 additions and 1 deletions

View File

@ -0,0 +1,86 @@
package notification
import (
"fmt"
"net/smtp"
"strings"
gomail "github.com/wneessen/go-mail"
"github.com/wneessen/go-mail/auth"
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/utils"
)
// NewOpportunisticSMTPAuth is an opportunistic smtp.Auth implementation.
func NewOpportunisticSMTPAuth(config *schema.SMTPNotifierConfiguration) *OpportunisticSMTPAuth {
if config.Username == "" && config.Password == "" {
return nil
}
return &OpportunisticSMTPAuth{
username: config.Username,
password: config.Password,
host: config.Host,
}
}
// OpportunisticSMTPAuth is an opportunistic smtp.Auth implementation.
type OpportunisticSMTPAuth struct {
username, password, host string
satPreference []gomail.SMTPAuthType
sa smtp.Auth
}
// Start begins an authentication with a server.
// It returns the name of the authentication protocol
// and optionally data to include in the initial AUTH message
// sent to the server.
// If it returns a non-nil error, the SMTP client aborts
// the authentication attempt and closes the connection.
func (a *OpportunisticSMTPAuth) Start(server *smtp.ServerInfo) (proto string, toServer []byte, err error) {
for _, pref := range a.satPreference {
if utils.IsStringInSlice(string(pref), server.Auth) {
switch pref {
case gomail.SMTPAuthPlain:
a.sa = smtp.PlainAuth("", a.username, a.password, a.host)
case gomail.SMTPAuthLogin:
a.sa = auth.LoginAuth(a.username, a.password, a.host)
case gomail.SMTPAuthCramMD5:
a.sa = smtp.CRAMMD5Auth(a.username, a.password)
}
break
}
}
if a.sa == nil {
for _, sa := range server.Auth {
switch gomail.SMTPAuthType(sa) {
case gomail.SMTPAuthPlain:
a.sa = smtp.PlainAuth("", a.username, a.password, a.host)
case gomail.SMTPAuthLogin:
a.sa = auth.LoginAuth(a.username, a.password, a.host)
case gomail.SMTPAuthCramMD5:
a.sa = smtp.CRAMMD5Auth(a.username, a.password)
}
}
}
if a.sa == nil {
return "", nil, fmt.Errorf("unsupported SMTP AUTH types: %s", strings.Join(server.Auth, ", "))
}
return a.sa.Start(server)
}
// Next continues the authentication. The server has just sent
// the fromServer data. If more is true, the server expects a
// response, which Next should return as toServer; otherwise
// Next should return toServer == nil.
// If Next returns a non-nil error, the SMTP client aborts
// the authentication attempt and closes the connection.
func (a *OpportunisticSMTPAuth) Next(fromServer []byte, more bool) (toServer []byte, err error) {
return a.sa.Next(fromServer, more)
}

View File

@ -22,7 +22,6 @@ func NewSMTPNotifier(config *schema.SMTPNotifierConfiguration, certPool *x509.Ce
opts := []gomail.Option{ opts := []gomail.Option{
gomail.WithPort(config.Port), gomail.WithPort(config.Port),
gomail.WithTLSConfig(utils.NewTLSConfig(config.TLS, certPool)), gomail.WithTLSConfig(utils.NewTLSConfig(config.TLS, certPool)),
gomail.WithPassword(config.Password),
gomail.WithHELO(config.Identifier), gomail.WithHELO(config.Identifier),
} }
@ -65,6 +64,7 @@ type SMTPNotifier struct {
opts []gomail.Option opts []gomail.Option
} }
// StartupCheck implements model.StartupCheck to perform startup check operations.
func (n *SMTPNotifier) StartupCheck() (err error) { func (n *SMTPNotifier) StartupCheck() (err error) {
var client *gomail.Client var client *gomail.Client
@ -85,6 +85,7 @@ func (n *SMTPNotifier) StartupCheck() (err error) {
return nil return nil
} }
// Send a notification via the SMTPNotifier.
func (n *SMTPNotifier) Send(ctx context.Context, recipient mail.Address, subject string, et *templates.EmailTemplate, data any) (err error) { func (n *SMTPNotifier) Send(ctx context.Context, recipient mail.Address, subject string, et *templates.EmailTemplate, data any) (err error) {
msg := gomail.NewMsg( msg := gomail.NewMsg(
gomail.WithMIMEVersion(gomail.Mime10), gomail.WithMIMEVersion(gomail.Mime10),
@ -118,10 +119,16 @@ func (n *SMTPNotifier) Send(ctx context.Context, recipient mail.Address, subject
var client *gomail.Client var client *gomail.Client
n.log.Debugf("creating client with %d options: %+v", len(n.opts), n.opts)
if client, err = gomail.NewClient(n.config.Host, n.opts...); err != nil { if client, err = gomail.NewClient(n.config.Host, n.opts...); err != nil {
return fmt.Errorf("notifier: smtp: failed to establish client: %w", err) return fmt.Errorf("notifier: smtp: failed to establish client: %w", err)
} }
if auth := NewOpportunisticSMTPAuth(n.config); auth != nil {
client.SetSMTPAuthCustom(auth)
}
if err = client.DialWithContext(ctx); err != nil { if err = client.DialWithContext(ctx); err != nil {
return fmt.Errorf("notifier: smtp: failed to dial connection: %w", err) return fmt.Errorf("notifier: smtp: failed to dial connection: %w", err)
} }