authelia/internal/notification/smtp_auth.go

86 lines
2.5 KiB
Go

package notification
import (
"fmt"
"strings"
"github.com/wneessen/go-mail"
"github.com/wneessen/go-mail/smtp"
"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.NotifierSMTP) *OpportunisticSMTPAuth {
if config.Username == "" && config.Password == "" {
return nil
}
return &OpportunisticSMTPAuth{
username: config.Username,
password: config.Password,
host: config.Address.Hostname(),
}
}
// OpportunisticSMTPAuth is an opportunistic smtp.Auth implementation.
type OpportunisticSMTPAuth struct {
username, password, host string
satPreference []mail.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 mail.SMTPAuthPlain:
a.sa = smtp.PlainAuth("", a.username, a.password, a.host)
case mail.SMTPAuthLogin:
a.sa = smtp.LoginAuth(a.username, a.password, a.host)
case mail.SMTPAuthCramMD5:
a.sa = smtp.CRAMMD5Auth(a.username, a.password)
}
break
}
}
if a.sa == nil {
for _, sa := range server.Auth {
switch mail.SMTPAuthType(sa) {
case mail.SMTPAuthPlain:
a.sa = smtp.PlainAuth("", a.username, a.password, a.host)
case mail.SMTPAuthLogin:
a.sa = smtp.LoginAuth(a.username, a.password, a.host)
case mail.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)
}