0

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.

peterh
  • 18,404
  • 12
  • 87
  • 115

1 Answers1

0

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.

Community
  • 1
  • 1
peterh
  • 18,404
  • 12
  • 87
  • 115