4.4.9.1编写服务器端认证插件

使用通用描述符格式声明服务器端插件,该格式用于所有服务器插件类型(参见第4.4.2.1节“服务器插件库和插件描述符”).为auth_simple插件,描述符看起来像这样:

mysql_declare_plugin(auth_simple) {MYSQL_AUTHENTICATION_PLUGIN, &auth_simple_handler, /*类型特定描述符*/ "auth_simple", /*插件名称*/ "作者名",/*作者*/ "任意密码认证插件",/*描述*/ PLUGIN_LICENSE_GPL, /* license类型*/ NULL, /* no init函数*/ NULL, /* no deinit函数*/ 0x0100, /*版本= 1.0 */ NULL, /* no状态变量*/ NULL, /* no系统变量*/ NULL,/* no reserved information */ 0 /* no flags */} mysql_declare_plugin_end;

的名字成员(auth_simple)表示在语句中引用插件时使用的名称,例如安装插件卸载插件.这也是显示的名称显示插件INFORMATION_SCHEMA。插件

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如果需要特定的插件,成员应该指明客户端插件的名称。的值意味着任何插件。在后一种情况下,无论客户端使用什么插件都可以。如果服务器插件不关心客户端插件或它发送的用户名或密码,这是很有用的。例如,如果服务器插件只验证本地客户端,并且使用操作系统的某些属性而不是客户端插件发送的信息,这可能是正确的。

auth_simple,类型特定描述符如下所示:

静态结构st_mysql_auth auth_simple_handler = {MYSQL_AUTHENTICATION_INTERFACE_VERSION, "auth_simple", /*必需的客户端插件名称*/ auth_simple_server /*服务器端插件主函数*/ generate_auth_string_hash, /*从密码字符串生成摘要*/ validate_auth_string_hash, /*验证密码摘要*/ set_salt, /*生成密码盐值*/ 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;无符号长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成员与字符串关联,则表示字符串长度(以字节为单位)。字符串也是以空结束的。

当认证插件被服务器调用时,它应该解释MYSQL_SERVER_AUTH_INFO结构成员如下。其中一些用于在客户端会话中设置SQL函数或系统变量的值。

  • user_name:客户端发送的用户名。值变成用户()函数值。

  • user_name_length的长度。user_name在字节。

  • auth_string:对象的值authentication_string中的行的列mysql.user匹配帐户名的系统表(即,匹配客户端用户名和主机名的行,服务器使用它来确定如何对客户端进行身份验证)。

    假设您使用以下语句创建一个帐户:

    创建用户my_user @'localhost' 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:认证失败时应用。插件可以设置它或忽略它。的失败错误消息身份验证失败。密码使用:% s.的价值password_used决定了% s处理,如下表所示。

    password_used % s处理
    0 没有
    1 是的
    2 不会有% s
  • host_or_ip:可解析的客户端主机名称,否则为IP地址。

  • host_or_ip_length的长度。host_or_ip在字节。

auth_simple主要功能,auth_simple_server (),从客户端读取密码(一个以空结尾的字符串),如果密码非空(第一个字节不为空)则成功:

静态int auth_simple_server (MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) {unsigned char *pkt;int pkt_len;/*将密码读取为空终止字符串,错误时失败*/ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)返回CR_ERROR;/*空密码失败*/ if (!pkt_len || *pkt == '\0') {info->password_used= PASSWORD_USED_NO;返回CR_ERROR;} /*接受任何非空密码*/ info->password_used= PASSWORD_USED_YES;返回CR_OK;}

main函数应该返回下表中所示的错误代码之一。

错误代码 意义
CR_OK 成功
CR_OK_HANDSHAKE_COMPLETE 不发送状态包回客户端
CR_ERROR 错误
CR_AUTH_USER_CREDENTIALS 身份验证失败
CR_AUTH_HANDSHAKE 身份验证握手失败
CR_AUTH_PLUGIN_ERROR 内部插件错误

有关握手如何工作的示例,请参阅插件/认证/ dialog.c源文件。

服务器在性能架构中统计插件错误host_cache表格

auth_simple_server ()非常基本,因此它不使用身份验证信息结构,只是设置指示是否接收到密码的成员。

支持代理用户的插件必须向服务器返回代理用户的名称(客户端用户应该获得的权限的MySQL用户)。为此,插件必须设置信息- > 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){/*失败,如果服务器指定的缓冲区不能复制到输出缓冲区*/ if (*buflen < inbuflen)返回1;/* error */ strncpy(outbuf, inbuf, inbuflen);* buflen = strlen (inbuf);返回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__((未使用)),unsigned Int buflen __attribute__((未使用))){返回0;/* success */}

set_salt对象使用插件描述符的成员mysql_native_password插件(见本机可插入身份验证).对于其他的认证插件,你可以使用这个简单的实现:

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;返回0;/* success */}

authentication_flags成员包含影响插件操作的标志。允许使用的标志是:

  • AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE:更改凭据是特权操作。如果设置了此标志,服务器要求用户具有全局创建用户特权或更新特权的mysql数据库。

  • AUTH_FLAG_USES_INTERNAL_STORAGE:插件是否使用内部存储(在authentication_string列的mysql.user行)。如果未设置此标志,则试图设置密码失败,服务器将产生警告。