使用 LDAP 協定驗證 AD 帳號密碼
1 |
除了使用 IIS 整合驗證跟呼叫 Windows API,.NET 還有一種流傳甚廣的 LDAP 帳號密碼驗證程式寫法:
var username = "Child\\someone";
var password = "P@ssW0rd";
// web Domain DC = 10.0.0.7
// child Domain DC = 10.0.0.6
var ldapPath = "LDAP://10.0.0.7";
AuthByLdap();
void AuthByLdap()
{
try
{
Console.WriteLine($"Connect {ldapPath} with {username}...");
DirectoryEntry entry = new DirectoryEntry(ldapPath, username, password);
// Bind NativeAdsObject 時將觸發身分驗證
object obj = entry.NativeObject;
Console.WriteLine("Login Successful");
// 執行到此沒出錯即代表帳號密碼有效,以下加碼搜尋 AD 所有名為 someone 的項目
DirectorySearcher search = new DirectorySearcher(entry);
// 搜尋 AD 帳號名稱為 someone 的項目 (child 跟 web 網域各有一位)
search.Filter = "(SAMAccountName=someone)";
foreach (SearchResult r in search.FindAll())
{
Console.WriteLine(r.Properties["distinguishedName"][0].ToString());
}
}
catch (Exception ex)
{
Console.WriteLine("Login failed: " + ex.Message);
}
}
面對這段程式碼,我有幾個疑問:
- 在 AD 架構中,DC 就是 LDAP 主機,若套用前幾天跨子網域登入 IIS的情境。 我是否可以用 child\someone 登入 web LDAP 主機(DC)?
- 若可以用 child\someone 登入網域 web LDAP,過程需要連到網域 child LDAP 嗎?
- DC 主機若具有 GC 角色,同時提供 389 (LDAP) 及 3268 (GC) 兩種 Port,LDAP 協定可選擇其一連接,依先前 PowerShell Get-ADUser/C# 跨網域搜尋 AD 帳號使用 3268 可跨網域搜索,在這段程式是否也會產生相同差異?
現在來一一驗證。先說測試環境:
- 程式在 10.0.0.8 主機上執行,機器加入 web 網域,以 web\someone 登入 Windows 執行程式
- web 網域 DC/LDAP 伺服器 IP = 10.0.0.7
- child 網域 DC/LDAP 伺服器 IP = 10.0.0.6
- web 網域與 child 網域都有一個名為 someone 的使用者
測試四次:
- 使用 web\someone 連 LDAP://10.0.0.7
成功登入,查到 web 的 someone - 使用 child\someone 連 LDAP://10.0.0.7
成功登入,查到 web 的 someone - 使用 web\someone 連 GC://10.0.0.7
成功登入,查到 web 跟 child 的 someone - 使用 child\someone 連 GC://10.0.0.7
成功登入,查到 web 跟 child 的 someone
使用 Wireshark 觀察封包,發現 .NET DirectoryEntry 底層是用 NTLMSSP Challenge/Response 完成認證,不需要直接傳輸密碼,而第 15 列 NTMLSSP_NEGOTIATEsasl 的 SASL 及第 17 列的 GSS-API(整合 Kerberos) 都是 LDAP 協定的安全認證框架。參考:
既然是用 NTLM,web DC (10.0.0.7) 便能直接驗證跨網域的 child\someone 帳號,不需接觸 child DC (10.0.0.6),就 bindResponse success:
將 LDAP://10.0.0.7 改成 GC://10.0.0.7,封包過程幾乎一模一樣,只差在連接埠由 389 Port 變成 3268 Port,而查詢對象為 GC,故可查到 web 跟 child 的 someone 共兩筆:
那如果將 GC://10.0.0.7 改成 GC://web.contoso.com,會跟 IIS 一樣改用 Kerberos 嗎?會!
此時 10.0.0.8 會與 child DC 10.0.0.6 建立 CLDAP (UDP 389 Port) 及 KRB5 (88 Port) 連線:
不過我的環境疑似 DNS SPN 沒設好,出現 KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN 錯誤,最後仍是走 NTLM: 參考
依據微軟文件,當條件被滿足時,AD DS 是可以支援 Kerberos 的,至於是哪裡沒設好?感覺愈游水愈深,這段就先不深究了,容我游回岸邊喘一會兒。
最後做個小結:
- 使用 DirectoryEntry 連線 AD DC/LDAP 主機時,在 Bind 階段會觸發帳號驗證,類似 IIS 可協商使用 NTLM 或 Kerberos。
- 若走 NTLM,由 DC 直接驗證跨網域帳號;當條件滿足時則會啟動 Kerberos,此時客戶端需連跨網域 DC 的 LDAP (389 UDP) 及 Kerberos (88 TCP)。
- DC 同時支援 389 及 3268,ldap:// 預設連 389、gc:// 預設連 3268,前者只能搜覽自己網域的項目,但資訊較完整;後者可查詢全網域所有物件,但屬目錄性質,完整資料需接洽該網域 DC 取得。
Experimenets about athenticating cross-domain account with AD DS.
Comments
# by player
關於以LDAP進行AD驗證帳密 記得小朱在ASP.NET 2.0時期寫的那本書 就有了 忘了是Q幾了,應該還能用吧? https://dotblogs.com.tw/regionbbs/2012/07/30/asp_net_q_and_a_in_practices_available_full_book_for_download