尝试将LDAP配置为Tomcat中的JNDI资源

8
我有一个LDAP服务器,用于对Tomcat Web应用程序中的用户进行身份验证。我正在使用JNDIRealm,并将其配置在上下文文件中,这非常有效。
我还需要搜索LDAP以获取用户信息。我已经通过创建自己的JNDI上下文并使用哈希表来完成了“jndi方法”的操作,而且在Tomcat之外也可以正常工作。但是,我不想在代码中配置JNDI属性,而是希望在我的上下文文件中创建一个JNDI资源,就像Realm配置旁边一样。
我认为我会这样做:
<Resource 
  name="ldap"
  auth="Container"
  type="com.sun.jndi.ldap.LdapCtxFactory"
  java.naming.factory.initial="com.sun.jndi.ldap.LdapCtxFactory"
  java.naming.provider.url="ldap://localhost:389"
  java.naming.security.authentication="simple"
  java.naming.security.principal="uid=rjcarr,dc=example"
  java.naming.security.credentials="abc123"
/>

但是无论是Tomcat告诉我资源无法创建,还是当我试图用类似以下方式初始化它时:

Context initctx = new InitialContext();
DirContext ctx = (DirContext) initctx.lookup("java:comp/env/ldap");

Tomcat告诉我:“无法创建资源实例”。我已经在web.xml文件中添加了正确的resource-ref,所以我认为那不是问题所在。

由于LDAP与JNDI方法一起使用,因此我假设它应该能够配置为资源,对吧?我错过了什么吗?

2个回答

4
这个回答有点晚了,但对其他用户可能有用。它基于EJP的回答
以下解决方案是在Apache Tomcat 7上测试过的。
如果需要,可以用DirContext替换LdapContext

创建一个ObjectFactory

创建一个实现ObjectFactory的类来实例化LdapContext
public class LdapContextFactory implements ObjectFactory {

    public Object getObjectInstance(Object obj, Name name, Context nameCtx, 
        Hashtable<?, ?> environment) throws Exception {

        Hashtable<Object, Object> env = new Hashtable<Object, Object>();
        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();

            switch (type) {

            case Context.INITIAL_CONTEXT_FACTORY:
                env.put(Context.INITIAL_CONTEXT_FACTORY, content);
                break;

            case Context.PROVIDER_URL:
                env.put(Context.PROVIDER_URL, content);
                break;

            case Context.SECURITY_AUTHENTICATION:
                env.put(Context.SECURITY_AUTHENTICATION, content);
                break;

            case Context.SECURITY_PRINCIPAL:
                env.put(Context.SECURITY_PRINCIPAL, content);
                break;

            case Context.SECURITY_CREDENTIALS:
                env.put(Context.SECURITY_CREDENTIALS, content);
                break;

            default:
                break;
            }
        }

        LdapContext context = new InitialLdapContext(env, null);
        return context;
    }
}

定义您的资源

将以下内容添加到您的context.xml中,引用工厂并定义值以创建一个LdapContext实例:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    ...
    <Resource name="ldap/LdapResource" auth="Container"
        type="javax.naming.ldap.LdapContext"
        factory="com.company.LdapContextFactory"
        singleton="false" 
        java.naming.factory.initial="com.sun.jndi.ldap.LdapCtxFactory"
        java.naming.provider.url="ldap://127.0.0.1:389"
        java.naming.security.authentication="simple"
        java.naming.security.principal="username"
        java.naming.security.credentials="password" />
</Context>

如果您需要添加更多属性/值到您的资源中,请考虑更新上面创建的ObjectFactory以读取这些新属性/值。

使用您的资源

在您需要的任何地方注入您的资源:

@Resource(name = "ldap/LdapResource")
private LdapContext bean;

或者查找它:

Context initialContext = new InitialContext();
LdapContext ldapContext = (LdapContext)
    initialContext.lookup("java:comp/env/ldap/LdapResource");

查看更多

Apache Tomcat的文档解释如何添加自定义资源工厂


我无法让它正常工作,这里是我的问题(带有开放的悬赏)。 - A_Di-Matteo

2

你是在编造。Tomcat资源的类型必须是实现了javax.naming.spi.ObjectFactory接口的类。请参考Tomcat文档中的自定义资源部分。


1
或者您可以使用Tomcat的BeanFactory,该工厂要求资源符合JavaBean规范。 - Marko Vranjkovic

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