在容器请求 LDAP 用户角色的过程中挂钩
在我的应用程序中,我使用基于表单的身份验证和 LDAP-Realm.对于授权,我使用数据库.据我了解,它的工作原理如下
In my application I use form-based authentication with a LDAP-Realm. For Authorization I use a database. As I understand this works as follows
App --> (user, pass) --> LDAP
<-- OK, user exists --
--> ask for security roles for 'user' --> JACC / Database
<-- Administrator --
我可以挂钩到我的应用程序调用 ask for security roles for 'user'
的过程吗?
Can I hook into the process where my application calls ask for security roles for 'user'
?
背景:
LDAP 说:好的,用户"已通过身份验证
数据库:给我所有用户名=用户的角色
并且现在我想自定义数据库查询:给我所有用户名 = 'user' 的角色以及更多属性
And now I want to customize the Database query: give me all roles where username = 'user' AND some more attributes
这有可能吗?
推荐答案
TL;DR: 看看 这个和那个 用于示例解决方案.
TL;DR: Have a look at this and that for a sample solution.
您的要求取决于您使用的供应商特定功能提供的灵活性程度;您的产品可能允许也可能不允许您扩展该/这些 LoginModule
/Realm
/IdentityStore
/whatever-it's/they's 的行为-称为专有类,或者甚至可能只是在某些管理 UI 的输入字段中键入 SQL 查询.底线是它是非标准功能.
What you ask for depends on the degree of flexibility offered by the vendor-specific feature you use; your product may or may not allow you to extend the behaviour of that/these LoginModule
/ Realm
/ IdentityStore
/ whatever-it's/they're-called proprietary class(es), or maybe even to just type an SQL query into some administrative UI's input field. The bottom line is that it's non-standard functionality.
在标准的 Java EE 方面,有 JASPIC(用户/消息身份验证)和 JACC(授权)SPI.两者都可用于从某些外部存储中检索与您的用户有关的安全相关信息.JASPIC 不能做的是在认证之后改变用户的角色;也就是说,在经过身份验证的请求 1期间,用户的角色是固定的.JASPIC 也不能将含义附加到这些角色上;因为它们只是简单的 String
,AS 将以某种专有方式从中派生组 Principal
.另一方面,JACC 可以做这些事情,因为它建立了一个规则库"(想想 Policy
) 精确关联角色、主体和 Permission
s 并且可以在每次用户-系统交互时查询.JACC 还可以覆盖或更改通过部署描述符和注释表达的 Java EE 安全约束的解释.
On the standard Java EE side of the spectrum there are the JASPIC (user / message authentication) and JACC (authorization) SPIs. Both can be used to retrieve security-related information pertaining to your users from some external store. What JASPIC cannot do is change a user's roles after authentication; that is, for the duration of an authenticated request 1 the user's roles are fixed. JASPIC can also not attach meaning to those roles; for it they're just plain String
s that the AS will in some proprietary manner derive group Principal
s from. JACC, on the other hand can do those things, as it establishes a "rulebase" (think Policy
) which precisely associates roles, principals and Permission
s and can be queried on each and every user-system interaction. JACC can also override or alter the interpretation of the Java EE security constraints expressed via deployment descriptors and annotations.
我将在这篇文章中包含一个基于 JASPIC 的解决方案,并在很大程度上忽略 JACC,因为:
I will include a JASPIC-based solution in this post and disregard JACC for the most part, because:
- 您可能不需要 JACC 提供的额外灵活性.
- 使用自定义 JACC 提供程序解决方案需要 相当 有点 工作 并且还在由于特定于 AS 的组到角色的映射,并非 100% 标准.
- 我不知道有一个开源项目使用自定义 JACC 提供程序来完成一些有意义的事情;Java EE Full Profile-implementing AS 是唯一的例外,因为他们被要求实施规范,有时也在内部使用他们的 JACC 提供程序(例如在 GlassFish 的情况下).
- 关于 JASPIC 仍然存在很多混淆(许多开发人员甚至不知道它的存在),它是两个规范中最简单的一个.在继续报道 JACC 之前,首先让 JASPIC 为更多人所知并平易近人"是合理的.
- 虽然现在 JASPIC 在线上有很多很好的示例,通过 JASPIC 提供程序实现实际身份验证的项目也是如此,-如果我弄错了,请纠正我-我还没有在 SO 上找到完整的 JASPIC 示例.
- You may not need the additional flexibility that JACC offers.
- Employing a custom JACC provider solution requires quite a bit of work and is still not 100% standard due to AS-specific group-to-role-mapping.
- I'm unaware of an open-source project using a custom JACC provider for accomplishing something meaningful; Java EE Full Profile-implementing AS's being the sole exception, as they are mandated to implement the spec and sometimes use their JACC providers internally too (as e.g. in the case of GlassFish).
- There's still a lot of confusion surrounding JASPIC (many developers are unaware it even exists) which is the simplest one of the two specs. It's imho reasonable to first make JASPIC known and "approachable" to more people before moving on to covering JACC.
- While there are now more than a mere few great examples on JASPIC online, as are projects implementing actual authentication via JASPIC providers, -correct me if I'm mistaken- I haven't yet found a complete JASPIC example here on SO.
关于以下内容的一些评论:
Some remarks on what follows:
- 没有保修/使用风险自负/如果您的应用/AS/系统爆炸或被外星人入侵/等,请不要起诉我.
- 请尽量忽略那些您认为需要优化、更好的设计或其他改进的地方.是的,您当然可以重用 DB/LDAP 连接;验证插入 LDAP 搜索过滤器的用户名;更关心线程安全;使用 TLS;为非格式良好的 XML 有效负载返回 400....解决这些问题超出了所提供解决方案的范围.打扰一下??你想知道单元测试在哪里???!抱歉,没听说过这个词!:)
- 提供了两个具体执行组(角色)身份验证和检索的 SAM:一个独立",它自己完成这两项任务,一个委托",顾名思义,它演示了 SAM 如何将实际身份验证工作委托给 JAAS
LoginModule
(LM),通过使用 JASPIC LoginModule Bridge Profile.后一个 SAM 需要在 AS 和源级别本身进行进一步的配置/调整,除非您使用的是 GlassFish.提供了一个随附的示例 JAASlogin.conf
条目. - 提供程序类已针对 GlassFish 4.1 进行了测试.他们努力保持规范兼容,因此也应该真正在您的 AS 上工作(显然除了第二个 SAM),前提是您的产品实现了完整的 Java EE(6,最好是 7)配置文件.如果没有,我很抱歉;不,我不会在你的 AS 上测试.
- 您可以避免学习/使用
AuthConfigProvider
和ServerAuthConfig
实现,但随后必须将实际 SAM 注册到您产品的AuthConfigFactory
以专有方式(通过供应商特定的foo-web.xml
和/或进一步使用部署/管理工具).您也不会让 SAM 实现ServerAuthContext
接口,并且必须从 SAM 中加载随附的Properties
.然后,您的 AS 将为您实例化缺少的类,可能会重用它为所有应用程序和消息层预先配置的全局"AuthConfigProvider
和/或ServerAuthConfig
.请注意,根据它是否跨请求重用其实例化的ServerAuthConfig
和ServerAuthContext
(几乎没有这种情况,尤其是后者),您的 SAM 的生命周期可能会受到影响. - 不包括组到角色的映射,因为它是特定于容器的.
- 我会在任何我想这样做的地方添加评论.并非所有都(完全)无用.在规范的帮助下,代码应该是可以理解的——但请随时询问是否有什么问题困扰着您.为篇幅过长致歉.
- 路径是标准 Maven 项目根目录的绝对路径.一旦您调整了 SAM 中的属性和/或身份验证/组检索方法,您就可以将所有文件构建为 WAR,并将后者按原样部署在您的 AS 上以对其进行测试.唯一的依赖是 (
provided
)javaee-api
7.0(加上您的 JDBC 驱动程序,除非 AS 类路径中已经存在). - 由于 SO 的帖子长度限制,我不得不将代码移至 Gist.
- No warranty / use at own risk / don't sue me if your app / AS / system explodes or gets hacked by alien / etc.
- Please, try to disregard those spots where optimization, better design or other improvements would in your opinion have been essential. Yes you could admittedly reuse DB / LDAP connections; validate usernames inserted into LDAP search filters; care more about thread safety; use TLS; return a 400 for non-well-formed XML payloads... . Addressing those concerns is outside the scope of the provided solution. Excuse me?? You wonder where the unit tests are???! Sorry, never heard of the term! :)
- Two SAMs concretely performing authentication and retrieval of groups (roles) are provided: a "standalone", which accomplishes both tasks on its own, and a "delegating" one, which, as its name suggests, demonstrates how a SAM can delegate actual authentication work to a JAAS
LoginModule
(LM), by employing the JASPIC LoginModule Bridge Profile. The latter SAM requires further configuration / adaptation, both at the AS and at the source level per se, except if you are using GlassFish. An accompanying example JAASlogin.conf
entry is provided. - The provider classes were tested against GlassFish 4.1. They strive to remain spec-compliant and should therefore really work on your AS too (except for the second SAM, obviously), provided that your product implements the Full Java EE (6, preferably 7) Profile. I'm sorry if it doesn't; and no, I won't test on your AS.
- You can avoid studying / using the
AuthConfigProvider
andServerAuthConfig
implementations, but will then have to register the actual SAM with your product'sAuthConfigFactory
in a proprietary way (via a vendor-specificfoo-web.xml
and/or further use of deployment / administrative tools). You will additionally not have the SAM implementing theServerAuthContext
interface and will have to load the accompanyingProperties
from within the SAM. Your AS will then instantiate the missing classes for you, possibly reusing a "global"AuthConfigProvider
and/orServerAuthConfig
it has pre-configured for all applications and message layers. Note that, depending on whether it reuses its instantiatedServerAuthConfig
andServerAuthContext
across requests (hardly ever the case especially with the latter), the lifecycle of your SAM may be affected. - Group-to-role mapping is not covered as it's container-specific.
- I included comments wherever I felt like doing so. Not all are (completely) useless. Aided by the spec, the code should be comprehensible --but feel free to ask if something's troubling you. Apologies for the overlength post.
- Paths are absolute from the root of a standard Maven project. Once you've adapted the properties and/or authentication / group retrieval methods in the SAMs, you can build all files as a WAR and deploy the latter on your AS as-is to test it. The sole dependency is that of (
provided
)javaee-api
7.0 (plus your JDBC driver, unless already present on the AS class path). - I had to move the code to a Gist due to SO's post length constraint.
ServletContextListener
注册AuthConfigProvider
.另存为/<project>/src/main/java/org/my/foosoft/authn/BigJaspicFactoryRegistrar.java
.AuthConfigProvider
.另存为/<project>/src/main/java/org/my/foosoft/authn/BigJaspicFactory.java
.ServerAuthConfig
.另存为/<project>/src/main/java/org/my/foosoft/authn/LittleJaspicServerFactory.java
.- 基础对偶
ServerAuthContext
-ServerAuthModule
实现助手类.这是实际答案的 1/3 部分.另存为/<project>/src/main/java/org/my/foosoft/authn/HttpServletSam.java
. - 独立 SAM 实现.实际答案,第 2/3 部分.另存为
/<project>/src/main/java/org/my/foosoft/authn/StandaloneLdapSam.java
. - JAAS LM-delegating SAM.实际答案,第 3/3 部分.另存为
/<project>/src/main/java/org/my/foosoft/authn/JaasDelegatingLdapSam.java
. - 方便异常类型.另存为
/<project>/src/main/java/org/my/foosoft/authn/JaspicMischief.java
. - 随附的
属性
.如果您想逐字测试实际的身份验证代码,请根据您的需要调整它们.另存为/<project>/src/main/resources/org/my/foosoft/authn/jaspic-provider.properties
. - 附带示例
login.conf
(6) 的片段;有关实际文件系统位置的信息,请参阅供应商文档. /<project>/src/main/java/org/my/foosoft/presentation/UserUtils.java
(可选 - 用于演示目的:JSF 支持 bean)/<project>/src/main/webapp/index.xhtml
(可选 - 用于演示目的:不受保护的索引页面)/<project>/src/main/webapp/login.xhtml
(可选 - 用于演示目的:登录页面)/<project>/src/main/webapp/restricted/info.xhtml
(可选 - 用于演示目的:受保护的索引页面,用于角色access_restricted_pages
)/<project>/src/main/webapp/WEB-INF/web.xml
(可选 - 出于演示目的和完整性考虑:网络模块 DD)
- The
ServletContextListener
registering theAuthConfigProvider
. Save as/<project>/src/main/java/org/my/foosoft/authn/BigJaspicFactoryRegistrar.java
. - The
AuthConfigProvider
. Save as/<project>/src/main/java/org/my/foosoft/authn/BigJaspicFactory.java
. - The
ServerAuthConfig
. Save as/<project>/src/main/java/org/my/foosoft/authn/LittleJaspicServerFactory.java
. - The base dual
ServerAuthContext
-ServerAuthModule
implementation helper class. This is part 1/3 of the actual answer. Save as/<project>/src/main/java/org/my/foosoft/authn/HttpServletSam.java
. - The standalone SAM implementation. Actual answer, part 2/3. Save as
/<project>/src/main/java/org/my/foosoft/authn/StandaloneLdapSam.java
. - The JAAS LM-delegating SAM. Actual answer, part 3/3. Save as
/<project>/src/main/java/org/my/foosoft/authn/JaasDelegatingLdapSam.java
. - Convenience exception type. Save as
/<project>/src/main/java/org/my/foosoft/authn/JaspicMischief.java
. - The accompanying
Properties
. Adapt them to your needs if you'd like to test the actual authentication code verbatim. Save as/<project>/src/main/resources/org/my/foosoft/authn/jaspic-provider.properties
. - Accompanying sample
login.conf
snippet for (6); consult vendor's documentation for actual file system location. /<project>/src/main/java/org/my/foosoft/presentation/UserUtils.java
(optional - for demonstration purposes: JSF backing bean)/<project>/src/main/webapp/index.xhtml
(optional - for demonstration purposes: unprotected index page)/<project>/src/main/webapp/login.xhtml
(optional - for demonstration purposes: login page)/<project>/src/main/webapp/restricted/info.xhtml
(optional - for demonstration purposes: protected index page for users in roleaccess_restricted_pages
)/<project>/src/main/webapp/WEB-INF/web.xml
(optional - for demonstration purposes and for the sake of completness: web module DD)
进一步阅读:
Further reading:
- JSR-196 (JASPIC) 规范
- Arjan Tijms 的 JASPIC ZEEF 页面
- JSR-115 (JACC) 规范
1 JASPIC 是一个非常通用的 SPI,理论上,当插入一个有能力的消息处理运行时时,它能够验证 JMS、SAML-over-SOAP 和任何其他类型的消息.即使是它主要使用的 Servlet Container Profile 也没有过度限制它.
1 JASPIC is very a generic SPI, in theory able to authenticate JMS, SAML-over-SOAP and any other kind of message, when plugged into a capable message processing runtime. Even its predominantly used Servlet Container Profile does not overly constrain it.
JASPIC 的低级、灵活特性需要不了解特定于协议的功能,例如 HTTP 会话.因此,ServerAuthContext
s/SAM 由运行时触发以对每个请求执行身份验证.
JASPIC's low-level, flexible nature entails unawareness of protocol-specific functionality, such as the HTTP session. Consequently, ServerAuthContext
s / SAMs are triggered by the runtime to perform authentication on every request.
然而,该规范通过允许 SAM 请求运行时通过 MessageInfo
Callback 属性来发起 容器身份验证会话,为这个潜在的缺点做出了规定.当被要求对同一客户端的后续请求进行身份验证时,SAM 可以避免重复整个过程,方法是要求运行时重用先前建立的 AS 身份验证会话,因此用户身份(调用者和/或组 Principal
(s)).这是通过执行示例代码的 HttpServletSam
中显示的do-nothing-/leave-authentication-state-as-is-protocol"来实现的.
The spec however makes a provision about this potential shortcoming by allowing SAMs to request initiation of a container authentication session by the runtime, via a MessageInfo
Callback Property. When asked to authenticate subsequent requests of the same client, SAMs can avoid repeating the entire process, by asking the runtime to reuse the previously established AS authentication session, hence the user identity (caller and/or group Principal
(s)). That is accomplished via execution of the "do-nothing-/leave-authentication-state-as-is-protocol" shown in the HttpServletSam
of the sample code.
最后应该注意的是,JASPIC 和 Servlet 规范都没有明确定义容器身份验证会话是什么.对于经过 SAM 身份验证的用户,出于所有实际目的,我认为 AS 身份验证会话等同于 HTTP 会话,只要 a) 身份验证与单个应用程序上下文相关并且 b) SAM,如上所述,信号在每个请求上重用 AS 身份验证会话.
It should lastly be noted that neither the JASPIC nor the Servlet spec clearly defines what a container authentication session is. For a SAM-authenticated user I would, for all practical purposes, consider the AS authentication session to be the equivalent of the HTTP session, as long as a) authentication pertains to a single application context and b) the SAM, as explained above, signals reuse of the AS authentication session on each request.
相关文章