使用Java JNDI类从Active Directory匿名获取RootDSE [英] Get RootDSE from Active Directory anonymously using Java JNDI classes

查看:86
本文介绍了使用Java JNDI类从Active Directory匿名获取RootDSE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

该问题与这个问题相同,但没有答案.另外,您可能会倾向于认为此答案解决了该问题,但事实并非如此.没错(我怀疑那些回答实际上已经在Active Directory上尝试过,是否有可能在其他LDAP实现上尝试过.)

目标是在没有用户身份的情况下检索RootDSE ,即所谓的匿名连接.(是的,AD支持这一点)

这是我尝试过的(使用Java 8):

  import java.util.Properties;导入javax.naming.Context;导入javax.naming.NamingEnumeration;导入javax.naming.NamingException;导入javax.naming.directory.SearchControls;导入javax.naming.directory.SearchResult;导入javax.naming.ldap.InitialLdapContext;导入javax.naming.ldap.LdapContext;公共类MyMain {公共静态void main(String [] args)引发NamingException {属性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");//不需要,只是要指出一点LdapContext ctx = new InitialLdapContext(props,null);//在连接上强制绑定ctx.reconnect(ctx.getConnectControls());//获取RootDSESearchControls searchControls = new SearchControls();searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);searchControls.setReturningAttributes(new String [] {"namingContexts"});NamingEnumeration< SearchResult>result = ctx.search(","objectClass = *",searchControls);}} 

无论我做什么,我总是会遇到以下异常.在上面的示例中,它会发生在最后一行,即 ctx.search(....).例外:

 线程"main"中的异常;javax.naming.NamingException:[LDAP:错误代码1-000004DC:LdapErr:DSID-0C09072B,注释:为了执行此操作,必须在连接上完成成功的绑定.,数据0,v2580];剩余的名字'' 

我尝试了其他工具,例如 Apache Directory Studio (开源LDAP浏览器,用Java)和 ldapsearch (来自 OpenLDAP套件的命令行工具)和那些工具确实能够在不进行身份验证的情况下检索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");//除了忽略"以外的任何东西都可以工作 

这将阻止Java JNDI随每个请求发送管理引用控件".

我认为我会选择 throw ,因为它可以完全控制何时将请求推迟到其他地方.将 Context.REFERRAL 值设置为除 ignore (默认值)以外的任何允许值将阻止JNDI LDAP Provider随管理引用控制一起发送,从而使Active Directory满意./p>

Oracle JNDI教程中的更多信息.确实确实提到了(第一页的底部)默认行为与Active Directory不兼容.

This question is admittedly a duplicate of this one but it has no answer. Also, you may be inclined to think that this answer solves the issue, but it doesn't. (I doubt that those answering have actually tried on an Active Directory, they have possible tried on some other LDAP implementation).

The goal is to retrieve the RootDSE without authenticating with a user, i.e. a so-called anonymous connection. (yes, AD supports this)

Here's what I've tried (using 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);
    }
}

Whatever I do I always end up in below exception. In the example above it will happen on the last line, i.e. the ctx.search(....). Exception:

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 ''

I have tried other tools such as Apache Directory Studio (open source LDAP browser, written in Java) and ldapsearch (command-line tool from OpenLDAP suite) and those tools are indeed able to retrieve the RootDSE without authenticating. I've used Wireshark to figure out what these tools to do differently than my JNDI implementation and can see some differences, but not quite sure I understand the Wireshark output completely (and wouldn't know how to translate that into something JNDI, as the latter is very high-level but Wireshark is of course quite low-level). But at least it proves that it is possible.

解决方案

Active Directory does not support the Manage Referral Control as specified by RFC 3296. If an anonymous LDAP client sends it along in a request it will result in this somewhat misleading error from Active Directory.

Unfortunately, the default in Java JNDI is to send along the Manage Referral Control (OID = 2.16.840.1.113730.3.4.2) with every search request.

The easiest solution is to set

props.put(Context.REFERRAL, "throw");   // anything but 'ignore' will work

This will stop the Java JNDI from sending the Manage Referral Control with every request.

I think I'll opt for throw as it allows full control of when the request if being deferred to somewhere else. Setting the Context.REFERRAL value to any allowed value except ignore (the default) will stop the JNDI LDAP Provider from sending along Manage Referral Control and thus make Active Directory happy.

More information in the Oracle JNDI Tutorial which indeed does mention (bottom of first page) that the default behavior is not compatible with Active Directory.

这篇关于使用Java JNDI类从Active Directory匿名获取RootDSE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆