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

2022-01-17 00:00:00 ldap java tomcat jndi

我有一个 ldap 服务器,用于在 tomcat Web 应用程序中对用户进行身份验证.我正在使用 JNDIRealm,它是在上下文文件中配置的,效果很好.

I have an ldap server that I'm using to authenticate users within a tomcat web application. I'm using the JNDIRealm and it's configured within a context file and this works great.

我还需要在 ldap 中搜索用户信息.我已经想出了如何使用jndi 方法"来做到这一点,并且通过使用哈希表创建我自己的 jndi 上下文,我让它在 tomcat 之外正常工作.但是,我不想在代码中配置 jndi 属性,而是想在 Realm 配置旁边的上下文文件中创建一个 JNDI Rsource.

I'll also need to search the ldap for user information. I've figured out how to do this with the "jndi method" and I have it working fine outside of tomcat by creating my own jndi context using a hashtable. However, instead of configuring the jndi properties in code, I'd like to create a JNDI Rsource in my context file right next to the Realm configuration.

我想我会做这样的事情:

I'm thinking I would do something like this:

<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 告诉我无法创建资源,要么当我尝试使用以下内容对其进行初始化时:

But either tomcat tells me the resource can't be created or when I try to initialize it with something like this:

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

Tomcat 告诉我无法创建资源实例".我还在 web.xml 文件中添加了正确的资源引用,所以我认为这不是问题.

Tomcat tells me the "Cannot create resource instance". I've also added the correct resource-ref in my web.xml file, so I don't think that's the problem.

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

Since LDAP is being used with the JNDI method I'm assuming it should be able to be configured as a Resource, right? What am I missing?

推荐答案

这个答案有点晚了,但可能对其他用户有用.它基于 EJP 的回答.

This answer is a bit late, but probably it'll be useful for other users. It's based on EJP's answer.

以下解决方案已在 Apache Tomcat 7 上进行了测试.
如果需要,可以替换 LdapContextDirContext.

The following solution was tested on Apache Tomcat 7.
If you need, you can replace LdapContext with DirContext.

创建一个实现 ObjectFactory 实例化一个 LdapContext:

Create a class which implements ObjectFactory to instantiate a 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 实例:

Define your resource

Add the following to your context.xml, referencing the factory and defining the values to create a LdapContext instance:

<?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 上面创建的用于读取这些新属性/值.

If you need to add more attributes/values to your resource, consider updating your ObjectFactory created above to read these new attributes/values.

在你需要的地方注入你的资源:

Inject your resource wherever you need:

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

或者查一下:

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

查看更多

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

相关文章