-
Notifications
You must be signed in to change notification settings - Fork 3
/
auth.go
103 lines (85 loc) · 2.49 KB
/
auth.go
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package packets1
import (
"bytes"
"fmt"
pkts "github.com/energomonitor/bisquitt/packets"
)
// Authentication reason constants.
const (
AUTH_SUCCESS uint8 = 0
AUTH_CONTINUE uint8 = 0x18
AUTH_REAUTHENTICATE uint8 = 0x19
)
// Auth method constants.
const (
AUTH_PLAIN = "PLAIN"
)
const authHeaderLength uint16 = 2
// Non-standard extension to allow user/password authentication in MQTT-SN.
//
// Implemented according to the OASIS Open MQTT-SN v. 2.0 draft
// https://www.oasis-open.org/committees/download.php/68568/mqtt-sn-v2.0-wd09.docx
//
// SASL PLAIN method specification: https://datatracker.ietf.org/doc/html/rfc4616
type Auth struct {
pkts.Header
// Fields
Reason uint8
Method string
Data []byte
}
// NewAuthPlain creates a new Auth with "PLAIN" method encoded
// authentication data.
func NewAuthPlain(user string, password []byte) *Auth {
p := &Auth{Header: *pkts.NewHeader(pkts.AUTH, 0)}
p.Method = "PLAIN"
var b bytes.Buffer
_ = b.WriteByte(0)
_, _ = b.Write([]byte(user))
_ = b.WriteByte(0)
_, _ = b.Write(password)
p.Data = b.Bytes()
p.computeLength()
return p
}
// DecodePlain decodes username and password from AUTH package data encoded
// using "PLAIN" method.
func (p *Auth) DecodePlain() (string, []byte, error) {
dataParts := bytes.Split(p.Data, []byte{0})
if len(dataParts) != 3 {
return "", nil, fmt.Errorf("invalid PLAIN auth data format: %v.", p.Data)
}
// NOTE: PLAIN first part (authorization identity) not used.
return string(dataParts[1]), dataParts[2], nil
}
func (p *Auth) Pack() ([]byte, error) {
p.computeLength()
buf := p.Header.PackToBuffer()
_ = buf.WriteByte(p.Reason)
_ = buf.WriteByte(byte(len(p.Method)))
_, _ = buf.Write([]byte(p.Method))
_, _ = buf.Write([]byte(p.Data))
return buf.Bytes(), nil
}
func (p *Auth) Unpack(buf []byte) error {
if len(buf) < 2 {
return fmt.Errorf("bad AUTH packet length: expected >2, got %d", len(buf))
}
p.Reason = buf[0]
methodLen := buf[1]
if len(buf) < int(2+methodLen) {
return fmt.Errorf("bad AUTH packet length: expected >=%d, got %d", 2+methodLen, len(buf))
}
p.Method = string(buf[2 : 2+methodLen])
p.Data = buf[2+methodLen:]
return nil
}
func (p Auth) String() string {
// We intentionally do not print Data because it contains sensitive data.
return fmt.Sprintf("AUTH(Reason=%d, Method=%#v)", p.Reason, p.Method)
}
func (p *Auth) computeLength() {
methodLen := uint16(len(p.Method))
dataLen := uint16(len(p.Data))
p.Header.SetVarPartLength(authHeaderLength + methodLen + dataLen)
}