File: external.go

package info (click to toggle)
golang-github-emersion-go-sasl 0.0~git20230613.1d333a0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 120 kB
  • sloc: makefile: 2
file content (67 lines) | stat: -rw-r--r-- 1,863 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package sasl

import (
	"bytes"
	"errors"
)

// The EXTERNAL mechanism name.
const External = "EXTERNAL"

type externalClient struct {
	Identity string
}

func (a *externalClient) Start() (mech string, ir []byte, err error) {
	mech = External
	ir = []byte(a.Identity)
	return
}

func (a *externalClient) Next(challenge []byte) (response []byte, err error) {
	return nil, ErrUnexpectedServerChallenge
}

// An implementation of the EXTERNAL authentication mechanism, as described in
// RFC 4422. Authorization identity may be left blank to indicate that the
// client is requesting to act as the identity associated with the
// authentication credentials.
func NewExternalClient(identity string) Client {
	return &externalClient{identity}
}

// ExternalAuthenticator authenticates users with the EXTERNAL mechanism. If
// the identity is left blank, it indicates that it is the same as the one used
// in the external credentials. If identity is not empty and the server doesn't
// support it, an error must be returned.
type ExternalAuthenticator func(identity string) error

type externalServer struct {
	done         bool
	authenticate ExternalAuthenticator
}

func (a *externalServer) Next(response []byte) (challenge []byte, done bool, err error) {
	if a.done {
		return nil, false, ErrUnexpectedClientResponse
	}

	// No initial response, send an empty challenge
	if response == nil {
		return []byte{}, false, nil
	}

	a.done = true

	if bytes.Contains(response, []byte("\x00")) {
		return nil, false, errors.New("identity contains a NUL character")
	}

	return nil, true, a.authenticate(string(response))
}

// NewExternalServer creates a server implementation of the EXTERNAL
// authentication mechanism, as described in RFC 4422.
func NewExternalServer(authenticator ExternalAuthenticator) Server {
	return &externalServer{authenticate: authenticator}
}