Jboss 具有表单身份验证的Elytron编程登录

Jboss 具有表单身份验证的Elytron编程登录,jboss,wildfly,elytron,Jboss,Wildfly,Elytron,我们目前正在从遗留安全子系统迁移到Elytron,并在JBoss EAP 7.3.6中部署了一个基于Struts2的web应用程序,该应用程序应支持多种“风格”的身份验证 登录的标准方式应该是用户以登录形式手动提供凭据(j_security_check),然后单击相应的按钮。这在我们的设置中与Elytron配合得很好 第二种可能性是,对web应用程序的受保护内容的GET请求可以包含包含JWT令牌的自定义cookie。此cookie被一个io.undertow.server.HttpHandler

我们目前正在从遗留安全子系统迁移到Elytron,并在JBoss EAP 7.3.6中部署了一个基于Struts2的web应用程序,该应用程序应支持多种“风格”的身份验证

登录的标准方式应该是用户以登录形式手动提供凭据(
j_security_check
),然后单击相应的按钮。这在我们的设置中与Elytron配合得很好

第二种可能性是,对web应用程序的受保护内容的GET请求可以包含包含JWT令牌的自定义cookie。此cookie被一个
io.undertow.server.HttpHandler
截获,它在其
io.undertow.server.HttpHandler#handleRequest
方法中处理传入请求。此处理程序由
io.undertow.servlet.api.DeploymentInfo#addSecurityWrapper
DeploymentInfo
注册,后者由
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请求的HTTP 200响应包含一个带有新的
JSESSIONID
Cookie的
Set Cookie

使用Elytron,
javax.servlet.http.HttpServletRequest#login
不会做任何事情,也不会触发对Elytron安全域和安全域的身份验证,也不会触发会话的创建。浏览器仅显示登录表单,所述拦截过程应跳过该表单

我调试了JBoss附带的
javax.servlet.http.HttpServletRequest#login
的实现。我们从调用
login=sc.login(用户名、密码)
io.undertow.servlet.spec.HttpServletRequestImpl#login开始。使用Elytron时,此
SecurityContext
org.wildfly.Elytron.web.undertow.server.SecurityContextImpl
org.wildfly.elytron.web.undertow.server.SecurityContextImpl#login
首先检查
是否(httpAuthenticator==null)
httpAuthenticator
仅在
org.wildfly.elytron.web.undertow.server.SecurityContextImpl#authenticate
中设置,它通过调用
javax.servlet.http.HttpServletRequest#authenticate
来调用

这就解释了为什么对
io.undertow.servlet.spec.HttpServletRequestImpl#login
的简单调用没有起到任何作用。我尝试先调用
javax.servlet.http.HttpServletRequest#authenticate
,在内部实例化
httpAuthenticator
,然后调用
javax.servlet.http.HttpServletRequest#login
。这至少最终触发了针对已配置的Elytron安全域和安全域的身份验证和授权。身份验证/授权成功,但Undertow仍然没有发出新的
JSESSIONID
cookie,浏览器再次显示登录表单,而不是继续访问受保护的资源

我目前还不知道如何处理这个问题,以及如何实现与遗留安全子系统相同的行为。为什么Elytron实现的
io.undertow.security.api.SecurityContext
与传统安全性(
io.undertow.security.impl.SecurityContextImpl
)相比表现如此不同?我应该如何使用Elytron和
javax.servlet.http.HttpServletRequest#login
和/或
javax.servlet.http.HttpServletRequest#authenticate
以编程方式登录基于表单的web应用程序

所有这些的相关JBoss配置如下所示:

底拖:

<application-security-domains>
    <application-security-domain name="my_app_security_domain" http-authentication-factory="MyHttpAuthFactory"/>
</application-security-domains>

爱丽特龙:

<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>