Add AUTH LOGIN tests

This commit is contained in:
Ian Kent 2014-11-23 13:47:32 +00:00
parent 8d1a721bac
commit e2226baeca
2 changed files with 111 additions and 1 deletions

View file

@ -36,6 +36,8 @@ type Protocol struct {
state State state State
message *data.SMTPMessage message *data.SMTPMessage
lastCommand *Command
Hostname string Hostname string
Ident string Ident string
@ -159,6 +161,9 @@ func (proto *Protocol) ProcessCommand(line string) (reply *Reply) {
// Command applies an SMTP verb and arguments to the state machine // Command applies an SMTP verb and arguments to the state machine
func (proto *Protocol) Command(command *Command) (reply *Reply) { func (proto *Protocol) Command(command *Command) (reply *Reply) {
defer func() {
proto.lastCommand = command
}()
switch { switch {
case "RSET" == command.verb: case "RSET" == command.verb:
proto.logf("Got RSET command, switching to MAIL state") proto.logf("Got RSET command, switching to MAIL state")
@ -199,7 +204,7 @@ func (proto *Protocol) Command(command *Command) (reply *Reply) {
proto.logf("Got LOGIN authentication response: '%s', switching to MAIL state", command.args) proto.logf("Got LOGIN authentication response: '%s', switching to MAIL state", command.args)
proto.state = MAIL proto.state = MAIL
if proto.ValidateAuthenticationHandler != nil { if proto.ValidateAuthenticationHandler != nil {
if reply, ok := proto.ValidateAuthenticationHandler("LOGIN", command.orig); !ok { if reply, ok := proto.ValidateAuthenticationHandler("LOGIN", proto.lastCommand.orig, command.orig); !ok {
return reply return reply
} }
} }

View file

@ -802,3 +802,108 @@ func TestAuthPlain(t *testing.T) {
So(handlerCalled, ShouldBeTrue) So(handlerCalled, ShouldBeTrue)
}) })
} }
func TestAuthCramMD5(t *testing.T) {
Convey("Two part AUTH CRAM-MD5 should call ValidateAuthenticationHandler", t, func() {
proto := NewProtocol()
handlerCalled := false
proto.ValidateAuthenticationHandler = func(mechanism string, args ...string) (*Reply, bool) {
handlerCalled = true
So(mechanism, ShouldEqual, "CRAM-MD5")
So(len(args), ShouldEqual, 1)
So(args[0], ShouldEqual, "oink!")
return nil, true
}
proto.Start()
proto.Command(ParseCommand("EHLO localhost"))
reply := proto.Command(ParseCommand("AUTH CRAM-MD5"))
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 334)
So(reply.Lines(), ShouldResemble, []string{"334 PDQxOTI5NDIzNDEuMTI4Mjg0NzJAc291cmNlZm91ci5hbmRyZXcuY211LmVkdT4=\n"})
_, reply = proto.Parse("oink!\n")
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 235)
So(reply.Lines(), ShouldResemble, []string{"235 Authentication successful\n"})
So(handlerCalled, ShouldBeTrue)
})
Convey("Two part AUTH CRAM-MD5 ValidateAuthenticationHandler errors should be returned", t, func() {
proto := NewProtocol()
handlerCalled := false
proto.ValidateAuthenticationHandler = func(mechanism string, args ...string) (*Reply, bool) {
handlerCalled = true
return ReplyError(errors.New("OINK :(")), false
}
proto.Start()
proto.Command(ParseCommand("EHLO localhost"))
reply := proto.Command(ParseCommand("AUTH CRAM-MD5"))
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 334)
So(reply.Lines(), ShouldResemble, []string{"334 PDQxOTI5NDIzNDEuMTI4Mjg0NzJAc291cmNlZm91ci5hbmRyZXcuY211LmVkdT4=\n"})
_, reply = proto.Parse("oink!\n")
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 550)
So(reply.Lines(), ShouldResemble, []string{"550 OINK :(\n"})
So(handlerCalled, ShouldBeTrue)
})
}
func TestAuthLogin(t *testing.T) {
Convey("AUTH LOGIN should call ValidateAuthenticationHandler", t, func() {
proto := NewProtocol()
handlerCalled := false
proto.ValidateAuthenticationHandler = func(mechanism string, args ...string) (*Reply, bool) {
handlerCalled = true
So(mechanism, ShouldEqual, "LOGIN")
So(len(args), ShouldEqual, 2)
So(args[0], ShouldEqual, "username!")
So(args[1], ShouldEqual, "password!")
return nil, true
}
proto.Start()
proto.Command(ParseCommand("EHLO localhost"))
reply := proto.Command(ParseCommand("AUTH LOGIN"))
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 334)
So(reply.Lines(), ShouldResemble, []string{"334 VXNlcm5hbWU6\n"})
_, reply = proto.Parse("username!\n")
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 334)
So(reply.Lines(), ShouldResemble, []string{"334 UGFzc3dvcmQ6\n"})
_, reply = proto.Parse("password!\n")
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 235)
So(reply.Lines(), ShouldResemble, []string{"235 Authentication successful\n"})
So(handlerCalled, ShouldBeTrue)
})
Convey("AUTH LOGIN ValidateAuthenticationHandler errors should be returned", t, func() {
proto := NewProtocol()
handlerCalled := false
proto.ValidateAuthenticationHandler = func(mechanism string, args ...string) (*Reply, bool) {
handlerCalled = true
return ReplyError(errors.New("OINK :(")), false
}
proto.Start()
proto.Command(ParseCommand("EHLO localhost"))
reply := proto.Command(ParseCommand("AUTH LOGIN"))
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 334)
So(reply.Lines(), ShouldResemble, []string{"334 VXNlcm5hbWU6\n"})
_, reply = proto.Parse("username!\n")
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 334)
So(reply.Lines(), ShouldResemble, []string{"334 UGFzc3dvcmQ6\n"})
_, reply = proto.Parse("password!\n")
So(reply, ShouldNotBeNil)
So(reply.Status, ShouldEqual, 550)
So(reply.Lines(), ShouldResemble, []string{"550 OINK :(\n"})
So(handlerCalled, ShouldBeTrue)
})
}