【发布时间】:2016-04-22 09:20:43
【问题描述】:
我目前面临的问题是 LDAP-Query 被传递到 LDAP-Server 并且 LDAP-Server 没有提供结果。
查询:(&(objectCategory=user)(mail=tester@oop-expert.de))
给定的电子邮件是为了找不到。所以预期结果为空。
在大多数环境配置中,此查询将完美通过,LDAP 立即返回空结果。
我将问题分解为可能与发送查询的网络或主机有关的问题。因此,如果从一个主机/网络和另一个主机/网络发送查询,则 LDAP-Server 将“饿死”我的 LDAP-Client,因此 LDAP-Client 会在客户端超时关闭连接。
另一方面:搜索存在的电子邮件总是会立即得到结果。来自哪个主机/网络无关紧要。
LDAP 服务器是一个活动目录。有几个域控制器提供 LDAP 服务,配置为“循环”。按 ip 或 dns 访问在这个问题上没有任何区别。
通信是通过 ssl 保护的。 (ldap)
在所有情况下都建立了连接。因此,身份验证并将查询传递给 LDAP 很顺利。
授权也不应该是一个问题。我在所有情况下都使用相同的 LDAP 用户。
LDAP 客户端始终是使用 InitialContext 的 JAVA 实现。
private InitialDirContext createDirContext(String principal, String credentials) throws NamingException {
if (credentials == null || credentials.isEmpty()) {
throw new LDAPLoginException();
}
return new InitialDirContext(createEnvironment(principal, credentials));
}
private Hashtable<String, String> createEnvironment(String principal, String credentials) {
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, this.ldapUrl);
// To get rid of the PartialResultException when using Active Directory
env.put(Context.REFERRAL, "follow");
// Needed for the Bind (User Authorized to Query the LDAP server)
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, principal);
env.put(Context.SECURITY_CREDENTIALS, credentials);
return env;
}
构建和执行查询的代码:
private LDAPUser getLDAPUserInfoByUniqueField(String attr, String value) {
DirContext serviceUserContext = null;
NamingEnumeration<SearchResult> results = null;
try {
String searchString = "(&(objectCategory=user)(" + attr + "=" + value + "))";
serviceUserContext = createDirContext(this.serviceUserPrincipal, serviceUserCredentials);
results = serviceUserContext.search("", searchString, createSearchControls()); // blocking...
return createLDAPUserInfo(results);
} catch (LDAPLoginException e) {
throw e;
} catch (Exception e) {
throw new LDAPFatalException(e);
} finally {
try {
if (results != null)
results.close();
} catch (NamingException e) {
}
try {
if (serviceUserContext != null)
serviceUserContext.close();
} catch (NamingException e) {
}
}
}
实用方法:
private LDAPUser createLDAPUserInfo(NamingEnumeration<SearchResult> results) throws NamingException {
LDAPUser ldapUserInfo = null;
if (results.hasMore()) { // blocking here
SearchResult result = (SearchResult) results.next();
String sAMAccountName = extractsAMAccountName(result);
String distinguishName = extractDistinguishName(result);
String department = extractDepartment(result);
String email = extractEmail(result);
ldapUserInfo = new LDAPUser(sAMAccountName, distinguishName, department, email);
}
return ldapUserInfo;
}
private String extractsAMAccountName(SearchResult result) throws NamingException {
Attributes attrs = result.getAttributes();
Attribute attr = attrs.get("sAMAccountName");
return (String) attr.get();
}
例外:
de.oopexpert.business.ldap.LDAPFatalException: javax.naming.PartialResultException [Root exception is javax.naming.CommunicationException: oopexpert.de:636 [Root exception is java.net.ConnectException: Connection timed out]]
at de.oopexpert.business.ldap.impl.LDAPImpl.getLDAPUserInfoByUniqueField(LDAPImpl.java:90)
at de.oopexpert.business.ldap.impl.LDAPImpl.getLDAPUserInfoByEmail(LDAPImpl.java:57)
Caused by: javax.naming.PartialResultException [Root exception is javax.naming.CommunicationException: oopexpert.de:636 [Root exception is java.net.ConnectException: Connection timed out]]
at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:242)
at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:189)
at de.oopexpert.business.ldap.impl.LDAPImpl.createLDAPUserInfo(LDAPImpl.java:139)
at de.oopexpert.business.ldap.impl.LDAPImpl.getLDAPUserInfoByUniqueField(LDAPImpl.java:84)
有什么提示吗?
【问题讨论】:
-
你的话有点不清楚。你是说当结果集应该为空时你永远不会得到结果?如果是这样,你怎么知道?程序永远挂起等待响应?
-
“你是说当结果集应该为空时你永远不会得到结果?”不,只有当我使用应该返回空结果的特殊查询从特殊主机查询 LDAP 服务器时。 “程序永远挂起等待响应?”正确的。但是在某些时候,由于客户端超时,客户端当然会停止请求。
-
这台主机有什么特别之处?
-
主机位于另一个网络 (TCP/IP)。主机运行 linux 而不是 windows(我的机器)。 Web 应用程序部署到主机上 docker 容器上的 tomcat。在我的机器上,我只使用没有 docker 环境的 tomcat。但是,如果您问,LDAP 服务器没有响应的主机有什么特别之处……这正是我的问题 :-)。
-
你还没有展示你是如何编写查询的,或者发送它,或者结果是什么,或者异常,或者超时,...
标签: java active-directory network-programming ldap