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

Java Tomcat 8-LDAP:NameNotFoundException错误代码32,剩余名称为空字符串,java,tomcat,ldap,weblogic,tomcat8,Java,Tomcat,Ldap,Weblogic,Tomcat8,试图将应用程序从WebLogic12.2.1迁移到Tomcat8.5.4,WebLogic下作为LDAP连接的外部JNDI提供者的条目已迁移到Tomcat下的新资源 堆栈溢出之后,一个自定义的LdapContextFactory被打包为Tomcatlib文件夹下的一个新的jar文件 在Tomcatserver.xml文件中,配置了以下GlobalNamingResources/Resource: <Resource name="ldapConnection" au

试图将应用程序从WebLogic12.2.1迁移到Tomcat8.5.4,WebLogic下作为LDAP连接的外部JNDI提供者的条目已迁移到Tomcat下的新
资源

堆栈溢出之后,一个自定义的
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" />
但是,在启动时,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在没有任何查询的情况下抛出此异常
  • 该错误表明一个空字符串
    '
    作为
    剩余名称
    ,因此显然不是真正找不到的内容
问题:这是将外部JNDI提供者条目从WebLogic迁移到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
中定义的全局JNDI资源初始化为全局资源元素的一部分。如果没有这个侦听器,所有全局资源都将不可用



Tomcat版本8.5.57.0.69也会发生同样的情况:只需添加上述新的全局资源和提供上述工厂的额外jar,指向剩余空名称的异常将被抛出。

stacktrace通过使用问题中提供的第一个工厂实现将LDAP架构DN附加到
java.naming.provider.url
属性而消失

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

通过将根元素的模式DN附加到连接URL,异常消失,LDAP资源现在通过Tomcat8中的JNDI共享


故障排除结果的更多详细信息

在Tomcat 8中,全局资源是通过全局资源侦听器处理的,全局资源侦听器是
GlobalResourcesLifecycleListener
,默认情况下在
server.xml
文件中定义。这样的监听器在创建bean时使用
context.listBindings(“”
),因此可以有效地浏览LDAP目录

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

来自官方:

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

因此,连接比连接更简单:

枚举命名上下文中绑定的名称以及绑定到这些名称的对象。不包括任何分包文本的内容


我不知道它为什么调用
listBindings()
。我的LDAP上下文工厂返回
iniitalLdapContext.lookup(url)
其中
url
是提供程序url,并在
最后
块中关闭
InitialLdapContext
@EJP实际上是在创建mbean的过程中调用了一个带有空字符串的
listBindings
,这很可能是问题的原因。然后我会为这个
资源(或所有资源)禁用mbean,但我找不到如何做,请用我的方式进行查找。@EJP samestacktrace@A_Di-马特奥,看看这个。此属性的值是以空格分隔的LDAP或LDAPS URL字符串列表,每个字符串指定LDAP服务器的主机名和端口号,以及要使用的命名上下文的根可分辨名称。。。默认的根可分辨名称是空字符串。如果未设置此属性,或者省略了主机名或端口号,则将使用默认值替换缺少的信息。
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;
}
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />