plain.go raw

   1  package sasl
   2  
   3  import (
   4  	"bytes"
   5  	"errors"
   6  )
   7  
   8  // The PLAIN mechanism name.
   9  const Plain = "PLAIN"
  10  
  11  type plainClient struct {
  12  	Identity string
  13  	Username string
  14  	Password string
  15  }
  16  
  17  func (a *plainClient) Start() (mech string, ir []byte, err error) {
  18  	mech = "PLAIN"
  19  	ir = []byte(a.Identity + "\x00" + a.Username + "\x00" + a.Password)
  20  	return
  21  }
  22  
  23  func (a *plainClient) Next(challenge []byte) (response []byte, err error) {
  24  	return nil, ErrUnexpectedServerChallenge
  25  }
  26  
  27  // A client implementation of the PLAIN authentication mechanism, as described
  28  // in RFC 4616. Authorization identity may be left blank to indicate that it is
  29  // the same as the username.
  30  func NewPlainClient(identity, username, password string) Client {
  31  	return &plainClient{identity, username, password}
  32  }
  33  
  34  // Authenticates users with an identity, a username and a password. If the
  35  // identity is left blank, it indicates that it is the same as the username.
  36  // If identity is not empty and the server doesn't support it, an error must be
  37  // returned.
  38  type PlainAuthenticator func(identity, username, password string) error
  39  
  40  type plainServer struct {
  41  	done         bool
  42  	authenticate PlainAuthenticator
  43  }
  44  
  45  func (a *plainServer) Next(response []byte) (challenge []byte, done bool, err error) {
  46  	if a.done {
  47  		err = ErrUnexpectedClientResponse
  48  		return
  49  	}
  50  
  51  	// No initial response, send an empty challenge
  52  	if response == nil {
  53  		return []byte{}, false, nil
  54  	}
  55  
  56  	a.done = true
  57  
  58  	parts := bytes.Split(response, []byte("\x00"))
  59  	if len(parts) != 3 {
  60  		err = errors.New("sasl: invalid response")
  61  		return
  62  	}
  63  
  64  	identity := string(parts[0])
  65  	username := string(parts[1])
  66  	password := string(parts[2])
  67  
  68  	err = a.authenticate(identity, username, password)
  69  	done = true
  70  	return
  71  }
  72  
  73  // A server implementation of the PLAIN authentication mechanism, as described
  74  // in RFC 4616.
  75  func NewPlainServer(authenticator PlainAuthenticator) Server {
  76  	return &plainServer{authenticate: authenticator}
  77  }
  78