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 | }
|
---|