使用 Java JNDI 类 从 Active Directory 匿名获取 RootDSE
Get RootDSE from Active Directory anonymously using Java JNDI classes
诚然,这个问题是 this one but it has no answer. Also, you may be inclined to think that this answer 的重复问题,但它没有解决问题。 (我怀疑那些回答者是否真的尝试过 Active Directory,他们可能已经尝试过其他一些 LDAP 实现)。
目标是检索 RootDSE 无需 用户身份验证,即所谓的匿名连接。 (是的,AD 支持这个)
这是我尝试过的(使用 Java 8):
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class MyMain {
public static void main(String[] args) throws NamingException {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, "ldap://myadsrv.mynet.net:389");
props.put(Context.SECURITY_AUTHENTICATION, "none"); // shouldn't be necessary, but just to make a point of it
LdapContext ctx = new InitialLdapContext(props, null);
// Force a bind on the connection
ctx.reconnect(ctx.getConnectControls());
// Get the RootDSE
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
searchControls.setReturningAttributes(new String[]{"namingContexts"});
NamingEnumeration<SearchResult> result = ctx.search("", "objectClass=*", searchControls);
}
}
无论我做什么,我总是以下面的异常结束。在上面的示例中,它将发生在最后一行,即 ctx.search(....)
。异常:
Exception in thread "main" javax.naming.NamingException:
[LDAP: error code 1 - 000004DC: LdapErr: DSID-0C09072B,
comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v2580];
remaining name ''
我已经尝试过其他工具,例如 Apache Directory Studio (open source LDAP browser, written in Java) and ldapsearch (command-line tool from OpenLDAP suite),这些工具确实能够在不进行身份验证的情况下检索 RootDSE。我已经使用 Wireshark 来弄清楚这些工具与我的 JNDI 实现有什么不同,并且可以看到一些差异,但不太确定我是否完全理解 Wireshark 输出(并且不知道如何将其转换为 JNDI,因为后者是非常高级的,但 Wireshark 当然是相当低级的)。但至少证明了这是可能的。
Active Directory 不支持 RFC 3296 指定的管理引用控制。如果匿名 LDAP 客户端在请求中发送它,它将导致 Active Directory 出现这种有点误导性的错误。
不幸的是,Java JNDI 中的默认设置是随每个搜索请求一起发送管理引用控制 (OID = 2.16.840.1.113730.3.4.2
)。
最简单的解决方案是设置
props.put(Context.REFERRAL, "throw"); // anything but 'ignore' will work
这将阻止 Java JNDI 随每个请求发送管理引用控制。
我想我会选择 throw
,因为它允许完全控制何时将请求推迟到其他地方。将 Context.REFERRAL
值设置为任何允许的值,除了 ignore
(默认值)将阻止 JNDI LDAP 提供程序发送管理引用控制,从而使 Active Directory 满意。
Oracle JNDI Tutorial 中的更多信息确实提到(第一页底部)默认行为与 Active Directory 不兼容。
诚然,这个问题是 this one but it has no answer. Also, you may be inclined to think that this answer 的重复问题,但它没有解决问题。 (我怀疑那些回答者是否真的尝试过 Active Directory,他们可能已经尝试过其他一些 LDAP 实现)。
目标是检索 RootDSE 无需 用户身份验证,即所谓的匿名连接。 (是的,AD 支持这个)
这是我尝试过的(使用 Java 8):
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class MyMain {
public static void main(String[] args) throws NamingException {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
props.put(Context.PROVIDER_URL, "ldap://myadsrv.mynet.net:389");
props.put(Context.SECURITY_AUTHENTICATION, "none"); // shouldn't be necessary, but just to make a point of it
LdapContext ctx = new InitialLdapContext(props, null);
// Force a bind on the connection
ctx.reconnect(ctx.getConnectControls());
// Get the RootDSE
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
searchControls.setReturningAttributes(new String[]{"namingContexts"});
NamingEnumeration<SearchResult> result = ctx.search("", "objectClass=*", searchControls);
}
}
无论我做什么,我总是以下面的异常结束。在上面的示例中,它将发生在最后一行,即 ctx.search(....)
。异常:
Exception in thread "main" javax.naming.NamingException:
[LDAP: error code 1 - 000004DC: LdapErr: DSID-0C09072B,
comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v2580];
remaining name ''
我已经尝试过其他工具,例如 Apache Directory Studio (open source LDAP browser, written in Java) and ldapsearch (command-line tool from OpenLDAP suite),这些工具确实能够在不进行身份验证的情况下检索 RootDSE。我已经使用 Wireshark 来弄清楚这些工具与我的 JNDI 实现有什么不同,并且可以看到一些差异,但不太确定我是否完全理解 Wireshark 输出(并且不知道如何将其转换为 JNDI,因为后者是非常高级的,但 Wireshark 当然是相当低级的)。但至少证明了这是可能的。
Active Directory 不支持 RFC 3296 指定的管理引用控制。如果匿名 LDAP 客户端在请求中发送它,它将导致 Active Directory 出现这种有点误导性的错误。
不幸的是,Java JNDI 中的默认设置是随每个搜索请求一起发送管理引用控制 (OID = 2.16.840.1.113730.3.4.2
)。
最简单的解决方案是设置
props.put(Context.REFERRAL, "throw"); // anything but 'ignore' will work
这将阻止 Java JNDI 随每个请求发送管理引用控制。
我想我会选择 throw
,因为它允许完全控制何时将请求推迟到其他地方。将 Context.REFERRAL
值设置为任何允许的值,除了 ignore
(默认值)将阻止 JNDI LDAP 提供程序发送管理引用控制,从而使 Active Directory 满意。
Oracle JNDI Tutorial 中的更多信息确实提到(第一页底部)默认行为与 Active Directory 不兼容。