1 | package sasl
|
---|
2 |
|
---|
3 | import (
|
---|
4 | "bytes"
|
---|
5 | "errors"
|
---|
6 | )
|
---|
7 |
|
---|
8 | // The EXTERNAL mechanism name.
|
---|
9 | const External = "EXTERNAL"
|
---|
10 |
|
---|
11 | type externalClient struct {
|
---|
12 | Identity string
|
---|
13 | }
|
---|
14 |
|
---|
15 | func (a *externalClient) Start() (mech string, ir []byte, err error) {
|
---|
16 | mech = External
|
---|
17 | ir = []byte(a.Identity)
|
---|
18 | return
|
---|
19 | }
|
---|
20 |
|
---|
21 | func (a *externalClient) Next(challenge []byte) (response []byte, err error) {
|
---|
22 | return nil, ErrUnexpectedServerChallenge
|
---|
23 | }
|
---|
24 |
|
---|
25 | // An implementation of the EXTERNAL authentication mechanism, as described in
|
---|
26 | // RFC 4422. Authorization identity may be left blank to indicate that the
|
---|
27 | // client is requesting to act as the identity associated with the
|
---|
28 | // authentication credentials.
|
---|
29 | func NewExternalClient(identity string) Client {
|
---|
30 | return &externalClient{identity}
|
---|
31 | }
|
---|
32 |
|
---|
33 | // ExternalAuthenticator authenticates users with the EXTERNAL mechanism. If
|
---|
34 | // the identity is left blank, it indicates that it is the same as the one used
|
---|
35 | // in the external credentials. If identity is not empty and the server doesn't
|
---|
36 | // support it, an error must be returned.
|
---|
37 | type ExternalAuthenticator func(identity string) error
|
---|
38 |
|
---|
39 | type externalServer struct {
|
---|
40 | done bool
|
---|
41 | authenticate ExternalAuthenticator
|
---|
42 | }
|
---|
43 |
|
---|
44 | func (a *externalServer) Next(response []byte) (challenge []byte, done bool, err error) {
|
---|
45 | if a.done {
|
---|
46 | return nil, false, ErrUnexpectedClientResponse
|
---|
47 | }
|
---|
48 |
|
---|
49 | // No initial response, send an empty challenge
|
---|
50 | if response == nil {
|
---|
51 | return []byte{}, false, nil
|
---|
52 | }
|
---|
53 |
|
---|
54 | a.done = true
|
---|
55 |
|
---|
56 | if bytes.Contains(response, []byte("\x00")) {
|
---|
57 | return nil, false, errors.New("identity contains a NUL character")
|
---|
58 | }
|
---|
59 |
|
---|
60 | return nil, true, a.authenticate(string(response))
|
---|
61 | }
|
---|
62 |
|
---|
63 | // NewExternalServer creates a server implementation of the EXTERNAL
|
---|
64 | // authentication mechanism, as described in RFC 4422.
|
---|
65 | func NewExternalServer(authenticator ExternalAuthenticator) Server {
|
---|
66 | return &externalServer{authenticate: authenticator}
|
---|
67 | }
|
---|