[822] | 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("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 | }
|
---|