From be453cc2b7505f6a8eb644986ed4c7c3afcb3068 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 6 May 2021 10:42:21 +0200 Subject: [PATCH 1/4] auth: added quoting for account names on output. --- auth/auth.go | 20 +++++++++++--------- auth/auth_test.go | 26 +++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/auth/auth.go b/auth/auth.go index a71d1eb91..523aba4da 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -18,6 +18,7 @@ import ( "crypto/sha1" "encoding/hex" "fmt" + "strings" "github.com/pingcap/errors" "github.com/pingcap/parser/format" @@ -45,19 +46,21 @@ func (user *UserIdentity) Restore(ctx *format.RestoreCtx) error { return nil } -// String converts UserIdentity to the format user@host. +func EscapeAccountName(s string) string { + return "'" + strings.ReplaceAll(s, "'", "\\'") + "'" +} + +// String converts UserIdentity to the format 'user'@'host'. func (user *UserIdentity) String() string { - // TODO: Escape username and hostname. if user == nil { return "" } - return fmt.Sprintf("%s@%s", user.Username, user.Hostname) + return fmt.Sprintf("%s@%s", EscapeAccountName(user.Username), EscapeAccountName(user.Hostname)) } -// AuthIdentityString returns matched identity in user@host format +// AuthIdentityString returns matched identity in 'user'@'host' format func (user *UserIdentity) AuthIdentityString() string { - // TODO: Escape username and hostname. - return fmt.Sprintf("%s@%s", user.AuthUsername, user.AuthHostname) + return fmt.Sprintf("%s@%s", EscapeAccountName(user.AuthUsername), EscapeAccountName(user.AuthHostname)) } type RoleIdentity struct { @@ -74,10 +77,9 @@ func (role *RoleIdentity) Restore(ctx *format.RestoreCtx) error { return nil } -// String converts UserIdentity to the format user@host. +// String converts UserIdentity to the format 'user'@'host'. func (role *RoleIdentity) String() string { - // TODO: Escape username and hostname. - return fmt.Sprintf("`%s`@`%s`", role.Username, role.Hostname) + return fmt.Sprintf("%s@%s", EscapeAccountName(role.Username), EscapeAccountName(role.Hostname)) } // CheckScrambledPassword check scrambled password received from client. diff --git a/auth/auth_test.go b/auth/auth_test.go index 93f0ade6f..222899b47 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -11,12 +11,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -package auth +package auth_test import ( + "testing" + . "github.com/pingcap/check" + . "github.com/pingcap/parser/auth" ) +func TestT(t *testing.T) { + TestingT(t) +} + var _ = Suite(&testAuthSuite{}) type testAuthSuite struct { @@ -48,3 +55,20 @@ func (s *testAuthSuite) TestCheckScramble(c *C) { res = CheckScrambledPassword(salt, hpwd, []byte("xxyyzz")) c.Assert(res, IsFalse) } + +func (s *testAuthSuite) TestEscapeAccountName(c *C) { + c.Assert(EscapeAccountName(""), Equals, "''") + c.Assert(EscapeAccountName("User"), Equals, "'User'") + c.Assert(EscapeAccountName("User's"), Equals, "'User\\'s'") + c.Assert(EscapeAccountName("User is me"), Equals, "'User is me'") + u := UserIdentity{Username: "U & I @ Party", Hostname: "10.%", CurrentUser: false, AuthUsername: "root's friend", AuthHostname: "server"} + c.Assert(u.String(), Equals, "'U & I @ Party'@'10.%'") + c.Assert(u.AuthIdentityString(), Equals, "'root\\'s friend'@'server'") + u = UserIdentity{Username: "", Hostname: "", CurrentUser: false, AuthUsername: "ceo", AuthHostname: "%"} + c.Assert(u.String(), Equals, "''@''") + c.Assert(u.AuthIdentityString(), Equals, "'ceo'@'%'") + var uNil *UserIdentity = nil + c.Assert(uNil.String(), Equals, "") + r := RoleIdentity{Username: "Admin", Hostname: "192.168.%"} + c.Assert(r.String(), Equals, "'Admin'@'192.168.%'") +} From 580183d7f5a42740d510c532fd79c39e2ef837ae Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Sat, 8 May 2021 13:53:38 +0200 Subject: [PATCH 2/4] Account name quoting, changed from backslash escape to double quoting To be agnostic about NO_BACKSLASH_ESCAPES sql_mode. Currently the interface for these functions do not include sql_mode, so by not using backslash as escape character, we avoid the need to check this sql_mode. --- auth/auth.go | 5 ++++- auth/auth_test.go | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/auth/auth.go b/auth/auth.go index 523aba4da..72ad701a4 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -47,7 +47,10 @@ func (user *UserIdentity) Restore(ctx *format.RestoreCtx) error { } func EscapeAccountName(s string) string { - return "'" + strings.ReplaceAll(s, "'", "\\'") + "'" + // We do not have access to the sql_mode here, + // so assume NO_BACKSLASH_ESCAPES in effect, + // since it is still correct if not set. + return "'" + strings.ReplaceAll(s, "'", "''") + "'" } // String converts UserIdentity to the format 'user'@'host'. diff --git a/auth/auth_test.go b/auth/auth_test.go index 222899b47..dfce82602 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -59,11 +59,11 @@ func (s *testAuthSuite) TestCheckScramble(c *C) { func (s *testAuthSuite) TestEscapeAccountName(c *C) { c.Assert(EscapeAccountName(""), Equals, "''") c.Assert(EscapeAccountName("User"), Equals, "'User'") - c.Assert(EscapeAccountName("User's"), Equals, "'User\\'s'") + c.Assert(EscapeAccountName("User's"), Equals, "'User''s'") c.Assert(EscapeAccountName("User is me"), Equals, "'User is me'") u := UserIdentity{Username: "U & I @ Party", Hostname: "10.%", CurrentUser: false, AuthUsername: "root's friend", AuthHostname: "server"} c.Assert(u.String(), Equals, "'U & I @ Party'@'10.%'") - c.Assert(u.AuthIdentityString(), Equals, "'root\\'s friend'@'server'") + c.Assert(u.AuthIdentityString(), Equals, "'root''s friend'@'server'") u = UserIdentity{Username: "", Hostname: "", CurrentUser: false, AuthUsername: "ceo", AuthHostname: "%"} c.Assert(u.String(), Equals, "''@''") c.Assert(u.AuthIdentityString(), Equals, "'ceo'@'%'") From 07badcafbc7116364ce38e7141b3fdb95c7556b7 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 22 Jun 2021 11:22:41 +0200 Subject: [PATCH 3/4] cleaned up the auth_test.go file --- auth/auth_test.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/auth/auth_test.go b/auth/auth_test.go index 6f116edf2..75e00ef89 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -11,19 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package auth_test +package auth import ( "testing" . "github.com/pingcap/check" - . "github.com/pingcap/parser/auth" ) -func TestT(t *testing.T) { - TestingT(t) -} - var _ = Suite(&testAuthSuite{}) type testAuthSuite struct { From de6d50e9aa8f58c43e542a18da997a1377195af6 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 22 Jun 2021 11:54:40 +0200 Subject: [PATCH 4/4] Added one more testcase with more quote variations --- auth/auth_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/auth/auth_test.go b/auth/auth_test.go index 75e00ef89..7f3ec90aa 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -33,6 +33,8 @@ func (s *testAuthSuite) TestEscapeAccountName(c *C) { c.Assert(EscapeAccountName("User"), Equals, "'User'") c.Assert(EscapeAccountName("User's"), Equals, "'User''s'") c.Assert(EscapeAccountName("User is me"), Equals, "'User is me'") + c.Assert(EscapeAccountName(`u'v"w\'x\"y@z`+"`a"+`\b\\c`), Equals, "'u''v\"w\\''x\\\"y@z`a\\b\\\\c'") // u'v"\'x\"y@z`a\b\\c -> 'u''v"\''x\"y@z`a\b\\c' + c.Assert(EscapeAccountName("u'v\"w\\'x\\\"y@z`a\\b\\\\c"), Equals, `'u''v"w\''x\"y@z`+"`"+`a\b\\c'`) // u'v"\'x\"y@z`a\b\\c -> 'u''v"\''x\"y@z`a\b\\c' u := UserIdentity{Username: "U & I @ Party", Hostname: "10.%", CurrentUser: false, AuthUsername: "root's friend", AuthHostname: "server"} c.Assert(u.String(), Equals, "'U & I @ Party'@'10.%'") c.Assert(u.AuthIdentityString(), Equals, "'root''s friend'@'server'")