Skip to content

Commit 8ecd6c6

Browse files
authored
Merge pull request #676 from skoef/serverAttributes
fixed reading connection attributes on server side
2 parents b4f7136 + 1b27657 commit 8ecd6c6

File tree

5 files changed

+301
-7
lines changed

5 files changed

+301
-7
lines changed

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24
1515
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726
1616
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07
17+
github.com/stretchr/testify v1.7.0
1718
go.uber.org/multierr v1.6.0 // indirect
1819
go.uber.org/zap v1.16.0 // indirect
1920
golang.org/x/text v0.3.6 // indirect

go.sum

+5-1
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@ github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8
5151
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
5252
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 h1:oI+RNwuC9jF2g2lP0u0cVEEZrc/AYBCuFdvwrLWM/6Q=
5353
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4=
54+
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
5455
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
5556
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
56-
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
5757
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
58+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
59+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
5860
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
5961
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
6062
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -112,5 +114,7 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXL
112114
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
113115
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
114116
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
117+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
118+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
115119
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
116120
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

mocks/Handler.go

+161
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/handshake_resp.go

+17-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (c *Conn) readHandshakeResponse() error {
3030

3131
pos = c.readPluginName(data, pos)
3232

33-
cont, err := c.handleAuthMatch(authData, pos)
33+
cont, err := c.handleAuthMatch()
3434
if err != nil {
3535
return err
3636
}
@@ -130,7 +130,7 @@ func (c *Conn) readDb(data []byte, pos int) (int, error) {
130130
func (c *Conn) readPluginName(data []byte, pos int) int {
131131
if c.capability&CLIENT_PLUGIN_AUTH != 0 {
132132
c.authPluginName = string(data[pos : pos+bytes.IndexByte(data[pos:], 0x00)])
133-
pos += len(c.authPluginName)
133+
pos += len(c.authPluginName) + 1
134134
} else {
135135
// The method used is Native Authentication if both CLIENT_PROTOCOL_41 and CLIENT_SECURE_CONNECTION are set,
136136
// but CLIENT_PLUGIN_AUTH is not set, so we fallback to 'mysql_native_password'
@@ -191,7 +191,7 @@ func (c *Conn) handlePublicKeyRetrieval(authData []byte) (bool, error) {
191191
return true, nil
192192
}
193193

194-
func (c *Conn) handleAuthMatch(authData []byte, pos int) (bool, error) {
194+
func (c *Conn) handleAuthMatch() (bool, error) {
195195
// if the client responds the handshake with a different auth method, the server will send the AuthSwitchRequest packet
196196
// to the client to ask the client to switch.
197197

@@ -207,17 +207,29 @@ func (c *Conn) handleAuthMatch(authData []byte, pos int) (bool, error) {
207207
}
208208

209209
func (c *Conn) readAttributes(data []byte, pos int) (int, error) {
210-
attrs := make(map[string]string)
210+
// read length of attribute data
211+
attrLen, isNull, skip := LengthEncodedInt(data[pos:])
212+
pos += skip
213+
if isNull {
214+
return pos, nil
215+
}
216+
217+
if len(data) < pos+int(attrLen) {
218+
return pos, errors.New("corrupt attributes data")
219+
}
220+
211221
i := 0
222+
attrs := make(map[string]string)
212223
var key string
213224

225+
// read until end of data or NUL for atrribute key/values
214226
for {
215227
str, isNull, strLen, err := LengthEncodedString(data[pos:])
216-
217228
if err != nil {
218229
return -1, err
219230
}
220231

232+
// end of data
221233
if isNull {
222234
break
223235
}

server/handshake_resp_test.go

+117-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import (
44
"bytes"
55
"testing"
66

7+
"github.com/go-mysql-org/go-mysql/mocks"
78
"github.com/go-mysql-org/go-mysql/mysql"
9+
"github.com/stretchr/testify/mock"
810
)
911

1012
func TestReadAuthData(t *testing.T) {
@@ -53,6 +55,120 @@ func TestDecodeFirstPart(t *testing.T) {
5355
}
5456
}
5557

58+
func TestReadDB(t *testing.T) {
59+
handler := &mocks.Handler{}
60+
c := &Conn{
61+
h: handler,
62+
}
63+
c.SetCapability(mysql.CLIENT_CONNECT_WITH_DB)
64+
var dbName string
65+
66+
// when handler's UseDB is called, copy dbName to local variable
67+
handler.On("UseDB", mock.IsType("")).Return(nil).Once().RunFn = func(args mock.Arguments) {
68+
dbName = args[0].(string)
69+
}
70+
71+
// example data from
72+
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse41
73+
data := []byte{
74+
0x54, 0x00, 0x00, 0x01, 0x8d, 0xa6, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x01,
75+
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77+
0x70, 0x61, 0x6d, 0x00, 0x14, 0xab, 0x09, 0xee, 0xf6, 0xbc, 0xb1, 0x32,
78+
0x3e, 0x61, 0x14, 0x38, 0x65, 0xc0, 0x99, 0x1d, 0x95, 0x7d, 0x75, 0xd4,
79+
0x47, 0x74, 0x65, 0x73, 0x74, 0x00, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f,
80+
0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77,
81+
0x6f, 0x72, 0x64, 0x00,
82+
}
83+
pos := 61
84+
85+
var err error
86+
pos, err = c.readDb(data, pos)
87+
if err != nil {
88+
t.Fatalf("unexpected error: %s", err.Error())
89+
}
90+
91+
if pos != 66 { // 61 + len("test") + 1
92+
t.Fatalf("unexpected pos, got %d", pos)
93+
}
94+
95+
if dbName != "test" {
96+
t.Fatalf("unexpected db, got %s", dbName)
97+
}
98+
99+
handler.AssertExpectations(t)
100+
}
101+
102+
func TestReadPluginName(t *testing.T) {
103+
// example data from
104+
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse41
105+
mysqlNativePassword := []byte{
106+
0x54, 0x00, 0x00, 0x01, 0x8d, 0xa6, 0x0f, 0x00, 0x00, 0x00, 0x00,
107+
0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109+
0x00, 0x00, 0x00, 0x70, 0x61, 0x6d, 0x00, 0x14, 0xab, 0x09, 0xee,
110+
0xf6, 0xbc, 0xb1, 0x32, 0x3e, 0x61, 0x14, 0x38, 0x65, 0xc0, 0x99,
111+
0x1d, 0x95, 0x7d, 0x75, 0xd4, 0x47, 0x74, 0x65, 0x73, 0x74, 0x00,
112+
0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76,
113+
0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00,
114+
}
115+
116+
// altered example data so it has different auth plugin
117+
otherPlugin := []byte{
118+
0x54, 0x00, 0x00, 0x01, 0x8d, 0xa6, 0x0f, 0x00, 0x00, 0x00, 0x00,
119+
0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121+
0x00, 0x00, 0x00, 0x70, 0x61, 0x6d, 0x00, 0x14, 0xab, 0x09, 0xee,
122+
0xf6, 0xbc, 0xb1, 0x32, 0x3e, 0x61, 0x14, 0x38, 0x65, 0xc0, 0x99,
123+
0x1d, 0x95, 0x7d, 0x75, 0xd4, 0x47, 0x74, 0x65, 0x73, 0x74, 0x00,
124+
0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x00,
125+
}
126+
127+
t.Run("mysql_native_password from plugin name", func(t *testing.T) {
128+
c := &Conn{}
129+
c.SetCapability(mysql.CLIENT_PLUGIN_AUTH)
130+
pos := 66
131+
132+
pos = c.readPluginName(mysqlNativePassword, pos)
133+
if pos != 88 { // 66 + len("mysql_native_password") + 1
134+
t.Fatalf("unexpected pos, got %d", pos)
135+
}
136+
137+
if c.authPluginName != "mysql_native_password" {
138+
t.Fatalf("unexpected plugin name, got %s", c.authPluginName)
139+
}
140+
})
141+
142+
t.Run("other plugin", func(t *testing.T) {
143+
c := &Conn{}
144+
c.SetCapability(mysql.CLIENT_PLUGIN_AUTH)
145+
pos := 66
146+
147+
pos = c.readPluginName(otherPlugin, pos)
148+
if pos != 73 { // 66 + len("foobar") + 1
149+
t.Fatalf("unexpected pos, got %d", pos)
150+
}
151+
152+
if c.authPluginName != "foobar" {
153+
t.Fatalf("unexpected plugin name, got %s", c.authPluginName)
154+
}
155+
})
156+
157+
t.Run("mysql_native_password as default", func(t *testing.T) {
158+
c := &Conn{}
159+
pos := 123 // can be anything
160+
161+
pos = c.readPluginName(mysqlNativePassword, pos)
162+
if pos != 123 { // capability not set, so same as initial pos
163+
t.Fatalf("unexpected pos, got %d", pos)
164+
}
165+
166+
if c.authPluginName != mysql.AUTH_NATIVE_PASSWORD {
167+
t.Fatalf("unexpected plugin name, got %s", c.authPluginName)
168+
}
169+
})
170+
}
171+
56172
func TestReadAttributes(t *testing.T) {
57173
var err error
58174
// example data from
@@ -75,7 +191,7 @@ func TestReadAttributes(t *testing.T) {
75191
0x6d, 0x06, 0x78, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x03, 0x66, 0x6f, 0x6f,
76192
0x03, 0x62, 0x61, 0x72,
77193
}
78-
pos := 85
194+
pos := 84
79195

80196
c := &Conn{}
81197

0 commit comments

Comments
 (0)