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