Spec-Zone .ru
спецификации, руководства, описания, API

23.2.4.9. Запись Плагинов Аутентификации

MySQL поддерживает сменную аутентификацию, в которой плагины вызываются, чтобы аутентифицировать клиентские соединения. Плагины аутентификации включают использованию методов аутентификации кроме встроенного метода паролей, сохраненных в mysql.user таблица. Например, плагины могут быть записаны, чтобы получить доступ к внешним методам аутентификации. Кроме того, плагины аутентификации могут поддерживать пользовательскую возможность прокси, так, что соединяющийся пользователь является прокси для другого пользователя и обрабатывается, в целях управления доступом, как наличие полномочий различного пользователя. Для получения дополнительной информации см. Раздел 6.3.7, "Сменная Аутентификация", и Раздел 6.3.8, "Пользователи Прокси".

Плагин аутентификации может быть записан для стороны сервера или стороны клиента. Серверные плагины используют тот же самый сменный API, который используется для других типов плагина сервера, таких как полнотекстовый синтаксический анализатор или контрольные плагины (хотя с различным специфичным для типа дескриптором). Клиентские плагины используют клиентский API плагина.

Несколько заголовочных файлов содержат информацию, относящуюся к плагинам аутентификации:

Чтобы записать плагин аутентификации, включайте следующие заголовочные файлы в сменный исходный файл. Другой MySQL или общие заголовочные файлы могли бы также быть необходимы.

plugin_auth.h включает plugin.h и plugin_auth_common.h, таким образом, Вы не должны включать последние файлы явно.

Этот раздел описывает, как записать пару простого сервера и плагинов аутентификации клиента, которые сотрудничают.

Предупреждение

Эти плагины принимают любой непустой пароль, и пароль отправляется в открытом тексте. Это небезопасно, таким образом, плагины не должны использоваться в продуктивных средах.

Серверные и клиентские плагины, разработанные здесь, обоих называют auth_simple. Как описано в Разделе 23.2.4.2, "Сменные Структуры данных", у сменного файла библиотеки должно быть то же самое базовое имя как клиентский плагин, таким образом, имя исходного файла auth_simple.c и производит названную библиотеку auth_simple.so (предполагающий, что Ваша система использует .so как суффикс для файлов библиотеки).

В исходных дистрибутивах MySQL источник плагина аутентификации располагается в plugin/auth каталог и может быть исследован как руководство по записи других плагинов аутентификации. Кроме того, чтобы видеть, как встроенные плагины аутентификации реализуются, см. sql/sql_acl.cc для плагинов, которые встраиваются к серверу MySQL и sql-common/client.c для плагинов, которые встраиваются к libmysqlclient клиентская библиотека. (Для встроенных клиентских плагинов отметьте что auth_plugin_t структуры, используемые там, отличаются от структур, используемых с обычными клиентскими макросами объявления плагина. В частности первые два элемента обеспечиваются явно, не макросами объявления.)

23.2.4.9.1. Запись Серверного Плагина Аутентификации

Объявите серверный плагин с обычным общим форматом дескриптора, который используется для всех типов плагина сервера (см. Раздел 23.2.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);};

st_mysql_auth у структуры есть три элемента: специфичный для типа номер версии API, клиентское имя плагина, и указатель на основную сменную функцию, которая связывается с клиентом. 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 */};

Основная функция берет два параметра, представляющие структуру ввода-вывода и a 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. Если есть a _length элемент, связанный со строкой, это указывает на строковую длину в байтах. Строки также завершаются нулем.

Когда плагин аутентификации вызывается сервером, он должен интерпретировать MYSQL_SERVER_AUTH_INFO элементы структуры следующим образом. Некоторые из них используются, чтобы установить значение функций SQL или системных переменных в пределах клиентского сеанса, как обозначено.

  • user_name: Имя пользователя передалось клиентом. Значение становится USER() значение функции.

  • user_name_length: Длина user_name в байтах.

  • auth_string: Значение authentication_string столбец mysql.user строка таблицы для соответствующего имени учетной записи (то есть, строка, которая соответствует клиентское имя пользователя и имя хоста и что использование сервера, чтобы определить, как аутентифицировать клиент).

    Предположите, что Вы создаете учетную запись, используя следующий оператор:

    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). Плагин может изменить это, чтобы указать, что у клиента должны быть полномочия различного пользователя. Например, если плагин поддерживает пользователей прокси, начальное значение является именем соединяющегося (прокси) пользователь, и плагин может изменить этот элемент на проксированное имя пользователя. Сервер тогда обрабатывает пользователя прокси как наличие полномочий проксированного пользователя (предполагающий, что другие условия для пользовательской поддержки прокси удовлетворяются; см. Раздел 23.2.4.9.4, "Реализовывая Пользовательскую Поддержку Прокси в Плагинах Аутентификации"). Значение представляется как строка самое большее MYSQL_USER_NAME_LENGTH байты долго, плюс завершающийся нуль. Значение становится CURRENT_USER() значение функции.

  • external_user: Сервер устанавливает это в пустую строку (завершенный нуль). Его значение становится external_user системное значение переменной. Если плагин хочет, чтобы у той системной переменной было различное значение, это должно установить этот элемент соответственно; например, к соединяющемуся имени пользователя. Значение представляется как строка, самое большее 511 байтов длиной плюс завершающийся нуль.

  • password_used: Этот элемент применяется, когда аутентификация перестала работать. Плагин может установить это или проигнорировать это. Значение используется, чтобы создать сообщение об ошибке отказа Authentication fails. 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(), читает пароль (завершенная нулем строка) от клиента и успешно выполняется, если пароль непуст (первый байт не нуль):

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 исходный файл.

Коды ошибки после CR_ERROR доступны от MySQL 5.6.5. Сервер считает сменные ошибки в Схеме Производительности host_cache таблица, также доступная с MySQL 5.6.5.

auth_simple_server_main() является настолько основным, что это не использует информационную структуру аутентификации кроме установить элемент, который указывает, был ли пароль получен.

Плагин, который поддерживает пользователей прокси, должен возвратить серверу имя проксированного пользователя (пользователь MySQL, права которого клиентский пользователь должен получить). Чтобы сделать это, плагин должен установить info->authenticated_as элемент к проксированному имени пользователя. Для получения информации о проксировании см. Раздел 6.3.8, "Пользователи Прокси", и Раздел 23.2.4.9.4, "Реализовывая Пользовательскую Поддержку Прокси в Плагинах Аутентификации".

23.2.4.9.2. Запись Клиентского Плагина Аутентификации

Объявите клиентский дескриптор плагина с mysql_declare_client_plugin() и mysql_end_client_plugin макросы (см. Раздел 23.2.4.2.3, "Клиентские Дескрипторы Плагина"). Для auth_simple плагин, дескриптор похож на это:

mysql_declare_client_plugin(AUTHENTICATION)  "auth_simple",                        /* plugin name */  "Author Name",                        /* author */  "Any-password authentication plugin", /* description */  {1,0,0},                              /* version = 1.0.0 */  "GPL",                                /* license type */  NULL,                                 /* for internal use */  NULL,                                 /* no init function */  NULL,                                 /* no deinit function */  NULL,                                 /* no option-handling function */  auth_simple_client                    /* main function */mysql_end_client_plugin;

Элементы дескриптора, характерные для всех клиентских плагинов, являются сменным именем через обрабатывающую опцию функцию. После общих элементов у плагина аутентификации также есть один дополнительный элемент. Это - "основная" функция, которая обрабатывает передачу с сервером. Функция берет два параметра, представляющие структуру ввода-вывода и обработчик соединения. Для нашего простого плагина любого-пароля основная функция действительно только пишет в сервер пароль, обеспеченный пользователем:

static int auth_simple_client (MYSQL_PLUGIN_VIO *vio, MYSQL *mysql){  int res;  /* send password as null-terminated string in clear text */  res= vio->write_packet(vio, (const unsigned char *) mysql->passwd,                          strlen(mysql->passwd) + 1);  return res ? CR_ERROR : CR_OK;}

Основная функция должна возвратить один из кодов ошибки, показанных в следующей таблице.

Код ошибки Значение
CR_OK Успех
CR_OK_HANDSHAKE_COMPLETE Успех, сделанный клиент
CR_ERROR Ошибка

CR_OK_HANDSHAKE_COMPLETE указывает, что клиент внес свой вклад успешно и считал последний пакет. Клиентский плагин может возвратиться CR_OK_HANDSHAKE_COMPLETE если число циклов обработки в протоколе аутентификации не известно заранее, и плагин должен считать другой пакет, чтобы определить, заканчивается ли аутентификация.

23.2.4.9.3. Используя Плагины Аутентификации

Чтобы скомпилировать и установить сменный объектный файл библиотеки, см. инструкции в Разделе 23.2.4.3, "Компилируя и Устанавливая Сменные Библиотеки". Чтобы использовать файл библиотеки, это должно быть установлено в сменном каталоге (каталог, названный plugin_dir системная переменная).

Зарегистрируйте серверный плагин в сервере. Например, чтобы загрузить плагин при запуске сервера, используйте a --plugin-load=auth_simple.so опция (изменяют суффикс библиотеки по мере необходимости для Вашей системы).

Создайте пользователя, для которого сервер будет использовать auth_simple плагин для аутентификации:

mysql> CREATE USER
            'x'@'localhost'    -> IDENTIFIED WITH auth_simple;

Используйте клиентскую программу, чтобы соединиться с сервером как пользователь x. Сторона сервера auth_simple плагин связывается с клиентской программой, что это должно использовать сторону клиента auth_simple плагин, и последний отправляют пароль серверу. Плагин сервера должен отклонить соединения, которые отправляют пустой пароль и принимают соединения, которые отправляют непустой пароль. Вызовите клиентскую программу каждый способ проверить это:

shell> mysql --user=x
            --skip-passwordERROR 1045 (28000): Access denied for user 'x'@'localhost' (using password: NO)shell> mysql --user=x --password=abcmysql>

Поскольку плагин сервера принимает любой непустой пароль, это нужно считать небезопасным. После тестирования плагина, чтобы проверить, что это работает, перезапустите сервер без --plugin-load опция, чтобы не к indavertently оставляют сервер, работающий с небезопасным плагином аутентификации загруженным. Кроме того, отбросьте пользователя с DROP USER 'x'@'localhost'.

Для дополнительной информации о загрузке и использовании плагинов аутентификации, см. Раздел 5.1.8.1, "Устанавливая и Удаляя Плагины", и Раздел 6.3.7, "Сменная Аутентификация".

Если Вы пишете клиентскую программу, которая поддерживает использование плагинов аутентификации, обычно такая программа заставляет плагин быть загруженным, вызывая mysql_options() установить MYSQL_DEFAULT_AUTH и MYSQL_PLUGIN_DIR опции:

char *plugin_dir = "path_to_plugin_dir";char *default_auth = "plugin_name";/* ... process command-line options ... */mysql_options(&mysql, MYSQL_PLUGIN_DIR, plugin_dir);mysql_options(&mysql, MYSQL_DEFAULT_AUTH, default_auth);

Как правило, программа также примет --plugin-dir и --default-auth опции, которые позволяют пользователям переопределить значения по умолчанию.

Если клиентская программа требует сменного управления низшего уровня, клиентская библиотека содержит функции, которые берут st_mysql_client_plugin параметр. См. Раздел 22.8.14, "Клиентские Функции Плагина API C".

23.2.4.9.4. Реализация Пользовательской Поддержки Прокси в Плагинах Аутентификации

Одна из возможностей, которые сменная аутентификация делает возможным, является пользователями прокси (см. Раздел 6.3.8, "Пользователи Прокси"). Для серверного плагина аутентификации, чтобы участвовать в пользовательской поддержке прокси, должны быть удовлетворены эти условия:

  • Когда соединяющийся клиент должен быть обработан как пользователь прокси, плагин должен возвратить другое имя в authenticated_as элемент MYSQL_SERVER_AUTH_INFO структура, чтобы указать на проксированное имя пользователя. Это может также дополнительно установить external_user элемент, чтобы установить значение external_user системная переменная.

  • Учетные записи пользователей прокси должны быть установлены, чтобы аутентифицироваться плагином. Используйте CREATE USER или GRANT оператор, чтобы связать учетные записи с плагинами.

  • Учетные записи пользователей прокси должны иметь PROXY полномочие для проксированных учетных записей. Используйте GRANT оператор, чтобы предоставить это полномочие.

Другими словами единственный аспект пользовательской поддержки прокси, требуемой плагина, - то, что это установило authenticated_as к проксированному имени пользователя. Остальное является дополнительным (установка external_user) или сделанный DBA, используя SQL-операторы.

Как плагин аутентификации определяет, который проксировал пользователя, чтобы возвратиться, когда пользователь прокси соединяется? Это зависит от плагина. Как правило, плагин отображает клиенты на проксированных пользователей, основанных на строке аутентификации, которую передает к этому сервер. Эта строка прибывает из AS часть IDENTIFIED WITH пункт CREATE USER оператор, который определяет использование плагина для аутентификации.

Сменный разработчик определяет правила синтаксиса для строки аутентификации и реализует плагин согласно тем правилам. Предположите, что плагин берет список разделенных запятой значений пар, которые отображают внешних пользователей на пользователей MySQL. Например:

CREATE USER ''@'%.example.com'  IDENTIFIED WITH my_plugin AS 'extuser1=mysqlusera, extuser2=mysqluserb'CREATE USER ''@'%.example.org'  IDENTIFIED WITH my_plugin AS 'extuser1=mysqluserc, extuser2=mysqluserd'

Когда сервер вызывает плагин, чтобы аутентифицировать клиент, он передает соответствующую строку аутентификации к плагину. Плагин ответственен:

  1. Проанализируйте строку в ее компоненты, чтобы определить отображение на использование

  2. Сравните клиентское имя пользователя с отображением

  3. Возвратите надлежащее имя пользователя MySQL

Например, если extuser2 соединяется от example.com узел, передачи сервера 'extuser1=mysqlusera, extuser2=mysqluserb' к плагину, и плагину должен скопировать mysqluserb в authenticated_as, с завершающимся нулевым байтом. Если extuser2 соединяется от example.org узел, передачи сервера 'extuser1=mysqluserc, extuser2=mysqluserd', и плагин должен скопировать mysqluserd вместо этого.

Если там не идет ни в какое сравнение в отображении, действие зависит от плагина. Если соответствие будет требоваться, то плагин, вероятно, возвратит ошибку. Или плагин мог бы просто возвратить имя клиента; в этом случае это не должно измениться authenticated_as, и сервер не будет обрабатывать клиент как прокси.

Следующий пример демонстрирует, как обработать пользователей прокси, использующих названный плагин auth_simple_proxy. Как auth_simple плагин, описанный ранее, auth_simple_proxy принимает любой непустой пароль как допустимый (и таким образом не должен использоваться в продуктивных средах). Кроме того, это исследует auth_string строковый элемент аутентификации и использование эти очень простые правила для того, чтобы интерпретировать это:

  • Если строка пуста, плагин возвращает имя пользователя как дано, и никакое проксирование не происходит. Таким образом, сменные листы значение authenticated_as неизменный.

  • Если строка непуста, плагин обрабатывает ее как имя проксированного пользователя и копирует ее в authenticated_as так, чтобы проксирование произошло.

Для того, чтобы протестировать, устанавливает одну учетную запись, которая не проксируется согласно предыдущим правилам, и тому, который является. Это означает, что одна учетная запись имеет нет AS пункт, и каждый включает AS пункт, который называет проксированного пользователя:

CREATE USER 'plugin_user1'@'localhost'  IDENTIFIED WITH auth_simple_proxy;CREATE USER 'plugin_user2'@'localhost'  IDENTIFIED WITH auth_simple_proxy AS 'proxied_user';

Кроме того, создайте учетную запись за проксированного пользователя и предоставление plugin_user2 PROXY полномочие для этого:

CREATE USER 'proxied_user'@'localhost'  IDENTIFIED BY 'proxied_user_pass';GRANT PROXY  ON 'proxied_user'@'localhost'  TO 'plugin_user2'@'localhost';

Прежде, чем сервер вызывает плагин аутентификации, он устанавливает authenticated_as к клиентскому имени пользователя. Чтобы указать, что пользователь является прокси, плагин должен установить authenticated_as к проксированному имени пользователя. Для auth_simple_proxy, это означает, что должно исследовать auth_string значение, и, если значение непусто, копирует его в authenticated_as элемент, чтобы возвратить это как имя проксированного пользователя. Кроме того, когда проксирование происходит, плагин устанавливает external_user элемент к клиентскому имени пользователя; это становится значением external_user системная переменная.

static int auth_simple_proxy_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;  /* if authentication string is nonempty, use as proxied user name */  /* and use client name as external_user value */  if (info->auth_string_length > 0)  {    strcpy (info->authenticated_as, info->auth_string);    strcpy (info->external_user, info->user_name);  }  return CR_OK;}

После успешного соединения, USER() функция должна указать на соединяющееся клиентское имя пользователя и имя хоста, и CURRENT_USER() должен указать на учетную запись, полномочия которой применяются во время сеанса. Последнее значение должно быть соединяющейся учетной записью пользователя, если никакое проксирование не происходит или проксированная учетная запись, если проксирование действительно происходит.

Скомпилируйте и установите плагин, затем протестируйте его. Во-первых, соединитесь как plugin_user1:

shell> mysql --user=plugin_user1
            --password=x

В этом случае не должно быть никакого проксирования:

mysql> SELECT USER(), CURRENT_USER(),
            @@proxy_user, @@external_user\G*************************** 1. row ***************************         USER(): plugin_user1@localhost CURRENT_USER(): plugin_user1@localhost   @@proxy_user: NULL@@external_user: NULL

Затем соединитесь как plugin_user2:

shell> mysql --user=plugin_user2
            --password=x

В этом случае, plugin_user2 должен быть проксирован к proxied_user:

mysql> SELECT USER(), CURRENT_USER(),
            @@proxy_user, @@external_user\G*************************** 1. row ***************************         USER(): plugin_user2@localhost CURRENT_USER(): proxied_user@localhost   @@proxy_user: 'plugin_user2'@'localhost'@@external_user: 'plugin_user2'@'localhost'