14.5. 关于 Java 认证和授权服务(JAAS)

JBoss EAP 6 的安全性架构由安全性配置子系统、包含在几个配置文件里的应用程序专有的安全性配置以及实现为 MBean 的 JAAS 安全性管理者组成。
与、服务器组和服务器专有的配置

服务器组(受管域里)和服务器(独立服务器里)包含了安全域的配置。安全域包括合并验证、授权、映射和审计模块的信息以及配置细节。应用程序在 jboss-web.xml 里通过名字指定它需要哪个安全域。

应用程序专有的配置

应用程序专有的配置出现在一个或多个下列的四个文件里。

表 14.1. 应用程序专有的配置文件

文件 描述
ejb-jar.xml
EJB 应用程序的部署描述符位于 META-INF 目录。请使用 ejb-jar.xml 来指定角色并映射到应用程序级别的 principal 上。你也可以将特定的方法和类限制到某些角色。这也可以用于其他和安全性无关的 EJB 专有的配置。
web.xml
Java EE web 应用程序的部署描述符。请使用 web.xml 来声明应用程序用于验证和授权的安全域,以及资源和传输约束,如限制允许哪种类型的 HTTP 请求。你也可以在这个文件里配置简单的基于 web 的验证。它也可以用于和安全性无关的其他应用程序专有的配置。
jboss-ejb3.xml
包含对 ejb-jar.xml 描述符的 JBoss 专有的扩展内容。
jboss-web.xml
包含对 web.xml 描述符的 JBoss 专有的扩展内容。

注意

ejb-jar.xmlweb.xml 是在 Java EE 规格里定义的。jboss-ejb3.xml 提供了对 ejb-jar.xml 的 JBoss 专有的扩展,而 jboss-web.xml 提供了对 web.xml 的 JBoss 专有的扩展。
JAAS 安全性管理者 MBean

Java 验证和授权服务(Java Authentication and Authorization Service,JAAS)是一个 Java 应用程序里用户级别安全性的框架,它使用可插拔的验证模块(Pluggable Authentication Module,PAM)。它被集成到 Java Runtime Environment(JRE)里。在 JBoss EAP 里,容器端的组件是 org.jboss.security.plugins.JaasSecurityManager MBean。它提供了对 AuthenticationManagerRealmMapping 接口的默认实现。

JaasSecurityManager MBean 根据 EJB 或 web 部署描述符文件里指定的安全域集成到 EJB 和 web 容器层里。当部署一个应用程序时,容器将部署描述符里指定的安全域和容器的安全性管理者实例相关联。按照服务器组或独立服务器上所配置的,安全性管理者将执行安全域的配置。
在客户和容器间使用 JAAS 的交互流程

JaasSecurityManager 使用 JAAS 软件包来实现 AuthenticationManager 和RealmMapping 接口行为。特别是,它的行为源于 JaasSecurityManager 已经分配的安全域里配置的登录模块实例的执行。登录模块实现了安全域的 principal 验证和角色映射行为。通过插入域的不同的登录模块配置,你可以在不同的安全域里使用 JaasSecurityManager。

为了说明 JaasSecurityManager 是如何使用 JAAS 验证过程的,下面的步骤概述了实现了 EJBHome 方法的客户端方法调用。EJB 已经部署在服务器里,它的 EJBHome 接口方法已经使用 ejb-jar.xml 里的 <method-permission> 元素进行了保护。它使用 jboss-ejb3.xml 里的 <security-domain> 元素指定的 jwdomain 安全域。下面的图表展示了这些步骤,我们在后面将进行解释。
EJB 的验证步骤

图 14.1. 安全的 EJB 方法调用的步骤

  1. 客户端执行了一个 JAAS 登录来建立用于验证的 principal 和凭证。这在图表里被标注为 Client Side Login。它也可以通过 JNDI 来执行。
    要执行 JAAS 登录,你可以创建一个 LoginContext 实例并传入要使用的配置的名称。在这里,配置的名称是 other。这个一次性的登录将登录 principal 以及凭证和随后的所有 EJB 调用相关联。这个过程并不需要验证用户。客户端登录的性质取决于客户使用的登录模块配置。在这个例子里,other 客户端登录配置条目使用了 ClientLoginModule 登录模块。这个模块绑定用户名和密码到 EJB 调用层以供服务器上之后的验证。客户端标识符不在客户端进行验证。
  2. 客户端包含 EJBHome 方法并在服务器上调用它。这个调用包含客户端传入的方法参数,以及来自客户端 JAAS 登录的用户标识符和凭证。
  3. 在服务器上,安全性拦截器验证调用方法的用户。这涉及了另外一个 JAAS 登录。
  4. 安全域确定了登录模块的选择。安全域的名字作为登录配置条目名称被传入 LoginContext 构造器。EJB 安全域是 jwdomain。如果 JAAS 验证成功,JAAS 主题将被创建。JAAS 主题将包括一个 PrincipalSet,它有如下内容:
    • 一个 java.security.Principal 实例,它对应部署安全环境的客户端标识符。
    • 名为 Rolesjava.security.acl.Group,它包含用户应用程序域的角色名称。类型为 org.jboss.security.SimplePrincipal 的对象代表角色名称。这些对象按照 ejb-jar.xml 里的约束和 EJBContext.isCallerInRole(String) 方法实现检验对 EJB 方法的访问。
    • 名为 CallerPrincipal 的可选 java.security.acl.Group,它包含一个对应应用程序域的调用者的标识符的 org.jboss.security.SimplePrincipal。CallerPrincipal 组成员是 EJBContext.getCallerPrincipal() 方法返回的值。这个映射允许可操作安全环境里的 Principal 映射到应用程序已知的 Principal。在缺乏 CallerPrincipal 映射的情况下,可操作的 principal 和应用程序域 principal 是相同的。
  5. 服务器检验调用 EJB 方法的用户是否具有权限。执行这个授权涉及两个步骤:
    • 获取被允许从 EJB 容器访问 EJB 方法的角色的名称。这些角色名称由 ejb-jar.xml 的 <role-name> 元素和包含被调用方法的 <method-permission> 元素来确定。
    • 如果没有分配角色,或者方法是在一个 exclude-list 元素里指定的,那对这个方法的访问将被拒绝。否则,安全性拦截器将在安全管理者上调用 doesUserHaveRole 方法以检查调用者是否具有分配的角色名称。这个方法迭代角色名称并检查已验证的用户的 Subject Roles 组是否包含具有分配的角色名称的 SimplePrincipal。如果任何角色名称是 Roles 组的成员,访问将被允许。而如果任何一个角色名称都不是成员,访问将被拒绝。
    • 如果 EJB 使用一个自定义的安全代理,那这个方法调用将被委托给这个代理。如果安全大力拒绝了对调用者的访问,它将抛出 java.lang.SecurityException。否则,对 EJB 方法的访问将被允许,且方法调用将传递给下一个容器拦截器。SecurityProxyInterceptor 处理这个检查且这个拦截器没有被显示。
    • 对于 web 连接请求,web 服务器将检查匹配请求的资源和被访问的 HTTP 方法的、 web.xml 里定义的安全性约束。
      如果存在对于这个请求的约束,web 服务器将调用 JaasSecurityManager 来执行 principal 验证,从而确保用户角色和 principal 对象相关联。