mirror of
https://gitlab.com/ric_harvey/MailHog.git
synced 2024-11-27 16:24:04 +00:00
Add LOGIN/PLAIN/CRAM-MD5 authentication hooks
This commit is contained in:
parent
fc25fce4d2
commit
1a5fd826ec
4 changed files with 54 additions and 22 deletions
|
@ -1603,8 +1603,8 @@ var _bintree = &_bintree_t{nil, map[string]*_bintree_t{
|
|||
"strutil.js": &_bintree_t{assets_js_strutil_js, map[string]*_bintree_t{}},
|
||||
}},
|
||||
"templates": &_bintree_t{nil, map[string]*_bintree_t{
|
||||
"index.html": &_bintree_t{assets_templates_index_html, map[string]*_bintree_t{}},
|
||||
"layout.html": &_bintree_t{assets_templates_layout_html, map[string]*_bintree_t{}},
|
||||
"index.html": &_bintree_t{assets_templates_index_html, map[string]*_bintree_t{}},
|
||||
}},
|
||||
}},
|
||||
}}
|
||||
|
|
|
@ -24,7 +24,7 @@ type Protocol struct {
|
|||
hostname string
|
||||
|
||||
// LogHandler is called for each log message. If nil, log messages will
|
||||
// be output using fmt.Printf instead.
|
||||
// be output using log.Printf instead.
|
||||
LogHandler func(message string, args ...interface{})
|
||||
// MessageReceivedHandler is called for each message accepted by the
|
||||
// SMTP protocol. It must return a MessageID or error. If nil, messages
|
||||
|
@ -39,7 +39,7 @@ type Protocol struct {
|
|||
// ValidateAuthenticationhandler should return true if the authentication
|
||||
// parameters are valid, otherwise false. If nil, all authentication
|
||||
// attempts will be accepted.
|
||||
ValidateAuthenticationHandler func(mechanism string, args ...string) bool
|
||||
ValidateAuthenticationHandler func(mechanism string, args ...string) (errorReply *Reply, ok bool)
|
||||
}
|
||||
|
||||
// NewProtocol returns a new SMTP state machine in INVALID state
|
||||
|
@ -167,14 +167,37 @@ func (proto *Protocol) Command(command *Command) (reply *Reply) {
|
|||
proto.logf("Got unknown command for ESTABLISH state: '%s'", command.verb)
|
||||
return ReplyUnrecognisedCommand()
|
||||
}
|
||||
case AUTH == proto.state:
|
||||
proto.logf("Got authentication response: '%s', switching to MAIL state", command.args)
|
||||
case AUTHPLAIN == proto.state:
|
||||
proto.logf("Got PLAIN authentication response: '%s', switching to MAIL state", command.args)
|
||||
proto.state = MAIL
|
||||
if proto.ValidateAuthenticationHandler != nil {
|
||||
if reply, ok := proto.ValidateAuthenticationHandler("CRAM-MD5", command.args); !ok {
|
||||
return reply
|
||||
}
|
||||
}
|
||||
return ReplyAuthOk()
|
||||
case AUTHLOGIN == proto.state:
|
||||
proto.logf("Got LOGIN authentication response: '%s', switching to AUTH state", command.args)
|
||||
proto.state = AUTH
|
||||
proto.logf("Got LOGIN authentication response: '%s', switching to AUTHLOGIN2 state", command.args)
|
||||
proto.state = AUTHLOGIN2
|
||||
return ReplyAuthResponse("UGFzc3dvcmQ6")
|
||||
case AUTHLOGIN2 == proto.state:
|
||||
proto.logf("Got LOGIN authentication response: '%s', switching to MAIL state", command.args)
|
||||
proto.state = MAIL
|
||||
if proto.ValidateAuthenticationHandler != nil {
|
||||
if reply, ok := proto.ValidateAuthenticationHandler("CRAM-MD5", command.args); !ok {
|
||||
return reply
|
||||
}
|
||||
}
|
||||
return ReplyAuthOk()
|
||||
case AUTHCRAMMD5 == proto.state:
|
||||
proto.logf("Got CRAM-MD5 authentication response: '%s', switching to MAIL state", command.args)
|
||||
proto.state = MAIL
|
||||
if proto.ValidateAuthenticationHandler != nil {
|
||||
if reply, ok := proto.ValidateAuthenticationHandler("CRAM-MD5", command.args); !ok {
|
||||
return reply
|
||||
}
|
||||
}
|
||||
return ReplyAuthOk()
|
||||
case MAIL == proto.state:
|
||||
switch command.verb {
|
||||
case "AUTH":
|
||||
|
@ -182,6 +205,11 @@ func (proto *Protocol) Command(command *Command) (reply *Reply) {
|
|||
switch {
|
||||
case strings.HasPrefix(command.args, "PLAIN "):
|
||||
proto.logf("Got PLAIN authentication: %s", strings.TrimPrefix(command.args, "PLAIN "))
|
||||
if proto.ValidateAuthenticationHandler != nil {
|
||||
if reply, ok := proto.ValidateAuthenticationHandler("PLAIN", strings.TrimPrefix(command.args, "PLAIN ")); !ok {
|
||||
return reply
|
||||
}
|
||||
}
|
||||
return ReplyAuthOk()
|
||||
case "LOGIN" == command.args:
|
||||
proto.logf("Got LOGIN authentication, switching to AUTH state")
|
||||
|
@ -189,17 +217,17 @@ func (proto *Protocol) Command(command *Command) (reply *Reply) {
|
|||
return ReplyAuthResponse("VXNlcm5hbWU6")
|
||||
case "PLAIN" == command.args:
|
||||
proto.logf("Got PLAIN authentication (no args), switching to AUTH2 state")
|
||||
proto.state = AUTH
|
||||
proto.state = AUTHPLAIN
|
||||
return ReplyAuthResponse("")
|
||||
case "CRAM-MD5" == command.args:
|
||||
proto.logf("Got CRAM-MD5 authentication, switching to AUTH state")
|
||||
proto.state = AUTH
|
||||
proto.state = AUTHCRAMMD5
|
||||
return ReplyAuthResponse("PDQxOTI5NDIzNDEuMTI4Mjg0NzJAc291cmNlZm91ci5hbmRyZXcuY211LmVkdT4=")
|
||||
case strings.HasPrefix(command.args, "EXTERNAL "):
|
||||
proto.logf("Got EXTERNAL authentication: %s", strings.TrimPrefix(command.args, "EXTERNAL "))
|
||||
if proto.ValidateAuthenticationHandler != nil {
|
||||
if !proto.ValidateAuthenticationHandler("EXTERNAL", command.args) {
|
||||
// TODO error reply
|
||||
if reply, ok := proto.ValidateAuthenticationHandler("EXTERNAL", strings.TrimPrefix(command.args, "EXTERNAL ")); !ok {
|
||||
return reply
|
||||
}
|
||||
}
|
||||
return ReplyAuthOk()
|
||||
|
|
|
@ -7,8 +7,10 @@ type State int
|
|||
const (
|
||||
INVALID = State(-1)
|
||||
ESTABLISH = State(iota)
|
||||
AUTH
|
||||
AUTHPLAIN
|
||||
AUTHLOGIN
|
||||
AUTHLOGIN2
|
||||
AUTHCRAMMD5
|
||||
MAIL
|
||||
RCPT
|
||||
DATA
|
||||
|
@ -17,12 +19,14 @@ const (
|
|||
|
||||
// StateMap provides string representations of SMTP conversation states
|
||||
var StateMap = map[State]string{
|
||||
INVALID: "INVALID",
|
||||
ESTABLISH: "ESTABLISH",
|
||||
AUTH: "AUTH",
|
||||
AUTHLOGIN: "AUTHLOGIN",
|
||||
MAIL: "MAIL",
|
||||
RCPT: "RCPT",
|
||||
DATA: "DATA",
|
||||
DONE: "DONE",
|
||||
INVALID: "INVALID",
|
||||
ESTABLISH: "ESTABLISH",
|
||||
AUTHPLAIN: "AUTHPLAIN",
|
||||
AUTHLOGIN: "AUTHLOGIN",
|
||||
AUTHLOGIN2: "AUTHLOGIN2",
|
||||
AUTHCRAMMD5: "AUTHCRAMMD5",
|
||||
MAIL: "MAIL",
|
||||
RCPT: "RCPT",
|
||||
DATA: "DATA",
|
||||
DONE: "DONE",
|
||||
}
|
||||
|
|
|
@ -38,8 +38,8 @@ func Accept(conn *net.TCPConn, conf *config.Config) {
|
|||
session.logf("Session ended")
|
||||
}
|
||||
|
||||
func (c *Session) validateAuthentication(mechanism string, args ...string) bool {
|
||||
return true
|
||||
func (c *Session) validateAuthentication(mechanism string, args ...string) (errorReply *protocol.Reply, ok bool) {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
func (c *Session) validateRecipient(to string) bool {
|
||||
|
|
Loading…
Reference in a new issue