将 Java 个 EE 应用程序迁移到 LDAP

migrate Java EE Application to LDAP

我对 LDAP (ActiveDirectory) 和现有 Java EE 应用程序有一些疑问。

在我们的 Java EE 应用程序中,我们混合了权限处理。所以有时我们问 isUserInRole("rolename") 有时我们问 hasUserPermission("permission).

现在,我们想将这个现有应用程序绑定到 LDAP,但我不知道 LDAP 是如何工作的;-) 所以我有几个问题:

  1. LDAP 只能与组一起使用,还是也可以与权限一起使用?
  2. 我在哪里存储权限?在 LDAP 或我的应用程序数据库中
  3. 组和权限之间的映射在哪里? (ldap 或应用程序)
  4. 在我的 Java EE 应用程序中使用 LDAP 时是否需要使用 JAAS?

我希望你能帮助我解决这些希望简单的问题!

注意:下面使用术语 LDAP 时,实际上是 LDAP 兼容的目录服务被引用。

1. How should a JEE app restrict users for doing some things with the help of a LDAP?

JavaEE 安全模型在授权方面仍然(主要)基于角色(不要与 RBAC 混淆);在一天结束时,运行时仍将根据用户的应用程序级角色授权您的用户(通常是调用者,而不管哪里( LDAP、关系数据库、SAML IdP、XML 文件等)和 how(即 SQL 类型、LDAP 属性类型等)这些是坚持。事实上,一些应用程序可能根本不在外部存储调用者的角色成员资格,而是在身份验证期间根据各自调用者的其他属性计算它们;作为一个人为的例子,身份验证机制可能 "see" 调用者 uid=jdoe, dc=users, dc=some, dc=org 有一个 hireDate 属性,该属性指的是过去 3 年以上的日期,以及 jobTitle 开发人员的属性,从而推断jdoe高级开发人员,将其分配为实际角色。

2. Where do I store the permissions? in LDAP or in my application database?
3. where do i the mapping between groups and permissions? (ldap or application)

首先,您的 权限 概念不适合 Java EE 安全模型,因此我的建议是完全放弃权限并直接使用相应的角色。这样做的好处应该是显而易见的:您可以从程序化授权转变为纯声明式授权,因为运行时现在可以为您处理所有授权检查。请注意,您绝不会被强制认为角色仅等同于 user groups;虽然它们确实可以表达像 "editor" 和 "can-view-stats-panel" 这样粗粒度的东西,但它们也可以表达像 "can-access-method-void-getBonus(BigDecimal)-of-instance-123-of-EJB-BonusGranter-with-arg-not-greater-than-100$-during-working-hours-every-13th-of-every-January-between-08:00:10Z-and-08:01:09Z-if-hardworking-and-weather's-sunny-and-manager's-in-a-good-mood" 这样细粒度的东西(你显然必须想出一个好的约定能够简洁直观地表达所有内容,但您明白了)。

还有一个名为 JACC 的规范,您的 Java EE 产品可能支持也可能不支持。如果您 绝对 需要比角色所能提供的更大的灵活性,理论上您可以利用它,因为它本质上允许您使用 Java SE Policy为了确定——在 Principal 分配的低级别的基础上,看似无限灵活的 java.security.Permissions——调用者是否确实有一个角色。无论如何,目标保持不变:将与授权相关的代码与业务逻辑分离。

至于你实际的两个问题——这不仅适用于你的权限(如果你想保留它们),而且适用于你的大部分持久数据——我简单的回答是,如果数据其他应用程序需要(或在可预见的将来依赖它的可能性很高),并且它 可以 "fit" 进入目录信息树(不一定这种情况),那么它可能存储在 LDAP 中。否则,应将其存储 "closer" 到应用程序,例如按照您的建议,在应用程序的 "dedicated" 数据库中。还要记住,至少在传统上,LDAP 被认为是存储低 读写比 数据的存储库的不佳选择。我不知道性能考虑在多大程度上(如果有的话)目前仍然有效,但我仍然不会使用 LDAP 来持久化高度动态的数据,例如 Web 服务的响应时间或可用性百分比。

4. Do I need to use JAAS when using LDAP with my Java EE Application?

你这样做并且应该 必须(直接)依赖 JAAS 在 Java EE 中进行身份验证或授权。这个问题在其他地方已经有广泛的讨论,因此我不会在这里详细说明。如前所述,为了利用容器管理的授权,您仍然必须使用容器管理的身份验证,其主要目的是建立身份(callergroup(角色)Principals) 您的调用者与运行时。现在,理想情况下,您只需声明如下内容

<login-config>
    <auth-method>FORM</auth-method>
    <LDAP-identity-store>
        <base-DN>dc=users, dc=some, dc=org</base-DN>
        <bind-DN>uid=admin</bind-DN>
        <bind-credential>
            <credential-alias ref="admin_LDAP_pass"/>
        </bind-credential>
        <base-search-DN>dc=users, dc=some, dc=org</base-search-DN>
        <search-filter>(uid={username_HTTP_param})</search-filter>
    </LDAP-identity-store>
</login-config>

在您的 web.xml 中,身份验证 有效。不幸的是,Java EE 的情况并非如此(至少从版本 7 开始,因为该领域的一些很有希望的变化预计将包含在该平台的下一个版本中)。假设您仍然想使用容器管理的身份验证,您有两个选择:

a) 使用 JASPIC 编写可移植的身份验证机制。您的 javax.security.auth.message.module.ServerAuthModule 基本上是:

  1. 连接到 LDAP 并验证您的呼叫者(即其形式-POSTed 用户名),如果成功,
  2. 检索(and/or 计算)呼叫者的角色(此时称为 ),
  3. 实例化经过身份验证的调用者的 Principal 表示,
  4. 实例化一个 String[] of group names(运行时将构建相应的 group Principal s), 最后
  5. 通过特定于 JASPIC 的 javax.security.Callbacks 将前两个步骤的结果传达给运行时。

优点:支持所有完整 Java EE 配置文件实现以及 Jetty 和 Tomcat(自 9.0.0.M4 起)。
缺点:需要一些努力,并不总是得到最佳支持。

b) 编写供应商特定的身份验证扩展,基于 JAAS 或其他方式,基本上完成相同的步骤,尽管是通过专有 API。

优点:通常需要编写零新代码(当然还有更少的样板文件)。
缺点:不可移植的方法。


延伸阅读: