mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-22 22:00:49 +01:00
Compare commits
No commits in common. "0c1908d7bf2e92cb0c325922cb8338f093262fef" and "a4fa95f7caefd0db40a91bf4687c21afc8fe6061" have entirely different histories.
0c1908d7bf
...
a4fa95f7ca
4 changed files with 1 additions and 106 deletions
22
auth.go
22
auth.go
|
@ -136,21 +136,6 @@ const (
|
||||||
//
|
//
|
||||||
// https://datatracker.ietf.org/doc/html/rfc7677
|
// https://datatracker.ietf.org/doc/html/rfc7677
|
||||||
SMTPAuthSCRAMSHA256PLUS SMTPAuthType = "SCRAM-SHA-256-PLUS"
|
SMTPAuthSCRAMSHA256PLUS SMTPAuthType = "SCRAM-SHA-256-PLUS"
|
||||||
|
|
||||||
// SMTPAuthAutoDiscover is a mechanism that dynamically discovers all authentication mechanisms
|
|
||||||
// supported by the SMTP server and selects the strongest available one.
|
|
||||||
//
|
|
||||||
// This type simplifies authentication by automatically negotiating the most secure mechanism
|
|
||||||
// offered by the server, based on a predefined security ranking. For instance, mechanisms like
|
|
||||||
// SCRAM-SHA-256(-PLUS) or XOAUTH2 are prioritized over weaker mechanisms such as CRAM-MD5 or PLAIN.
|
|
||||||
//
|
|
||||||
// The negotiation process ensures that mechanisms requiring additional capabilities (e.g.,
|
|
||||||
// SCRAM-SHA-X-PLUS with TLS channel binding) are only selected when the necessary prerequisites
|
|
||||||
// are in place, such as an active TLS-secured connection.
|
|
||||||
//
|
|
||||||
// By automating mechanism selection, SMTPAuthAutoDiscover minimizes configuration effort while
|
|
||||||
// maximizing security and compatibility with a wide range of SMTP servers.
|
|
||||||
SMTPAuthAutoDiscover SMTPAuthType = "AUTODISCOVER"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SMTP Auth related static errors
|
// SMTP Auth related static errors
|
||||||
|
@ -185,19 +170,12 @@ var (
|
||||||
// ErrSCRAMSHA256PLUSAuthNotSupported is returned when the server does not support the "SCRAM-SHA-256-PLUS" SMTP
|
// ErrSCRAMSHA256PLUSAuthNotSupported is returned when the server does not support the "SCRAM-SHA-256-PLUS" SMTP
|
||||||
// authentication type.
|
// authentication type.
|
||||||
ErrSCRAMSHA256PLUSAuthNotSupported = errors.New("server does not support SMTP AUTH type: SCRAM-SHA-256-PLUS")
|
ErrSCRAMSHA256PLUSAuthNotSupported = errors.New("server does not support SMTP AUTH type: SCRAM-SHA-256-PLUS")
|
||||||
|
|
||||||
// ErrNoSupportedAuthDiscovered is returned when the SMTP Auth AutoDiscover process fails to identify
|
|
||||||
// any supported authentication mechanisms offered by the server.
|
|
||||||
ErrNoSupportedAuthDiscovered = errors.New("SMTP Auth autodiscover was not able to detect a supported " +
|
|
||||||
"authentication mechanism")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// UnmarshalString satisfies the fig.StringUnmarshaler interface for the SMTPAuthType type
|
// UnmarshalString satisfies the fig.StringUnmarshaler interface for the SMTPAuthType type
|
||||||
// https://pkg.go.dev/github.com/kkyr/fig#StringUnmarshaler
|
// https://pkg.go.dev/github.com/kkyr/fig#StringUnmarshaler
|
||||||
func (sa *SMTPAuthType) UnmarshalString(value string) error {
|
func (sa *SMTPAuthType) UnmarshalString(value string) error {
|
||||||
switch strings.ToLower(value) {
|
switch strings.ToLower(value) {
|
||||||
case "auto", "autodiscover", "autodiscovery":
|
|
||||||
*sa = SMTPAuthAutoDiscover
|
|
||||||
case "cram-md5", "crammd5", "cram":
|
case "cram-md5", "crammd5", "cram":
|
||||||
*sa = SMTPAuthCramMD5
|
*sa = SMTPAuthCramMD5
|
||||||
case "custom":
|
case "custom":
|
||||||
|
|
|
@ -12,9 +12,6 @@ func TestSMTPAuthType_UnmarshalString(t *testing.T) {
|
||||||
authString string
|
authString string
|
||||||
expected SMTPAuthType
|
expected SMTPAuthType
|
||||||
}{
|
}{
|
||||||
{"AUTODISCOVER: auto", "auto", SMTPAuthAutoDiscover},
|
|
||||||
{"AUTODISCOVER: autodiscover", "autodiscover", SMTPAuthAutoDiscover},
|
|
||||||
{"AUTODISCOVER: autodiscovery", "autodiscovery", SMTPAuthAutoDiscover},
|
|
||||||
{"CRAM-MD5: cram-md5", "cram-md5", SMTPAuthCramMD5},
|
{"CRAM-MD5: cram-md5", "cram-md5", SMTPAuthCramMD5},
|
||||||
{"CRAM-MD5: crammd5", "crammd5", SMTPAuthCramMD5},
|
{"CRAM-MD5: crammd5", "crammd5", SMTPAuthCramMD5},
|
||||||
{"CRAM-MD5: cram", "cram", SMTPAuthCramMD5},
|
{"CRAM-MD5: cram", "cram", SMTPAuthCramMD5},
|
||||||
|
|
41
client.go
41
client.go
|
@ -1100,16 +1100,7 @@ func (c *Client) auth() error {
|
||||||
return fmt.Errorf("server does not support SMTP AUTH")
|
return fmt.Errorf("server does not support SMTP AUTH")
|
||||||
}
|
}
|
||||||
|
|
||||||
authType := c.smtpAuthType
|
switch c.smtpAuthType {
|
||||||
if c.smtpAuthType == SMTPAuthAutoDiscover {
|
|
||||||
discoveredType, err := c.authTypeAutoDiscover(smtpAuthType)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
authType = discoveredType
|
|
||||||
}
|
|
||||||
|
|
||||||
switch authType {
|
|
||||||
case SMTPAuthPlain:
|
case SMTPAuthPlain:
|
||||||
if !strings.Contains(smtpAuthType, string(SMTPAuthPlain)) {
|
if !strings.Contains(smtpAuthType, string(SMTPAuthPlain)) {
|
||||||
return ErrPlainAuthNotSupported
|
return ErrPlainAuthNotSupported
|
||||||
|
@ -1181,36 +1172,6 @@ func (c *Client) auth() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) authTypeAutoDiscover(supported string) (SMTPAuthType, error) {
|
|
||||||
if supported == "" {
|
|
||||||
return "", ErrNoSupportedAuthDiscovered
|
|
||||||
}
|
|
||||||
preferList := []SMTPAuthType{
|
|
||||||
SMTPAuthSCRAMSHA256PLUS, SMTPAuthSCRAMSHA256, SMTPAuthSCRAMSHA1PLUS, SMTPAuthSCRAMSHA1,
|
|
||||||
SMTPAuthXOAUTH2, SMTPAuthCramMD5, SMTPAuthPlain, SMTPAuthLogin,
|
|
||||||
}
|
|
||||||
if !c.isEncrypted {
|
|
||||||
preferList = []SMTPAuthType{SMTPAuthSCRAMSHA256, SMTPAuthSCRAMSHA1, SMTPAuthXOAUTH2, SMTPAuthCramMD5}
|
|
||||||
}
|
|
||||||
mechs := strings.Split(supported, " ")
|
|
||||||
|
|
||||||
for _, item := range preferList {
|
|
||||||
if sliceContains(mechs, string(item)) {
|
|
||||||
return item, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", ErrNoSupportedAuthDiscovered
|
|
||||||
}
|
|
||||||
|
|
||||||
func sliceContains(slice []string, item string) bool {
|
|
||||||
for _, s := range slice {
|
|
||||||
if s == item {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendSingleMsg sends out a single message and returns an error if the transmission or
|
// sendSingleMsg sends out a single message and returns an error if the transmission or
|
||||||
// delivery fails. It is invoked by the public Send methods.
|
// delivery fails. It is invoked by the public Send methods.
|
||||||
//
|
//
|
||||||
|
|
|
@ -2304,11 +2304,6 @@ func TestClient_auth(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
authType SMTPAuthType
|
authType SMTPAuthType
|
||||||
}{
|
}{
|
||||||
{"LOGIN via AUTODISCOVER", SMTPAuthAutoDiscover},
|
|
||||||
{"PLAIN via AUTODISCOVER", SMTPAuthAutoDiscover},
|
|
||||||
{"SCRAM-SHA-1 via AUTODISCOVER", SMTPAuthAutoDiscover},
|
|
||||||
{"SCRAM-SHA-256 via AUTODISCOVER", SMTPAuthAutoDiscover},
|
|
||||||
{"XOAUTH2 via AUTODISCOVER", SMTPAuthAutoDiscover},
|
|
||||||
{"CRAM-MD5", SMTPAuthCramMD5},
|
{"CRAM-MD5", SMTPAuthCramMD5},
|
||||||
{"LOGIN", SMTPAuthLogin},
|
{"LOGIN", SMTPAuthLogin},
|
||||||
{"LOGIN-NOENC", SMTPAuthLoginNoEnc},
|
{"LOGIN-NOENC", SMTPAuthLoginNoEnc},
|
||||||
|
@ -2514,42 +2509,6 @@ func TestClient_auth(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_authTypeAutoDiscover(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
supported string
|
|
||||||
tls bool
|
|
||||||
expect SMTPAuthType
|
|
||||||
shouldFail bool
|
|
||||||
}{
|
|
||||||
{"LOGIN SCRAM-SHA-256 SCRAM-SHA-1 SCRAM-SHA-256-PLUS SCRAM-SHA-1-PLUS", true, SMTPAuthSCRAMSHA256PLUS, false},
|
|
||||||
{"LOGIN SCRAM-SHA-256 SCRAM-SHA-1 SCRAM-SHA-256-PLUS SCRAM-SHA-1-PLUS", false, SMTPAuthSCRAMSHA256, false},
|
|
||||||
{"LOGIN PLAIN SCRAM-SHA-1 SCRAM-SHA-1-PLUS", true, SMTPAuthSCRAMSHA1PLUS, false},
|
|
||||||
{"LOGIN PLAIN SCRAM-SHA-1 SCRAM-SHA-1-PLUS", false, SMTPAuthSCRAMSHA1, false},
|
|
||||||
{"LOGIN XOAUTH2 SCRAM-SHA-1-PLUS", false, SMTPAuthXOAUTH2, false},
|
|
||||||
{"PLAIN LOGIN CRAM-MD5", false, SMTPAuthCramMD5, false},
|
|
||||||
{"CRAM-MD5", false, SMTPAuthCramMD5, false},
|
|
||||||
{"PLAIN", true, SMTPAuthPlain, false},
|
|
||||||
{"LOGIN PLAIN", true, SMTPAuthPlain, false},
|
|
||||||
{"LOGIN PLAIN", false, "no secure mechanism", true},
|
|
||||||
{"", false, "supported list empty", true},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run("AutoDiscover selects the strongest auth type: "+string(tt.expect), func(t *testing.T) {
|
|
||||||
client := &Client{smtpAuthType: SMTPAuthAutoDiscover, isEncrypted: tt.tls}
|
|
||||||
authType, err := client.authTypeAutoDiscover(tt.supported)
|
|
||||||
if err != nil && !tt.shouldFail {
|
|
||||||
t.Fatalf("failed to auto discover auth type: %s", err)
|
|
||||||
}
|
|
||||||
if tt.shouldFail && err == nil {
|
|
||||||
t.Fatal("expected auto discover to fail")
|
|
||||||
}
|
|
||||||
if !tt.shouldFail && authType != tt.expect {
|
|
||||||
t.Errorf("expected strongest auth type: %s, got: %s", tt.expect, authType)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestClient_Send(t *testing.T) {
|
func TestClient_Send(t *testing.T) {
|
||||||
message := testMessage(t)
|
message := testMessage(t)
|
||||||
t.Run("connect and send email", func(t *testing.T) {
|
t.Run("connect and send email", func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue