Compare commits

..

1 commit

Author SHA1 Message Date
Michael Fuchs
0354aa1c7e
Merge cc4c5bfd04 into c903f6e1b4 2024-10-17 14:21:22 +00:00
11 changed files with 40 additions and 291 deletions

View file

@ -54,7 +54,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
@ -65,7 +65,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 uses: github/codeql-action/autobuild@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
@ -79,4 +79,4 @@ jobs:
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13

View file

@ -28,4 +28,4 @@ jobs:
- name: 'Checkout Repository' - name: 'Checkout Repository'
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: 'Dependency Review' - name: 'Dependency Review'
uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5 uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4

View file

@ -75,6 +75,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard. # Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning" - name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
with: with:
sarif_file: results.sarif sarif_file: results.sarif

73
auth.go
View file

@ -4,11 +4,7 @@
package mail package mail
import ( import "errors"
"errors"
"fmt"
"strings"
)
// SMTPAuthType is a type wrapper for a string type. It represents the type of SMTP authentication // SMTPAuthType is a type wrapper for a string type. It represents the type of SMTP authentication
// mechanism to be used. // mechanism to be used.
@ -48,25 +44,6 @@ const (
// https://datatracker.ietf.org/doc/html/draft-murchison-sasl-login-00 // https://datatracker.ietf.org/doc/html/draft-murchison-sasl-login-00
SMTPAuthLogin SMTPAuthType = "LOGIN" SMTPAuthLogin SMTPAuthType = "LOGIN"
// SMTPAuthLoginNoEnc is the "LOGIN" SASL authentication mechanism. This authentication mechanism
// does not have an official RFC that could be followed. There is a spec by Microsoft and an
// IETF draft. The IETF draft is more lax than the MS spec, therefore we follow the I-D, which
// automatically matches the MS spec.
//
// Since the "LOGIN" SASL authentication mechanism transmits the username and password in
// plaintext over the internet connection, by default we only allow this mechanism over
// a TLS secured connection. This authentiation mechanism overrides this default and will
// allow LOGIN authentication via an unencrypted channel. This can be useful if the
// connection has already been secured in a different way (e. g. a SSH tunnel)
//
// Note: Use this authentication method with caution. If used in the wrong way, you might
// expose your authentication information over unencrypted channels!
//
// https://msopenspecs.azureedge.net/files/MS-XLOGIN/%5bMS-XLOGIN%5d.pdf
//
// https://datatracker.ietf.org/doc/html/draft-murchison-sasl-login-00
SMTPAuthLoginNoEnc SMTPAuthType = "LOGIN-NOENC"
// SMTPAuthNoAuth is equivalent to performing no authentication at all. It is a convenience // SMTPAuthNoAuth is equivalent to performing no authentication at all. It is a convenience
// option and should not be used. Instead, for mail servers that do no support/require // option and should not be used. Instead, for mail servers that do no support/require
// authentication, the Client should not be passed the WithSMTPAuth option at all. // authentication, the Client should not be passed the WithSMTPAuth option at all.
@ -81,20 +58,6 @@ const (
// https://datatracker.ietf.org/doc/html/rfc4616/ // https://datatracker.ietf.org/doc/html/rfc4616/
SMTPAuthPlain SMTPAuthType = "PLAIN" SMTPAuthPlain SMTPAuthType = "PLAIN"
// SMTPAuthPlainNoEnc is the "PLAIN" authentication mechanism as described in RFC 4616.
//
// Since the "PLAIN" SASL authentication mechanism transmits the username and password in
// plaintext over the internet connection, by default we only allow this mechanism over
// a TLS secured connection. This authentiation mechanism overrides this default and will
// allow PLAIN authentication via an unencrypted channel. This can be useful if the
// connection has already been secured in a different way (e. g. a SSH tunnel)
//
// Note: Use this authentication method with caution. If used in the wrong way, you might
// expose your authentication information over unencrypted channels!
//
// https://datatracker.ietf.org/doc/html/rfc4616/
SMTPAuthPlainNoEnc SMTPAuthType = "PLAIN-NOENC"
// SMTPAuthXOAUTH2 is the "XOAUTH2" SASL authentication mechanism. // SMTPAuthXOAUTH2 is the "XOAUTH2" SASL authentication mechanism.
// https://developers.google.com/gmail/imap/xoauth2-protocol // https://developers.google.com/gmail/imap/xoauth2-protocol
SMTPAuthXOAUTH2 SMTPAuthType = "XOAUTH2" SMTPAuthXOAUTH2 SMTPAuthType = "XOAUTH2"
@ -171,37 +134,3 @@ var (
// 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")
) )
// UnmarshalString satisfies the fig.StringUnmarshaler interface for the SMTPAuthType type
// https://pkg.go.dev/github.com/kkyr/fig#StringUnmarshaler
func (sa *SMTPAuthType) UnmarshalString(value string) error {
switch strings.ToLower(value) {
case "cram-md5", "crammd5", "cram":
*sa = SMTPAuthCramMD5
case "custom":
*sa = SMTPAuthCustom
case "login":
*sa = SMTPAuthLogin
case "login-noenc":
*sa = SMTPAuthLoginNoEnc
case "none", "noauth", "no":
*sa = SMTPAuthNoAuth
case "plain":
*sa = SMTPAuthPlain
case "plain-noenc":
*sa = SMTPAuthPlainNoEnc
case "scram-sha-1", "scram-sha1", "scramsha1":
*sa = SMTPAuthSCRAMSHA1
case "scram-sha-1-plus", "scram-sha1-plus", "scramsha1plus":
*sa = SMTPAuthSCRAMSHA1PLUS
case "scram-sha-256", "scram-sha256", "scramsha256":
*sa = SMTPAuthSCRAMSHA256
case "scram-sha-256-plus", "scram-sha256-plus", "scramsha256plus":
*sa = SMTPAuthSCRAMSHA256PLUS
case "xoauth2", "oauth2":
*sa = SMTPAuthXOAUTH2
default:
return fmt.Errorf("unsupported SMTP auth type: %s", value)
}
return nil
}

View file

@ -1,59 +0,0 @@
// SPDX-FileCopyrightText: 2024 The go-mail Authors
//
// SPDX-License-Identifier: MIT
package mail
import "testing"
func TestSMTPAuthType_UnmarshalString(t *testing.T) {
tests := []struct {
name string
authString string
expected SMTPAuthType
}{
{"CRAM-MD5: cram-md5", "cram-md5", SMTPAuthCramMD5},
{"CRAM-MD5: crammd5", "crammd5", SMTPAuthCramMD5},
{"CRAM-MD5: cram", "cram", SMTPAuthCramMD5},
{"CUSTOM", "custom", SMTPAuthCustom},
{"LOGIN", "login", SMTPAuthLogin},
{"LOGIN-NOENC", "login-noenc", SMTPAuthLoginNoEnc},
{"NONE: none", "none", SMTPAuthNoAuth},
{"NONE: noauth", "noauth", SMTPAuthNoAuth},
{"NONE: no", "no", SMTPAuthNoAuth},
{"PLAIN", "plain", SMTPAuthPlain},
{"PLAIN-NOENC", "plain-noenc", SMTPAuthPlainNoEnc},
{"SCRAM-SHA-1: scram-sha-1", "scram-sha-1", SMTPAuthSCRAMSHA1},
{"SCRAM-SHA-1: scram-sha1", "scram-sha1", SMTPAuthSCRAMSHA1},
{"SCRAM-SHA-1: scramsha1", "scramsha1", SMTPAuthSCRAMSHA1},
{"SCRAM-SHA-1-PLUS: scram-sha-1-plus", "scram-sha-1-plus", SMTPAuthSCRAMSHA1PLUS},
{"SCRAM-SHA-1-PLUS: scram-sha1-plus", "scram-sha1-plus", SMTPAuthSCRAMSHA1PLUS},
{"SCRAM-SHA-1-PLUS: scramsha1plus", "scramsha1plus", SMTPAuthSCRAMSHA1PLUS},
{"SCRAM-SHA-256: scram-sha-256", "scram-sha-256", SMTPAuthSCRAMSHA256},
{"SCRAM-SHA-256: scram-sha256", "scram-sha256", SMTPAuthSCRAMSHA256},
{"SCRAM-SHA-256: scramsha256", "scramsha256", SMTPAuthSCRAMSHA256},
{"SCRAM-SHA-256-PLUS: scram-sha-256-plus", "scram-sha-256-plus", SMTPAuthSCRAMSHA256PLUS},
{"SCRAM-SHA-256-PLUS: scram-sha256-plus", "scram-sha256-plus", SMTPAuthSCRAMSHA256PLUS},
{"SCRAM-SHA-256-PLUS: scramsha256plus", "scramsha256plus", SMTPAuthSCRAMSHA256PLUS},
{"XOAUTH2: xoauth2", "xoauth2", SMTPAuthXOAUTH2},
{"XOAUTH2: oauth2", "oauth2", SMTPAuthXOAUTH2},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var authType SMTPAuthType
if err := authType.UnmarshalString(tt.authString); err != nil {
t.Errorf("UnmarshalString() for type %s failed: %s", tt.authString, err)
}
if authType != tt.expected {
t.Errorf("UnmarshalString() for type %s failed: expected %s, got %s",
tt.authString, tt.expected, authType)
}
})
}
t.Run("should fail", func(t *testing.T) {
var authType SMTPAuthType
if err := authType.UnmarshalString("invalid"); err == nil {
t.Error("UnmarshalString() should have failed")
}
})
}

View file

@ -1096,22 +1096,12 @@ func (c *Client) auth() error {
if !strings.Contains(smtpAuthType, string(SMTPAuthPlain)) { if !strings.Contains(smtpAuthType, string(SMTPAuthPlain)) {
return ErrPlainAuthNotSupported return ErrPlainAuthNotSupported
} }
c.smtpAuth = smtp.PlainAuth("", c.user, c.pass, c.host, false) c.smtpAuth = smtp.PlainAuth("", c.user, c.pass, c.host)
case SMTPAuthPlainNoEnc:
if !strings.Contains(smtpAuthType, string(SMTPAuthPlain)) {
return ErrPlainAuthNotSupported
}
c.smtpAuth = smtp.PlainAuth("", c.user, c.pass, c.host, true)
case SMTPAuthLogin: case SMTPAuthLogin:
if !strings.Contains(smtpAuthType, string(SMTPAuthLogin)) { if !strings.Contains(smtpAuthType, string(SMTPAuthLogin)) {
return ErrLoginAuthNotSupported return ErrLoginAuthNotSupported
} }
c.smtpAuth = smtp.LoginAuth(c.user, c.pass, c.host, false) c.smtpAuth = smtp.LoginAuth(c.user, c.pass, c.host)
case SMTPAuthLoginNoEnc:
if !strings.Contains(smtpAuthType, string(SMTPAuthLogin)) {
return ErrLoginAuthNotSupported
}
c.smtpAuth = smtp.LoginAuth(c.user, c.pass, c.host, true)
case SMTPAuthCramMD5: case SMTPAuthCramMD5:
if !strings.Contains(smtpAuthType, string(SMTPAuthCramMD5)) { if !strings.Contains(smtpAuthType, string(SMTPAuthCramMD5)) {
return ErrCramMD5AuthNotSupported return ErrCramMD5AuthNotSupported

View file

@ -110,7 +110,7 @@ func TestNewClientWithOptions(t *testing.T) {
{"WithSMTPAuth()", WithSMTPAuth(SMTPAuthLogin), false}, {"WithSMTPAuth()", WithSMTPAuth(SMTPAuthLogin), false},
{ {
"WithSMTPAuthCustom()", "WithSMTPAuthCustom()",
WithSMTPAuthCustom(smtp.PlainAuth("", "", "", "", false)), WithSMTPAuthCustom(smtp.PlainAuth("", "", "", "")),
false, false,
}, },
{"WithUsername()", WithUsername("test"), false}, {"WithUsername()", WithUsername("test"), false},
@ -605,8 +605,8 @@ func TestSetSMTPAuthCustom(t *testing.T) {
sf bool sf bool
}{ }{
{"SMTPAuth: CRAM-MD5", smtp.CRAMMD5Auth("", ""), "CRAM-MD5", false}, {"SMTPAuth: CRAM-MD5", smtp.CRAMMD5Auth("", ""), "CRAM-MD5", false},
{"SMTPAuth: LOGIN", smtp.LoginAuth("", "", "", false), "LOGIN", false}, {"SMTPAuth: LOGIN", smtp.LoginAuth("", "", ""), "LOGIN", false},
{"SMTPAuth: PLAIN", smtp.PlainAuth("", "", "", "", false), "PLAIN", false}, {"SMTPAuth: PLAIN", smtp.PlainAuth("", "", "", ""), "PLAIN", false},
} }
si := smtp.ServerInfo{TLS: true} si := smtp.ServerInfo{TLS: true}
for _, tt := range tests { for _, tt := range tests {
@ -807,7 +807,7 @@ func TestClient_DialWithContextInvalidAuth(t *testing.T) {
} }
c.user = "invalid" c.user = "invalid"
c.pass = "invalid" c.pass = "invalid"
c.SetSMTPAuthCustom(smtp.LoginAuth("invalid", "invalid", "invalid", false)) c.SetSMTPAuthCustom(smtp.LoginAuth("invalid", "invalid", "invalid"))
ctx := context.Background() ctx := context.Background()
if err = c.DialWithContext(ctx); err == nil { if err = c.DialWithContext(ctx); err == nil {
t.Errorf("dial succeeded but was supposed to fail") t.Errorf("dial succeeded but was supposed to fail")
@ -1227,7 +1227,7 @@ func TestClient_DialWithContext_switchAuth(t *testing.T) {
// We switch to CUSTOM by providing PLAIN auth as function - the server supports this // We switch to CUSTOM by providing PLAIN auth as function - the server supports this
client.SetSMTPAuthCustom(smtp.PlainAuth("", os.Getenv("TEST_SMTPAUTH_USER"), client.SetSMTPAuthCustom(smtp.PlainAuth("", os.Getenv("TEST_SMTPAUTH_USER"),
os.Getenv("TEST_SMTPAUTH_PASS"), os.Getenv("TEST_HOST"), false)) os.Getenv("TEST_SMTPAUTH_PASS"), os.Getenv("TEST_HOST")))
if client.smtpAuthType != SMTPAuthCustom { if client.smtpAuthType != SMTPAuthCustom {
t.Errorf("expected auth type to be Custom, got: %s", client.smtpAuthType) t.Errorf("expected auth type to be Custom, got: %s", client.smtpAuthType)
} }
@ -1955,7 +1955,7 @@ func TestClient_DialSendConcurrent_local(t *testing.T) {
wg.Wait() wg.Wait()
if err = client.Close(); err != nil { if err = client.Close(); err != nil {
t.Logf("failed to close server connection: %s", err) t.Errorf("failed to close server connection: %s", err)
} }
} }

View file

@ -10,10 +10,9 @@ import (
// loginAuth is the type that satisfies the Auth interface for the "SMTP LOGIN" auth // loginAuth is the type that satisfies the Auth interface for the "SMTP LOGIN" auth
type loginAuth struct { type loginAuth struct {
username, password string username, password string
host string host string
respStep uint8 respStep uint8
allowUnencryptedAuth bool
} }
// LoginAuth returns an [Auth] that implements the LOGIN authentication // LoginAuth returns an [Auth] that implements the LOGIN authentication
@ -36,8 +35,8 @@ type loginAuth struct {
// LoginAuth will only send the credentials if the connection is using TLS // LoginAuth will only send the credentials if the connection is using TLS
// or is connected to localhost. Otherwise authentication will fail with an // or is connected to localhost. Otherwise authentication will fail with an
// error, without sending the credentials. // error, without sending the credentials.
func LoginAuth(username, password, host string, allowUnEnc bool) Auth { func LoginAuth(username, password, host string) Auth {
return &loginAuth{username, password, host, 0, allowUnEnc} return &loginAuth{username, password, host, 0}
} }
// Start begins the SMTP authentication process by validating server's TLS status and hostname. // Start begins the SMTP authentication process by validating server's TLS status and hostname.
@ -48,7 +47,7 @@ func (a *loginAuth) Start(server *ServerInfo) (string, []byte, error) {
// In particular, it doesn't matter if the server advertises LOGIN auth. // In particular, it doesn't matter if the server advertises LOGIN auth.
// That might just be the attacker saying // That might just be the attacker saying
// "it's ok, you can trust me with your password." // "it's ok, you can trust me with your password."
if !a.allowUnencryptedAuth && !server.TLS && !isLocalhost(server.Name) { if !server.TLS && !isLocalhost(server.Name) {
return "", nil, ErrUnencrypted return "", nil, ErrUnencrypted
} }
if server.Name != a.host { if server.Name != a.host {

View file

@ -17,7 +17,6 @@ package smtp
type plainAuth struct { type plainAuth struct {
identity, username, password string identity, username, password string
host string host string
allowUnencryptedAuth bool
} }
// PlainAuth returns an [Auth] that implements the PLAIN authentication // PlainAuth returns an [Auth] that implements the PLAIN authentication
@ -28,8 +27,8 @@ type plainAuth struct {
// PlainAuth will only send the credentials if the connection is using TLS // PlainAuth will only send the credentials if the connection is using TLS
// or is connected to localhost. Otherwise authentication will fail with an // or is connected to localhost. Otherwise authentication will fail with an
// error, without sending the credentials. // error, without sending the credentials.
func PlainAuth(identity, username, password, host string, allowUnEnc bool) Auth { func PlainAuth(identity, username, password, host string) Auth {
return &plainAuth{identity, username, password, host, allowUnEnc} return &plainAuth{identity, username, password, host}
} }
func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) { func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
@ -38,7 +37,7 @@ func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
// In particular, it doesn't matter if the server advertises PLAIN auth. // In particular, it doesn't matter if the server advertises PLAIN auth.
// That might just be the attacker saying // That might just be the attacker saying
// "it's ok, you can trust me with your password." // "it's ok, you can trust me with your password."
if !a.allowUnencryptedAuth && !server.TLS && !isLocalhost(server.Name) { if !server.TLS && !isLocalhost(server.Name) {
return "", nil, ErrUnencrypted return "", nil, ErrUnencrypted
} }
if server.Name != a.host { if server.Name != a.host {

View file

@ -67,7 +67,7 @@ var (
func ExamplePlainAuth() { func ExamplePlainAuth() {
// hostname is used by PlainAuth to validate the TLS certificate. // hostname is used by PlainAuth to validate the TLS certificate.
hostname := "mail.example.com" hostname := "mail.example.com"
auth := smtp.PlainAuth("", "user@example.com", "password", hostname, false) auth := smtp.PlainAuth("", "user@example.com", "password", hostname)
err := smtp.SendMail(hostname+":25", auth, from, recipients, msg) err := smtp.SendMail(hostname+":25", auth, from, recipients, msg)
if err != nil { if err != nil {
@ -77,7 +77,7 @@ func ExamplePlainAuth() {
func ExampleSendMail() { func ExampleSendMail() {
// Set up authentication information. // Set up authentication information.
auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com", false) auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com")
// Connect to the server, authenticate, set the sender and recipient, // Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step. // and send the email all in one step.

View file

@ -50,7 +50,7 @@ type authTest struct {
var authTests = []authTest{ var authTests = []authTest{
{ {
PlainAuth("", "user", "pass", "testserver", false), PlainAuth("", "user", "pass", "testserver"),
[]string{}, []string{},
"PLAIN", "PLAIN",
[]string{"\x00user\x00pass"}, []string{"\x00user\x00pass"},
@ -58,15 +58,7 @@ var authTests = []authTest{
false, false,
}, },
{ {
PlainAuth("", "user", "pass", "testserver", true), PlainAuth("foo", "bar", "baz", "testserver"),
[]string{},
"PLAIN",
[]string{"\x00user\x00pass"},
[]bool{false, false},
false,
},
{
PlainAuth("foo", "bar", "baz", "testserver", false),
[]string{}, []string{},
"PLAIN", "PLAIN",
[]string{"foo\x00bar\x00baz"}, []string{"foo\x00bar\x00baz"},
@ -74,7 +66,7 @@ var authTests = []authTest{
false, false,
}, },
{ {
PlainAuth("foo", "bar", "baz", "testserver", false), PlainAuth("foo", "bar", "baz", "testserver"),
[]string{"foo"}, []string{"foo"},
"PLAIN", "PLAIN",
[]string{"foo\x00bar\x00baz", ""}, []string{"foo\x00bar\x00baz", ""},
@ -82,7 +74,7 @@ var authTests = []authTest{
false, false,
}, },
{ {
LoginAuth("user", "pass", "testserver", false), LoginAuth("user", "pass", "testserver"),
[]string{"Username:", "Password:"}, []string{"Username:", "Password:"},
"LOGIN", "LOGIN",
[]string{"", "user", "pass"}, []string{"", "user", "pass"},
@ -90,15 +82,7 @@ var authTests = []authTest{
false, false,
}, },
{ {
LoginAuth("user", "pass", "testserver", true), LoginAuth("user", "pass", "testserver"),
[]string{"Username:", "Password:"},
"LOGIN",
[]string{"", "user", "pass"},
[]bool{false, false},
false,
},
{
LoginAuth("user", "pass", "testserver", false),
[]string{"User Name\x00", "Password\x00"}, []string{"User Name\x00", "Password\x00"},
"LOGIN", "LOGIN",
[]string{"", "user", "pass"}, []string{"", "user", "pass"},
@ -106,7 +90,7 @@ var authTests = []authTest{
false, false,
}, },
{ {
LoginAuth("user", "pass", "testserver", false), LoginAuth("user", "pass", "testserver"),
[]string{"Invalid", "Invalid:"}, []string{"Invalid", "Invalid:"},
"LOGIN", "LOGIN",
[]string{"", "user", "pass"}, []string{"", "user", "pass"},
@ -114,7 +98,7 @@ var authTests = []authTest{
false, false,
}, },
{ {
LoginAuth("user", "pass", "testserver", false), LoginAuth("user", "pass", "testserver"),
[]string{"Invalid", "Invalid:", "Too many"}, []string{"Invalid", "Invalid:", "Too many"},
"LOGIN", "LOGIN",
[]string{"", "user", "pass", ""}, []string{"", "user", "pass", ""},
@ -253,47 +237,7 @@ func TestAuthPlain(t *testing.T) {
}, },
} }
for i, tt := range tests { for i, tt := range tests {
auth := PlainAuth("foo", "bar", "baz", tt.authName, false) auth := PlainAuth("foo", "bar", "baz", tt.authName)
_, _, err := auth.Start(tt.server)
got := ""
if err != nil {
got = err.Error()
}
if got != tt.err {
t.Errorf("%d. got error = %q; want %q", i, got, tt.err)
}
}
}
func TestAuthPlainNoEnc(t *testing.T) {
tests := []struct {
authName string
server *ServerInfo
err string
}{
{
authName: "servername",
server: &ServerInfo{Name: "servername", TLS: true},
},
{
// OK to use PlainAuth on localhost without TLS
authName: "localhost",
server: &ServerInfo{Name: "localhost", TLS: false},
},
{
// Also OK on non-TLS secured connections. The NoEnc mechanism is meant to allow
// non-encrypted connections.
authName: "servername",
server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
},
{
authName: "servername",
server: &ServerInfo{Name: "attacker", TLS: true},
err: "wrong host name",
},
}
for i, tt := range tests {
auth := PlainAuth("foo", "bar", "baz", tt.authName, true)
_, _, err := auth.Start(tt.server) _, _, err := auth.Start(tt.server)
got := "" got := ""
if err != nil { if err != nil {
@ -339,51 +283,7 @@ func TestAuthLogin(t *testing.T) {
}, },
} }
for i, tt := range tests { for i, tt := range tests {
auth := LoginAuth("foo", "bar", tt.authName, false) auth := LoginAuth("foo", "bar", tt.authName)
_, _, err := auth.Start(tt.server)
got := ""
if err != nil {
got = err.Error()
}
if got != tt.err {
t.Errorf("%d. got error = %q; want %q", i, got, tt.err)
}
}
}
func TestAuthLoginNoEnc(t *testing.T) {
tests := []struct {
authName string
server *ServerInfo
err string
}{
{
authName: "servername",
server: &ServerInfo{Name: "servername", TLS: true},
},
{
// OK to use LoginAuth on localhost without TLS
authName: "localhost",
server: &ServerInfo{Name: "localhost", TLS: false},
},
{
// Also OK on non-TLS secured connections. The NoEnc mechanism is meant to allow
// non-encrypted connections.
authName: "servername",
server: &ServerInfo{Name: "servername", Auth: []string{"LOGIN"}},
},
{
authName: "servername",
server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
},
{
authName: "servername",
server: &ServerInfo{Name: "attacker", TLS: true},
err: "wrong host name",
},
}
for i, tt := range tests {
auth := LoginAuth("foo", "bar", tt.authName, true)
_, _, err := auth.Start(tt.server) _, _, err := auth.Start(tt.server)
got := "" got := ""
if err != nil { if err != nil {
@ -417,11 +317,7 @@ func TestXOAuth2OK(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("NewClient: %v", err) t.Fatalf("NewClient: %v", err)
} }
defer func() { defer c.Close()
if err := c.Close(); err != nil {
t.Errorf("failed to close client: %s", err)
}
}()
auth := XOAuth2Auth("user", "token") auth := XOAuth2Auth("user", "token")
err = c.Auth(auth) err = c.Auth(auth)
@ -459,11 +355,7 @@ func TestXOAuth2Error(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("NewClient: %v", err) t.Fatalf("NewClient: %v", err)
} }
defer func() { defer c.Close()
if err := c.Close(); err != nil {
t.Errorf("failed to close client: %s", err)
}
}()
auth := XOAuth2Auth("user", "token") auth := XOAuth2Auth("user", "token")
err = c.Auth(auth) err = c.Auth(auth)
@ -815,7 +707,7 @@ func TestBasic(t *testing.T) {
// fake TLS so authentication won't complain // fake TLS so authentication won't complain
c.tls = true c.tls = true
c.serverName = "smtp.google.com" c.serverName = "smtp.google.com"
if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com", false)); err != nil { if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")); err != nil {
t.Fatalf("AUTH failed: %s", err) t.Fatalf("AUTH failed: %s", err)
} }
@ -1386,7 +1278,7 @@ func TestHello(t *testing.T) {
case 3: case 3:
c.tls = true c.tls = true
c.serverName = "smtp.google.com" c.serverName = "smtp.google.com"
err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com", false)) err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com"))
case 4: case 4:
err = c.Mail("test@example.com") err = c.Mail("test@example.com")
case 5: case 5:
@ -1631,7 +1523,7 @@ func TestSendMailWithAuth(t *testing.T) {
} }
}() }()
err = SendMail(l.Addr().String(), PlainAuth("", "user", "pass", "smtp.google.com", false), "test@example.com", []string{"other@example.com"}, []byte(strings.Replace(`From: test@example.com err = SendMail(l.Addr().String(), PlainAuth("", "user", "pass", "smtp.google.com"), "test@example.com", []string{"other@example.com"}, []byte(strings.Replace(`From: test@example.com
To: other@example.com To: other@example.com
Subject: SendMail test Subject: SendMail test
@ -1639,7 +1531,6 @@ SendMail is working for me.
`, "\n", "\r\n", -1))) `, "\n", "\r\n", -1)))
if err == nil { if err == nil {
t.Error("SendMail: Server doesn't support AUTH, expected to get an error, but got none ") t.Error("SendMail: Server doesn't support AUTH, expected to get an error, but got none ")
return
} }
if err.Error() != "smtp: server doesn't support AUTH" { if err.Error() != "smtp: server doesn't support AUTH" {
t.Errorf("Expected: smtp: server doesn't support AUTH, got: %s", err) t.Errorf("Expected: smtp: server doesn't support AUTH, got: %s", err)
@ -1667,7 +1558,7 @@ func TestAuthFailed(t *testing.T) {
c.tls = true c.tls = true
c.serverName = "smtp.google.com" c.serverName = "smtp.google.com"
err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com", false)) err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com"))
if err == nil { if err == nil {
t.Error("Auth: expected error; got none") t.Error("Auth: expected error; got none")