-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
*: implement auth plugin support in the extension framework (#53494)
close #53181
- Loading branch information
Showing
16 changed files
with
1,210 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
// Copyright 2024 PingCAP, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package extension | ||
|
||
import ( | ||
"crypto/tls" | ||
"slices" | ||
|
||
"github.com/pingcap/errors" | ||
"github.com/pingcap/tidb/pkg/parser/auth" | ||
"github.com/pingcap/tidb/pkg/parser/mysql" | ||
"github.com/pingcap/tidb/pkg/privilege/conn" | ||
) | ||
|
||
// AuthPlugin contains attributes needed for an authentication plugin. | ||
type AuthPlugin struct { | ||
// Name is the name of the auth plugin. It will be registered as a system variable in TiDB which can be used inside the `CREATE USER ... IDENTIFIED WITH 'plugin_name'` statement. | ||
Name string | ||
|
||
// RequiredClientSidePlugin is the name of the client-side plugin required by the server-side plugin. It will be used to check if the client has the required plugin installed and require the client to use it if installed. | ||
// The user can require default MySQL plugins such as 'caching_sha2_password' or 'mysql_native_password'. | ||
// If this is empty then `AuthPlugin.Name` is used as the required client-side plugin. | ||
RequiredClientSidePlugin string | ||
|
||
// AuthenticateUser is called when a client connects to the server as a user and the server authenticates the user. | ||
// If an error is returned, the login attempt fails, otherwise it succeeds. | ||
// request: The request context for the authentication plugin to authenticate a user | ||
AuthenticateUser func(request AuthenticateRequest) error | ||
|
||
// GenerateAuthString is a function for user to implement customized ways to encode the password (e.g. hash/salt/clear-text). The returned string will be stored as the encoded password in the mysql.user table. | ||
// If the input password is considered as invalid, this should return an error. | ||
// pwd: User's input password in CREATE/ALTER USER statements in clear-text | ||
GenerateAuthString func(pwd string) (string, bool) | ||
|
||
// ValidateAuthString checks if the password hash stored in the mysql.user table or passed in from `IDENTIFIED AS` is valid. | ||
// This is called when retrieving an existing user to make sure the password stored is valid and not modified and make sure user is passing a valid password hash in `IDENTIFIED AS`. | ||
// pwdHash: hash of the password stored in the internal user table | ||
ValidateAuthString func(pwdHash string) bool | ||
|
||
// VerifyPrivilege is called for each user queries, and serves as an extra check for privileges for the user. | ||
// It will only be executed if the user has already been granted the privilege in SQL layer. | ||
// Returns true if user has the requested privilege. | ||
// request: The request context for the authorization plugin to authorize a user's static privilege | ||
VerifyPrivilege func(request VerifyStaticPrivRequest) bool | ||
|
||
// VerifyDynamicPrivilege is called for each user queries, and serves as an extra check for dynamic privileges for the user. | ||
// It will only be executed if the user has already been granted the dynamic privilege in SQL layer. | ||
// Returns true if user has the requested privilege. | ||
// request: The request context for the authorization plugin to authorize a user's dynamic privilege | ||
VerifyDynamicPrivilege func(request VerifyDynamicPrivRequest) bool | ||
} | ||
|
||
// AuthenticateRequest contains the context for the authentication plugin to authenticate a user. | ||
type AuthenticateRequest struct { | ||
// User The username in the connect attempt | ||
User string | ||
// StoredAuthString The user's auth string stored in mysql.user table | ||
StoredAuthString string | ||
// InputAuthString The user's auth string passed in from the connection attempt in bytes | ||
InputAuthString []byte | ||
// Salt Randomly generated salt for the current connection | ||
Salt []byte | ||
// ConnState The TLS connection state (contains the TLS certificate) if client is using TLS. It will be nil if the client is not using TLS | ||
ConnState *tls.ConnectionState | ||
// AuthConn Interface for the plugin to communicate with the client | ||
AuthConn conn.AuthConn | ||
} | ||
|
||
// VerifyStaticPrivRequest contains the context for the plugin to authorize a user's static privilege. | ||
type VerifyStaticPrivRequest struct { | ||
// User The username in the connect attempt | ||
User string | ||
// Host The host that the user is connecting from | ||
Host string | ||
// DB The database to check for privilege | ||
DB string | ||
// Table The table to check for privilege | ||
Table string | ||
// Column The column to check for privilege (currently just a placeholder in TiDB as column-level privilege is not supported by TiDB yet) | ||
Column string | ||
// StaticPriv The privilege type of the SQL statement that will be executed | ||
StaticPriv mysql.PrivilegeType | ||
// ConnState The TLS connection state (contains the TLS certificate) if client is using TLS. It will be nil if the client is not using TLS | ||
ConnState *tls.ConnectionState | ||
// ActiveRoles List of active MySQL roles for the current user | ||
ActiveRoles []*auth.RoleIdentity | ||
} | ||
|
||
// VerifyDynamicPrivRequest contains the context for the plugin to authorize a user's dynamic privilege. | ||
type VerifyDynamicPrivRequest struct { | ||
// User The username in the connect attempt | ||
User string | ||
// Host The host that the user is connecting from | ||
Host string | ||
// DynamicPriv the dynamic privilege required by the user's SQL statement | ||
DynamicPriv string | ||
// ConnState The TLS connection state (contains the TLS certificate) if client is using TLS. It will be nil if the client is not using TLS | ||
ConnState *tls.ConnectionState | ||
// ActiveRoles List of active MySQL roles for the current user | ||
ActiveRoles []*auth.RoleIdentity | ||
// WithGrant Whether the statement to be executed is granting the user privilege for executing GRANT statements | ||
WithGrant bool | ||
} | ||
|
||
// validateAuthPlugin validates the auth plugin functions and attributes. | ||
func validateAuthPlugin(m *Manifest) error { | ||
pluginNames := make(map[string]bool) | ||
// Validate required functions for the auth plugins | ||
for _, p := range m.authPlugins { | ||
if p.Name == "" { | ||
return errors.Errorf("auth plugin name cannot be empty for %s", p.Name) | ||
} | ||
if pluginNames[p.Name] { | ||
return errors.Errorf("auth plugin name %s has already been registered", p.Name) | ||
} | ||
pluginNames[p.Name] = true | ||
if slices.Contains(mysql.DefaultAuthPlugins, p.Name) { | ||
return errors.Errorf("auth plugin name %s is a reserved name for default auth plugins", p.Name) | ||
} | ||
if p.AuthenticateUser == nil { | ||
return errors.Errorf("auth plugin AuthenticateUser function cannot be nil for %s", p.Name) | ||
} | ||
if p.GenerateAuthString == nil { | ||
return errors.Errorf("auth plugin GenerateAuthString function cannot be nil for %s", p.Name) | ||
} | ||
if p.ValidateAuthString == nil { | ||
return errors.Errorf("auth plugin ValidateAuthString function cannot be nil for %s", p.Name) | ||
} | ||
} | ||
return nil | ||
} |
Oops, something went wrong.