mirror of
https://gitlab.com/ric_harvey/MailHog.git
synced 2024-11-23 22:34:04 +00:00
Add basic AUTH support (RFC4954)
This commit is contained in:
parent
fa2e16587c
commit
8709ba9de6
3 changed files with 46 additions and 5 deletions
|
@ -19,10 +19,13 @@ type Session struct {
|
||||||
state int
|
state int
|
||||||
message *data.SMTPMessage
|
message *data.SMTPMessage
|
||||||
mongo *storage.MongoDB
|
mongo *storage.MongoDB
|
||||||
|
isTLS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ESTABLISH = iota
|
ESTABLISH = iota
|
||||||
|
AUTH
|
||||||
|
AUTH2
|
||||||
MAIL
|
MAIL
|
||||||
RCPT
|
RCPT
|
||||||
DATA
|
DATA
|
||||||
|
@ -32,7 +35,7 @@ const (
|
||||||
// TODO replace ".." lines with . in data
|
// TODO replace ".." lines with . in data
|
||||||
|
|
||||||
func StartSession(conn *net.TCPConn, conf *mailhog.Config, mongo *storage.MongoDB) {
|
func StartSession(conn *net.TCPConn, conf *mailhog.Config, mongo *storage.MongoDB) {
|
||||||
conv := &Session{conn, "", conf, ESTABLISH, &data.SMTPMessage{}, mongo}
|
conv := &Session{conn, "", conf, ESTABLISH, &data.SMTPMessage{}, mongo, false}
|
||||||
conv.log("Starting session")
|
conv.log("Starting session")
|
||||||
conv.Write("220", conv.conf.Hostname + " ESMTP Go-MailHog")
|
conv.Write("220", conv.conf.Hostname + " ESMTP Go-MailHog")
|
||||||
conv.Read()
|
conv.Read()
|
||||||
|
@ -145,13 +148,45 @@ func (c *Session) Process(line string) {
|
||||||
c.log("Got EHLO command, switching to MAIL state")
|
c.log("Got EHLO command, switching to MAIL state")
|
||||||
c.state = MAIL
|
c.state = MAIL
|
||||||
c.message.Helo = args
|
c.message.Helo = args
|
||||||
c.Write("250", "Hello " + args, "PIPELINING")
|
c.Write("250", "Hello " + args, "PIPELINING", "AUTH EXTERNAL CRAM-MD5 LOGIN PLAIN")
|
||||||
default:
|
default:
|
||||||
c.log("Got unknown command for ESTABLISH state: '%s'", command)
|
c.log("Got unknown command for ESTABLISH state: '%s'", command)
|
||||||
c.Write("500", "Unrecognised command")
|
c.Write("500", "Unrecognised command")
|
||||||
}
|
}
|
||||||
case c.state == MAIL:
|
case c.state == AUTH:
|
||||||
|
c.log("Got authentication response: '%s', switching to MAIL state", args)
|
||||||
|
c.state = MAIL
|
||||||
|
c.Write("235", "Authentication successful")
|
||||||
|
case c.state == AUTH2:
|
||||||
|
c.log("Got LOGIN authentication response: '%s', switching to AUTH state", args)
|
||||||
|
c.state = AUTH
|
||||||
|
c.Write("334", "VXNlcm5hbWU6")
|
||||||
|
case c.state == MAIL: // TODO rename/split state
|
||||||
switch command {
|
switch command {
|
||||||
|
case "AUTH":
|
||||||
|
c.log("Got AUTH command, staying in MAIL state")
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(args, "PLAIN "):
|
||||||
|
c.log("Got PLAIN authentication: %s", strings.TrimPrefix(args, "PLAIN "))
|
||||||
|
c.Write("235", "Authentication successful")
|
||||||
|
case args == "LOGIN":
|
||||||
|
c.log("Got LOGIN authentication, switching to AUTH state")
|
||||||
|
c.state = AUTH
|
||||||
|
c.Write("334", "VXNlcm5hbWU6")
|
||||||
|
case args == "PLAIN":
|
||||||
|
c.log("Got PLAIN authentication (no args), switching to AUTH state")
|
||||||
|
c.state = AUTH
|
||||||
|
c.Write("334", "")
|
||||||
|
case args == "CRAM-MD5":
|
||||||
|
c.log("Got CRAM-MD5 authentication, switching to AUTH state")
|
||||||
|
c.state = AUTH
|
||||||
|
c.Write("334", "PDQxOTI5NDIzNDEuMTI4Mjg0NzJAc291cmNlZm91ci5hbmRyZXcuY211LmVkdT4=")
|
||||||
|
case args == "EXTERNAL ":
|
||||||
|
c.log("Got EXTERNAL authentication: %s", strings.TrimPrefix(args, "EXTERNAL "))
|
||||||
|
c.Write("235", "Authentication successful")
|
||||||
|
default:
|
||||||
|
c.Write("504", "Unsupported authentication mechanism")
|
||||||
|
}
|
||||||
case "MAIL":
|
case "MAIL":
|
||||||
c.log("Got MAIL command, switching to RCPT state")
|
c.log("Got MAIL command, switching to RCPT state")
|
||||||
r, _ := regexp.Compile("From:<([^>]+)>")
|
r, _ := regexp.Compile("From:<([^>]+)>")
|
||||||
|
|
|
@ -34,7 +34,10 @@ func TestBasicHappyPath(t *testing.T) {
|
||||||
assert.Equal(t, string(buf[0:n]), "250-Hello localhost\n")
|
assert.Equal(t, string(buf[0:n]), "250-Hello localhost\n")
|
||||||
n, err = conn.Read(buf)
|
n, err = conn.Read(buf)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, string(buf[0:n]), "250 PIPELINING\n")
|
assert.Equal(t, string(buf[0:n]), "250-PIPELINING\n")
|
||||||
|
n, err = conn.Read(buf)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, string(buf[0:n]), "250 AUTH EXTERNAL CRAM-MD5 LOGIN PLAIN\n")
|
||||||
|
|
||||||
// Send MAIL
|
// Send MAIL
|
||||||
_, err = conn.Write([]byte("MAIL From:<nobody@mailhog.example>\r\n"))
|
_, err = conn.Write([]byte("MAIL From:<nobody@mailhog.example>\r\n"))
|
||||||
|
|
|
@ -34,7 +34,10 @@ func TestBasicMIMEHappyPath(t *testing.T) {
|
||||||
assert.Equal(t, string(buf[0:n]), "250-Hello localhost\n")
|
assert.Equal(t, string(buf[0:n]), "250-Hello localhost\n")
|
||||||
n, err = conn.Read(buf)
|
n, err = conn.Read(buf)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, string(buf[0:n]), "250 PIPELINING\n")
|
assert.Equal(t, string(buf[0:n]), "250-PIPELINING\n")
|
||||||
|
n, err = conn.Read(buf)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, string(buf[0:n]), "250 AUTH EXTERNAL CRAM-MD5 LOGIN PLAIN\n")
|
||||||
|
|
||||||
// Send MAIL
|
// Send MAIL
|
||||||
_, err = conn.Write([]byte("MAIL From:<nobody@mailhog.example>\r\n"))
|
_, err = conn.Write([]byte("MAIL From:<nobody@mailhog.example>\r\n"))
|
||||||
|
|
Loading…
Reference in a new issue