LDAP資料同步
【此篇文章主要是記錄下如何與LDAP Server連線並取回節點資料】
在看本篇文章前,尚未接觸過LDAP的話可以先看看以下篇文章,先了解一下LDAP,這樣看這篇文章比較不會有太多問號
1.【LDAP基礎說明】http://blog.xuite.net/tolarku/blog/151029105-LDAP+%E5%9F%BA%E7%A4%8E%E8%AA%AA%E6%98%8E
2.【LDAP入門】http://www.l-penguin.idv.tw/article/ldap-1.htm
要從客戶家的LDAP Server拿資料可以想像成對MSSQL查詢資料,必須建立連線,必須要有Server的位址、登入帳號、密碼以及拿取資料的節點
LDAP拿資料有很多小細節要注意,下方會提到。
跟LDAP要資料會Using 下面這兩個命名空間
using System.DirectoryServices;
using System.DirectoryServices.Protocols;
1.建立連線
//建立LdapConnection,後面的【Port】我設為389
LdapConnection connection = new LdapConnection(new LdapDirectoryIdentifier(【LDAP Server的IP】, 【Port】);
//設定要使用的LDAP通訊協定版本
connection.SessionOptions.ProtocolVersion = 3;
//如果啟用 Secure Sockets Layer,則這個屬性為 true,否則為 false
connection.SessionOptions.SecureSocketLayer = false;
//LDAP登入身份, 若設定為Anonymous則為匿名登入
connection.AuthType = AuthType.Negotiate;
//設定登入帳號&密碼
connection.Credential = new NetworkCredential(【登入帳號】, 【登入密碼】, 【LDAP Domain】);
//連線
connection.Bind();
開發期間遇到的一個問題:LDAP Server 的根節點為DC=egan,DC=com,DC=tw,而下一層的部門節點為 OU=RD2,DC=egan,DC=com,DC=tw,連接第二層的部門節點可以Bind,但當connection 連接至根節點竟然發生Exception,起初以為是登入權限問題與SizeLimit回傳數量限制的問題,但用LDP小工具卻是能夠連接根節點的,這證明登入帳號是有權限存取根節點的,且跟節點回傳的物件數量也不到100個,後來測試為AuthType這個屬性設定上的問題,原先設定為 AuthType.Basic,後來設定成AuthType.Negotiate就排除問題了,因學藝不精無法詳述AuthType各種設定的差異,往後搞懂會再行補充。
AuthType:https://msdn.microsoft.com/zh-tw/library/system.directoryservices.protocols.authtype(v=vs.110).aspx
LDP小工具:https://technet.microsoft.com/zh-tw/library/cc754970(v=ws.11).aspx)
2.取得LDAP Server的Data
SearchRequest request = new SearchRequest();
//設定要搜尋的節點
request.DistinguishedName = "DC=egan,DC=com,DC=tw";
//設定搜尋範圍 Basic:搜尋連接的節點 OneLevel:搜尋連接的節點下一層的所有節點 Subtree:搜尋連接的節點下所有節點(包含連接的節點)
request.Scope =System.DirectoryServices.Protocols.SearchScope.OneLevel;
//設定傳回之物件(資料)的最大數目
request.SizeLimit = 1000;
//設定過濾條件
request.Filter = "(!(|(ou=RD2)(ou=RD3)))";
//取的LDAP Server回傳物件
SearchResponse response = (SearchResponse)connection.SendRequest(request);
Scope設定的差別可以參考下方這張圖
SizeLimit這個屬性為『單次request』回傳物件的最大數量設定,如果設定為500但回傳數量為600就會發生Exception,但不是將設定SizeLimit很大就沒問題,數量為LDAP Server那邊設定所限制的,預設回傳最大物件數量是1000,假設今天要拿回10000筆資料,就要打10次request,故要向LDAP Server拿大量資料可以參考以下作法:
a.先從根節點以Scope為OneLevel拿到下一層的所有路徑(DN) b.然後再對各路徑以Scope為Subtree的方式拿資料,這樣的方式就能避免直接對根節點以Scope為Subtree的方式拿資料,然而因回傳物件的最大數量的限制導致拿取資料失敗。
Filter就像MSSQL的搜尋條件,上方程式碼的 (!(|(ou=RD2)(ou=RD3)))翻譯成中文就是「OU為RD2或RD3的資料過濾掉」,拆解成下方這樣看比較清楚:
(不要
(或
(ou=RD2)(ou=RD3)
)
)
3.讀取回傳的物件
foreach(SearchResultEntry entry in response.Entries) {
SearchResultAttributeCollection Attribute = entry.Attributes;//取得此筆資料之所有參數(array)
#region 示範解析回傳節點物件的資料
for(int i = 0; i < Attribute["這邊設定回傳物件的欄位名稱"].Count; i++)
{
string[] attributeValues = departmentAttribute["這邊設定回傳物件的欄位名稱"][i].ToString().Split(',');
for(int a = 0; a < attributeValues.Length; a++)
{
string[] value = attributeValues[i].Split('=');
if(value[1].Equals("Organizational-Unit"))
{
//做事
}
}
}
#endregion
}
回傳的物件可能為多個節點資料,如:OU=RD4,DC=egan,DC=com,DC=tw 、OU=RD5,DC=egan,DC=com,DC=tw、CN=00198,DC=egan,DC=com,DC=tw ....很多
所以要用foreach 迴圈將資料一筆一筆拿出來,然後再對entrys的Attributes解析
response.Entries可以想像成查詢SQL資料表所拿到回來的一大堆的Row 而 entry.Attributes就是每行Row的Column
在Attributes的解析應規格需求可以像上方程式碼將欄位的字串切割後拿取需要的資料,之前有做過用RegularExpression來爬WIKI百科的資料,所以Attributes的解析應該也能用RegularExpression的方式來解析(因為RegularExpression不夠熟,如果要以這樣的方式寫會比較花時間,另一方面希望能快點將功能產出,故直覺的用字串分割的方式來解析資料)
RegularExpression:http://www.ksana.tw/productivity/RegularExpressionTutorialVer350.pdf
此次開發過程亦經過公司前輩多次協助一步步將問題排除才完成,為了防止自己忘記,另一方面則訓練自己的表達能力,故記錄這篇文章,希望能幫助自己或是其他人。
剛入行一年的菜鳥軟工,如有錯誤,或是有更好的做法(寫法)再請先進們補充,謝謝。
註:對LDAP拿取資料可以AD的方式拿取,但目前還沒碰過,趟若之後有以AD的方式來實作功能在另外補充。
egan2608@gmail.com