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
parent
3ecb9f1d44
commit
7b8ed46537
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue