Tomcat 8 - LDAP:NameNotFoundException 错误代码 32,剩余名称为空字符串
Posted
技术标签:
【中文标题】Tomcat 8 - LDAP:NameNotFoundException 错误代码 32,剩余名称为空字符串【英文标题】:Tomcat 8 - LDAP: NameNotFoundException error code 32, remaining name empty string 【发布时间】:2017-01-15 06:58:35 【问题描述】:尝试将应用程序从 WebLogic 12.2.1 迁移到 Tomcat 8.5.4,Weblogic 下的条目是 Foreign JNDI Providers对于 LDAP 连接已迁移到 Tomcat 下的新 Resource
。
继 Stack Overflow 上的 this advice 之后,自定义 LdapContextFactory
已被打包为 Tomcat lib
文件夹下的新 jar
文件。
在 Tomcat server.xml
文件中,已配置以下 GlobalNamingResources/Resource
:
<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" />
通过 LDAP 浏览器(如 Eclipse 中嵌入的 Apache Directory Studio / 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<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);
但是,Tomcat 在启动时会抛出以下异常:
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 问题和调查表明 LDAP DN 无效,但是:
相同的 LDAP 配置可以通过 LDAP 客户端正常工作 实际上不执行任何搜索,在启动时 Tomcat 会抛出此异常而无需任何查询 错误提示空字符串''
为 remaining name
,因此显然不是真正找不到的东西
问题:这是将 Foreign JNDI Providers 条目从 WebLogic 迁移到 Tomcat 的正确方法吗?如何修复具有空剩余名称的无效 LDAP DN 条目?会不会是缺少baseDN
在某处进行配置?
更新
根据 cmets 的建议,将 LdapContextFactory
更改为以下内容时会发生同样的错误:
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;
通过日志记录确认更改,以确保正确部署。
所涉及的侦听器默认在server.xml
文件的顶部定义为
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
并且不能按照official documentation禁用:
全局资源生命周期侦听器将
server.xml
中定义的全局 JNDI 资源初始化为全局资源元素的一部分。如果没有此侦听器,将无法使用任何全局资源。
同样的情况也发生在 Tomcat 版本 8.5.5 和 7.0.69 上:只需像上面那样添加新的全局资源和提供上述工厂的附加 jar,指向空的剩余名称的异常将被抛出。
【问题讨论】:
我不知道它为什么叫listBindings()
。我的 LDAP 上下文工厂返回 iniitalLdapContext.lookup(url);
,其中 url
是提供程序 URL,并在 finally
块中关闭 InitialLdapContext
。 .
@EJP 确实看起来 here,在 mbean 创建期间它调用带有空字符串的 listBindings
,这很可能是问题的原因。然后我会为此 Resource
(或全部)禁用 mbean,但我找不到如何做到这一点
用我的方式试试吧。
@EJP 相同的堆栈跟踪
@A_Di-Matteo ,检查这个docs.oracle.com/javase/7/docs/technotes/guides/jndi/… 。此属性的值是以空格分隔的 LDAP 或 LDAPS URL 字符串列表,每个字符串指定 LDAP 服务器的主机名和端口号,以及要使用的命名上下文的 根专有名称 . ...默认的根专有名称是空字符串。如果未设置此属性,或者省略主机名或端口号,则使用默认值代替缺少的信息。
【参考方案1】:
堆栈跟踪通过使用问题中提供的第一个工厂实现将 LDAP 模式 DN 附加到 java.naming.provider.url
属性而消失。
下面是在此上下文中使用的 LDAP 客户端的屏幕截图,即嵌入在 Eclipse 中的 Apache Directory Studio / LDAP 浏览器,从中可以简单地使用问题的初始值浏览相关的 LDAP。
通过将 Root 元素的模式 DN 附加到连接 URL,异常消失了,LDAP 资源现在通过 Tomcat 8 中的 JNDI 共享。
作为故障排除结果的更多详细信息:
在 Tomcat 8 中,全局资源通过全局资源侦听器处理,GlobalResourcesLifecycleListener
,默认情况下在 server.xml
文件中定义。这样一个监听器 invokes 一个 context.listBindings("")
用于创建 bean,从而有效地浏览 LDAP 目录。
这种初始浏览很可能是 Tomcat 和 WebLogic 之间的区别,其中 LDAP 仅在需要时通过 JNDI 查找,因此通过直接查询,而不是在启动时使用通用查询。因此,在 Tomcat 中,LDAP url 需要更多详细信息,也就是说,作为其 url 一部分的稍微不同的配置直接指向有效的基本 DN。
来自官方WebLogic documentation:
在启动时,WebLogic Server 会尝试连接到 JNDI 源。如果连接成功,WebLogic Server 会在本地 JNDI 树中设置请求的对象和链接,使它们可供 WebLogic Server 客户端使用。
因此,连接比listBindings
更简单:
枚举绑定在命名上下文中的名称,以及绑定到它们的对象。不包括任何子上下文的内容。
【讨论】:
以上是关于Tomcat 8 - LDAP:NameNotFoundException 错误代码 32,剩余名称为空字符串的主要内容,如果未能解决你的问题,请参考以下文章
Grails 3 Spring Security LDAP 插件和 Tomcat 8
通过 Tomcat 的 Spring Boot LDAP 身份验证(预身份验证)