带有 FORM 身份验证的 Elytron 编程登录

时间:2021-04-16 18:22:28

标签: jboss wildfly elytron

我们目前正在从传统安全子系统迁移到 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 方法中处理传入请求。此处理程序由 DeploymentInfoio.undertow.servlet.ServletExtension 注册,ServletExtensionMETA-INF/services/io.undertow.servlet.ServletExtension 的实现提供。 io.undertow.server.HttpHandler#handleRequestjavax.servlet.http.HttpServletRequest#login 中注册为服务提供者。

我们的 Set-Cookie 实现中的请求处理从 cookie 中提取 JWT 令牌,对其进行预验证并确定包含的用户名。此用户名和作为密码的令牌用作调用 JSESSIONID 的输入。

对于旧版安全子系统,服务器的行为是,此登录调用触发了针对配置的旧版安全域的身份验证,并在 Undertow 中创建了一个会话,以便前一个 GET 请求的 HTTP 200 响应包含一个 {带有新的 javax.servlet.http.HttpServletRequest#login cookie 的 {1}} 标头。

对于 Elytron,javax.servlet.http.HttpServletRequest#login 不执行任何操作,既不会触发针对 Elytron 安全域和安全领域的身份验证,也不会触发会话的创建。浏览器仅显示登录表单,所描述的拦截过程应跳过该表单。

我调试了 JBoss 附带的 io.undertow.servlet.spec.HttpServletRequestImpl#login 的实现。我们从调用 login = sc.login(username, password)SecurityContext 开始。当使用 Elytron 时,此 org.wildfly.elytron.web.undertow.server.SecurityContextImplorg.wildfly.elytron.web.undertow.server.SecurityContextImpl#loginif (httpAuthenticator == null) 首先检查 httpAuthenticatororg.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,然后是 JSESSIONID。这至少最终触发了针对配置的 Elytron 安全域和安全域的身份验证和授权。身份验证/授权成功,但 Undertow 仍然没有发出新的 io.undertow.security.api.SecurityContext cookie,浏览器再次显示登录表单,而不是继续访问受保护的资源。

我目前没有想法,如何处理这个问题以及如何实现与旧安全子系统相同的行为。为什么 io.undertow.security.impl.SecurityContextImpl 的 Elytron 实现与遗留安全性 (javax.servlet.http.HttpServletRequest#login) 的实现方式如此不同?我应该如何使用带有 javax.servlet.http.HttpServletRequest#authenticate 和/或 <application-security-domains> <application-security-domain name="my_app_security_domain" http-authentication-factory="MyHttpAuthFactory"/> </application-security-domains> 的 Elytron 以编程方式登录基于 FORM 的 Web 应用程序?

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

潜流:

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

Elytron:

 str1 = ''.join(str(e) for e in x)
 print(str1)

0 个答案:

没有答案