Tomcat 8 – LDAP:NameNotFoundException错误代码32,剩余名称为空字符串

尝试将应用程序从WebLogic 12.2.1迁移到Tomcat 8.5.4 ,Weblogic下的内容是作为LDAP连接的外部JNDI提供程序的条目已迁移到Tomcat下的新Resource

遵循Stack Overflow的这个建议 ,自定义LdapContextFactory已被打包为Tomcat lib文件夹下的新jar文件。

在Tomcat server.xml文件中,已配置以下GlobalNamingResources/Resource

   

通过嵌入在Eclipse中的Apache Directory Studio / LDAP Browser等LDAP浏览器浏览LDAP目录时,上述连接可正常工作。

自定义com.sample.custom.LdapContextFactory非常简单:

 public class LdapContextFactory implements ObjectFactory { public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { Hashtable env = new Hashtable(); Reference reference = (Reference) obj; Enumeration 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); } } 

但是,在启动时,Tomcat会抛出以下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) 

类似的问题和调查表明LDAP DN无效,但是:

  • 相同的LDAP配置可通过LDAP客户端正常工作
  • 实际上没有执行任何搜索,在启动时Tomcat会抛出此exception而不进行任何查询
  • 该错误表明一个空字符串''作为remaining name ,因此显然不是真正找不到的东西

问题 :这是将外部JNDI提供程序条目从WebLogic迁移到Tomcat的正确方法吗? 如何修复剩余名称为空的无效LDAP DN条目? 在某处配置它可能是一个缺少的baseDN吗?


更新
LdapContextFactory更改为以下内容时会发生同样的错误,如通过注释所示:

 public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { Hashtable env = new Hashtable(); Reference reference = (Reference) obj; Enumeration 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; } 

通过日志记录确认更改,以确保正确部署。

默认情况下,涉及的侦听器在server.xml文件的顶部定义为

  

并且不能根据官方文档禁用:

Global Resources Lifecycle Listener初始化server.xml定义的Global JNDI资源,作为Global Resources元素的一部分。 没有这个监听器,全局资源都不可用。


在Tomcat版本8.5.57.0.69上也会发生同样的情况:只需添加上面的新全局资源以及提供上述工厂的附加jar,将抛出指向空的剩余名称的exception。

通过使用问题中提供的第一个工厂实现将LDAP模式DN附加到java.naming.provider.url属性, java.naming.provider.url消失了。

在此上下文中使用的LDAP客户端的屏幕截图下方,嵌入在Eclipse中的Apache Directory Studio / LDAP浏览器,只需使用问题的初始值就可以从中浏览相关的LDAP。

在此处输入图像描述

通过将Root元素的模式DN附加到连接URL,exception消失,现在通过Tomcat 8中的JNDI共享LDAP资源。


作为故障排除结果的进一步细节

在Tomcat 8中,全局资源是通过全局资源侦听器处理的, GlobalResourcesLifecycleListener默认在server.xml文件中定义。 这样的监听器在bean创建时调用 context.listBindings("") ,从而有效地浏览LDAP目录。

这种初始浏览可能很可能是Tomcat和WebLogic之间的区别,其中LDAP仅在需要时通过JNDI查找,因此通过直接查询,而不是在启动时使用通用查询。 因此,在Tomcat中,LDAP url需要进一步的细节,即,作为其url的一部分稍微不同的配置,以直接指向有效的基本DN。

从官方WebLogic文档 :

启动时,WebLogic Server会尝试连接到JNDI源。 如果连接成功,WebLogic Server将在本地JNDI树中设置请求的对象和链接,使其可供WebLogic Server客户端使用。

因此,连接比listBindings简单得多:

枚举命名上下文中绑定的名称以及绑定到它们的对象。 不包括任何子上下文的内容。