Java 中文官方教程 2022 版(四十八)(1)https://developer.aliyun.com/article/1488508
检索 Distinguished Name
在 JDK 5.0 之前的版本中,没有直接的方法从搜索结果中获取 Distinguished Name (DN)。SearchResults.getName()
方法始终返回相对于执行搜索的上下文的名称。为了获取搜索条目的绝对或完整名称,需要一定的记录来跟踪祖先上下文。在 JDK 5.0 中添加了以下两个新的 API,用于在对上下文执行搜索、列出或列出绑定操作时从 NameClassPair 中检索绝对名称:
这是一个从 LDAP 搜索中检索 DN 的示例:
public static void printSearchEnumeration(NamingEnumeration retEnum) { try { while (retEnum.hasMore()) { SearchResult sr = (SearchResult) retEnum.next(); System.out.println(">>" + sr.getNameInNamespace()); } } catch (NamingException e) { e.printStackTrace(); } }
完整的示例可以从这里
获取。该程序生成以下输出:
>>cn=Jon Ruiz, ou=People, o=JNDITutorial >>cn=Scott Seligman, ou=People, o=JNDITutorial >>cn=Samuel Clemens, ou=People, o=JNDITutorial >>cn=Rosanna Lee, ou=People, o=JNDITutorial >>cn=Maxine Erlund, ou=People, o=JNDITutorial >>cn=Niels Bohr, ou=People, o=JNDITutorial >>cn=Uri Geller, ou=People, o=JNDITutorial >>cn=Colleen Sullivan, ou=People, o=JNDITutorial >>cn=Vinnie Ryan, ou=People, o=JNDITutorial >>cn=Rod Serling, ou=People, o=JNDITutorial >>cn=Jonathan Wood, ou=People, o=JNDITutorial >>cn=Aravindan Ranganathan, ou=People, o=JNDITutorial >>cn=Ian Anderson, ou=People, o=JNDITutorial >>cn=Lao Tzu, ou=People, o=JNDITutorial >>cn=Don Knuth, ou=People, o=JNDITutorial >>cn=Roger Waters, ou=People, o=JNDITutorial >>cn=Ben Dubin, ou=People, o=JNDITutorial >>cn=Spuds Mackenzie, ou=People, o=JNDITutorial >>cn=John Fowler, ou=People, o=JNDITutorial >>cn=Londo Mollari, ou=People, o=JNDITutorial >>cn=Ted Geisel, ou=People,o=JNDITutorial
标准 LDAP 控件
原文:
docs.oracle.com/javase/tutorial/jndi/newstuff/controls-std.html
在 LDAP v3 中,控件是通过将其与对服务器或客户端有用的更多信息相关联来增强现有 LDAP 操作的消息。控件可以是请求控件或响应控件。请求控件与 LDAP 请求一起从客户端发送到服务器。响应控件与 LDAP 响应一起从服务器发送到客户端。任何一种都由接口javax.naming.ldap.Control
表示。
如果您以前没有使用控件进行编程,请查看JNDI 教程中的控件课程。
在本课程中,我们将讨论添加到 JDK 5.0 的标准 LDAP 控件。必要的 LDAP 控件已经在 JNDI/LDAP 服务提供程序的com.sun.jndi.ldap.ctl
包下支持的 LDAP Booster Pack 扩展包中支持。由 IETF 标准化的 LDAP 控件现在通过以下类在 JDK 的javax.naming.ldap
包中提供。
ManageReferralControl
( RFC 3296 )PagedResultsControl
( RFC 2696 )PagedResultsResponseControl
SortControl
( RFC 2891 )SortKey
SortResponseControl
BasicControl
分页结果控件
原文:
docs.oracle.com/javase/tutorial/jndi/newstuff/paged-results.html
BasicControl
javax.naming.ldap.BasicControl
实现了 javax.naming.ldap.Control
,作为扩展其他控件的基本实现。
分页结果控件
分页结果控件对于希望以受控方式接收搜索结果的 LDAP 客户端非常有用,受页面大小限制。页面大小可以由客户端根据其资源的可用性(如带宽和处理能力)进行配置。
服务器使用 cookie(类似于 HTTP 会话 cookie 机制)来维护搜索请求的状态,以跟踪发送给客户端的结果。分页结果控件在 RFC 2696 中指定。下面的类提供了支持分页结果控件所需的功能。
如何使用分页结果控件?
下面的示例说明了客户端执行搜索并请求页面大小限制为 5 的客户端-服务器交互。服务器返回的整个结果集包含 21 个条目。
- 客户端发送搜索请求,请求页面大小为 5 的分页结果。
// Activate paged results int pageSize = 5; // 5 entries per page byte[] cookie = null; int total; ctx.setRequestControls(new Control[]{ new PagedResultsControl(pageSize, Control.CRITICAL) }); // Perform the search NamingEnumeration results = ctx.search("", "(objectclass=*)", new SearchControls());
- 服务器响应包含条目以及搜索结果中总共 21 个条目的指示,还有一个不透明的 cookie,客户端在检索后续页面时要使用该 cookie。
// Iterate over a batch of search results sent by the server while (results != null && results.hasMore()) { // Display an entry SearchResult entry = (SearchResult)results.next(); System.out.println(entry.getName()); // Handle the entry's response controls (if any) if (entry instanceof HasControls) { // ((HasControls)entry).getControls(); } } // Examine the paged results control response Control[] controls = ctx.getResponseControls(); if (controls != null) { for (int i = 0; i < controls.length; i++) { if (controls[i] instanceof PagedResultsResponseControl) { PagedResultsResponseControl prrc = (PagedResultsResponseControl)controls[i]; total = prrc.getResultSize(); cookie = prrc.getCookie(); } else { // Handle other response controls (if any) } } }
- 客户端发送相同的搜索请求,返回不透明的 cookie,并请求下一页。
// Re-activate paged results ctx.setRequestControls(new Control[]{ new PagedResultsControl(pageSize, cookie, Control.CRITICAL) });
- 服务器响应包含五个条目,并指示还有更多条目。客户端重复执行第 4 步中执行的搜索,直到服务器返回空 cookie,表示服务器不再发送更多条目。
完整的 JNDI 示例可以在 这里
找到。
注意: 分页搜索控件受 Windows Active Directory 服务器支持。Oracle Directory Server 版本 5.2 不支持。
排序控制
当客户端希望服务器发送排序后的搜索结果时,使用排序控制。服务器端排序在客户端需要根据某些标准对结果进行排序但无法自行执行排序过程的情况下非常有用。排序控制在RFC 2891中指定。下面的类提供了支持排序控制所需的功能。
SortKey 是一个基于其排序结果的键的有序列表。
如何使用排序控制?
下面的示例说明了客户端执行搜索请求服务器端基于属性“cn”进行排序的客户端-服务器交互。
- 客户端发送搜索请求请求
// Activate sorting String sortKey = "cn"; ctx.setRequestControls(new Control[] { new SortControl(sortKey, Control.CRITICAL) }); // Perform a search NamingEnumeration results = ctx.search("", "(objectclass=*)", new SearchControls());
- 服务器响应的条目是根据“cn”属性及其对应的匹配规则排序的。
// Iterate over sorted search results while (results != null && results.hasMore()) { // Display an entry SearchResult entry = (SearchResult)results.next(); System.out.println(entry.getName()); // Handle the entry's response controls (if any) if (entry instanceof HasControls) { // ((HasControls)entry).getControls(); } } // Examine the sort control response Control[] controls = ctx.getResponseControls(); if (controls != null) { for (int i = 0; i < controls.length; i++) { if (controls[i] instanceof SortResponseControl) { SortResponseControl src = (SortResponseControl)controls[i]; if (! src.isSorted()) { throw src.getException(); } } else { // Handle other response controls (if any) } } }
完整的 JNDI 示例可以在这里
找到。
注意: 排序控制由 Oracle Directory Server 和 Windows Active Directory 服务器都支持。
管理引荐控件
原文:
docs.oracle.com/javase/tutorial/jndi/newstuff/mdsaIT.html
管理引荐控件(RFC 3296)允许在执行 LDAP 操作时将引荐和其他特殊对象操作为普通对象。换句话说,管理引荐控件告诉 LDAP 服务器将引荐条目返回为普通条目,而不是返回"引荐"错误响应或继续引用。 JDK 5.0 中的新类使您可以在 LDAP 请求中发送管理引荐控件:
javax.naming.ldap.ManageReferralControl
JDK 中的 LDAP 服务提供程序将自动发送此控件以及任何请求。您还可以通过将 Context.REFERRAL 环境属性设置为"ignore"来显式启用它。有关引荐处理的更多信息,请查看 JNDI 教程的引荐部分。
这是一个示例,它在 LDAP 请求中发送了管理引荐控件。
// Create initial context LdapContext ctx = (LdapContext) new InitialDirContext(env); ctx.setRequestControl(new Control[] new ManageReferralControl()); // Set controls for performing subtree search SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); // Perform search NamingEnumeration answer = ctx.search("", "(objectclass=*)", ctls); // Print the answer while (answer.hasMore()) { System.out.println(">>>" + ((SearchResult)answer.next()).getName()); } // Close the context when we're done ctx.close();
完整示例可以在这里
找到。
注意 1: 以上示例将要求您使用配置文件refserver.ldif
设置第二个服务器。服务器必须支持 LDAP v3 和 RFC 3296。如果服务器不支持这种方式的引荐,则示例将无法正常工作。配置文件包含引荐,指向您设置的原始服务器。它假定原始服务器位于本地机器的端口 389 上。如果您在另一台机器或端口上设置了服务器,则需要编辑 refserver.ldif 文件中的"ref"条目,并将"localhost:389"替换为适当的设置。第二个服务器应在本地机器的端口 489 上设置。如果您在另一台机器或端口上设置了第二个服务器,则需要相应地调整初始上下文的 Context.PROVIDER_URL 环境属性的设置。
设置目录服务器通常由目录或系统管理员执行。有关更多信息,请参阅软件设置课程。
注意 2: Windows Active Directory:由于 Active Directory 不支持管理引荐控件,本课程中的所有示例都无法针对 Active Directory 工作。
操作 LdapName(专有名称)
原文:
docs.oracle.com/javase/tutorial/jndi/newstuff/ldapname.html
Distinguished Name(DN)在 LDAP 中以字符串表示形式使用。用于表示 DN 的字符串格式在RFC 2253中指定。DN 由称为相对专有名称(RDN)的组件组成。以下是 DN 的示例:
“CN=John Smith, O=Isode Limited, C=GB”
它由以下 RDN 组成:
- CN=John Smith
- O=Isode Limited
- C=GB
下面的类分别表示 DN 和 RDN。
LdapName 类实现了javax.naming.Name
接口,类似于javax.naming.CompoundName
和javax.naming.CompositeName
类。
LdapName 和 Rdn 类允许轻松操作 DN 和 RDN。使用这些 API,通过将名称和值配对,轻松构造 RDN。可以使用 RDN 列表构造 DN。同样,可以从它们的字符串表示中检索 DN 和 RDN 的各个组件。
LdapName
可以使用其在RFC 2253中定义的字符串表示形式或使用 Rdns 列表创建 LdapName。当使用前一种方式时,指定的字符串将根据 RFC2253 中定义的规则进行解析。如果字符串不是有效的 DN,则会抛出InvalidNameException
。以下是使用构造函数解析 LDAP 名称并打印其组件的示例。
String name = "cn=Mango,ou=Fruits,o=Food"; try { LdapName dn = new LdapName(name); System.out.println(dn + " has " + dn.size() + " RDNs: "); for (int i = 0; i < dn.size(); i++) { System.out.println(dn.get(i)); } } catch (InvalidNameException e) { System.out.println("Cannot parse name: " + name); }
使用输入"cn=Mango,ou=Fruits,o=Food"
运行此示例会产生以下结果:
cn=Mango,ou=Fruits,o=Food has 3 RDNs: o=Food ou=Fruits cn=Mango
LdapName 类包含方法,用于将其组件作为 RDN 和字符串访问,修改 LdapName,比较两个 LdapName 是否相等,并获取名称的字符串表示形式。
访问 LDAP 名称的名称组件:
以下是您可以使用的方法来访问名称组件作为 RDN 和字符串:
要检索 LdapName 中特定位置的组件,您可以使用 getRdn()或 get()。前面的构造函数示例展示了其用法的示例。getRdns()
返回所有 RDN 的列表,getAll()
将 LdapName 的所有组件作为枚举返回。
最右边的 RDN 位于索引 0,最左边的 RDN 位于索引 n-1。例如,专有名称:"cn=Mango, ou=Fruits, o=Food"按以下顺序编号,范围从 0 到 2:{o=Food, ou=Fruits, cn=Mango}
您还可以将 LdapName 的后缀或前缀作为 LdapName 实例获取。这里有一个示例
,展示了如何获取 LDAP 名称的后缀和前缀。
LdapName dn = new LdapName("cn=Mango, ou=Fruits, o=Food"); Name suffix = dn.getSuffix(1); // 1 <= index < cn.size() Name prefix = dn.getPrefix(1); // 0 <= index < 1
运行此程序时,它会生成以下输出:
cn=Mango ou=Fruits o=Food
要复制 LdapName,您可以使用 clone()。
修改 LDAP 名称
以下是您可以使用的方法来修改 LDAP 名称:
addAll(int posn, List suffixRdns)
创建 LdapName 实例后,您可以向其添加和删除组件。这里有一个示例
,演示了如何将一个 LdapName 附加到现有 LdapName 中,在开头和结尾添加组件,以及删除第二个组件。
LdapName dn = new LdapName("ou=Fruits,o=Food"); LdapName dn2 = new LdapName("ou=Summer"); System.out.println(dn.addAll(dn2)); // ou=Summer,ou=Fruits,o=Food System.out.println(dn.add(0, "o=Resources")); // ou=Summer,ou=Fruits,o=Food,o=Resources System.out.println(dn.add("cn=WaterMelon")); // cn=WaterMelon,ou=Summer,ou=Fruits,o=Food,o=Resources System.out.println(dn.remove(1)); // o=Food System.out.println(dn); // cn=WaterMelon,ou=Summer,ou=Fruits,o=Resources
比较 LDAP 名称
以下是您可以使用的方法来比较两个 LDAP 名称:
您可以使用compareTo()
对 LdapName 实例列表进行排序。equals()
方法可让您确定两个 LdapNames 是否在语法上相等。如果两个 LdapNames 在相同顺序中具有相同(大小写匹配)的组件,则它们是相等的。
使用startsWith()
和endsWith()
,您可以了解一个 LdapName 是否以另一个 LdapName 开头或结尾;也就是说,一个 LdapName 是否是另一个 LdapName 的后缀或前缀。
便利方法isEmpty()
使您能够确定 LdapName 是否具有零个组件。您还可以使用表达式size() == 0
执行相同的检查。
这里有一个示例,CompareLdapNames
,使用了其中一些比较方法。
LdapName one = new LdapName("cn=Vincent Ryan, ou=People, o=JNDITutorial"); LdapName two = new LdapName("cn=Vincent Ryan"); LdapName three = new LdapName("o=JNDITutorial"); LdapName four = new LdapName(""); System.out.println(one.equals(two)); // false System.out.println(one.startsWith(three)); // true System.out.println(one.endsWith(two)); // true System.out.println(one.startsWith(four)); // true System.out.println(one.endsWith(four)); // true System.out.println(one.endsWith(three)); // false System.out.println(one.isEmpty()); // false System.out.println(four.isEmpty()); // true System.out.println(four.size() == 0); // true
获取字符串表示
下面的方法可以让您获取根据 RFC 2253 中指定的语法格式化的 LDAP 名称的字符串表示:
当您使用 LdapName 构造函数时,您提供 LDAP 名称的字符串表示,并获得一个 LdapName 实例。要执行相反操作,即获取 LdapName 实例的字符串表示,您可以使用toString()
。toString()
的结果可以再次传递给构造函数,以生成与原始 LdapName 实例相等的 LdapName 实例。这里有一个示例,LdapNametoString
:
LdapName dn = new LdapName(name); String str = dn.toString(); System.out.println(str); LdapName dn2 = new LdapName(str); System.out.println(dn.equals(dn2)); // true
作为上下文方法的参数的 LdapName
Context 方法要求将复合名称或复合名称作为参数传递给其方法。因此,可以直接将 LdapName 传递给上下文方法,如示例中所示,LookupLdapName
:
// Create the initial context Context ctx = new InitialContext(env); // An LDAP name LdapName dn = new LdapName("ou=People,o=JNDITutorial"); // Perform the lookup using the dn Object obj = ctx.lookup(dn);
Java 中文官方教程 2022 版(四十八)(3)https://developer.aliyun.com/article/1488519