配置

推荐的 Spring LDAP 配置方式是使用自定义 XML 配置命名空间。要使此命名空间可用,您需要在 bean 文件中包含 Spring LDAP 命名空间声明,如下所示

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:ldap="http://www.springframework.org/schema/ldap"
       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/ldap https://www.springframework.org/schema/ldap/spring-ldap.xsd">

ContextSource 配置

ContextSource 通过使用 <ldap:context-source> 标签定义。最简单的 context-source 声明需要您指定服务器 URL、用户名和密码,如下所示

示例 1. 最简单的 context-source 声明
<ldap:context-source
    username="cn=Administrator"
    password="secret"
    url="ldap://127.0.0.1:389" />

上述示例创建了一个 LdapContextSource,并使用默认值(请参阅本段之后的表格)以及指定的 URL 和身份验证凭据。context-source 上的可配置属性如下所示(必填属性标有 *)

表 1. ContextSource 配置属性
属性 默认值 描述

id

contextSource

创建的 bean 的 ID。

username

用于对 LDAP 服务器进行身份验证的用户名(主体)。这通常是管理员用户的可分辨名称(例如,cn=Administrator),但可能因服务器和身份验证方法而异。如果未显式配置 authentication-source-ref,则为必填。

password

用于对 LDAP 服务器进行身份验证的密码(凭据)。如果未显式配置 authentication-source-ref,则为必填。

url *

要使用的 LDAP 服务器的 URL。URL 应采用以下格式:ldap://myserver.example.com:389。对于 SSL 访问,请使用 ldaps 协议和相应的端口,例如 ldaps://myserver.example.com:636。如果需要故障转移功能,您可以指定多个 URL,并用逗号 (,) 分隔。

base

LdapUtils.emptyLdapName()

基础 DN。配置此属性后,提供给 LDAP 操作和从 LDAP 操作接收的所有可分辨名称都相对于指定的 LDAP 路径。这可以大大简化针对 LDAP 树的操作。但是,在某些情况下,您需要访问基础路径。有关此内容的更多信息,请参阅 获取对基础 LDAP 路径的引用

anonymous-read-only

false

定义是否使用匿名(未经身份验证)上下文执行只读操作。请注意,将此参数设置为 true 以及补偿性事务支持不受支持,并将被拒绝。

referral

null

定义处理引用的策略,如 此处 所述。有效值为

  • ignore

  • follow

  • throw

native-pooling

false

指定是否应使用本机 Java LDAP 连接池。建议改为使用 Spring LDAP 连接池。有关更多信息,请参阅 连接池支持

authentication-source-ref

一个 SimpleAuthenticationSource 实例。

要使用的 AuthenticationSource 实例的 ID(请参阅 自定义主体和凭据管理)。

authentication-strategy-ref

一个 SimpleDirContextAuthenticationStrategy 实例。

要使用的 DirContextAuthenticationStrategy 实例的 ID(请参阅 自定义 DirContext 身份验证处理)。

base-env-props-ref

对自定义环境属性的 Map 的引用,这些属性应与构造时发送到 DirContext 的环境一起提供。

DirContext 身份验证

当创建 DirContext 实例以用于对 LDAP 服务器执行操作时,这些上下文通常需要进行身份验证。Spring LDAP 提供了多种配置此功能的选项。

本节介绍如何在 ContextSource 的核心功能中对上下文进行身份验证,以构造 DirContext 实例供 LdapClientLdapTemplate 使用。LDAP 通常用于用户身份验证的唯一目的,ContextSource 也可用于此目的。该过程在 使用 Spring LDAP 进行用户认证 中进行了讨论。

默认情况下,会为只读和读写操作创建经过身份验证的上下文。您应该在 context-source 元素上指定用于身份验证的 LDAP 用户的 usernamepassword

如果 username 是 LDAP 用户的可分辨名称 (DN),则它需要是 LDAP 树根目录下用户的完整 DN,无论 context-source 元素上是否指定了 base LDAP 路径。

某些 LDAP 服务器设置允许匿名只读访问。如果要对只读操作使用匿名上下文,请将 anonymous-read-only 属性设置为 true

自定义 DirContext 身份验证处理

Spring LDAP 中使用的默认身份验证机制是 SIMPLE 身份验证。这意味着主体(由 username 属性指定)和凭据(由 password 指定)都设置在发送到 DirContext 实现构造函数的 Hashtable 中。

在许多情况下,这种处理方式是不够的。例如,LDAP 服务器通常被设置为仅在安全的 TLS 通道上接受通信。可能需要使用特定的 LDAP 代理身份验证机制或其他考虑因素。

您可以通过向 context-source 元素提供 DirContextAuthenticationStrategy 实现引用来指定替代的身份验证机制。为此,请设置 authentication-strategy-ref 属性。

TLS

Spring LDAP 为需要 TLS 安全通道通信的 LDAP 服务器提供了两种不同的配置选项:DefaultTlsDirContextAuthenticationStrategyExternalTlsDirContextAuthenticationStrategy。这两种实现都在目标连接上协商 TLS 通道,但它们在实际的身份验证机制上有所不同。其中 DefaultTlsDirContextAuthenticationStrategy 在安全通道上应用 SIMPLE 身份验证(通过使用指定的 usernamepassword),而 ExternalTlsDirContextAuthenticationStrategy 使用 EXTERNAL SASL 身份验证,应用通过使用系统属性配置的客户端证书进行身份验证。

由于不同的 LDAP 服务器实现对 TLS 通道的显式关闭的响应不同(某些服务器要求连接以优雅的方式关闭,而其他服务器不支持它),因此 TLS DirContextAuthenticationStrategy 实现支持通过使用 shutdownTlsGracefully 参数来指定关闭行为。如果此属性设置为 false(默认值),则不会发生显式 TLS 关闭。如果它为 true,则 Spring LDAP 会尝试在关闭目标上下文之前以优雅的方式关闭 TLS 通道。

在使用 TLS 连接时,您需要确保已关闭本机 LDAP 池功能(如通过使用 native-pooling 属性指定的那样)。如果 shutdownTlsGracefully 设置为 false,则这一点尤其重要。但是,由于 TLS 通道协商过程非常昂贵,因此您可以通过使用 Spring LDAP 池支持获得巨大的性能优势,如池支持中所述。

自定义主体和凭据管理

虽然用于创建已认证 Context 的用户名(即用户 DN)和密码默认情况下是静态定义的(在 context-source 元素配置中定义的那些在 ContextSource 的整个生命周期中使用),但在某些情况下,这不是所需的行为。一个常见的场景是,在为该用户执行 LDAP 操作时,应使用当前用户的 principals 和凭据。您可以通过向 context-source 元素提供对 AuthenticationSource 实现的引用来修改默认行为,方法是使用 authentication-source-ref 元素,而不是显式指定 usernamepassword。每次要创建已认证的 Context 时,ContextSource 都会查询 AuthenticationSource 以获取 principals 和凭据。

如果您使用Spring Security,您可以确保始终使用当前登录用户的 principals 和凭据,方法是使用 Spring Security 附带的 SpringSecurityAuthenticationSource 实例配置您的 ContextSource。以下示例显示了如何执行此操作

示例 2. 使用 SpringSecurityAuthenticationSource
<beans>
...
    <ldap:context-source
        url="ldap://127.0.0.1:389"
        authentication-source-ref="springSecurityAuthenticationSource"/>

    <bean id="springSecurityAuthenticationSource"
        class="org.springframework.security.ldap.authentication.SpringSecurityAuthenticationSource" />
...
</beans>
当使用 AuthenticationSource 时,我们不为 context-source 指定任何 usernamepassword。仅当使用默认行为时才需要这些属性。
当使用 SpringSecurityAuthenticationSource 时,您需要使用 Spring Security 的 LdapAuthenticationProvider 来对 LDAP 认证用户。

原生 Java LDAP 池

内部 Java LDAP 提供程序提供了一些非常基本的池功能。您可以通过使用 AbstractContextSource 上的 pooled 标志来打开或关闭此 LDAP 连接池。默认值为 false(自 1.3 版起)——也就是说,原生 Java LDAP 池已关闭。LDAP 连接池的配置是通过使用 System 属性管理的,因此您需要手动处理它,而不是在 Spring 上下文配置中处理。您可以在此处找到原生池配置的详细信息。

内置 LDAP 连接池存在一些严重的缺陷,因此 Spring LDAP 提供了一种更复杂的方法来处理 LDAP 连接池,如池支持中所述。如果您需要池功能,这是推荐的方法。
无论池配置如何,ContextSource#getContext(String principal, String credentials) 方法始终明确地不使用原生 Java LDAP 池,以便重置密码尽快生效。

高级 ContextSource 配置

本节介绍配置 ContextSource 的更高级方法。

自定义 DirContext 环境属性

在某些情况下,您可能希望指定其他环境设置属性,除了 context-source 上可以直接配置的属性之外。您应该在 Map 中设置这些属性,并在 base-env-props-ref 属性中引用它们。

LdapClient 配置

LdapClient 是用于调用 LDAP 后端的新的接口。它在以下方面改进了 LdapTemplate

  • 提供内置的 Stream 支持

  • 提供一个围绕绑定 ©、搜索 ®、修改 (U)、解绑 (D) 和身份验证的简化 API。

LdapClient 尚未支持 ODM。如果您需要此功能,LdapTemplate 具有此功能。如果需要,LdapClientLdapTemplate 可以很好地共存于同一个应用程序中。

LdapClient 是通过使用 LdapClient#create 工厂方法来定义的,如下所示

示例 3. 最简单的 LdapClient 声明
<bean id="ldapClient" class="org.springframework.ldap.core.LdapClient" factory-method="create">
   <constructor-arg ref="contextSource" />
</bean>

此元素引用默认的 ContextSource,预期其 ID 为 contextSourcecontext-source 元素的默认值)。

您可以为 LdapClient 实例配置如何处理某些已检查异常以及应为查询使用哪些默认 SearchControls

LdapTemplate 配置

LdapTemplate 是通过使用 <ldap:ldap-template> 元素来定义的。最简单的 ldap-template 声明是元素本身

示例 4. 最简单的 ldap-template 声明
<ldap:ldap-template />

元素本身会创建一个具有默认 ID 的 LdapTemplate 实例,并引用默认的 ContextSource,预期其 ID 为 contextSourcecontext-source 元素的默认值)。

下表描述了 ldap-template 上的可配置属性

表 2. LdapTemplate 配置属性
属性 默认值 描述

id

ldapTemplate

创建的 bean 的 ID。

context-source-ref

contextSource

要使用的 ContextSource 实例的 ID。

count-limit

0

搜索的默认计数限制。0 表示没有限制。

time-limit

0

搜索的默认时间限制,以毫秒为单位。0 表示没有限制。

search-scope

SUBTREE

搜索的默认搜索范围。有效值为

  • OBJECT

  • ONELEVEL

  • SUBTREE

ignore-name-not-found

false

指定是否应忽略搜索中的 NameNotFoundException。将此属性设置为 true 会使由无效搜索基准引起的错误被静默吞噬。

ignore-partial-result

false

指定是否应忽略搜索中的 PartialResultException。某些 LDAP 服务器在引用方面存在问题。这些通常应自动跟随。但是,如果这不起作用,则会以 PartialResultException 的形式表现出来。将此属性设置为 true 提供了此问题的解决方法。

odm-ref

要使用的 ObjectDirectoryMapper 实例的 ID。默认为默认配置的 DefaultObjectDirectoryMapper

获取对基本 LDAP 路径的引用

如前所述,您可以向 ContextSource 提供基本 LDAP 路径,指定所有操作相对于的 LDAP 树中的根。这意味着您只在整个系统中使用相对的区分名称,这通常非常方便。但是,在某些情况下,您可能需要访问基本路径才能能够构建相对于 LDAP 树实际根的完整 DN。一个示例是在处理 LDAP 组(例如,groupOfNames 对象类)时。在这种情况下,每个组成员属性值都需要是被引用的成员的完整 DN。

为此,Spring LDAP 提供了一种机制,通过该机制,任何 Spring 控制的 bean 都可以在启动时获得基本路径。为了使 bean 能够收到基本路径的通知,需要具备两件事。首先,想要基本路径引用的 bean 需要实现 BaseLdapNameAware 接口。其次,您需要在应用程序上下文中定义 BaseLdapPathBeanPostProcessor。以下示例显示了如何实现 BaseLdapNameAware

示例 5. 实现 BaseLdapNameAware
public class PersonService implements PersonService, BaseLdapNameAware {
   ...
   private LdapName basePath;

   public void setBaseLdapPath(LdapName basePath) {
      this.basePath = basePath;
   }
   ...
   private LdapName getFullPersonDn(Person person) {
      return LdapNameBuilder.newInstance(basePath)
          .add(person.getDn())
          .build();
   }
   ...
}

以下示例显示了如何定义 BaseLdapPathBeanPostProcessor

示例 6. 在您的 ApplicationContext 中指定 BaseLdapPathBeanPostProcessor
<beans>
   ...
   <ldap:context-source
          username="cn=Administrator"
          password="secret"
          url="ldap://127.0.0.1:389"
          base="dc=261consulting,dc=com" />
   ...
   <bean class="org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor" />
</beans>

BaseLdapPathBeanPostProcessor 的默认行为是使用 ApplicationContext 中定义的单个 BaseLdapPathSourceAbstractContextSource)的基本路径。如果定义了多个 BaseLdapPathSource,则需要通过设置 baseLdapPathSourceName 属性来指定要使用哪个 BaseLdapPathSource