Skip to content

Commit

Permalink
Merge related changes
Browse files Browse the repository at this point in the history
  • Loading branch information
morgo committed Dec 7, 2021
1 parent be6c044 commit 635c0ba
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 108 deletions.
68 changes: 37 additions & 31 deletions server/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ func (cc *clientConn) String() string {
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest
// https://bugs.mysql.com/bug.php?id=93044
func (cc *clientConn) authSwitchRequest(ctx context.Context, plugin string) ([]byte, error) {
failpoint.Inject("FakeAuthSwitch", func() {
failpoint.Return([]byte(plugin), nil)
})
enclen := 1 + len(plugin) + 1 + len(cc.salt) + 1
data := cc.alloc.AllocWithLen(4, enclen)
data = append(data, mysql.AuthSwitchRequest) // switch request
Expand Down Expand Up @@ -708,7 +711,7 @@ func (cc *clientConn) readOptionalSSLRequestAndHandshakeResponse(ctx context.Con

func (cc *clientConn) handleAuthPlugin(ctx context.Context, resp *handshakeResponse41) error {
if resp.Capability&mysql.ClientPluginAuth > 0 {
newAuth, err := cc.checkAuthPlugin(ctx, &resp.AuthPlugin)
newAuth, err := cc.checkAuthPlugin(ctx, resp)
if err != nil {
logutil.Logger(ctx).Warn("failed to check the user authplugin", zap.Error(err))
return err
Expand All @@ -719,30 +722,18 @@ func (cc *clientConn) handleAuthPlugin(ctx context.Context, resp *handshakeRespo

switch resp.AuthPlugin {
case mysql.AuthCachingSha2Password:
resp.Auth, err = cc.authSha(ctx)
if err != nil {
return err
}
case mysql.AuthNativePassword:
case mysql.AuthSocket:
default:
logutil.Logger(ctx).Warn("Unknown Auth Plugin", zap.String("plugin", resp.AuthPlugin))
}
} else {
// MySQL 5.1 and older clients don't support authentication plugins.
logutil.Logger(ctx).Warn("Client without Auth Plugin support; Please upgrade client")
if cc.ctx == nil {
err := cc.openSession()
if err != nil {
return err
}
}
userplugin, err := cc.ctx.AuthPluginForUser(&auth.UserIdentity{Username: cc.user, Hostname: cc.peerHost})
_, err := cc.checkAuthPlugin(ctx, resp)
if err != nil {
return err
}
if userplugin != mysql.AuthNativePassword && userplugin != "" {
return errNotSupportedAuthMode
}
resp.AuthPlugin = mysql.AuthNativePassword
}
return nil
Expand Down Expand Up @@ -846,7 +837,7 @@ func (cc *clientConn) openSessionAndDoAuth(authData []byte, authPlugin string) e
}

// Check if the Authentication Plugin of the server, client and user configuration matches
func (cc *clientConn) checkAuthPlugin(ctx context.Context, authPlugin *string) ([]byte, error) {
func (cc *clientConn) checkAuthPlugin(ctx context.Context, resp *handshakeResponse41) ([]byte, error) {
// Open a context unless this was done before.
if cc.ctx == nil {
err := cc.openSession()
Expand All @@ -855,14 +846,15 @@ func (cc *clientConn) checkAuthPlugin(ctx context.Context, authPlugin *string) (
}
}

userplugin, err := cc.ctx.AuthPluginForUser(&auth.UserIdentity{Username: cc.user, Hostname: cc.peerHost})
authData := resp.Auth
hasPassword := "YES"
if len(authData) == 0 {
hasPassword = "NO"
}
host, _, err := cc.PeerHost(hasPassword)
if err != nil {
return nil, err
}
<<<<<<< HEAD
if userplugin == mysql.AuthSocket {
*authPlugin = mysql.AuthSocket
=======
// Find the identity of the user based on username and peer host.
identity, err := cc.ctx.MatchIdentity(cc.user, host)
if err != nil {
Expand All @@ -882,17 +874,26 @@ func (cc *clientConn) checkAuthPlugin(ctx context.Context, authPlugin *string) (
return nil, errAccessDenied.FastGenByArgs(cc.user, host, hasPassword)
}
resp.AuthPlugin = mysql.AuthSocket
>>>>>>> 7fc6ebbda... privilege, session, server: consistently map user login to identity (#30204)
user, err := user.LookupId(fmt.Sprint(cc.socketCredUID))
if err != nil {
return nil, err
}
return []byte(user.Username), nil
}
if len(userplugin) == 0 {
logutil.Logger(ctx).Warn("No user plugin set, assuming MySQL Native Password",
zap.String("user", cc.user), zap.String("host", cc.peerHost))
*authPlugin = mysql.AuthNativePassword
// No user plugin set, assuming MySQL Native Password
// This happens if the account doesn't exist or if the account doesn't have
// a password set.
if resp.AuthPlugin != mysql.AuthNativePassword {
if resp.Capability&mysql.ClientPluginAuth > 0 {
resp.AuthPlugin = mysql.AuthNativePassword
authData, err := cc.authSwitchRequest(ctx, mysql.AuthNativePassword)
if err != nil {
return nil, err
}
return authData, nil
}
}
return nil, nil
}

Expand All @@ -901,13 +902,18 @@ func (cc *clientConn) checkAuthPlugin(ctx context.Context, authPlugin *string) (
// or if the authentication method send by the server doesn't match the authentication
// method send by the client (*authPlugin) then we need to switch the authentication
// method to match the one configured for that specific user.
if (cc.authPlugin != userplugin) || (cc.authPlugin != *authPlugin) {
authData, err := cc.authSwitchRequest(ctx, userplugin)
if err != nil {
return nil, err
if (cc.authPlugin != userplugin) || (cc.authPlugin != resp.AuthPlugin) {
if resp.Capability&mysql.ClientPluginAuth > 0 {
authData, err := cc.authSwitchRequest(ctx, userplugin)
if err != nil {
return nil, err
}
resp.AuthPlugin = userplugin
return authData, nil
} else if userplugin != mysql.AuthNativePassword {
// MySQL 5.1 and older don't support authentication plugins yet
return nil, errNotSupportedAuthMode
}
*authPlugin = userplugin
return authData, nil
}

return nil, nil
Expand Down
80 changes: 3 additions & 77 deletions server/conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -894,8 +894,6 @@ func TestShowErrors(t *testing.T) {
}

func TestHandleAuthPlugin(t *testing.T) {
t.Parallel()

store, clean := testkit.CreateMockStore(t)
defer clean()

Expand All @@ -905,44 +903,28 @@ func TestHandleAuthPlugin(t *testing.T) {
drv := NewTiDBDriver(store)
srv, err := NewServer(cfg, drv)
require.NoError(t, err)
ctx := context.Background()

<<<<<<< HEAD
=======
tk := testkit.NewTestKit(t, store)
tk.MustExec("CREATE USER unativepassword")
defer func() {
tk.MustExec("DROP USER unativepassword")
}()

// 5.7 or newer client trying to authenticate with mysql_native_password
>>>>>>> 7fc6ebbda... privilege, session, server: consistently map user login to identity (#30204)
cc := &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
collation: mysql.DefaultCollationID,
peerHost: "localhost",
pkt: &packetIO{
bufWriter: bufio.NewWriter(bytes.NewBuffer(nil)),
},
<<<<<<< HEAD
collation: mysql.DefaultCollationID,
server: srv,
user: "root",
=======
server: srv,
user: "unativepassword",
>>>>>>> 7fc6ebbda... privilege, session, server: consistently map user login to identity (#30204)
}
ctx := context.Background()
resp := handshakeResponse41{
Capability: mysql.ClientProtocol41 | mysql.ClientPluginAuth,
<<<<<<< HEAD
}
err = cc.handleAuthPlugin(ctx, &resp)
require.NoError(t, err)

resp.Capability = mysql.ClientProtocol41
err = cc.handleAuthPlugin(ctx, &resp)
require.NoError(t, err)
=======
AuthPlugin: mysql.AuthNativePassword,
}
err = cc.handleAuthPlugin(ctx, &resp)
Expand All @@ -953,7 +935,6 @@ func TestHandleAuthPlugin(t *testing.T) {
cc = &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
chunkAlloc: chunk.NewAllocator(),
collation: mysql.DefaultCollationID,
peerHost: "localhost",
pkt: &packetIO{
Expand All @@ -975,7 +956,6 @@ func TestHandleAuthPlugin(t *testing.T) {
cc = &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
chunkAlloc: chunk.NewAllocator(),
collation: mysql.DefaultCollationID,
peerHost: "localhost",
pkt: &packetIO{
Expand All @@ -998,7 +978,6 @@ func TestHandleAuthPlugin(t *testing.T) {
cc = &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
chunkAlloc: chunk.NewAllocator(),
collation: mysql.DefaultCollationID,
peerHost: "localhost",
pkt: &packetIO{
Expand All @@ -1021,7 +1000,6 @@ func TestHandleAuthPlugin(t *testing.T) {
cc = &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
chunkAlloc: chunk.NewAllocator(),
collation: mysql.DefaultCollationID,
peerHost: "localhost",
pkt: &packetIO{
Expand All @@ -1043,7 +1021,6 @@ func TestHandleAuthPlugin(t *testing.T) {
cc = &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
chunkAlloc: chunk.NewAllocator(),
collation: mysql.DefaultCollationID,
peerHost: "localhost",
pkt: &packetIO{
Expand All @@ -1067,7 +1044,6 @@ func TestHandleAuthPlugin(t *testing.T) {
cc = &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
chunkAlloc: chunk.NewAllocator(),
collation: mysql.DefaultCollationID,
peerHost: "localhost",
pkt: &packetIO{
Expand All @@ -1090,7 +1066,6 @@ func TestHandleAuthPlugin(t *testing.T) {
cc = &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
chunkAlloc: chunk.NewAllocator(),
collation: mysql.DefaultCollationID,
peerHost: "localhost",
pkt: &packetIO{
Expand All @@ -1112,7 +1087,6 @@ func TestHandleAuthPlugin(t *testing.T) {
cc = &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
chunkAlloc: chunk.NewAllocator(),
collation: mysql.DefaultCollationID,
peerHost: "localhost",
pkt: &packetIO{
Expand All @@ -1128,51 +1102,3 @@ func TestHandleAuthPlugin(t *testing.T) {
require.Error(t, err)
require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/server/FakeUser"))
}

func TestAuthPlugin2(t *testing.T) {

t.Parallel()

store, clean := testkit.CreateMockStore(t)
defer clean()

cfg := newTestConfig()
cfg.Socket = ""
cfg.Port = 0
cfg.Status.StatusPort = 0

drv := NewTiDBDriver(store)
srv, err := NewServer(cfg, drv)
require.NoError(t, err)

cc := &clientConn{
connectionID: 1,
alloc: arena.NewAllocator(1024),
chunkAlloc: chunk.NewAllocator(),
pkt: &packetIO{
bufWriter: bufio.NewWriter(bytes.NewBuffer(nil)),
},
server: srv,
user: "root",
}
ctx := context.Background()
se, _ := session.CreateSession4Test(store)
tc := &TiDBContext{
Session: se,
stmts: make(map[int]*TiDBStatement),
}
cc.ctx = tc

resp := handshakeResponse41{
Capability: mysql.ClientProtocol41 | mysql.ClientPluginAuth,
}

cc.isUnixSocket = true
require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/server/FakeAuthSwitch", "return(1)"))
respAuthSwitch, err := cc.checkAuthPlugin(ctx, &resp)
require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/server/FakeAuthSwitch"))
require.Equal(t, respAuthSwitch, []byte(mysql.AuthNativePassword))
require.NoError(t, err)

>>>>>>> 7fc6ebbda... privilege, session, server: consistently map user login to identity (#30204)
}
1 change: 1 addition & 0 deletions server/http_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ func (ts *basicHTTPHandlerTestSuite) startServer(c *C) {
cfg.Port = 0
cfg.Status.StatusPort = 0
cfg.Status.ReportStatus = true
cfg.Socket = ""

server, err := NewServer(cfg, ts.tidbdrv)
c.Assert(err, IsNil)
Expand Down
1 change: 1 addition & 0 deletions server/plan_replayer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func TestDumpPlanReplayerAPI(t *testing.T) {
client := newTestServerClient()
cfg := newTestConfig()
cfg.Port = client.port
cfg.Socket = ""
cfg.Status.StatusPort = client.statusPort
cfg.Status.ReportStatus = true

Expand Down
1 change: 1 addition & 0 deletions server/statistics_handler_serial_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func TestDumpStatsAPI(t *testing.T) {
client := newTestServerClient()
cfg := newTestConfig()
cfg.Port = client.port
cfg.Socket = ""
cfg.Status.StatusPort = client.statusPort
cfg.Status.ReportStatus = true

Expand Down

0 comments on commit 635c0ba

Please sign in to comment.