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