mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-24 06:30:49 +01:00
Add SMTP authentication auto-discovery
Implemented a mechanism to automatically discover and select the strongest supported SMTP authentication type. This feature simplifies the authentication process for users and enhances security by prioritizing stronger mechanisms based on server capabilities. Corresponding tests and documentation have been updated.
This commit is contained in:
parent
a4fa95f7ca
commit
ac9117dc50
3 changed files with 60 additions and 1 deletions
20
auth.go
20
auth.go
|
@ -136,6 +136,21 @@ 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
|
||||||
|
@ -170,6 +185,11 @@ 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
|
||||||
|
|
36
client.go
36
client.go
|
@ -1100,7 +1100,16 @@ func (c *Client) auth() error {
|
||||||
return fmt.Errorf("server does not support SMTP AUTH")
|
return fmt.Errorf("server does not support SMTP AUTH")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch c.smtpAuthType {
|
authType := 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
|
||||||
|
@ -1172,6 +1181,31 @@ func (c *Client) auth() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) authTypeAutoDiscover(supported string) (SMTPAuthType, error) {
|
||||||
|
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,6 +2304,11 @@ 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},
|
||||||
|
|
Loading…
Reference in a new issue