如何将 JAAS 授权检查委托给 Shiro?

发布于 2024-11-02 10:26:02 字数 164 浏览 1 评论 0 原文

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

但我的问题是我找不到将 JAAS 授权检查委托给 Shiro 的方法。我怎样才能实现这个目标?

I'm developing a server-side application that needs authentication and authorization based on objects. I like Shiro's simplicity, but for being compatible with JAAS, I wrote a LoginModule that uses Apache Shiro as the underlying mechanism.

But my problem is that I couldn't find a way to delegate JAAS authorization checks to Shiro. How can I achieve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

对不⑦ 2024-11-09 10:26:02

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


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

  1. 有效的 SecurityManager,特别是它的 checkXXX 方法组。
  2. ProtectionDomain 类,特别是它的 implies(Permission) 方法。
  3. 有效implies(ProtectionDomain, Permission)方法rel="nofollow noreferrer">政策
  4. 其次,隐含方法CodeSourcePermissionCollection, 权限,以及校长

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

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

1. 仅基于 SNAA 的授权

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

  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,相应地,当前或提供的访问控制上下文)。对于任何给定的许可,应该咨询哪些(哪些)以及以什么顺序当然取决于实现。当两者都被调用时,应该首先查询 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. 作者1 a DomainCombiner

    1. 由 SNAA 构建;

    2. 实现combine(ProtectionDomain[], ProtectionDomain[]),使得

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

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


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


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

Note: The answer addresses the general case where an external authorization system is to be integrated with the JVM, by means of the standard security framework. It is not Shiro- or JMX-specific, as I am familiar with neither.


Conceptually, it appears that you are after the policy decision point (PDP) -- the facility where authorization queries ("is entity X allowed to do Y?") are evaluated, that is. The JDK offers several of these:

  1. The effective SecurityManager, specifically its checkXXX group of methods.
  2. The ProtectionDomain class, particularly its implies(Permission) method.
  3. The key implies(ProtectionDomain, Permission) method of the effective Policy.
  4. Secondarily, the implies methods of CodeSource, PermissionCollection, Permission, and Principal.

Any of the aforementioned methods may be overridden in order to customize, at ascending granularity, the functionality of the conceptual PDP. It should be noted that JAAS did (contrary to what its name suggests) not really bring its own PDP along; rather, it provided the means for the domain and policy to support principal-based queries, in addition to the original trust factor of code origin. Hence, to my eye, your requirement of remaining "JAAS-compatible" basically translates to wanting to use the (original-plus-JAAS) Java SE authorization model, a.k.a. the sandbox, which I doubt to be what you desire. Frameworks such as Shiro tend to be employed when the standard model is deemed either too low-level and/or performance-intensive; in other words, when authorization logic need not evaluate every single stack frame for a given set of trust factors, due to those factors being more frequently context-insensitive than not. Depending on the validity of my assumption, three main cases arise for examination:

  1. Authorization is AccessControlContext-independent. Shiro-native authorization attributes (SNAAs), whatever they are, apply to the entire thread. Code origin is irrelevant.
  2. Code origin matters, mandating use of the sandbox. SNAAs are still AccessControlContext-independent.
  3. Code origin and SNAAs are both relevant and AccessControlContext-dependent.

1. Authorization based solely on SNAAs

  1. Manage authentication however you see fit. If you wish to continue using JAAS' javax.security.auth SPI for authentication, forget about establishing a standard Subject as the authentication outcome, instead directly tying the Shiro-specific one to thread-local storage. This way you get more convenient access to the SNAAs, and avoid having to use AccessControlContext (and suffer the potential performance penalty), for their retrieval.

  2. Subclass SecurityManager, overriding at least the two checkPermission methods such that they

    1. translate, if necessary, the Permission argument into something Shiro's PDP (SPDP) understands, prior to
    2. delegating to the SPDP with the thread-local SNAAs and permission (and throwing a SecurityException should the SPDP signal access denial).

    The security context-receiving overload may simply disregard the corresponding argument. At application initialization time, instantiate and install (System::setSecurityManager) your implementation.


2. Hybrid authorization, combining code origin with context-insensitive SNAAs

  1. Manage authentication however you see fit; once again associate the Shiro-specific Subject with the thread itself.
  2. Subclass SecurityManager, overriding at least the two checkPermission methods, this time around such that they delegate to both the SPDP and/or the overridden implementation (which in turn calls checkPermission on, accordingly, the current or supplied access control context). Which one(s) and in what order should be consulted for any given permission is of course implementation-dependent. When both are to be invoked, the SPDP should be queried first, since it will likely respond faster than the access control context.
  3. If the SPDP is to additionally handle evaluation of permissions granted to code originating from a certain location and/or set of code signers, you will also have to subclass Policy, implementing implies(ProtectionDomain, Permission) such that, like SecurityManager::checkPermission above, it passes some intelligible representation of the domain (typically only its CodeSource) and permission arguments -- but logically not the SNAAs -- to the SPDP. The implementation should be efficient to the extent possible, since it will be invoked once per domain per access control context at checkPermission time. Instantiate and install (Policy::setPolicy) your implementation.

3. Hybrid authorization, combining code origin with SNAAs, both context-sensitive

  1. Manage authentication however you see fit. Unfortunately the subject handling part is not as trivial as creating a ThreadLocal in this case.

  2. Subclass, instantiate, and install a Policy that performs the combined duties of SecurityManager::checkPermission and Policy::implies, as individually described in the second case.

  3. Instantiate and install a standard SecurityManager.

  4. Create a ProtectionDomain subclass, capable of storing and exposing the SNAAs.

  5. Author1 a DomainCombiner that

    1. is constructed with the SNAAs;

    2. implements combine(ProtectionDomain[], ProtectionDomain[]) such that

      1. it replaces the first (the "current" context) array argument's domains with equivalent instances of the custom implementation;
      2. then appends the second (the "assigned" or "inherited" context) argument's ones, if any, to the former as-is; and lastly
      3. returns the concatenation.

    Like Policy::implies, the implementation should be efficient (e.g. by eliminating duplicates), as it will be invoked every time the getContext and checkPermission AccessController methods are.

  6. Upon successful authentication, create a new AccessControlContext that wraps the current one, along with an instance of the custom DomainCombiner, in turn wrapping the SNAAs. Wrap code to be executed beyond
    that point "within" an AccessController::doPrivilegedWithCombiner invocation, also passing along the replacement access control context.


1    Instead of using custom domains and your own combiner implementation, there is also the seemingly simpler alternative of translating the SNAAs into Principals and, using the standard SubjectDomainCombiner, binding them to the current AccessControlContext's domains (as above, or simply via Subject::doAs). Whether this approach reduces the policy's efficiency depends primarily on the call stack's depth (how many distinct domains the access control context comprises). Eventually the caching optimizations you thought you could avoid implementing as part of the domain combiner will hit you back when authoring the policy, so this is essentially a design decision you will have to make at that point.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文