尝试将应用程序从WebLogic 12.2.1 迁移到Tomcat 8.5.4 ,Weblogic下的内容是外部JNDI提供程序对于LDAP连接,已迁移到Tomcat下的新Resource
。
在Stack Overflow上关注this advice后,自定义LdapContextFactory
已打包为Tomcat jar
文件夹下的新lib
文件。
在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" />
通过嵌入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<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无效,但是:
''
为remaining name
,因此并非真正找不到的东西,显然 问题:这是将外部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
文件的顶部定义为
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
并且无法根据official documentation禁用
全局资源生命周期监听器初始化
server.xml
中定义的全局JNDI资源,作为全局资源元素的一部分。没有这个监听器,全局资源都不可用。
在Tomcat版本 8.5.5 和 7.0.69 上也会发生同样的情况:只需添加上面的新全局资源以及上面提供工厂的附加jar,将抛出指向空的剩余名称的异常。
答案 0 :(得分:2)
堆栈跟踪通过使用问题中提供的第一个工厂实现附加到LDAP模式DN的java.naming.provider.url
属性而消失。
在此上下文中使用的LDAP客户端的屏幕截图下方,嵌入在Eclipse中的Apache Directory Studio / LDAP浏览器,只需使用问题的初始值就可以从中浏览相关的LDAP。
通过将Root元素的模式DN附加到连接URL,异常消失,现在通过Tomcat 8中的JNDI共享LDAP资源。
作为问题排查结果的详细信息:
在Tomcat 8中,全局资源是通过GlobalResourcesLifecycleListener
文件中默认定义的全局资源侦听器server.xml
来处理的。这样一个监听器invokes一个context.listBindings("")
关于bean的创建,因此有效地浏览了LDAP目录。
这种初始浏览很可能是Tomcat和WebLogic之间的区别,只有在需要时才通过JNDI查找LDAP,因此通过直接查询,而不是在启动时使用通用查询。因此,在Tomcat中,LDAP url需要进一步的细节,即,作为其url的一部分稍微不同的配置,以直接指向有效的基本DN。
启动时,WebLogic Server会尝试连接到JNDI源。如果连接成功,WebLogic Server将在本地JNDI树中设置请求的对象和链接,使其可供WebLogic Server客户端使用。
因此,连接比listBindings
更简单:
枚举命名上下文中绑定的名称以及绑定到它们的对象。不包括任何子上下文的内容。