【问题标题】:How can I delegate JAAS authorization checks to Shiro?如何将 JAAS 授权检查委托给 Shiro?
【发布时间】:2011-08-09 19:33:21
【问题描述】:

我正在开发一个需要基于对象进行身份验证和授权的服务器端应用程序。我喜欢 Shiro 的简单,但是为了兼容 JAAS,我写了一个 LoginModule,它使用 Apache Shiro 作为底层机制。

但我的问题是我找不到将 JAAS 授权检查委托给 Shiro 的方法。我怎样才能做到这一点?

【问题讨论】:

  • Deniz,您是否找到了将 Shiro 与 JAAS 结合使用的方法?如果没有,你采取了什么方法?谢谢,凯文
  • 我主要关心的是使用 Shiro 来实现 JMX 安全,它使用 JAAS 作为主要的安全方法。我通过实现一个 JMXAuthenticator 解决了这个问题,它在当前访问控制上下文中创建一个可变的 JAAS 主题并将 Shiro 主题存储在 JAAS 主题的私有凭据集中。后来,我实现了一个 LoginModule,它实际上是 Shiro 的 Authenticator 接口(由 SecurityManagers 扩展)的包装器。
  • 或许您可以提供更多关于问题所在的详细信息,包括 LoginModule 的代码、遇到的错误以及运行时配置。

标签: java authorization authentication jaas shiro


【解决方案1】:

注意:答案解决了通过标准安全框架将外部授权系统与 JVM 集成的一般情况。它不是 Shiro 或 JMX 特定的,因为我都不熟悉。


从概念上讲,您似乎是在策略决策点 (PDP) 之后——即评估授权查询(“实体 X 是否允许执行 Y?”)的设施。 JDK 提供了其中的几个:

  1. 有效的SecurityManager,特别是它的checkXXX 方法组。
  2. ProtectionDomain 类,尤其是它的 implies(Permission) 方法。
  3. 有效Policy的关键implies(ProtectionDomain, Permission)方法。
  4. 其次是CodeSourcePermissionCollectionPermissionPrincipalimplies方法。

可以覆盖上述任何方法,以便以递增的粒度自定义概念 PDP 的功能。应该指出的是,JAAS 确实(与其名称所暗示的相反)并没有真正带来自己的 PDP。相反,它为域和策略提供了means,以支持基于主体的查询,以及代码来源的原始信任因素。因此,在我看来,您对保持“与 JAAS 兼容”的要求基本上转化为想要使用(原始加 JAAS)Java SE 授权模型,也就是我怀疑的 the 沙箱你想要什么。当标准模型被认为太低级和/或性能密集时,往往会使用 Shiro 等框架;换句话说,当授权逻辑不需要为给定的一组信任因素评估每个堆栈帧时,因为这些因素更频繁地是上下文不敏感的。根据我的假设的有效性,需要检查三个主要案例:

  1. 授权独立于AccessControlContext。 Shiro-native 授权属性 (SNAA),无论它们是什么,都适用于整个线程。代码来源无关紧要。
  2. 代码来源很重要,强制使用沙箱。 SNAA 仍然是 AccessControlContext-independent。
  3. 代码来源和 SNAA 都是相关的并且AccessControlContext-依赖

1。仅基于 SNAA 的授权

  1. 以您认为合适的方式管理身份验证。如果您希望继续使用 JAAS 的 javax.security.auth SPI 进行身份验证,请忘记建立标准 Subject 作为身份验证结果,而是直接将 Shiro 特定的一个绑定到线程本地存储。通过这种方式,您可以更方便地访问 SNAA,并避免使用AccessControlContext(并承受潜在的performance penalty)来检索它们。

  2. 子类 SecurityManager,至少覆盖两个 checkPermission 方法,以便它们

    1. 如有必要,将 Permission 参数翻译成 Shiro 的 PDP (SPDP) 可以理解的内容,然后
    2. 使用线程本地 SNAA 和权限委派给 SPDP(如果 SPDP 发出拒绝访问信号,则抛出 SecurityException)。

    安全上下文接收重载可以简单地忽略相应的参数。在应用程序初始化时,实例化并安装 (System::setSecurityManager) 您的实现。


2。混合授权,将代码源与上下文不敏感的 SNAA 相结合

  1. 以您认为合适的方式管理身份验证;再次将 Shiro 特定的 Subject 与线程本身相关联。
  2. 子类SecurityManager,至少重写两个checkPermission 方法,这一次它们委托给SPDP 和/或重写的实现(反过来调用checkPermission,相应地,当前或提供的访问控制上下文)。对于任何给定的权限,应该咨询哪个(s)和以什么顺序咨询当然取决于实现。当两者都被调用时,应首先查询 SPDP,因为它的响应速度可能比访问控制上下文快。
  3. 如果 SPDP 要额外处理授予来自某个位置和/或一组代码签名者的代码的权限评估,您还必须继承 Policy,实现 implies(ProtectionDomain, Permission),例如 SecurityManager::checkPermission上面,它将域的一些可理解的表示(通常只有其CodeSource)和权限参数 - 但逻辑上不是 SNAA - 传递给 SPDP。该实现应尽可能高效,因为它将在checkPermission 时间每个访问控制上下文的每个域调用一次。实例化并安装 (Policy::setPolicy) 您的实现。

3。混合授权,将代码源与 SNAA 相结合,两者都是上下文相关的

  1. 以您认为合适的方式管理身份验证。不幸的是,在这种情况下,主题处理部分并不像创建 ThreadLocal 那样简单。

  2. 子类化、实例化并安装一个Policy,它执行SecurityManager::checkPermissionPolicy::implies 的组合职责,如第二种情况中单独描述的那样。

  3. 实例化并安装一个标准的SecurityManager

  4. 创建一个ProtectionDomain 子类,能够存储和公开SNAA。

  5. 作者1DomainCombiner

    1. 由 SNAA 构建;

    2. 实现combine(ProtectionDomain[], ProtectionDomain[]) 这样

      1. 它将第一个(“当前”上下文)数组参数的域替换为自定义实现的等效实例;
      2. 然后将第二个(“分配的”或“继承的”上下文)参数的参数(如果有)按原样附加到前者;最后
      3. 返回串联。

    Policy::implies 一样,实现应该是高效的(例如通过消除重复项),因为每次getContextcheckPermission AccessController 方法时都会调用它。

  6. 身份验证成功后,创建一个新的AccessControlContext 来包装当前的,以及自定义DomainCombiner 的实例,依次包装SNAA。包装要执行的代码 该点“在”AccessController::doPrivilegedWithCombiner 调用中,也传递了替换访问控制上下文。


1    除了使用自定义域和您自己的组合器实现之外,还有一种看似更简单的替代方法,将 SNAA 转换为 Principals,并使用标准 SubjectDomainCombiner,将它们绑定到当前的 @987654380 @ 的域(如上,或简单地通过Subject::doAs)。这种方法是否会降低策略的效率主要取决于调用堆栈的深度(访问控制上下文包含多少不同的域)。最终,您认为可以避免作为域组合器的一部分实施的缓存优化会在编写策略时对您产生反作用,因此这本质上是您必须在那时做出的设计决策。

【讨论】:

  • 虽然我在 6 年前找到了解决方案并回答了我自己的问题,但您在这里为所有偶然发现这个问题的人提供的有用信息量绝对值得被接受。
猜你喜欢
  • 2016-07-07
  • 2018-03-22
  • 1970-01-01
  • 2011-12-06
  • 2012-03-22
  • 1970-01-01
  • 2015-05-09
  • 2021-07-30
  • 2014-07-26
相关资源
最近更新 更多