如何将 JAAS 授权检查委托给 Shiro?
我正在开发一个服务器端应用程序,需要基于对象的身份验证和授权。我喜欢 Shiro 的简单性,但为了与 JAAS 兼容,我编写了一个使用 Apache Shiro 作为底层机制的 LoginModule。
但我的问题是我找不到将 JAAS 授权检查委托给 Shiro 的方法。我怎样才能实现这个目标?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
注意:答案解决了外部授权系统通过标准安全框架与 JVM 集成的一般情况。它不是 Shiro 或 JMX 特定的,因为我对两者都不熟悉。
从概念上讲,您似乎正在追求策略决策点 (PDP),即评估授权查询(“实体 X 是否允许执行 Y?”)的设施。 JDK 提供了其中的几个:
SecurityManager
,特别是它的checkXXX
方法组。ProtectionDomain
类,特别是它的implies(Permission)
方法。政策
。隐含
方法CodeSource
,PermissionCollection
,权限
,以及校长
。任何上述方法都可以被重写,以便以递增的粒度定制概念性PDP的功能。应该指出的是,JAAS 并没有真正带来自己的 PDP(与它的名字所暗示的相反);相反,它提供了手段除了代码来源的原始信任因素之外,域和策略还支持基于主体的查询。因此,在我看来,您对保持“JAAS 兼容”的要求基本上转化为想要使用(原始加 JAAS)Java SE 授权模型,又名沙箱,我怀疑它是你想要什么。当标准模型被认为级别太低和/或性能密集时,往往会采用 Shiro 等框架;换句话说,当授权逻辑不需要评估给定一组信任因素的每个堆栈帧时,因为这些因素通常是上下文不敏感的。根据我的假设的有效性,需要检查三种主要情况:
AccessControlContext
无关。 Shiro 原生授权属性 (SNAA),无论它们是什么,都适用于整个线程。代码来源无关紧要。AccessControlContext
。AccessControlContext
-依赖。1. 仅基于 SNAA 的授权
按照您认为合适的方式管理身份验证。如果您希望继续使用 JAAS 的
javax.security.auth
SPI 进行身份验证,请忘记建立标准Subject
作为身份验证结果,而是直接绑定 Shiro 特定的结果到线程本地存储。通过这种方式,您可以更方便地访问 SNAA,并避免使用AccessControlContext
(并遭受潜在的 性能损失),用于检索。子类
SecurityManager
,至少重写两个checkPermission
方法,以便它们Permission
参数转换为 Shiro 的 PDP (SPDP) 可以理解的内容SecurityException
)。安全上下文接收重载可能会简单地忽略相应的参数。在应用程序初始化时,实例化并安装 (
System::setSecurityManager
) 您的实现。2. 混合授权,将代码源与上下文不敏感的 SNAA 相结合
Subject
与线程本身关联起来。SecurityManager
,至少重写两个checkPermission
方法,这一次它们委托给 SPDP 和/或重写的实现(进而调用checkPermission
,相应地,当前或提供的访问控制上下文)。对于任何给定的许可,应该咨询哪些(哪些)以及以什么顺序当然取决于实现。当两者都被调用时,应该首先查询 SPDP,因为它可能比访问控制上下文响应得更快。Policy
,实现implies(ProtectionDomain, Permission )
这样,就像上面的SecurityManager::checkPermission
一样,它传递一些可理解的域表示(通常只有它的CodeSource
)和权限参数 - 但逻辑上不是 SNAA - 是 SPDP。该实现应该尽可能高效,因为它将在checkPermission
时针对每个域每个访问控制上下文调用一次。实例化并安装 (Policy::setPolicy
) 您的实现。3. 混合授权,将代码来源与 SNAA 相结合,两者都是上下文相关的
按照您认为合适的方式管理身份验证。不幸的是,主题处理部分并不像在本例中创建 ThreadLocal 那样微不足道。
子类化、实例化并安装一个
Policy
,该策略分别执行SecurityManager::checkPermission
和Policy::implies
的组合职责第二种情况描述。实例化并安装标准的
SecurityManager
。创建一个
ProtectionDomain
子类,能够存储和公开 SNAA。作者1 a
DomainCombiner
由 SNAA 构建;
实现
combine(ProtectionDomain[], ProtectionDomain[])
,使得像
Policy::implies
一样,实现应该是高效的(例如通过消除重复项),因为每次getContext
和checkPermission<时都会调用它/code>
AccessController
方法是。身份验证成功后,创建一个新的
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:
SecurityManager
, specifically itscheckXXX
group of methods.ProtectionDomain
class, particularly itsimplies(Permission)
method.implies(ProtectionDomain, Permission)
method of the effectivePolicy
.implies
methods ofCodeSource
,PermissionCollection
,Permission
, andPrincipal
.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:
AccessControlContext
-independent. Shiro-native authorization attributes (SNAAs), whatever they are, apply to the entire thread. Code origin is irrelevant.AccessControlContext
-independent.AccessControlContext
-dependent.1. Authorization based solely on SNAAs
Manage authentication however you see fit. If you wish to continue using JAAS'
javax.security.auth
SPI for authentication, forget about establishing a standardSubject
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 useAccessControlContext
(and suffer the potential performance penalty), for their retrieval.Subclass
SecurityManager
, overriding at least the twocheckPermission
methods such that theyPermission
argument into something Shiro's PDP (SPDP) understands, prior toSecurityException
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
Subject
with the thread itself.SecurityManager
, overriding at least the twocheckPermission
methods, this time around such that they delegate to both the SPDP and/or the overridden implementation (which in turn callscheckPermission
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.Policy
, implementingimplies(ProtectionDomain, Permission)
such that, likeSecurityManager::checkPermission
above, it passes some intelligible representation of the domain (typically only itsCodeSource
) 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 atcheckPermission
time. Instantiate and install (Policy::setPolicy
) your implementation.3. Hybrid authorization, combining code origin with SNAAs, both context-sensitive
Manage authentication however you see fit. Unfortunately the subject handling part is not as trivial as creating a
ThreadLocal
in this case.Subclass, instantiate, and install a
Policy
that performs the combined duties ofSecurityManager::checkPermission
andPolicy::implies
, as individually described in the second case.Instantiate and install a standard
SecurityManager
.Create a
ProtectionDomain
subclass, capable of storing and exposing the SNAAs.Author1 a
DomainCombiner
thatis constructed with the SNAAs;
implements
combine(ProtectionDomain[], ProtectionDomain[])
such thatLike
Policy::implies
, the implementation should be efficient (e.g. by eliminating duplicates), as it will be invoked every time thegetContext
andcheckPermission
AccessController
methods are.Upon successful authentication, create a new
AccessControlContext
that wraps the current one, along with an instance of the customDomainCombiner
, in turn wrapping the SNAAs. Wrap code to be executed beyondthat 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
Principal
s and, using the standardSubjectDomainCombiner
, binding them to the currentAccessControlContext
's domains (as above, or simply viaSubject::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.