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

17

尝试将应用程序从WebLogic 12.2.1迁移到Tomcat 8.5.4,在Weblogic下作为LDAP连接的Foreign JNDI Providers条目已被迁移到Tomcat下的一个新的Resource

根据Stack Overflow上的这篇文章建议,在Tomcat的lib文件夹下打包了一个自定义的LdapContextFactory作为新的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浏览器(如Apache Directory Studio / Eclipse中的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)

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

  • 相同的LDAP配置通过LDAP客户端正常工作
  • 实际上没有执行任何搜索,在启动时间Tomcat抛出此异常而没有任何查询
  • 错误提示为空字符串''作为remaining name,因此显然不是找不到某些东西

问题:这是否是将WebLogic中的Foreign JNDI Providers条目迁移到Tomcat的正确方法?如何使用空的剩余名称修复无效的LDAP DN条目?是否可以在某个地方缺少baseDN进行配置?


更新
更改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" />
根据官方文档,全局资源生命周期侦听器会初始化在server.xml中定义的全局JNDI资源作为全局资源元素的一部分。没有使用此侦听器,则无法使用任何全局资源。
在Tomcat版本8.5.57.0.69上也是如此:只需按照上述方法添加新的全局资源和提供工厂的其他jar包,就会抛出指向空剩余名称的异常。

1
我不知道为什么它在调用“listBindings()”。我的LDAP上下文工厂返回“iniitalLdapContext.lookup(url);”,其中“url”是提供者URL,并且在“finally”块中关闭“InitialLdapContext”。 - user207421
1
@EJP确实在这里查看(https://svn.apache.org/repos/asf/tomcat/trunk/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java),在mbean创建期间,它使用空字符串调用`listBindings`,这很可能是问题的原因。然后我会禁用此“资源”的mbean(或所有资源的mbean),但我找不到如何执行此操作。 - A_Di-Matteo
用我的方式尝试使用查找。 - user207421
不确定我能否帮忙,我的系统中没有MBean监听器。 - user207421
1
@A_Di-Matteo,请查看此链接:http://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-ldap-gl.html#url 。 该属性的值是一个由空格分隔的LDAP或LDAPS URL字符串列表,每个字符串指定LDAP服务器的主机名和端口号以及要使用的命名上下文的根区别名称。... 默认的根区别名称为空字符串。如果未设置此属性,或者省略了主机名或端口号,则将使用缺失信息的默认值。 - ROMANIA_engineer
显示剩余7条评论
1个回答

2
堆栈跟踪消失了,通过将LDAP模式DN附加到java.naming.provider.url属性中,使用问题中提供的第一个工厂实现。
以下是在此上下文中使用的LDAP客户端的屏幕截图,即嵌入在Eclipse中的Apache Directory Studio / LDAP浏览器,可以使用问题的初始值简单地浏览相关的LDAP。

enter image description here

通过将根元素的模式DN附加到连接URL中,异常消失了,并且LDAP资源现在可以通过Tomcat 8中的JNDI共享。
故障排除的结果进一步细节:
在Tomcat 8中,全局资源通过全局资源监听器处理,即默认在server.xml文件中定义的GlobalResourcesLifecycleListener。这样的监听器会在bean创建时调用context.listBindings(""),从而有效地浏览LDAP目录。
这种初始浏览可能是Tomcat和WebLogic之间最大的区别,其中LDAP只有在需要时才通过JNDI查找,因此通过直接查询而不是在启动时进行通用查询。因此,在Tomcat中,LDAP网址需要更多的详细信息,即作为其网址的一部分稍微不同的配置,以直接指向有效的基本DN。
来自官方WebLogic文档:
启动时,WebLogic Server 尝试连接到 JNDI 源。如果连接成功,WebLogic Server 在本地 JNDI 树中设置所请求的对象和链接,使它们对 WebLogic Server 客户端可用。
因此,连接比 listBindings 更简单:
列出命名上下文中绑定的名称以及绑定在它们上面的对象。不包括任何子上下文的内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接