/
smtp_auth.go
85 lines (72 loc) · 2.53 KB
/
smtp_auth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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)
}