Trying to migrate an application from WebLogic 12.2.1 to Tomcat 8.5.4, what under Weblogic was an entry as Foreign JNDI Providers for an LDAP connection has been migrated to a new Resource
under Tomcat.
Following this advice on Stack Overflow, a custom LdapContextFactory
has been packaged as a new jar
file under Tomcat lib
folder.
In the Tomcat server.xml
file the following GlobalNamingResources/Resource
has been configured:
<Resource name="ldapConnection"
auth="Container"
type="javax.naming.ldap.LdapContext"
factory="com.sample.custom.LdapContextFactory"
singleton="false"
java.naming.referral="follow"
java.naming.factory.initial="com.sun.jndi.ldap.LdapCtxFactory"
java.naming.provider.url="ldap://some.host:389"
java.naming.security.authentication="simple"
java.naming.security.principal="CN=some,OU=some,OU=some,DC=some,DC=a,DC=b"
java.naming.security.credentials="password"
com.sun.jndi.ldap.connect.pool="true"
com.sun.jndi.ldap.connect.pool.maxsize="10"
com.sun.jndi.ldap.connect.pool.prefsize="4"
com.sun.jndi.ldap.connect.pool.timeout="30000" />
The connection above works fine when browsing the LDAP directory via an LDAP browser like Apache Directory Studio / LDAP Browser embedded in Eclipse.
The custom com.sample.custom.LdapContextFactory
is quite simple:
public class LdapContextFactory implements ObjectFactory {
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
throws Exception {
Hashtable<Object, Object> env = new Hashtable<>();
Reference reference = (Reference) obj;
Enumeration<RefAddr> references = reference.getAll();
while (references.hasMoreElements()) {
RefAddr address = references.nextElement();
String type = address.getType();
String content = (String) address.getContent();
env.put(type, content);
}
return new InitialLdapContext(env, null);
}
}
However, at start-up Tomcat is throwing the following exception:
07-Sep-2016 15:04:01.064 SEVERE [main] org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans Exception processing Global JNDI Resources
javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031001E5, problem 2001 (NO_OBJECT), data 0, best match of:
''
]; remaining name ''
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3160)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3081)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2888)
at com.sun.jndi.ldap.LdapCtx.c_listBindings(LdapCtx.java:1189)
at com.sun.jndi.toolkit.ctx.ComponentContext.p_listBindings(ComponentContext.java:592)
at com.sun.jndi.toolkit.ctx.PartialCompositeContext.listBindings(PartialCompositeContext.java:330)
at com.sun.jndi.toolkit.ctx.PartialCompositeContext.listBindings(PartialCompositeContext.java:317)
at javax.naming.InitialContext.listBindings(InitialContext.java:472)
at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:136)
at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:145)
at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:110)
at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.lifecycleEvent(GlobalResourcesLifecycleListener.java:82)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:94)
at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:401)
at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:345)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:784)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:152)
at org.apache.catalina.startup.Catalina.start(Catalina.java:655)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:355)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:495)
Similar questions and investigations suggest an invalid LDAP DN, but:
- The same LDAP configuration works fine via an LDAP Client
- No search is actually performed, at start-up time Tomcat throws this exception without any query
- The error suggests an empty string
''
asremaining name
, hence not really something not found, apparently
Question(s): Is this the correct way to migrate an Foreign JNDI Providers entry from WebLogic to Tomcat? How to fix an invalid LDAP DN entry with an empty remaining name? Could it be a missing baseDN
to configure somewhere?
Update
The same exact error happens when changing the LdapContextFactory
to the following, as suggested via comments:
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
throws Exception {
Hashtable<Object, Object> env = new Hashtable<>();
Reference reference = (Reference) obj;
Enumeration<RefAddr> references = reference.getAll();
String providerUrl = "no valid URL";
while (references.hasMoreElements()) {
RefAddr address = references.nextElement();
String type = address.getType();
String content = (String) address.getContent();
switch (type) {
case Context.PROVIDER_URL:
env.put(Context.PROVIDER_URL, content);
providerUrl = content;
break;
default:
env.put(type, content);
break;
}
}
InitialLdapContext context = null;
Object result = null;
try {
context = new InitialLdapContext(env, null);
LOGGER.info("looking up for " + providerUrl);
result = context.lookup(providerUrl);
} finally {
if (context != null) {
context.close();
}
}
LOGGER.info("Created new LDAP Context");
return result;
}
Change is confirmed via logging, to make sure it was deployed properly.
The involved listener is defined by default at the top of the server.xml
file as
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
And cannot be disabled as per official documentation:
The Global Resources Lifecycle Listener initializes the Global JNDI resources defined in
server.xml
as part of the Global Resources element. Without this listener, none of the Global Resources will be available.
The same also happens on Tomcat version 8.5.5 and 7.0.69: simply adding the new global resource as above and the additional jar providing the factory above, the exception pointing at an empty remaining name will be thrown.