29. LDAP Authentication(LDAP身份验证)

29.1 Overview

组织通常将LDAP用作用户信息的中央存储库和身份验证服务。它还可以用来存储应用程序用户的角色信息。

对于如何配置LDAP服务器有许多不同的场景,因此Spring Security的LDAP提供程序是完全可配置的。它使用独立的策略接口进行身份验证和角色检索,并提供默认实现,可以配置这些实现来处理各种情况。

在尝试将LDAP与Spring Security一起使用之前,您应该熟悉它。以下链接很好地介绍了相关概念,并提供了使用免费的LDAP服务器OpenLDAP建立目录的指南:http://www.zytrax.com/books/ldap/.熟悉一些用于从Java访问LDAP的JNDI应用编程接口可能也是有用的。我们不使用任何第三方LDAP库(Mozilla、JLDAP等)。)中,但是Spring LDAP得到了广泛的使用,所以如果您计划添加自己的定制,那么对该项目的一些熟悉可能会有所帮助。

使用LDAP身份验证时,确保正确配置LDAP连接池非常重要。如果您不熟悉如何做到这一点,您可以参考Java LDAP文档。

29.2 Using LDAP with Spring Security

Spring Security中的LDAP身份验证可以大致分为以下几个阶段。

1、从登录名中获取唯一的LDAP“可分辨名称”。这通常意味着在目录中执行搜索,除非预先知道用户名到DNs的确切映射。因此,用户可能在登录时输入名称“joe”,但是用于向LDAP进行身份验证的实际名称将是完整的DN,例如uid=joe,ou = users,dc=spring,dc=io。

2、通过将用户“绑定”为该用户或通过对用户密码与域名目录条目中的密码属性执行远程“比较”操作来验证用户身份

3、正在为用户加载授权列表。

唯一的例外是,当LDAP目录只是用来检索用户信息并在本地对其进行身份验证时。这可能是不可能的,因为目录通常设置为对属性(如用户密码)具有有限的读取权限。

我们将在下面看一些配置场景。有关可用配置选项的完整信息,请参考安全命名空间模式(这些信息应该在您的XML编辑器中提供)。

29.3 Configuring an LDAP Server

您需要做的第一件事是配置应该进行身份验证的服务器。这是使用安全命名空间中的< ldap-server >元素完成的。这可以配置为指向外部LDAP服务器,使用url属性:

29.3.1 Using an Embedded Test Server(使用嵌入式测试服务器)

< ldap-server >元素也可以用来创建嵌入式服务器,这对测试和演示非常有用。在这种情况下,您可以在没有url属性的情况下使用它:


 

这里我们指定了目录的根DIT应该是“dc=springframework,dc=org”,这是默认的。通过这种方式,名称空间解析器将创建一个嵌入式Apache目录服务器,并扫描类路径中的任何LDIF文件,它将尝试将这些文件加载到服务器中。您可以使用ldif属性自定义此行为,该属性定义了要加载的LDIF资源:


 

这使得用LDAP启动和运行变得容易得多,因为一直使用外部服务器可能不方便。它还将用户与连接Apache目录服务器所需的复杂bean配置隔离开来。使用普通的Spring Beans,配置会更加混乱。您必须为您的应用程序提供必要的Apache目录依赖项jar来使用。这些可以从LDAP示例应用程序中获得。

29.3.2 Using Bind Authentication(使用绑定身份验证)

这是最常见的LDAP身份验证场景。


 

这个简单的示例将通过在提供的模式中替换用户登录名并尝试用登录密码作为该用户进行绑定来获取用户的域名。如果您的所有用户都存储在目录中的一个节点下,这是可以的。如果您希望配置一个LDAP搜索过滤器来定位用户,您可以使用以下内容:

 


 

如果与上面的服务器定义一起使用,这将在DN ou =人员、dc=springframework、dc=org下使用user-search-filter属性的值作为筛选器来执行搜索。同样,用户登录名替换了筛选器名称中的参数,因此它将搜索uid属性等于用户名的条目。如果没有提供user-search-base,将从根执行搜索。

29.3.3 Loading Authorities

如何从LDAP目录中的组加载权限由以下属性控制。

1、group-search-base 定义目录树中应该执行组搜索的部分。

2、group-role-attribute 包含由组条目定义的机构名称的属性。默认为cn

3、group-search-filter 用于搜索组成员的过滤器。默认为uniqueMember={0},对应于组唯一名称LDAP类。在这种情况下,替代参数是用户的完整可分辨名称。如果要筛选登录名,可以使用参数{1}。

所以如果我们使用以下配置

 


 

并且成功地被认证为用户“ben ”,则随后的权限加载将在目录条目下执行搜索ou=groups,dc=springframework,dc=org,查找包含带值的唯一成员属性的条目uid=ben,ou=people,dc=springframework,dc=org,默认情况下,机构名称的前缀是ROLE _ 。您可以使用role-prefix属性对此进行更改。如果您不想要任何前缀,请使用role-prefix="none"。有关加载权限的更多信息,请参见DefaultLdapAuthoritiesPopulator类的Javadoc。

29.4 Implementation Classes

我们上面使用的命名空间配置选项使用起来很简单,比显式使用Spring beans要简洁得多。有些情况下,您可能需要知道如何在应用程序上下文中直接配置Spring Security LDAP。例如,您可能希望自定义某些类的行为。如果您喜欢使用名称空间配置,那么您可以跳过这一节和下一节。

主要的LDAP提供程序类,LdapAuthenticationProvider,实际上并不做太多工作,而是将工作委托给另外两个beans,一个LdapAuthenticator和一个LdapAuthoritiesPopulator,它们分别负责验证用户和检索用户的授权权限集。

29.4.1 LdapAuthenticator实现

验证器还负责检索任何所需的用户属性。这是因为属性的权限可能取决于所使用的身份验证类型。例如,如果绑定为用户,可能需要使用用户自己的权限来读取它们。

Spring Security目前提供了两种身份验证策略:

    1、直接向LDAP服务器进行身份验证(“绑定”身份验证)。

     2、密码比较,将用户提供的密码与存储在存储库中的密码进行比较。这可以通过检索密码属性的值并在本地进行检查来完成,也可以通过执行LDAP“比较”操作来完成,在该操作中,提供的密码被传递给服务器进行比较,而实际的密码值永远不会被检索到。

Common Functionality

在对用户进行身份验证(通过任何一种策略)之前,必须从提供给应用程序的登录名中获取可分辨名称。这可以通过简单的模式匹配(通过设置setUserDnPatterns数组属性)或userSearch 搜索属性来实现。对于DN模式匹配方法,使用标准的Java模式格式,登录名将替换参数{0}。该模式应该是相对于配置的SpringSecurityContextSource将绑定到的DN的(有关这方面的更多信息,请参见连接到LDAP服务器一节)。例如,如果您使用的LDAP服务器的URL是LDAP://monkey machine . co . uk/dc=springframework,dc=org,并且具有模式uid={0},ou = greategies,则登录名“gorilla”将映射到DN uid=gorilla,ou = greategies,DC = spring framework,dc=org将依次尝试每个已配置的域名模式,直到找到匹配项。有关使用搜索的信息,请参见下面关于搜索对象的部分。也可以使用这两种方法的组合——首先检查模式,如果没有找到匹配的域名,将使用搜索。

BindAuthenticator绑定验证器

org . spring framework . security . LDAP . authentication包中的BindAuthenticator类实现了绑定身份验证策略。它只是试图作为用户绑定。

PasswordComparisonAuthenticator(密码比较身份验证器)

类PasswordComparisonAuthenticator实现了密码比较身份验证策略。

29.4.2 Connecting to the LDAP Server

上面讨论的beans必须能够连接到服务器。它们都必须提供一个SpringSecurityContextSource,它是Spring LDAP的上下文源的扩展。除非您有特殊要求,否则您通常会配置一个DefaultSpringsecurityContextSource bean,该bean可以用您的LDAP服务器的网址来配置,也可以用“管理员”用户的用户名和密码来配置,默认情况下,当绑定到服务器时会使用该用户名和密码(而不是匿名绑定)。有关更多信息,请阅读这个类的Javadoc和Spring LDAP的抽象上下文源。

29.4.3 LDAP Search Objects(LDAP搜索对象)

通常需要比简单的域名匹配更复杂的策略来定位目录中的用户条目。这可以封装在一个LdapUserSearch实例中,该实例可以提供给认证器实现,例如,允许它们定位用户。提供的实现是FilterBasedLdapUserSearch。

FilterBasedLdapUserSearch

这个bean使用一个LDAP过滤器来匹配目录中的用户对象。在Javadoc中解释了这个过程,以便在JDK DirContext类中找到相应的搜索方法。如这里所解释的,搜索过滤器可以被提供参数。对于此类,唯一有效的参数是{0},它将被替换为用户的登录名。

29.4.4 LdapAuthoritiesPopulator

成功验证用户后,LdapAuthenticationProvider将通过调用已配置的LDapauthenticationpopulator bean,尝试为用户加载一组权限。DefaultLdapAuthoritiesPopulator是一个实现,它将通过在目录中搜索用户所属的组来加载权限(通常这些组groupOfNames 或groupOfUniqueNames )。如果您只想将LDAP用于身份验证,但从不同的来源(如数据库)加载权限,那么您可以提供自己的接口实现,并将其注入。

 

29.4.5 Spring Bean Configuration

使用我们在此讨论的一些beans的典型配置可能如下所示:

 


 

这将设置提供程序访问一个带有以下网址的LDAP服务器:LDAP://monkey machine:389/DC = spring framework,dc=org。将通过尝试用DN uid=<user-login-name>,ou=people,dc=springframework,dc=org绑定来执行身份验证。身份验证成功后,将通过使用默认筛选器(member=<user’s-DN>)在ou=groups,dc=springframework,dc=org下进行搜索,将角色分配给用户。角色名称将取自每个匹配的“ou”属性。

要配置一个用户搜索对象,该对象使用过滤器(uid=<user-login-name>)来代替DN模式(或除此之外),您需要配置以下bean

 


 

并通过设置BindAuthenticator bean的userSearch 属性来使用它。然后,在尝试绑定为该用户之前,验证者将调用搜索对象来获取正确的用户的域名。

29.4.6 LDAP Attributes and Customized UserDetails(LDAP属性和自定义用户详细信息)

使用LdapAuthenticationProvider的身份验证的最终结果与使用标准UserDetailsService接口的普通Spring Security身份验证相同。UserDetails 对象被创建并存储在返回的Authentication 对象中。与UserDetailsService一样,一个常见的需求是能够定制这个实现并添加额外的属性。

当使用LDAP时,这些通常是用户条目的属性。UserDetails 对象的创建由提供者的UserDetailsContextMapper 策略控制,该策略负责将用户对象映射到LDAP上下文数据和从LDAP上下文数据映射用户对象:

 


 

只有第一种方法与身份验证相关。如果您提供了此接口的一个实现,并将其注入到LdapAuthenticationProvider中,您就可以精确地控制用户详细信息对象的创建方式。第一个参数是Spring LDAP的DirContextOperations 一个实例,它允许您访问在身份验证期间加载的LDAP属性。用户名参数是用于进行身份验证的名称,最后一个参数是由已配置的LDAP authorities填充器(LdapAuthoritiesPopulator)为用户加载的权限集合。

根据您使用的身份验证类型,上下文数据的加载方式略有不同。使用绑定验证器,从绑定操作返回的上下文将用于读取属性,否则将使用从配置的上下文源(ContextSource )获得的标准上下文来读取数据(当搜索被配置为定位用户时,这将是搜索对象返回的数据)。

 

29.5 Active Directory Authentication(活动目录身份验证)

活动目录支持它自己的非标准身份验证选项,正常的使用模式不太适合标准的LDAP身份验证提供程序。通常,身份验证是使用域用户名(以用户@域的形式)执行的,而不是使用LDAP可分辨名称。为了使这变得更容易,Spring Security 3.1有一个为典型的活动目录设置定制的身份验证提供程序。

29.5.1 ActiveDirectoryLdapAuthenticationProvider(活动目录Ldap身份验证提供程序)

配置活动目录身份验证提供程序(ActiveDirectoryLdapAuthenticationProvider )非常简单。您只需要提供域名和提供服务器地址的LDAP网址[20]。示例配置如下所示:

 


 

请注意,不需要指定单独的上下文源来定义服务器位置bean,它是完全独立的。一个名叫“Sharon”的用户。例如,将能够通过输入用户名sharon或完整的Active Directory user principalname(即sharon@mydomain.com)进行身份验证。然后将定位用户的目录条目,并返回属性,以便在定制创建的用户详细信息对象时可能使用(可以为此目的注入用户详细信息文本映射器(UserDetailsContextMapper )),如上所述)。与目录的所有交互都以用户自身的身份进行。没有“manager”用户的概念。

默认情况下,用户权限从用户条目的成员属性值(memberOf)中获取。分配给用户的权限也可以使用用户详细信息文本映射器(UserDetailsContextMapper)进行自定义。您还可以将授权授权映射器(GrantedAuthoritiesMapper )注入到提供程序实例中,以控制最终出现在身份验证对象中的授权。

Active Directory Error Codes(活动目录错误代码)

默认情况下,失败的结果将导致标准的spring安全不良证书异常(BadCredentialsException)。如果将属性ConvertsuberrorCodeStoExceptions设置为true,将会分析异常消息,以尝试提取特定于活动目录的错误代码并引发更特定的异常。有关更多信息,请查看Javadoc类。

posted @ 2020-08-16 18:10  节日快乐  阅读(4800)  评论(0编辑  收藏  举报