問題描述
在使用 LDAP 協議從 Active Directory 等目錄管理服務獲取組織結構數據時,一般總是需要對目錄的檢索路徑進行配置。但是由於實際使用中的目錄組織結構通常會比較復雜,往往會出現有多個樹(或者 AD 中的網域)的情況。如果配置人員對所需訪問路徑不熟悉,或者目錄組織結構特別龐大的情況下,直接人工設置容易出現配置錯誤或是檢索效率低下的問題。所以在設計相關的配置功能時,如果能夠自動獲取各目錄樹的根路徑列表,可為配置 LDAP 連接帶來較大的便利。
現有案例
在此方面,常見的 LDAP 管理工具 LDAP Administrator 就提供了一個很好的方案。在設置服務器信息時,提供了一個 Fetch Base DNs 的按鈕(參見下圖),以幫助用戶從服務器獲取基准 DN 信息,作為設置檢索 RootDSE,也就是目錄信息樹的根。
實現原理
要獲取目錄樹的基准 DN 其實並不復雜,首先注意到 RFC 2252 文檔第 13 頁中針對 LDAP 的 namingContexts 屬性給出了如下說明:
5.2.1. namingContexts
— RFC 2252, LDAPv3: Attribute Syntax Definitions, Page 13
這段內容的最后一句就直接指出,該屬性能夠允許客戶端在與服務器聯系時選擇用於檢索信息的基准對象。基於文檔中的表述,實際操作中,僅需要從服務器上通過查詢對象的方式獲得 namingContexts 屬性值,即可整理出基准 DN 列表。
除此以外,通常在獲取服務器 Base DN 的過程中,並不需要用戶提供連接服務器的用戶登錄信息,一般都可以直接獲取。在 LDAP Administrator 中也僅需提供服務器的訪問地址、端口以及加密選項,便可直接抓取。
代碼實現
獲取 LDAP 基准 DN 列表的具體實現可參考下面的 Java 代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
Hashtable<String,String> env =
new
Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory"
);
env.put(Context.REFERRAL,
"follow"
);
// 初始化 LDAP 上下文
LdapContext context =
new
InitialLdapContext(env,
null
);
String base =
""
;
String filter =
"(objectclass=*)"
;
SearchControls controls =
new
SearchControls();
controls.setSearchScope(SearchControls.OBJECT_SCOPE);
// 通過獲取 namingContexts 屬性值得到基准 DN
NamingEnumeration<SearchResult> results = context.search(base, filter, controls);
List<String> namingContextsList =
new
ArrayList<String>();
// 處理結果
if
(results.hasMore()) {
Attributes attrs = results.next().getAttributes();
if
(attrs !=
null
) {
Attribute namingContexts = attrs.get(
"namingContexts"
);
NamingEnumeration enumeration = namingContexts.getAll();
while
(enumeration.hasMore()) {
namingContextsList.add((String) enumeration.next());
}
}
}
context.close();
System.out.println(namingContextsList);
|