Added the LOGIN authentication mechanism support

Closes #16.
This commit is contained in:
Alexandre Cesaro 2015-02-10 19:22:29 +01:00
parent d7294067b8
commit de623e612d
3 changed files with 130 additions and 0 deletions

View File

@ -76,6 +76,16 @@ bypass the verification of the server's certificate chain and host name by using
Note, however, that this is insecure and should not be used in production. Note, however, that this is insecure and should not be used in production.
### 504 5.7.4 Unrecognized authentication type
If you get this error, you should try using the LOGIN authentication mechanism:
addr := "smtp.example.com:587"
auth := gomail.LoginAuth("username", "password", "smtp.example.com")
mailer := gomail.NewCustomMailer(addr, auth)
See [issue #16](https://github.com/go-gomail/gomail/issues/16).
## Contact ## Contact

54
login.go Normal file
View File

@ -0,0 +1,54 @@
package gomail
import (
"errors"
"fmt"
"net/smtp"
"strings"
)
type loginAuth struct {
username string
password string
host string
}
// LoginAuth returns an Auth that implements the LOGIN authentication mechanism.
func LoginAuth(username, password, host string) smtp.Auth {
return &loginAuth{username, password, host}
}
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
if !server.TLS {
advertised := false
for _, mechanism := range server.Auth {
if mechanism == "LOGIN" {
advertised = true
break
}
}
if !advertised {
return "", nil, errors.New("gomail: unencrypted connection")
}
}
if server.Name != a.host {
return "", nil, errors.New("gomail: wrong host name")
}
return "LOGIN", nil, nil
}
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if !more {
return nil, nil
}
command := strings.ToLower(strings.TrimSuffix(string(fromServer), ":"))
switch command {
case "username":
return []byte(fmt.Sprintf("%s", a.username)), nil
case "password":
return []byte(fmt.Sprintf("%s", a.password)), nil
default:
return nil, fmt.Errorf("gomail: unexpected server challenge: %s", command)
}
}

66
login_test.go Normal file
View File

@ -0,0 +1,66 @@
package gomail
import (
"net/smtp"
"testing"
)
type output struct {
proto string
data []string
err error
}
const (
testUser = "user"
testPwd = "pwd"
)
func TestPlainAuth(t *testing.T) {
tests := []struct {
serverProtos []string
serverChallenges []string
proto string
data []string
}{
{
serverProtos: []string{"LOGIN"},
serverChallenges: []string{"Username:", "Password:"},
proto: "LOGIN",
data: []string{"", testUser, testPwd},
},
}
for _, test := range tests {
auth := LoginAuth(testUser, testPwd, testHost)
server := &smtp.ServerInfo{
Name: testHost,
TLS: true,
Auth: test.serverProtos,
}
proto, toServer, err := auth.Start(server)
if err != nil {
t.Fatalf("Start error: %v", err)
}
if proto != test.proto {
t.Errorf("Invalid protocol, got %q, want %q", proto, test.proto)
}
i := 0
got := string(toServer)
if got != test.data[i] {
t.Errorf("Invalid response, got %q, want %q", got, test.data[i])
}
for _, challenge := range test.serverChallenges {
toServer, err = auth.Next([]byte(challenge), true)
if err != nil {
t.Fatalf("Auth error: %v", err)
}
i++
got = string(toServer)
if got != test.data[i] {
t.Errorf("Invalid response, got %q, want %q", got, test.data[i])
}
}
}
}