配置

配置 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://localhost:389" />

前面的示例使用默认值(参见本段之后的表格)以及指定的 URL 和认证凭据创建一个 LdapContextSource 实例。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 操作接收的所有判别名 (Distinguished Names) 都相对于指定的 LDAP 路径。这可以显著简化对 LDAP 树的操作。但是,在某些情况下,您可能需要访问基准路径,以便构建相对于 LDAP 树实际根的完整 DN。一个例子是处理 LDAP 组(例如 groupOfNames 对象类)时。在这种情况下,每个组成员属性值都需要是被引用成员的完整 DN。更多信息请参见 获取基准 LDAP 路径的引用

anonymous-read-only

false

定义是否使用匿名(未认证)上下文执行只读操作。请注意,将此参数设置为 true 并同时启用补偿性事务支持是不被支持的,并且会被拒绝。

referral

null

定义处理 referrals 的策略,如 这里 所述。有效值包括

  • 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 认证

创建用于在 LDAP 服务器上执行操作的 DirContext 实例时,这些上下文通常需要经过认证。Spring LDAP 提供了各种配置选项。

本节涉及在 ContextSource 的核心功能中认证上下文,以构建供 LdapClientLdapTemplate 使用的 DirContext 实例。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 Proxy Auth 机制或其他考虑事项。

您可以通过向 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 操作时,应使用该用户的主体和凭据。您可以通过向 context-source 元素提供 AuthenticationSource 实现引用,而不是显式指定 usernamepassword,来修改默认行为。ContextSource 会在每次需要创建已认证 Context 时查询 AuthenticationSource 获取主体和凭据。

如果您使用 Spring Security,可以通过使用 Spring Security 中提供的 SpringSecurityAuthenticationSource 实例配置您的 ContextSource,确保始终使用当前登录用户的主体和凭据。以下示例展示了如何操作

示例 2. 使用 SpringSecurityAuthenticationSource
<beans>
...
    <ldap:context-source
        url="ldap://localhost: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 Context 配置之外手动处理。您可以在 这里 找到原生连接池配置的详细信息。

内置的 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 支持

  • 提供一个围绕 bind ©、search ®、modify (U)、unbind (D) 和 authenticate 的简化 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 为 contextSource(即 context-source 元素的默认值)。

您可以配置 LdapClient 实例如何处理某些已检查异常以及任何默认的 SearchControls 应如何用于查询。

LdapTemplate 配置

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

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

元素本身会创建一个 ID 为默认值、引用默认 ContextSourceLdapTemplate 实例,该 ContextSource 的 ID 预期为 contextSource(即 context-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 服务器在处理 referrals 时存在问题。这些通常应自动跟随。然而,如果不起作用,则会以 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://localhost:389"
          base="dc=261consulting,dc=com" />
   ...
   <bean class="org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor" />
</beans>

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