使用所有服务器插件类型通用的常规描述符格式声明服务器端插件(参见 第 4.4.2.1 节,“服务器插件库和插件描述符”)。对于 auth_simple
插件,描述符如下所示
mysql_declare_plugin(auth_simple)
{
MYSQL_AUTHENTICATION_PLUGIN,
&auth_simple_handler, /* type-specific descriptor */
"auth_simple", /* plugin name */
"Author Name", /* author */
"Any-password authentication plugin", /* description */
PLUGIN_LICENSE_GPL, /* license type */
NULL, /* no init function */
NULL, /* no deinit function */
0x0100, /* version = 1.0 */
NULL, /* no status variables */
NULL, /* no system variables */
NULL, /* no reserved information */
0 /* no flags */
}
mysql_declare_plugin_end;
name
成员 (auth_simple
) 指示在语句(如 INSTALL PLUGIN
或 UNINSTALL PLUGIN
)中引用插件时使用的名称。这也是 SHOW PLUGINS
或 INFORMATION_SCHEMA.PLUGINS
显示的名称。
常规描述符的 auth_simple_handler
成员指向特定于类型的描述符。对于身份验证插件,特定于类型的描述符是 st_mysql_auth
结构的实例(在 plugin_auth.h
中定义)
struct st_mysql_auth
{
int interface_version;
const char *client_auth_plugin;
int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info);
int (*generate_authentication_string)(char *outbuf,
unsigned int *outbuflen, const char *inbuf, unsigned int inbuflen);
int (*validate_authentication_string)(char* const inbuf, unsigned int buflen);
int (*set_salt)(const char *password, unsigned int password_len,
unsigned char* salt, unsigned char *salt_len);
const unsigned long authentication_flags;
};
st_mysql_auth
结构具有以下成员
interface_version
:特定于类型的 API 版本号,始终为MYSQL_AUTHENTICATION_INTERFACE_VERSION
client_auth_plugin
:客户端插件名称authenticate_user
:指向与客户端通信的主插件函数的指针generate_authentication_string
:指向生成身份验证字符串密码摘要的插件函数的指针validate_authentication_string
:指向验证密码摘要的插件函数的指针set_salt
:指向将加密密码转换为二进制形式的插件函数的指针authentication_flags
:标志字
client_auth_plugin
成员应指示客户端插件的名称(如果需要特定插件)。NULL
值表示 “任何插件。” 在后一种情况下,客户端使用的任何插件都可以。如果服务器插件不关心客户端插件或它发送的用户名或密码,这将很有用。例如,如果服务器插件只验证本地客户端并使用操作系统的某些属性而不是客户端插件发送的信息,则可能如此。
对于 auth_simple
,特定于类型的描述符如下所示
static struct st_mysql_auth auth_simple_handler =
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
"auth_simple", /* required client-side plugin name */
auth_simple_server /* server-side plugin main function */
generate_auth_string_hash, /* generate digest from password string */
validate_auth_string_hash, /* validate password digest */
set_salt, /* generate password salt value */
AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE
};
主函数 auth_simple_server()
接受两个参数,分别表示 I/O 结构和 MYSQL_SERVER_AUTH_INFO
结构。结构定义在 plugin_auth.h
中,如下所示
typedef struct st_mysql_server_auth_info
{
char *user_name;
unsigned int user_name_length;
const char *auth_string;
unsigned long auth_string_length;
char authenticated_as[MYSQL_USERNAME_LENGTH+1];
char external_user[512];
int password_used;
const char *host_or_ip;
unsigned int host_or_ip_length;
} MYSQL_SERVER_AUTH_INFO;
字符串成员的字符集为 UTF-8。如果与字符串相关联的 _length
成员,它指示字符串的字节长度。字符串也是以 null 结尾的。
当服务器调用身份验证插件时,它应将 MYSQL_SERVER_AUTH_INFO
结构成员解释如下。如所述,其中一些用于设置客户端会话中 SQL 函数或系统变量的值。
user_name
:客户端发送的用户名。该值成为USER()
函数值。user_name_length
:user_name
的字节长度。-
auth_string
:mysql.user
系统表中匹配帐户名称的行的authentication_string
列的值(即,与客户端用户名和主机名匹配的行,并且服务器使用该行来确定如何验证客户端)。假设您使用以下语句创建一个帐户
CREATE USER 'my_user'@'localhost' IDENTIFIED WITH my_plugin AS 'my_auth_string';
当
my_user
从本地主机连接时,服务器调用my_plugin
并将'
传递给它作为my_auth_string
'auth_string
值。 auth_string_length
:auth_string
的字节长度。authenticated_as
:服务器将其设置为用户名(user_name
的值)。插件可以更改它以指示客户端应该具有不同用户的权限。例如,如果插件支持代理用户,则初始值为连接(代理)用户的名称,并且插件可以将此成员更改为代理用户的名称。然后,服务器将代理用户视为具有代理用户的权限(假设代理用户支持的其他条件得到满足;参见 第 4.4.9.4 节,“在身份验证插件中实现代理用户支持”)。该值表示为一个字符串,其长度最多为MYSQL_USER_NAME_LENGTH
字节,加上一个终止 null。该值成为CURRENT_USER()
函数值。external_user
:服务器将其设置为空字符串(以 null 结尾)。其值成为external_user
系统变量值。如果插件希望该系统变量具有不同的值,它应该相应地设置此成员(例如,设置为连接用户名)。该值表示为一个字符串,其长度最多为 511 字节,加上一个终止 null。-
password_used
:此成员适用于身份验证失败时。插件可以设置它或忽略它。该值用于构建Authentication fails. Password used: %s
的失败错误消息。password_used
的值决定了%s
的处理方式,如下表所示。 host_or_ip
:如果可以解析,则为客户端主机的名称,否则为 IP 地址。host_or_ip_length
:host_or_ip
的字节长度。
auth_simple
主函数 auth_simple_server()
从客户端读取密码(以 null 结尾的字符串),如果密码非空(第一个字节不为 null),则成功
static int auth_simple_server (MYSQL_PLUGIN_VIO *vio,
MYSQL_SERVER_AUTH_INFO *info)
{
unsigned char *pkt;
int pkt_len;
/* read the password as null-terminated string, fail on error */
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
return CR_ERROR;
/* fail on empty password */
if (!pkt_len || *pkt == '\0')
{
info->password_used= PASSWORD_USED_NO;
return CR_ERROR;
}
/* accept any nonempty password */
info->password_used= PASSWORD_USED_YES;
return CR_OK;
}
主函数应返回以下表格中所示的错误代码之一。
错误代码 | 含义 |
---|---|
CR_OK |
成功 |
CR_OK_HANDSHAKE_COMPLETE |
不要向客户端发送状态包 |
CR_ERROR |
错误 |
CR_AUTH_USER_CREDENTIALS |
身份验证失败 |
CR_AUTH_HANDSHAKE |
身份验证握手失败 |
CR_AUTH_PLUGIN_ERROR |
内部插件错误 |
有关握手工作原理的示例,请参见 plugin/auth/dialog.c
源文件。
服务器在 Performance Schema host_cache
表中计算插件错误。
auth_simple_server()
非常基础,它不使用身份验证信息结构,除非设置指示是否收到密码的成员。
支持代理用户的插件必须将代理用户的名称(客户端用户应该获得其权限的 MySQL 用户)返回给服务器。为此,插件必须将 info->authenticated_as
成员设置为代理用户名。有关代理的更多信息,请参见 代理用户 和 第 4.4.9.4 节,“在身份验证插件中实现代理用户支持”。
插件描述符的 generate_authentication_string
成员接受密码并从中生成密码哈希(摘要)
前两个参数是指向输出缓冲区及其最大字节长度的指针。函数应将密码哈希写入输出缓冲区并将长度重置为实际哈希长度。
后两个参数指示密码输入缓冲区及其字节长度。
函数返回 0 表示成功,1 表示发生错误。
对于 auth_simple
插件,generate_auth_string_hash()
函数实现 generate_authentication_string
成员。它只是复制密码,除非密码太长而无法放入输出缓冲区。
int generate_auth_string_hash(char *outbuf, unsigned int *buflen,
const char *inbuf, unsigned int inbuflen)
{
/*
fail if buffer specified by server cannot be copied to output buffer
*/
if (*buflen < inbuflen)
return 1; /* error */
strncpy(outbuf, inbuf, inbuflen);
*buflen= strlen(inbuf);
return 0; /* success */
}
插件描述符的 validate_authentication_string
成员验证密码哈希
参数是指向密码哈希及其字节长度的指针。
函数返回 0 表示成功,1 表示无法验证密码哈希。
对于 auth_simple
插件,validate_auth_string_hash()
函数实现 validate_authentication_string
成员。它无条件地返回成功
int validate_auth_string_hash(char* const inbuf __attribute__((unused)),
unsigned int buflen __attribute__((unused)))
{
return 0; /* success */
}
插件描述符的 set_salt
成员仅由 mysql_native_password
插件使用,该插件在 MySQL 9.0 中不再受支持。对于其他身份验证插件,您可以使用这种简单的实现
int set_salt(const char* password __attribute__((unused)),
unsigned int password_len __attribute__((unused)),
unsigned char* salt __attribute__((unused)),
unsigned char* salt_len)
{
*salt_len= 0;
return 0; /* success */
}
插件描述符的 authentication_flags
成员包含影响插件操作的标志。允许的标志为
AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE
: 凭据更改是特权操作。如果设置了此标志,服务器要求用户具有全局CREATE USER
权限或mysql
数据库的UPDATE
权限。AUTH_FLAG_USES_INTERNAL_STORAGE
: 插件是否使用内部存储(在mysql.user
行的authentication_string
列中)。如果未设置此标志,则尝试设置密码会失败,并且服务器会发出警告。AUTH_FLAG_REQUIRES_REGISTRATION
: 此标志针对需要注册过程的身份验证插件设置。它在CREATE USER
和ALTER USER
语句中进行检查,以及在为authentication_policy
系统变量分配值时进行检查。