读书人

应用 Acegi 保护 Java 应用程序: 续二

发布时间: 2012-10-25 10:58:57 作者: rapoo

使用 Acegi 保护 Java 应用程序: 续二

使用 Acegi 保护 Java 应用程序: 续二

?

了解了 Acegi 安全系统(Acegi Security System)的 基础知识 后,我们将介绍该系统的更加高级的应用。在本文中,Bilal Siddiqui 向您展示了如何结合使用 Acegi 和一个 LDAP 目录服务器,实现灵活的具有高性能的 Java? 应用程序的安全性。还将了解如何编写访问控制策略并将其存储在 ApacheDS 中,然后配置 Acegi 使其与目录服务器交互,从而实现身份验证和授权的目的。

?

这期共分三部分的系列文章介绍了如何使用 Acegi 安全系统保护 Java 企业应用程序。在 本系列第一篇文章 中,我介绍了 Acegi 并解释了如何使用安全过滤器实现一个简单的基于 URL 的安全系统。在第二篇文章中,我将讨论 Acegi 的更加高级的应用,首先我将编写一个访问控制策略并将其存储在 ApacheDS 中,ApacheDS 是一个开源的 LDAP 目录服务器。我还将展示配置 Acegi 的方法,使它能够与目录服务器交互并实现您的访问控制策略。本文的结尾提供了一个示例应用程序,它使用 ApacheDS 和 Acegi 实现了一个安全的访问控制策略。

实现访问控制策略通常包含两个步骤:

    将有关用户和用户角色的数据存储在目录服务器中。 编写安全代码,它将定义有权访问并使用数据的人员。

Acegi 将减轻代码编写的工作,因此在这篇文章中,我将展示如何将用户和用户角色信息存储到 ApacheDS 中,然后实现这些信息的访问控制策略。在该系列的最后一篇文章中,我将展示如何配置 Acegi,实现对 Java 类的安全访问。

您可以在本文的任何位置 下载样例应用程序。参见 参考资料 下载 Acegi、Tomcat 和 ApacheDS,您需要使用它们运行样例代码和示例应用程序。

?

?

?

?

在图 1 中,根节点的名称为 org。根节点可以封装与不同企业有关的数据。例如,本系列第 1 部分开发的制造业企业被显示为 org 节点的直接子节点。该制造业企业具有两个名为 departments 和 partners 的子节点。

partners 子节点封装了不同类型的合作伙伴。图 1 所示的三个分别为 customers、employees 和 suppliers。注意,这三种类型的合作伙伴其行为与企业系统用户一样。每一种类型的用户所扮演的业务角色不同,因此访问系统的权利也不同。

?

类似地,departments 节点包含该制造业企业的不同部门的数据 —— 例如 engineering 和 marketing 字节点。每个部门节点还包含一组或多组用户。在 图 1 中,engineers 组是 engineering 部门的子节点。

假设每个部门的子节点表示一组用户。因此,部门节点的子节点具有不同的用户成员。例如,设计部门的所有工程师都是 engineering 部门内 engineers 组的成员。

?

最后,注意 图 1 中 departments 节点的最后一个子节点。specialUser 是一名用户,而非一组用户。在目录设置中,像 alice 和 bob 之类的用户一般都包含在 partners 节点中。我将这个特殊用户包含在 departments 节点中,以此证明 Acegi 允许用户位于 LADP 目录中任何地点的灵活性。稍后在本文中,您将了解如何配置 Acegi 以应用 specialUser。

?

?

首先,注意图 2 中根节点的 DN。它的 DN 为 dc=org,这是与 org 根节点相关的属性值对。每个节点都有若干个与之相关的属性。dc 属性代表 “domain component” 并由 LDAP RFC 2256 定义(参见 参考资料 中有关官方 RFC 文档的链接),LDAP 目录中的根节点通常表示为一个域组件。

?

每个 LDAP 属性是由 RFC 定义的。LDAP 允许使用多个属性创建一个 DN,但是本文的示例只使用了以下 4 个属性:

dc(域组件) o(组织) ou(组织单元) uid(用户 ID)

示例使用 dc 表示域,用 o 表示组织名称,ou 表示组织的不同单元,而 uid 表示用户。

?

由于 org 是根节点,其 DN 只需指定自身的名称(dc=org)。比较一下,manufacturingEnterprise 节点的 DN 是 o=manufacturingEnterprise,dc=org。当向下移动节点树时,每个父节点的 DN 被包含在其子节点的 DN 中。

?


应用 Acegi 保护 Java 应用程序: 续二
应用 Acegi 保护 Java 应用程序: 续二
回页首

清单 1 编辑了 examplePartitionConfiguration bean 的两个属性:

一个属性名为 suffix,它定义根条目的 DN。

另一个属性名为 contextEntry,定义 org 节点将使用的对象类。注意,org 根节点使用两个对象类:top 和 domain。

本文的 源代码下载 部分包含了编辑模式的 server.xml 文件。如果希望继续学习本示例,请将 server.xml 文件从源代码中复制到您的 ApacheDS 安装目录中的正确位置,即 conf 文件夹。

图 3 所示的屏幕截图展示了在 ApacheDS 中创建根节点后,JXplorer 是如何显示该根节点的:


图 3. JXplorer 显示根节点
?应用 Acegi 保护 Java 应用程序: 续二

将 LDIF 文件导入到 ApacheDS 之后,JXplorer 将显示用户节点和部门节点树,如 图 1 所示。现在您可以开始配置 Acegi,使其能够与您的 LDAP 服务器通信。


应用 Acegi 保护 Java 应用程序: 续二
应用 Acegi 保护 Java 应用程序: 续二
应用 Acegi 保护 Java 应用程序: 续二
回页首

查看一下清单 2,您曾经为 APF 提供了 4 个参数。您只需在 LDAP 服务器中为存储重新配置第一个参数(authenticationManager)即可。其他三个参数保持不变。

在清单 3 中,org.acegisecurity.providers.ProviderManager 是一个管理器类,它管理 Acegi 的身份验证过程。为此,身份验证管理器需要一个或多个身份验证提供者。您可以使用管理器 bean 的提供者属性来配置一个或多个提供者。清单 3 只包含了一个提供者,即 LDAP 身份验证提供者。

LDAP 身份验证提供者处理所有与后端 LDAP 目录的通信。您必须对其进行配置,下一节内容将讨论该主题。


应用 Acegi 保护 Java 应用程序: 续二
应用 Acegi 保护 Java 应用程序: 续二
回页首

搜索查询的参数

清单 6 展示了 userSearch bean 是 org.acegisecurity.ldap.search.FilterBasedLdapUserSearch 类的一个实例,该类的构造函数具有三个参数。第一个参数指定 authenticator 在哪个节点中搜索用户。第一个参数的值为 ou=departments,该值是一个 RDN,指定了 图 2 所示的 departments 节点。

第二个参数 (uid={0}) 指定了一个搜索过滤器。由于使用 uid 属性指定用户,因此可以通过查找 uid 属性具有特定值的节点来查找用户。正如您所料,花括号里面的 0 向 Acegi 表示使用进行身份验证的用户的用户名(本例中为 specialUser)替换 {0}。

第三个参数是对讨论 清单 5 中的 BindAuthenticator 构造函数时引入的相同初始上下文的引用。回想一下,当指定了初始上下文后,稍后将在该初始上下文节点的子节点内进行所有的搜索操作。注意,应将指定为 清单 5 中第一个参数(ou=departments)的值的 RDN 前加到初始上下文。

除了这三个构造器参数,清单 6 所示的 userSearch bean 还具有一个名为 searchSubtree 的属性。如果将其值指定为 true,搜索操作将包括节点的子树(即所有子节点、孙节点、孙节点的子节点等),该节点被指定为构造函数的第一个参数的值。

authenticator bean 的配置完成后,下一步将查看 populator bean 的配置,如 清单 4 所示。


应用 Acegi 保护 Java 应用程序: 续二
应用 Acegi 保护 Java 应用程序: 续二
应用 Acegi 保护 Java 应用程序: 续二
回页首


应用 Acegi 保护 Java 应用程序: 续二
应用 Acegi 保护 Java 应用程序: 续二
回页首

无论 APF 使用属性文件进行内部的身份验证还是与 LDAP 服务器进行通信,步骤 1 到步骤 9 与第 1 部分是相同的。这里简单描述了前 9 个步骤,您可以从步骤 10 开始继续学习特定于 LDAP 的事件:

    过滤器链前面的过滤器将请求、响应和过滤器链对象传递给 APF。

    APF 使用取自请求对象的用户名、密码和其他信息创建一个身份验证标记。

    APF 将身份验证标记传递给身份验证管理器。

    身份验证管理器可能包含一个或多个身份验证提供者。每个提供者恰好支持一种身份验证类型。管理器将检查哪一种提供者支持从 APF 接收到的身份验证标记。

    身份验证管理器将身份验证标记传递给适合该类型身份验证的提供者。

    身份验证提供者从身份验证标记中提取用户名并将其传递到名为 user cache service 的服务。Acegi 缓存了已经进行过身份验证的用户。该用户下次登录时,Acegi 可以从缓存中加载他或她的详细信息(比如用户名、密码和权限),而不是从后端数据存储中读取数据。这种方法使得性能得到了改善。

    user cache service 检查用户的详细信息是否存在于缓存中。

    user cache service 将用户的详细信息返回给身份验证提供者。如果缓存不包含用户详细信息,则返回 null。

    身份验证提供者检查缓存服务返回的是用户的详细信息还是 null。

    从这里开始,身份验证处理将特定于 LDAP。 如果缓存返回 null,LDAP 身份验证提供者将把用户名(在步骤 6 中提取的)和密码传递给 清单 5 中配置的 authenticator bean。

    authenticator 将使用在 清单 5 的 userDnPatterns 属性中配置的 DN 模式创建用户 DN。通过从一个 DN 模式中创建一个 DN,然后将该 DN 和用户密码(从用户请求中获得)发送到 LDAP 目录,它将逐一尝试所有可用的 DN 模式。LDAP 目录将检查该 DN 是否存在以及密码是否正确。如果其中任何一个 DN 模式可行的话,用户被绑定到 LDAP 目录中,authenticator 将继续执行步骤 15。

    如果任何一种 DN 模式都不能工作的话(这意味着在 DN 模式指定的任何位置都不存在使用给定密码的用户),authenticator 根据 清单 6 配置的搜索查询在 LDAP 目录中搜索用户。如果 LDAP 目录没有找到用户,那么身份验证以失败告终。

    如果 LDAP 目录查找到了用户,它将用户的 DN 返回到 authenticator。

    authenticator 将用户 DN 和密码发送到 LDAP 目录来检查用户密码是否正确。如果 LDAP 目录发现用户密码是正确的,该用户将被绑定到 LDAP 目录。

    authenticator 将用户信息发送回 LDAP 身份验证提供者。

    LDAP 身份验证提供者将控制权传递给 populator bean。

    populator 搜索用户所属的组。

    LDAP 目录将用户角色信息返回给 populator。

    populator 将用户角色信息返回给 LDAP 身份验证提供者。

    LDAP 身份验证提供者将用户的详细信息(以及用户业务角色信息)返回给 APF。用户现在成功进行了身份验证。

不论使用何种身份验证方法,最后三个步骤是相同的(步骤21、21 和 23)。

在清单 9 中,IF 包含三个参数。其中第一个和第三个参数与第 1 部分中最初配置的参数相同。这里添加了第二个参数(名为 accessDecisionManager 的 bean)。

accessDecisionManager bean 负责指定授权决策。它使用清单 9 中第三个参数提供的访问控制定义来指定授权(或访问控制)决策。第三个参数是 objectDefinitionSource。

在清单 10 中,accessDecisionManager bean 是 org.acegisecurity.vote.AffirmativeBased 类的实例。accessDecisionManager bean 只包含一个参数,即投票者(voter)列表。

在 Acegi 中,投票者确定是否允许某个用户访问特定的资源。当使用 accessDecisionManager 查询时,投票者具有三个选项:允许访问(access-granted)、拒绝访问(access-denied),如果不确定的话则放弃投票(abstain from voting)。

不同类型的访问决策管理器解释投票者决策的方法也有所不同。清单 10 所示的 AffirmativeBased 访问决策管理器实现了简单的决策逻辑:如果任何投票者强制执行肯定投票,将允许用户访问所请求的资源。


应用 Acegi 保护 Java 应用程序: 续二
应用 Acegi 保护 Java 应用程序: 续二
回页首

结束语

在本文中,您了解了如何将用户和业务角色信息托管在 LDAP 目录中。您还详细了解了配置 Acegi 的方法,从而与 LDAP 目录交互实现访问控制策略。在本系列最后一期文章中,我将展示如何配置 Acegi 来保护对 Java 类的访问。

?

?

?

实例程序见附件

?

?

?

?

未完待续!

?

?

?

?

?

?

读书人网 >软件架构设计

热点推荐