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("sasl: 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 }
68