我们目前正在从传统的安全子系统迁移到Elytron,并在JBoss EAP7.3.6中部署了一个基于Struts2的web应用程序,它应该支持多种“风格”的身份验证。
登录的标准方式应该是用户在登录表单(j_security_check)中手动提供凭据,然后单击相应的按钮。在我们的设置中,这与Elytron配合得很好。
第二种可能性是,对web应用程序的受保护内容的GET请求可以包含包含JWT令牌的自定义cookie。此cookie由在其io.undertow.server.HttpHandler#handleRequest方法中处理传入请求的io.undertow.server.HttpHandler截获。此处理程序由io.undertow.servlet.api.DeploymentInfo#addSecurityWrapper使用DeploymentInfo注册,该an由io.undertow.servlet.ServletExtension的实现提供。ServletExtension在META-INF/services/io.undertow.servlet.ServletExtension中注册为服务提供商。
我们的io.undertow.server.HttpHandler#handleRequest实现中的请求处理从cookie中提取JWT令牌,预先验证它并确定包含的用户名。此用户名和作为密码的令牌用作调用javax.servlet.http.HttpServletRequest#login的输入。
对于遗留安全子系统,服务器的行为是,此登录调用触发了针对已配置的遗留安全域的身份验证,并在Undertow中创建了一个会话,以便前一个GET请求的HTTP200响应包含一个带有新的JSESSIONID cookie的Set-Cookie标头。
使用Elytron,javax.servlet.http.HttpServletRequest#login不会做任何事情,既不会触发对Elytron安全域和安全领域的身份验证,也不会触发会话的创建。浏览器只显示登录表单,该表单应该被所描述的拦截过程跳过。
我调试了JBoss附带的javax.servlet.http.HttpServletRequest#login实现。我们从调用login = sc.login(username, password)的io.undertow.servlet.spec.HttpServletRequestImpl#login开始。使用Elytron时,此SecurityContext为org.wildfly.elytron.web.undertow.server.SecurityContextImpl。org.wildfly.elytron.web.undertow.server.SecurityContextImpl#login首先检查if (httpAuthenticator == null)。httpAuthenticator仅在通过调用javax.servlet.http.HttpServletRequest#authenticate调用的org.wildfly.elytron.web.undertow.server.SecurityContextImpl#authenticate中设置。
这就解释了为什么对io.undertow.servlet.spec.HttpServletRequestImpl#login的简单调用什么也做不了。我尝试先调用javax.servlet.http.HttpServletRequest#authenticate,在内部实例化该httpAuthenticator,然后调用javax.servlet.http.HttpServletRequest#login。这至少最终触发了对已配置的Elytron安全域和安全域的身份验证和授权。身份验证/授权成功,但Undertow仍然没有发布新的JSESSIONID cookie,浏览器再次显示登录表单,而不是继续访问受保护的资源。
我现在没有想法,如何处理这个问题,以及如何实现与遗留安全子系统相同的行为。为什么与遗留安全(io.undertow.security.impl.SecurityContextImpl)的实现相比,io.undertow.security.api.SecurityContext的Elytron实现的行为如此不同?如何使用带有javax.servlet.http.HttpServletRequest#login和/或javax.servlet.http.HttpServletRequest#authenticate的Elytron以编程方式登录基于表单的web应用程序
所有这些的相关JBoss配置如下所示:
暗流:
<application-security-domains>
<application-security-domain name="my_app_security_domain" http-authentication-factory="MyHttpAuthFactory"/>
</application-security-domains>Elytron:
<security-domains>
<security-domain name="MySecurityDomain" default-realm="MyCachingRealm" permission-mapper="default-permission-mapper">
<realm name="MyCachingRealm" role-decoder="FromRolesAttributeDecoder"/>
</security-domain>
</security-domains>
<security-realms>
<custom-realm name="MyCustomRealm" module="module name redacted" class-name="class name redacted"/>
<caching-realm name="MyCachingRealm" realm="MyCustomRealm" maximum-age="300000"/>
<identity-realm name="local" identity="$local"/>
</security-realms>
<mappers>
<simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
<permission-mapping>
<principal name="anonymous"/>
<permission-set name="default-permissions"/>
</permission-mapping>
<permission-mapping match-all="true">
<permission-set name="login-permission"/>
<permission-set name="default-permissions"/>
</permission-mapping>
</simple-permission-mapper>
<constant-realm-mapper name="local" realm-name="local"/>
<constant-realm-mapper name="MyRealmMapper" realm-name="MyCachingRealm"/>
<simple-role-decoder name="FromRolesAttributeDecoder" attribute="Roles"/>
</mappers>
<http>
<http-authentication-factory name="MyHttpAuthFactory" security-domain="MySecurityDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="FORM" realm-mapper="MyRealmMapper">
<mechanism-realm realm-name="MyRealm"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
<provider-http-server-mechanism-factory name="global"/>
</http>发布于 2021-09-08 14:24:42
这是JBoss EAP中的一个错误,已在EAP 7.3.8和7.4.1中修复。详细信息请参见https://issues.redhat.com/browse/JBEAP-21737和https://issues.redhat.com/browse/JBEAP-21738。
https://stackoverflow.com/questions/67130360
复制相似问题