Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: create a user using tidb_auth_token authentication #38585

Merged
merged 31 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7f6f17f
Create user with `tidb_auth_token`
CbcWestwolf Oct 21, 2022
d21fab3
Add test for create user
CbcWestwolf Oct 25, 2022
28b9548
Merge branch 'master' into tidb_auth_token
CbcWestwolf Oct 25, 2022
7be6f51
Fix UT
CbcWestwolf Oct 25, 2022
ca7a000
Support `token_require` and `token_issuer`
CbcWestwolf Oct 25, 2022
a1e3c5f
show create user
CbcWestwolf Oct 25, 2022
d559001
bazel
CbcWestwolf Oct 26, 2022
ab25f46
Fix UT
CbcWestwolf Oct 26, 2022
10476c2
Add more test
CbcWestwolf Oct 26, 2022
13a4b0f
Merge branch 'master' of github.com:pingcap/tidb into tidb_auth_token
CbcWestwolf Oct 26, 2022
c50c762
Update
CbcWestwolf Oct 26, 2022
241aea7
Add warning while specifying `token_require` for other auth
CbcWestwolf Oct 26, 2022
16a8ec5
Fix parser
CbcWestwolf Oct 26, 2022
a5adcf7
Fix
CbcWestwolf Oct 26, 2022
23156c9
Fix
CbcWestwolf Oct 26, 2022
a2b0cf9
Fix UT
CbcWestwolf Oct 26, 2022
13c7567
Merge branch 'master' into tidb_auth_token
CbcWestwolf Oct 26, 2022
536ec01
Add more warnings
CbcWestwolf Oct 26, 2022
dd8b19a
Merge TLSOption and AuthTokenOption into AuthTokenOrTLSOption
CbcWestwolf Oct 26, 2022
01d21df
Merge branch 'tidb_auth_token' of github.com:CbcWestwolf/tidb into ti…
CbcWestwolf Oct 26, 2022
ff20723
Update
CbcWestwolf Oct 26, 2022
b09987b
Merge branch 'tidb_auth_token' of github.com:CbcWestwolf/tidb into ti…
CbcWestwolf Oct 27, 2022
b3034f4
Merge branch 'master' of github.com:pingcap/tidb into tidb_auth_token
CbcWestwolf Oct 27, 2022
c39474b
Merge branch 'master' of github.com:pingcap/tidb into tidb_auth_token
CbcWestwolf Oct 28, 2022
50b54bd
Fix build
CbcWestwolf Oct 28, 2022
a758fb6
Update
CbcWestwolf Oct 28, 2022
daed722
Rename
CbcWestwolf Oct 28, 2022
b2f1d75
Apply suggestions from code review
CbcWestwolf Oct 28, 2022
5f3294d
Update
CbcWestwolf Oct 28, 2022
340811b
Update UT
CbcWestwolf Oct 28, 2022
ffc937c
Merge branch 'master' into tidb_auth_token
ti-chi-bot Oct 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions executor/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1005,14 +1005,14 @@ func (b *executorBuilder) buildReplace(vals *InsertValues) Executor {

func (b *executorBuilder) buildGrant(grant *ast.GrantStmt) Executor {
e := &GrantExec{
baseExecutor: newBaseExecutor(b.ctx, nil, 0),
Privs: grant.Privs,
ObjectType: grant.ObjectType,
Level: grant.Level,
Users: grant.Users,
WithGrant: grant.WithGrant,
TLSOptions: grant.TLSOptions,
is: b.is,
baseExecutor: newBaseExecutor(b.ctx, nil, 0),
Privs: grant.Privs,
ObjectType: grant.ObjectType,
Level: grant.Level,
Users: grant.Users,
WithGrant: grant.WithGrant,
AuthTokenOrTLSOptions: grant.AuthTokenOrTLSOptions,
is: b.is,
}
return e
}
Expand Down
52 changes: 27 additions & 25 deletions executor/grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ var (
type GrantExec struct {
baseExecutor

Privs []*ast.PrivElem
ObjectType ast.ObjectTypeType
Level *ast.GrantLevel
Users []*ast.UserSpec
TLSOptions []*ast.TLSOption
Privs []*ast.PrivElem
ObjectType ast.ObjectTypeType
Level *ast.GrantLevel
Users []*ast.UserSpec
AuthTokenOrTLSOptions []*ast.AuthTokenOrTLSOption

is infoschema.InfoSchema
WithGrant bool
Expand Down Expand Up @@ -186,7 +186,7 @@ func (e *GrantExec) Next(ctx context.Context, req *chunk.Chunk) error {
// DB scope: mysql.DB
// Table scope: mysql.Tables_priv
// Column scope: mysql.Columns_priv
if e.TLSOptions != nil {
if e.AuthTokenOrTLSOptions != nil {
err = checkAndInitGlobalPriv(internalSession, user.User.Username, user.User.Hostname)
if err != nil {
return err
Expand Down Expand Up @@ -356,24 +356,24 @@ func initColumnPrivEntry(sctx sessionctx.Context, user string, host string, db s
// grantGlobalPriv grants priv to user in global scope.
func (e *GrantExec) grantGlobalPriv(sctx sessionctx.Context, user *ast.UserSpec) error {
ctx := kv.WithInternalSourceType(context.Background(), kv.InternalTxnPrivilege)
if len(e.TLSOptions) == 0 {
if len(e.AuthTokenOrTLSOptions) == 0 {
return nil
}
priv, err := tlsOption2GlobalPriv(e.TLSOptions)
priv, err := tlsOption2GlobalPriv(e.AuthTokenOrTLSOptions)
if err != nil {
return errors.Trace(err)
}
_, err = sctx.(sqlexec.SQLExecutor).ExecuteInternal(ctx, `UPDATE %n.%n SET PRIV=%? WHERE User=%? AND Host=%?`, mysql.SystemDB, mysql.GlobalPrivTable, priv, user.User.Username, user.User.Hostname)
return err
}

func tlsOption2GlobalPriv(tlsOptions []*ast.TLSOption) (priv []byte, err error) {
if len(tlsOptions) == 0 {
func tlsOption2GlobalPriv(authTokenOrTLSOptions []*ast.AuthTokenOrTLSOption) (priv []byte, err error) {
if len(authTokenOrTLSOptions) == 0 {
priv = []byte("{}")
return
}
dupSet := make(map[int]struct{})
for _, opt := range tlsOptions {
dupSet := make(map[ast.AuthTokenOrTLSOptionType]struct{})
for _, opt := range authTokenOrTLSOptions {
if _, dup := dupSet[opt.Type]; dup {
var typeName string
switch opt.Type {
Expand All @@ -385,15 +385,16 @@ func tlsOption2GlobalPriv(tlsOptions []*ast.TLSOption) (priv []byte, err error)
typeName = "SUBJECT"
case ast.SAN:
typeName = "SAN"
case ast.TokenIssuer:
}
err = errors.Errorf("Duplicate require %s clause", typeName)
return
}
dupSet[opt.Type] = struct{}{}
}
gp := privileges.GlobalPrivValue{SSLType: privileges.SslTypeNotSpecified}
for _, tlsOpt := range tlsOptions {
switch tlsOpt.Type {
for _, opt := range authTokenOrTLSOptions {
switch opt.Type {
case ast.TlsNone:
gp.SSLType = privileges.SslTypeNone
case ast.Ssl:
Expand All @@ -402,36 +403,37 @@ func tlsOption2GlobalPriv(tlsOptions []*ast.TLSOption) (priv []byte, err error)
gp.SSLType = privileges.SslTypeX509
case ast.Cipher:
gp.SSLType = privileges.SslTypeSpecified
if len(tlsOpt.Value) > 0 {
if _, ok := util.SupportCipher[tlsOpt.Value]; !ok {
err = errors.Errorf("Unsupported cipher suit: %s", tlsOpt.Value)
if len(opt.Value) > 0 {
if _, ok := util.SupportCipher[opt.Value]; !ok {
err = errors.Errorf("Unsupported cipher suit: %s", opt.Value)
return
}
gp.SSLCipher = tlsOpt.Value
gp.SSLCipher = opt.Value
}
case ast.Issuer:
err = util.CheckSupportX509NameOneline(tlsOpt.Value)
err = util.CheckSupportX509NameOneline(opt.Value)
if err != nil {
return
}
gp.SSLType = privileges.SslTypeSpecified
gp.X509Issuer = tlsOpt.Value
gp.X509Issuer = opt.Value
case ast.Subject:
err = util.CheckSupportX509NameOneline(tlsOpt.Value)
err = util.CheckSupportX509NameOneline(opt.Value)
if err != nil {
return
}
gp.SSLType = privileges.SslTypeSpecified
gp.X509Subject = tlsOpt.Value
gp.X509Subject = opt.Value
case ast.SAN:
gp.SSLType = privileges.SslTypeSpecified
_, err = util.ParseAndCheckSAN(tlsOpt.Value)
_, err = util.ParseAndCheckSAN(opt.Value)
if err != nil {
return
}
gp.SAN = tlsOpt.Value
gp.SAN = opt.Value
case ast.TokenIssuer:
default:
err = errors.Errorf("Unknown ssl type: %#v", tlsOpt.Type)
err = errors.Errorf("Unknown ssl type: %#v", opt.Type)
return
}
}
Expand Down
13 changes: 9 additions & 4 deletions executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -1504,7 +1504,7 @@ func (e *ShowExec) fetchShowCollation() error {
return nil
}

// fetchShowCreateUser composes show create create user result.
// fetchShowCreateUser composes 'show create user' result.
func (e *ShowExec) fetchShowCreateUser(ctx context.Context) error {
checker := privilege.GetPrivilegeManager(e.ctx)
if checker == nil {
Expand All @@ -1528,7 +1528,7 @@ func (e *ShowExec) fetchShowCreateUser(ctx context.Context) error {

exec := e.ctx.(sqlexec.RestrictedSQLExecutor)

rows, _, err := exec.ExecRestrictedSQL(ctx, nil, `SELECT plugin, Account_locked, JSON_UNQUOTE(JSON_EXTRACT(user_attributes, '$.metadata'))
rows, _, err := exec.ExecRestrictedSQL(ctx, nil, `SELECT plugin, Account_locked, JSON_UNQUOTE(JSON_EXTRACT(user_attributes, '$.metadata')), Token_issuer
FROM %n.%n WHERE User=%? AND Host=%?`,
mysql.SystemDB, mysql.UserTable, userName, strings.ToLower(hostName))
if err != nil {
Expand Down Expand Up @@ -1557,6 +1557,11 @@ func (e *ShowExec) fetchShowCreateUser(ctx context.Context) error {
userAttributes = " ATTRIBUTE " + userAttributes
}

tokenIssuer := rows[0].GetString(3)
if len(tokenIssuer) > 0 {
tokenIssuer = " token_issuer " + tokenIssuer
}

rows, _, err = exec.ExecRestrictedSQL(ctx, nil, `SELECT Priv FROM %n.%n WHERE User=%? AND Host=%?`, mysql.SystemDB, mysql.GlobalPrivTable, userName, hostName)
if err != nil {
return errors.Trace(err)
Expand All @@ -1580,8 +1585,8 @@ func (e *ShowExec) fetchShowCreateUser(ctx context.Context) error {
}

// FIXME: the returned string is not escaped safely
showStr := fmt.Sprintf("CREATE USER '%s'@'%s' IDENTIFIED WITH '%s'%s REQUIRE %s PASSWORD EXPIRE DEFAULT ACCOUNT %s%s",
e.User.Username, e.User.Hostname, authplugin, authStr, require, accountLocked, userAttributes)
showStr := fmt.Sprintf("CREATE USER '%s'@'%s' IDENTIFIED WITH '%s'%s REQUIRE %s%s PASSWORD EXPIRE DEFAULT ACCOUNT %s%s",
e.User.Username, e.User.Hostname, authplugin, authStr, require, tokenIssuer, accountLocked, userAttributes)
e.appendRow([]interface{}{showStr})
return nil
}
Expand Down
6 changes: 6 additions & 0 deletions executor/showtest/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,12 @@ func TestShowCreateUser(t *testing.T) {
tk.MustQuery("SHOW CREATE USER commentUser").Check(testkit.Rows(`CREATE USER 'commentUser'@'%' IDENTIFIED WITH 'mysql_native_password' AS '' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK ATTRIBUTE {"comment": "1234"}`))
tk.MustExec(`CREATE USER attributeUser attribute '{"name": "Tom", "age": 19}'`)
tk.MustQuery("SHOW CREATE USER attributeUser").Check(testkit.Rows(`CREATE USER 'attributeUser'@'%' IDENTIFIED WITH 'mysql_native_password' AS '' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK ATTRIBUTE {"age": 19, "name": "Tom"}`))

// Creating users with 'IDENTIFIED WITH 'tidb_auth_token''
tk.MustExec(`CREATE USER 'token_user'@'%' IDENTIFIED WITH 'tidb_auth_token' ATTRIBUTE '{"email": "user@pingcap.com"}'`)
tk.MustQuery("SHOW CREATE USER token_user").Check(testkit.Rows(`CREATE USER 'token_user'@'%' IDENTIFIED WITH 'tidb_auth_token' AS '' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK ATTRIBUTE {"email": "user@pingcap.com"}`))
tk.MustExec(`ALTER USER 'token_user'@'%' REQUIRE token_issuer 'issuer-ABC'`)
tk.MustQuery("SHOW CREATE USER token_user").Check(testkit.Rows(`CREATE USER 'token_user'@'%' IDENTIFIED WITH 'tidb_auth_token' AS '' REQUIRE NONE token_issuer issuer-ABC PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK ATTRIBUTE {"email": "user@pingcap.com"}`))
}

func TestUnprivilegedShow(t *testing.T) {
Expand Down
79 changes: 74 additions & 5 deletions executor/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ func (e *SimpleExec) executeCreateUser(ctx context.Context, s *ast.CreateUserStm
}
}

privData, err := tlsOption2GlobalPriv(s.TLSOptions)
privData, err := tlsOption2GlobalPriv(s.AuthTokenOrTLSOptions)
if err != nil {
return err
}
Expand Down Expand Up @@ -836,8 +836,16 @@ func (e *SimpleExec) executeCreateUser(ctx context.Context, s *ast.CreateUserStm
}
}

tokenIssuer := ""
for _, authTokenOption := range s.AuthTokenOrTLSOptions {
switch authTokenOption.Type {
case ast.TokenIssuer:
tokenIssuer = authTokenOption.Value
}
}

sql := new(strings.Builder)
sqlexec.MustFormatSQL(sql, `INSERT INTO %n.%n (Host, User, authentication_string, plugin, user_attributes, Account_locked) VALUES `, mysql.SystemDB, mysql.UserTable)
sqlexec.MustFormatSQL(sql, `INSERT INTO %n.%n (Host, User, authentication_string, plugin, user_attributes, Account_locked, Token_issuer) VALUES `, mysql.SystemDB, mysql.UserTable)

users := make([]*auth.UserIdentity, 0, len(s.Specs))
for _, spec := range s.Specs {
Expand Down Expand Up @@ -877,13 +885,23 @@ func (e *SimpleExec) executeCreateUser(ctx context.Context, s *ast.CreateUserStm
}

switch authPlugin {
case mysql.AuthNativePassword, mysql.AuthCachingSha2Password, mysql.AuthTiDBSM3Password, mysql.AuthSocket:
case mysql.AuthNativePassword, mysql.AuthCachingSha2Password, mysql.AuthTiDBSM3Password, mysql.AuthSocket, mysql.AuthTiDBAuthToken:
default:
return ErrPluginIsNotLoaded.GenWithStackByArgs(spec.AuthOpt.AuthPlugin)
}

recordTokenIssuer := tokenIssuer
if len(recordTokenIssuer) > 0 && authPlugin != mysql.AuthTiDBAuthToken {
err := fmt.Errorf("TOKEN_ISSUER is no need for '%s' user", authPlugin)
e.ctx.GetSessionVars().StmtCtx.AppendWarning(err)
recordTokenIssuer = ""
} else if len(recordTokenIssuer) == 0 && authPlugin == mysql.AuthTiDBAuthToken {
err := fmt.Errorf("TOKEN_ISSUER is need for 'tidb_auth_token' user, please use 'alter user' to declare it")
e.ctx.GetSessionVars().StmtCtx.AppendWarning(err)
}

hostName := strings.ToLower(spec.User.Hostname)
sqlexec.MustFormatSQL(sql, `(%?, %?, %?, %?, %?, %?)`, hostName, spec.User.Username, pwd, authPlugin, userAttributes, lockAccount)
sqlexec.MustFormatSQL(sql, `(%?, %?, %?, %?, %?, %?, %?)`, hostName, spec.User.Username, pwd, authPlugin, userAttributes, lockAccount, recordTokenIssuer)
users = append(users, spec.User)
}
if len(users) == 0 {
Expand Down Expand Up @@ -962,7 +980,7 @@ func (e *SimpleExec) executeAlterUser(ctx context.Context, s *ast.AlterUserStmt)
}
}

privData, err := tlsOption2GlobalPriv(s.TLSOptions)
privData, err := tlsOption2GlobalPriv(s.AuthTokenOrTLSOptions)
if err != nil {
return err
}
Expand All @@ -978,6 +996,13 @@ func (e *SimpleExec) executeAlterUser(ctx context.Context, s *ast.AlterUserStmt)
hasRestrictedUserPriv := checker.RequestDynamicVerification(activeRoles, "RESTRICTED_USER_ADMIN", false)
hasSystemSchemaPriv := checker.RequestVerification(activeRoles, mysql.SystemDB, mysql.UserTable, "", mysql.UpdatePriv)

var authTokenOptions []*ast.AuthTokenOrTLSOption
for _, authTokenOrTLSOption := range s.AuthTokenOrTLSOptions {
if authTokenOrTLSOption.Type == ast.TokenIssuer {
authTokenOptions = append(authTokenOptions, authTokenOrTLSOption)
}
}

for _, spec := range s.Specs {
user := e.ctx.GetSessionVars().User
if spec.User.CurrentUser || ((user != nil) && (user.Username == spec.User.Username) && (user.AuthHostname == spec.User.Hostname)) {
Expand Down Expand Up @@ -1021,6 +1046,22 @@ func (e *SimpleExec) executeAlterUser(ctx context.Context, s *ast.AlterUserStmt)
continue
}

type AuthTokenOptionHandler int
const (
// NotAuthToken means the final auth plugin is NOT tidb_auth_plugin
NotAuthToken AuthTokenOptionHandler = iota
// NoNeedAuthTokenOptions means the final auth_plugin is tidb_auth_plugin but need no AuthTokenOptions here
NoNeedAuthTokenOptions
// NeedAuthTokenOptions means the final auth_plugin is tidb_auth_plugin and need AuthTokenOptions here
NeedAuthTokenOptions
)
authTokenOptionHandler := NotAuthToken
if currentAuthPlugin, err := e.userAuthPlugin(spec.User.Username, spec.User.Hostname); err != nil {
return err
} else if currentAuthPlugin == mysql.AuthTiDBAuthToken {
authTokenOptionHandler = NoNeedAuthTokenOptions
}

exec := e.ctx.(sqlexec.RestrictedSQLExecutor)
type alterField struct {
expr string
Expand All @@ -1037,6 +1078,11 @@ func (e *SimpleExec) executeAlterUser(ctx context.Context, s *ast.AlterUserStmt)
}
switch spec.AuthOpt.AuthPlugin {
case mysql.AuthNativePassword, mysql.AuthCachingSha2Password, mysql.AuthTiDBSM3Password, mysql.AuthSocket, "":
authTokenOptionHandler = NotAuthToken
case mysql.AuthTiDBAuthToken:
if authTokenOptionHandler != NoNeedAuthTokenOptions {
authTokenOptionHandler = NeedAuthTokenOptions
}
default:
return ErrPluginIsNotLoaded.GenWithStackByArgs(spec.AuthOpt.AuthPlugin)
}
Expand Down Expand Up @@ -1064,6 +1110,29 @@ func (e *SimpleExec) executeAlterUser(ctx context.Context, s *ast.AlterUserStmt)
fields = append(fields, alterField{"user_attributes=json_merge_patch(user_attributes, %?)", newAttributesStr})
}

switch authTokenOptionHandler {
case NotAuthToken:
if len(authTokenOptions) > 0 {
err := errors.New("TOKEN_ISSUER is no need for the auth plugin")
e.ctx.GetSessionVars().StmtCtx.AppendWarning(err)
}
case NoNeedAuthTokenOptions:
if len(authTokenOptions) > 0 {
for _, authTokenOption := range authTokenOptions {
fields = append(fields, alterField{authTokenOption.Type.String() + "=%?", authTokenOption.Value})
}
}
case NeedAuthTokenOptions:
if len(authTokenOptions) > 0 {
for _, authTokenOption := range authTokenOptions {
fields = append(fields, alterField{authTokenOption.Type.String() + "=%?", authTokenOption.Value})
}
} else {
err := errors.New("Auth plugin 'tidb_auth_plugin' needs TOKEN_ISSUER")
e.ctx.GetSessionVars().StmtCtx.AppendWarning(err)
}
}

if len(fields) > 0 {
sql := new(strings.Builder)
sqlexec.MustFormatSQL(sql, "UPDATE %n.%n SET ", mysql.SystemDB, mysql.UserTable)
Expand Down
16 changes: 16 additions & 0 deletions executor/simpletest/simple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,22 @@ func TestUser(t *testing.T) {
dropUserSQL = `DROP USER IF EXISTS 'test1'@'localhost' ;`
tk.MustExec(dropUserSQL)

// Test create/alter user with `tidb_auth_token`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Test that alter something else of the user (such as username) when the auth plugin is tidb_auth_token. The expectation is that it doesn't need to specify the token_issuer because you just want to change the username.
  2. Test that alter auth plugin also works.

tk.MustExec(`CREATE USER token_user IDENTIFIED WITH 'tidb_auth_token' REQUIRE token_issuer 'issuer-abc'`)
tk.MustQuery(`SELECT plugin, token_issuer FROM mysql.user WHERE user = 'token_user'`).Check(testkit.Rows("tidb_auth_token issuer-abc"))
tk.MustExec(`ALTER USER token_user REQUIRE token_issuer 'issuer-123'`)
tk.MustQuery(`SELECT plugin, token_issuer FROM mysql.user WHERE user = 'token_user'`).Check(testkit.Rows("tidb_auth_token issuer-123"))
tk.MustExec(`CREATE USER token_user1 IDENTIFIED WITH 'tidb_auth_token'`)
tk.MustQuery(`show warnings`).Check(testkit.RowsWithSep("|", "Warning|1105|TOKEN_ISSUER is need for 'tidb_auth_token' user, please use 'alter user' to declare it"))
tk.MustExec(`CREATE USER temp_user IDENTIFIED WITH 'mysql_native_password' BY '1234' REQUIRE token_issuer 'issuer-abc'`)
tk.MustQuery(`show warnings`).Check(testkit.RowsWithSep("|", "Warning|1105|TOKEN_ISSUER is no need for 'mysql_native_password' user"))
tk.MustExec(`ALTER USER temp_user IDENTIFIED WITH 'tidb_auth_token' REQUIRE token_issuer 'issuer-abc'`)
tk.MustQuery(`show warnings`).Check(testkit.Rows())
tk.MustExec(`ALTER USER temp_user IDENTIFIED WITH 'mysql_native_password' REQUIRE token_issuer 'issuer-abc'`)
tk.MustQuery(`show warnings`).Check(testkit.RowsWithSep("|", "Warning|1105|TOKEN_ISSUER is no need for the auth plugin"))
tk.MustExec(`ALTER USER temp_user IDENTIFIED WITH 'tidb_auth_token'`)
tk.MustQuery(`show warnings`).Check(testkit.RowsWithSep("|", "Warning|1105|Auth plugin 'tidb_auth_plugin' needs TOKEN_ISSUER"))

// Test alter user.
createUserSQL = `CREATE USER 'test1'@'localhost' IDENTIFIED BY '123', 'test2'@'localhost' IDENTIFIED BY '123', 'test3'@'localhost' IDENTIFIED BY '123', 'test4'@'localhost' IDENTIFIED BY '123';`
tk.MustExec(createUserSQL)
Expand Down
Loading