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

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

Усовершенствованные пользователи со специальными требованиями к защите могут создать свои собственные плагины аутентификации для приложений Соединителя/Сети. Можно расширить протокол квитирования, добавляя пользовательскую логику. Эта возможность требует Соединителя/Сети 6.6.3 или выше, и MySQL 5.5.16 или выше. Для фона и информации об использовании о плагинах аутентификации MySQL, см., Раздел 22.2.3.7, "Плагины Аутентификации" и Раздел 22.2.4.9, "Пишущий Плагины Аутентификации".

Чтобы записать пользовательский плагин аутентификации, Вы будете нуждаться в ссылке на блок MySql.Data.dll. Классы, важные для записи плагинов аутентификации, доступны в пространстве имен MySql.Data.MySqlClient.Authentication.

Как Пользовательский Плагин Аутентификации Работает

В некоторый момент во время квитирования, внутреннего метода

void Authenticate(bool reset)

Создание Класса Плагина Аутентификации

Вы помещаете логику плагина аутентификации в новом class, полученном из MySql.Data.MySqlClient.Authentication.MySqlAuthenticationPlugin. Следующие методы доступны, чтобы быть переопределенными:

protected virtual void CheckConstraints()protected virtual void AuthenticationFailed(Exception ex)protected virtual void AuthenticationSuccessful()protected virtual byte[] MoreData(byte[] data)protected virtual void AuthenticationChange()public abstract string PluginName { get; }public virtual string GetUsername()public virtual object GetPassword()protected byte[] AuthData;

Следующее является кратким объяснением каждого:

/// <summary>/// This method must check authentication method specific constraints in the environment and throw an Exception/// if the conditions are not met. The default implementation does nothing./// </summary>protected virtual void CheckConstraints()/// <summary>/// This method, called when the authentication failed, provides a chance to plugins to manage the error/// the way they consider decide (either showing a message, logging it, etc.)./// The default implementation wraps the original exception in a MySqlException with an standard message and rethrows it./// </summary>/// <param name="ex">The exception with extra information on the error.</param>protected virtual void AuthenticationFailed(Exception ex)/// <summary>/// This method is invoked when the authentication phase was successful accepted by the server./// Derived classes must override this if they want to be notified of such condition./// </summary>/// <remarks>The default implementation does nothing.</remarks>protected virtual void AuthenticationSuccessful()/// <summary>/// This method provides a chance for the plugin to send more data when the server requests so during the /// authentication phase. This method will be called at least once, and more than one depending upon whether the/// server response packets have the 0x01 prefix./// </summary>/// <param name="data">The response data from the server, during the authentication phase the first time is called is null, in subsequent calls contains the server response.</param>/// <returns>The data generated by the plugin for server consumption.</returns>/// <remarks>The default implementation always returns null.</remarks>protected virtual byte[] MoreData(byte[] data)/// <summary>/// The plugin name./// </summary>public abstract string PluginName { get; }/// <summary>/// Gets the user name to send to the server in the authentication phase./// </summary>/// <returns>An string with the user name</returns>/// <remarks>Default implementation returns the UserId passed from the connection string.</remarks>public virtual string GetUsername()/// <summary>/// Gets the password to send to the server in the authentication phase. This can can be an string or a/// </summary>/// <returns>An object, can be byte[], string or null, with the password.</returns>/// <remarks>Default implementation returns null.</remarks>public virtual object GetPassword()/// <summary>/// The authentication data passed when creating the plugin. /// For example in mysql_native_password this is the seed to encrypt the password./// </summary>protected byte[] AuthData;

Демонстрационный Плагин Аутентификации

Вот пример, показывающий, как создать плагин аутентификации, затем включите этому посредством конфигурационного файла. Следуйте за этими шагами:

  1. Создайте консольное приложение, добавляя ссылку на MySql.Data.dll.

  2. Разработайте основную программу следующим образом:

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using MySql.Data.MySqlClient;namespace AuthPluginTest{  class Program  {    static void Main(string[] args)    {      // Customize the connection string as necessary.      MySqlConnection con = new MySqlConnection("server=localhost; database=test; user id=myuser; password=mypass");      con.Open();      con.Close();    }  }}
  3. Создайте свой сменный class. В этом примере мы добавляем "альтернативную" реализацию Собственного плагина пароля, только используя тот же самый код от исходного плагина. Мы называем наш class MySqlNativePasswordPlugin2:

    using System.IO;using System;using System.Text;using System.Security.Cryptography;using MySql.Data.MySqlClient.Authentication;using System.Diagnostics;namespace AuthPluginTest{  public class MySqlNativePasswordPlugin2 : MySqlAuthenticationPlugin  {    public override string PluginName    {      get { return "mysql_native_password"; }    }    public override object GetPassword()    {      Debug.WriteLine("Calling MySqlNativePasswordPlugin2.GetPassword");      return Get411Password(Settings.Password, AuthData);    }    /// <summary>    /// Returns a byte array containing the proper encryption of the     /// given password/seed according to the new 4.1.1 authentication scheme.    /// </summary>    /// <param name="password"></param>    /// <param name="seed"></param>    /// <returns></returns>    private byte[] Get411Password(string password, byte[] seedBytes)    {      // if we have no password, then we just return 1 zero byte      if (password.Length == 0) return new byte[1];      SHA1 sha = new SHA1CryptoServiceProvider();      byte[] firstHash = sha.ComputeHash(Encoding.Default.GetBytes(password));      byte[] secondHash = sha.ComputeHash(firstHash);      byte[] input = new byte[seedBytes.Length + secondHash.Length];      Array.Copy(seedBytes, 0, input, 0, seedBytes.Length);      Array.Copy(secondHash, 0, input, seedBytes.Length, secondHash.Length);      byte[] thirdHash = sha.ComputeHash(input);      byte[] finalHash = new byte[thirdHash.Length + 1];      finalHash[0] = 0x14;      Array.Copy(thirdHash, 0, finalHash, 1, thirdHash.Length);      for (int i = 1; i < finalHash.Length; i++)        finalHash[i] = (byte)(finalHash[i] ^ firstHash[i - 1]);      return finalHash;    }  }}
  4. Заметьте, что сменная реализация только переопределяет GetPassword, и обеспечивает реализацию, чтобы зашифровать пароль, используя 4.1 протокола. Мы также вставляем следующую строку GetPassword тело:

    Debug.WriteLine("Calling MySqlNativePasswordPlugin2.GetPassword");
  5. Включите новому плагину в конфигурационном файле:

    <?xml version="1.0"?><configuration>  <configSections>    <section name="MySQL" type="MySql.Data.MySqlClient.MySqlConfiguration, MySql.Data"/>  </configSections>  <MySQL>    <AuthenticationPlugins>      <add name="mysql_native_password" type="AuthPluginTest.MySqlNativePasswordPlugin2, AuthPluginTest"></add>    </AuthenticationPlugins>      </MySQL><startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
  6. Запустите приложение. В Visual Studio Вы будете видеть сообщение Calling MySqlNativePasswordPlugin2.GetPassword в окне отладки.

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