如何在Wildfly 8上使用Picketbox/Undertow捕获FailedLoginException并应用CORS

3
借助ContainerResponseFilter的帮助,我可以将CORS标头应用于所有传出响应,并且通过ExceptionMapper可以在所有错误和异常上执行相同操作,但是Picketbox/Undertow在Wildfly中应该抛出任何身份验证相关的异常时都不会被捕获。无论我尝试什么,我的ExceptionMapper都从未捕获它,因此前端无法读取401状态,因为响应没有附加CORS标头(XHR HTTP状态代码变为0)。
我正在使用this PBKDF2设置来对MySQL数据库进行身份验证,一开始我认为由于身份验证在单独的模块中运行,所以可能没有被我的应用程序捕获,但即使将所有身份验证代码移动到我的应用程序中,我仍然遇到了同样的问题。
这是我在尝试使用错误密码进行身份验证时得到的日志条目(当我根本没有发送凭据时,我得到非常相似的结果):
2014-11-29 16:11:08,053 TRACE [org.jboss.security] (default task-4) PBOX000224: End getAppConfigurationEntry(PBKDF2DatabaseDomain), AuthInfo: AppConfigurationEntry[]: [0] LoginModule Class: com.example.myapplication.security.SaltedDatabaseServerLoginModule ControlFlag: LoginModuleControlFlag: required Options: name=dsJndiName, value=java:/user name=principalsQuery, value=SELECT Hash FROM account WHERE ID=? name=rolesQuery, value=SELECT Role, 'Roles' FROM account WHERE account.ID=?
2014-11-29 16:11:08,053 TRACE [org.jboss.security] (default task-4) PBOX000236: Begin initialize method 2014-11-29 16:11:08,053 TRACE [org.jboss.security] (default task-4) PBOX000262: Module options [dsJndiName: java:/user, principalsQuery: SELECT Hash FROM account WHERE ID=?, rolesQuery: SELECT Role, 'Roles' FROM account WHERE account.ID=?, suspendResume: true] 2014-11-29 16:11:08,053 TRACE [org.jboss.security] (default task-4) PBOX000240: Begin login method 2014-11-29 16:11:08,053 TRACE [org.jboss.security] (default task-4) PBOX000263: Executing query SELECT Hash FROM account WHERE ID=? with username 1@2.se 2014-11-29 16:11:08,062 DEBUG [org.jboss.security] (default task-4) PBOX000283: Bad password for username 1@2.com 2014-11-29 16:11:08,062 TRACE [org.jboss.security] (default task-4) PBOX000244: Begin abort method 2014-11-29 16:11:08,062 DEBUG [org.jboss.security] (default task-4) PBOX000206: Login failure: javax.security.auth.login.FailedLoginException: PBOX000070: Password invalid/Password required at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:284) [picketbox-4.0.21.Beta1.jar:4.0.21.Beta1] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.8.0_25] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) [rt.jar:1.8.0_25] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.8.0_25] at java.lang.reflect.Method.invoke(Method.java:483) [rt.jar:1.8.0_25] at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755) [rt.jar:1.8.0_25] at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195) [rt.jar:1.8.0_25] at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682) [rt.jar:1.8.0_25] at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680) [rt.jar:1.8.0_25] at java.security.AccessController.doPrivileged(Native Method) [rt.jar:1.8.0_25] at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) [rt.jar:1.8.0_25] at javax.security.auth.login.LoginContext.login(LoginContext.java:587) [rt.jar:1.8.0_25] at org.jboss.security.authentication.JBossCachedAuthenticationManager.defaultLogin(JBossCachedAuthenticationManager.java:408) [picketbox-infinispan-4.0.21.Beta1.jar:4.0.21.Beta1] at org.jboss.security.authentication.JBossCachedAuthenticationManager.proceedWithJaasLogin(JBossCachedAuthenticationManager.java:345) [picketbox-infinispan-4.0.21.Beta1.jar:4.0.21.Beta1] at org
这是我的ExceptionMapper类(目前设置为捕获所有Throwables,希望使其工作):
@Provider
public class NotAuthorizedExceptionMapper implements ExceptionMapper<Throwable>{

@Override
public Response toResponse(Throwable exception) {
    Response response = Response.status(Response.Status.UNAUTHORIZED).build();
    response.getHeaders().putSingle("Access-Control-Allow-Origin", "*");
    response.getHeaders().putSingle("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, DELETE");
    response.getHeaders().putSingle("Access-Control-Allow-Headers", "origin, content-type, accept, authorization, access-control-allow-origin, access-control-allow-methods, access-control-allow-headers, allow, content-length, date, last-modified");
    return response;
}

我该怎么做才能捕获这些身份验证异常并在它们上面添加CORS呢?

我正在使用Keycloak并遇到了同样的问题。看起来在这种情况下,应用程序(包括Web过滤器、jax-rs过滤器等)从未发挥作用。 - Stijn de Witt
1个回答

2
最终我设法弄清楚了,在Wildfly上可以通过修改配置文件(standalone.xml)向所有非错误的出站响应添加自定义标头。这对我解决了问题。
    <subsystem xmlns="urn:jboss:domain:undertow:1.1">
        <buffer-cache name="default"/>
        <server name="default-server">
            <https-listener name="default" socket-binding="https" security-realm="ApplicationRealm"/>
            <host name="default-host" alias="localhost">
                <location name="/" handler="welcome-content"/>
                <filter-ref name="cors-origin"/>
                <filter-ref name="cors-methods"/>
                <filter-ref name="cors-headers"/>
            </host>
        </server>
        <servlet-container name="default">
            <jsp-config/>
        </servlet-container>
        <handlers>
            <file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
        </handlers>
        <filters>
            <response-header name="cors-origin" header-name="Access-Control-Allow-Origin" header-value="your-domain-here.com"/>
            <response-header name="cors-methods" header-name="Access-Control-Allow-Methods" header-value="OPTIONS, GET, POST, PUT, DELETE"/>
            <response-header name="cors-headers" header-name="Access-Control-Allow-Headers" header-value="origin, content-type, accept, authorization, access-control-allow-origin, access-control-allow-methods, access-control-allow-headers, allow, content-length, date, last-modified, if-modified-since"/>
        </filters>
    </subsystem>

编辑:事实证明Wildfly没有将CORS标头附加到未经授权的响应中,但当它遇到500错误时,它非常干净地忽略它们。有任何修复方法吗?非常感谢。


header-name="Access-Control-Allow-Origin" header-value="*" 唉... "*" 不再被主流浏览器接受为值。你必须在此处填写实际的来源名称... 使这个解决方案不再非常有用。 - Stijn de Witt
@StijndeWitt:我已经更新了解决方案,使用“your-domain-here.com”而不是通配符。但是,如果您将实际域名放在那里,我想不出为什么该解决方案在那种情况下不会非常有用?它应该完全相同,只不过不适用于除自己之外的其他域。从安全角度来看,您永远不应该在那里使用通配符。 - Koeus
如果您只有一个域名,那么这是一个合理的解决方案。但是,一旦您拥有多个域名,就会遇到麻烦。最终,我不得不编写自己的Undertow过滤器来完成它,所以我认为在这个意义上,Wildfly存在问题,即在Wildfly堆栈上以正确的方式设置CORS标头太难了。 - Stijn de Witt
哦,关于未经授权的响应,我发现处理例如403响应的唯一方法是在web.xml中设置错误页面。也许使用jax-rs有更好的方法,但我已经花费了相当多的时间,并没有找到任何东西,所以是的。总的来说,在Jax、Undertow、自定义错误页面等方面,这是一个相当混乱的解决方案。在我看来,不是很好。但我离题了 :) - Stijn de Witt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接