Glassfish V3 LDAP 身份验证失败不显示表单错误页面
Posted
技术标签:
【中文标题】Glassfish V3 LDAP 身份验证失败不显示表单错误页面【英文标题】:Glassfish V3 failed LDAP authentication does not display the form-error-page 【发布时间】:2012-01-06 10:40:59 【问题描述】:我有一个声明了标准表单身份验证的 Web 应用程序,如下所示:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>ldap-realm</realm-name>
<form-login-config>
<form-login-page>/home</form-login-page>
<form-error-page>/home?error=true</form-error-page>
</form-login-config>
</login-config>
我在 Glassfish 服务器中声明了 ldap-realm,以及连接到我的 LDAP 服务器所需的所有凭据。
问题是这样的:
在 Glassfish V2 上,如果我部署此应用程序,当尝试使用错误用户(或现有用户但密码错误)登录时,我会被重定向到 <form-error-page>
(/home?error=true) 中声明的 URL 和此页面显示用户友好的错误消息,例如“您无法验证 bla bla”。此外,如果此时查看日志,我会看到一条 WARN 消息,告诉我用户输入的凭据无法针对 LDAP 服务器进行身份验证。
在 Glassfish V3(在 3.0 和 3.1 上都尝试过)上,当我部署完全相同的应用程序并在 GF 中配置完全相同的 ldap-realm 时,当用户尝试使用正确的凭据进行身份验证时一切正常,但是当他输入错误用户或正确用户/错误密码我收到 404 页面未找到错误,而不是从 <form-error-page>
重定向到 URL。更重要的是,发生的情况是,在验证无效时,用户会看到我为 404 错误声明的 html 页面,而不是 form-error-page。同样在 glassfish 日志中,我现在有一个异常堆栈跟踪,如下所示:
[#|2012-01-05T16:49:28.878+0100|WARNING|glassfish3.1|javax.enterprise.system.container.web.com.sun.web.security|_ThreadID=130;_ThreadName=Thread-1;|Exception
com.sun.enterprise.security.auth.login.common.LoginException: Login failed: Failed file login for aaaa.
at com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:394)
at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:240)
at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:153)
at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:483)
at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:425)
at org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:269)
at org.apache.catalina.authenticator.AuthenticatorBase.processSecurityCheck(AuthenticatorBase.java:909)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:546)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:623)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:326)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:227)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:170)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:822)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:719)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1013)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:662)
Caused by: javax.security.auth.login.LoginException: Failed file login for aaaa.
at com.sun.enterprise.security.auth.login.FileLoginModule.authenticate(FileLoginModule.java:84)
at com.sun.enterprise.security.auth.login.PasswordLoginModule.authenticateUser(PasswordLoginModule.java:117)
at com.sun.appserv.security.AppservPasswordLoginModule.login(AppservPasswordLoginModule.java:148)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
at com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:382)
老实说,我很困惑。 ldap-realm 定义正确,因为 VALID 身份验证可以正常工作。表单错误页面的 URL 也是有效的,因为如果我在地址栏中手动输入它,我会得到身份验证错误页面。我唯一想做的就是制作一个自定义的 LdapRealm 实现,并且在身份验证失败时不再抛出该异常。但这不是很酷。
我的问题是,有谁知道 Glassfish V2 和 V3 处理失败身份验证的方式是否有所不同? Glassfish V3 是否有一些额外的配置参数可用,使其在用户身份验证无效时返回表单错误页面,而不是抛出异常并返回 404?
【问题讨论】:
【参考方案1】:嗯,没有人回答,我找到了一种解决方法,虽然不是一个好的方法。如问题中所述,我将<form-error-page>
的url 声明为servlet,并且从未在GF3 中显示。我所做的就是将该 url 替换为指向静态文件(如 /loginError.html)的 URL,并在该静态页面中重定向到所需的 url(处理登录错误的 servlet 的那个)。这样我就得到了想要的行为。
【讨论】:
以上是关于Glassfish V3 LDAP 身份验证失败不显示表单错误页面的主要内容,如果未能解决你的问题,请参考以下文章
Spring boot Ldap 身份验证失败,LDAP 错误代码 49 - 80090308 数据 52e