diff options
Diffstat (limited to 'vendor/github.com/emersion/go-sasl/login.go')
-rw-r--r-- | vendor/github.com/emersion/go-sasl/login.go | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/vendor/github.com/emersion/go-sasl/login.go b/vendor/github.com/emersion/go-sasl/login.go new file mode 100644 index 0000000..3847ee1 --- /dev/null +++ b/vendor/github.com/emersion/go-sasl/login.go @@ -0,0 +1,89 @@ +package sasl + +import ( + "bytes" +) + +// The LOGIN mechanism name. +const Login = "LOGIN" + +var expectedChallenge = []byte("Password:") + +type loginClient struct { + Username string + Password string +} + +func (a *loginClient) Start() (mech string, ir []byte, err error) { + mech = "LOGIN" + ir = []byte(a.Username) + return +} + +func (a *loginClient) Next(challenge []byte) (response []byte, err error) { + if bytes.Compare(challenge, expectedChallenge) != 0 { + return nil, ErrUnexpectedServerChallenge + } else { + return []byte(a.Password), nil + } +} + +// A client implementation of the LOGIN authentication mechanism for SMTP, +// as described in http://www.iana.org/go/draft-murchison-sasl-login +// +// It is considered obsolete, and should not be used when other mechanisms are +// available. For plaintext password authentication use PLAIN mechanism. +func NewLoginClient(username, password string) Client { + return &loginClient{username, password} +} + +// Authenticates users with an username and a password. +type LoginAuthenticator func(username, password string) error + +type loginState int + +const ( + loginNotStarted loginState = iota + loginWaitingUsername + loginWaitingPassword +) + +type loginServer struct { + state loginState + username, password string + authenticate LoginAuthenticator +} + +// A server implementation of the LOGIN authentication mechanism, as described +// in https://tools.ietf.org/html/draft-murchison-sasl-login-00. +// +// LOGIN is obsolete and should only be enabled for legacy clients that cannot +// be updated to use PLAIN. +func NewLoginServer(authenticator LoginAuthenticator) Server { + return &loginServer{authenticate: authenticator} +} + +func (a *loginServer) Next(response []byte) (challenge []byte, done bool, err error) { + switch a.state { + case loginNotStarted: + // Check for initial response field, as per RFC4422 section 3 + if response == nil { + challenge = []byte("Username:") + break + } + a.state++ + fallthrough + case loginWaitingUsername: + a.username = string(response) + challenge = []byte("Password:") + case loginWaitingPassword: + a.password = string(response) + err = a.authenticate(a.username, a.password) + done = true + default: + err = ErrUnexpectedClientResponse + } + + a.state++ + return +} |