Merge pull request #163 from stapelberg/starttls

smtp: STARTTLS before querying auth mechanisms
This commit is contained in:
Fabian Reinartz 2015-12-01 12:44:51 +01:00
commit 685b24b7b4
2 changed files with 21 additions and 29 deletions

View File

@ -516,9 +516,9 @@ func writeEmailBodyWithTime(w io.Writer, from, to, status string, a *Alert, mome
return nil return nil
} }
func getSMTPAuth(hasAuth bool, mechs string) (smtp.Auth, *tls.Config, error) { func getSMTPAuth(hasAuth bool, mechs string) (smtp.Auth, error) {
if !hasAuth { if !hasAuth {
return nil, nil, nil return nil, nil
} }
username := os.Getenv("SMTP_AUTH_USERNAME") username := os.Getenv("SMTP_AUTH_USERNAME")
@ -530,7 +530,7 @@ func getSMTPAuth(hasAuth bool, mechs string) (smtp.Auth, *tls.Config, error) {
if secret == "" { if secret == "" {
continue continue
} }
return smtp.CRAMMD5Auth(username, secret), nil, nil return smtp.CRAMMD5Auth(username, secret), nil
case "PLAIN": case "PLAIN":
password := os.Getenv("SMTP_AUTH_PASSWORD") password := os.Getenv("SMTP_AUTH_PASSWORD")
if password == "" { if password == "" {
@ -541,15 +541,14 @@ func getSMTPAuth(hasAuth bool, mechs string) (smtp.Auth, *tls.Config, error) {
// We need to know the hostname for both auth and TLS. // We need to know the hostname for both auth and TLS.
host, _, err := net.SplitHostPort(*smtpSmartHost) host, _, err := net.SplitHostPort(*smtpSmartHost)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("invalid address: %s", err) return nil, fmt.Errorf("invalid address: %s", err)
} }
auth := smtp.PlainAuth(identity, username, password, host) auth := smtp.PlainAuth(identity, username, password, host)
cfg := &tls.Config{ServerName: host} return auth, nil
return auth, cfg, nil
} }
} }
return nil, nil, nil return nil, nil
} }
func (n *notifier) sendEmailNotification(to string, op notificationOp, a *Alert) error { func (n *notifier) sendEmailNotification(to string, op notificationOp, a *Alert) error {
@ -567,16 +566,21 @@ func (n *notifier) sendEmailNotification(to string, op notificationOp, a *Alert)
} }
defer c.Quit() defer c.Quit()
// Authenticate if we and the server are both configured for it. // We need to know the hostname for both auth and TLS.
auth, tlsConfig, err := getSMTPAuth(c.Extension("AUTH")) host, _, err := net.SplitHostPort(*smtpSmartHost)
if err != nil { if err != nil {
return err return fmt.Errorf("invalid address: %s", err)
} }
if tlsConfig != nil { tlsConfig := &tls.Config{ServerName: host}
if err := c.StartTLS(tlsConfig); err != nil { if err := c.StartTLS(tlsConfig); err != nil {
return fmt.Errorf("starttls failed: %s", err) return fmt.Errorf("starttls failed: %s", err)
} }
// Authenticate if we and the server are both configured for it.
auth, err := getSMTPAuth(c.Extension("AUTH"))
if err != nil {
return err
} }
if auth != nil { if auth != nil {

View File

@ -15,7 +15,6 @@ package manager
import ( import (
"bytes" "bytes"
"crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"html" "html"
@ -85,7 +84,7 @@ type authTestCase struct {
} }
func (tc *authTestCase) test(t *testing.T) { func (tc *authTestCase) test(t *testing.T) {
auth, cfg, err := getSMTPAuth(tc.hasAuth, tc.mechs) auth, err := getSMTPAuth(tc.hasAuth, tc.mechs)
if err != nil { if err != nil {
tc.fail(t, "unexpected error: %s", err) tc.fail(t, "unexpected error: %s", err)
return return
@ -94,21 +93,10 @@ func (tc *authTestCase) test(t *testing.T) {
if auth != nil { if auth != nil {
tc.fail(t, "expected auth to be nil, got %T", auth) tc.fail(t, "expected auth to be nil, got %T", auth)
} }
if cfg != nil {
tc.fail(t, "expected tls config to be nil, got %v", cfg)
}
} else { } else {
if fmt.Sprintf("%T", auth) != tc.expAuthType { if fmt.Sprintf("%T", auth) != tc.expAuthType {
tc.fail(t, "expected auth to be %s, got %T", tc.expAuthType, auth) tc.fail(t, "expected auth to be %s, got %T", tc.expAuthType, auth)
} }
if tc.expAuthType == "*smtp.plainAuth" {
if cfg == nil {
tc.fail(t, "expected tls config")
} else if cfg.ServerName != "testSMTPHost" {
tc.fail(t, "expected tls config to be %v, got %v",
&tls.Config{ServerName: "testSMTPHost"}, cfg)
}
}
} }
} }
@ -179,8 +167,8 @@ func TestGetSMTPAuth(t *testing.T) {
{true, "PLAIN", ""}, {true, "PLAIN", ""},
}) })
os.Setenv("SMTP_AUTH_PASSWORD", "p") os.Setenv("SMTP_AUTH_PASSWORD", "p")
if auth, cfg, err := getSMTPAuth(true, "PLAIN"); err == nil { if auth, err := getSMTPAuth(true, "PLAIN"); err == nil {
t.Errorf("PLAIN auth with bad host-port: expected error but got %T, %v", auth, cfg) t.Errorf("PLAIN auth with bad host-port: expected error but got %T", auth)
} }
} }