可插拔身份驗證所實現的功能之一是代理使用者 (請參閱代理使用者)。若要讓伺服器端身份驗證外掛程式參與代理使用者支援,必須滿足以下條件
當連線用戶端應被視為代理使用者時,外掛程式必須在
MYSQL_SERVER_AUTH_INFO
結構的authenticated_as
成員中傳回不同的名稱,以指示被代理的使用者名稱。它也可以選擇性地設定external_user
成員,以設定external_user
系統變數的值。必須設定代理使用者帳戶,以便透過外掛程式進行驗證。使用
CREATE USER
或GRANT
陳述式,將帳戶與外掛程式建立關聯。
換句話說,外掛程式所需的代理使用者支援的唯一方面是將 authenticated_as
設定為被代理的使用者名稱。其餘部分是選擇性的 (設定 external_user
) 或由 DBA 使用 SQL 陳述式完成。
當代理使用者連線時,身份驗證外掛程式如何判斷要傳回哪個被代理的使用者?這取決於外掛程式。通常,外掛程式會根據伺服器傳遞給它的身份驗證字串,將用戶端對應至被代理的使用者。此字串來自 CREATE USER
陳述式的 IDENTIFIED WITH
子句的 AS
部分,該陳述式指定將外掛程式用於身份驗證。
外掛程式開發人員會決定身份驗證字串的語法規則,並根據這些規則實作外掛程式。假設外掛程式會採用以逗號分隔的配對清單,這些配對會將外部使用者對應至 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'
當伺服器調用外掛程式以驗證用戶端時,它會將適當的身份驗證字串傳遞給外掛程式。外掛程式負責
將字串剖析為其組件,以判斷要使用的對應
將用戶端使用者名稱與對應進行比較
傳回正確的 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
身分連線
$> mysql --user=plugin_user1 --password
Enter 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
身分連線
$> mysql --user=plugin_user2 --password
Enter 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'