调度传入的RPC调用时发生异常:encodedRequest不能为空

时间:2013-09-24 19:14:47

标签: apache internet-explorer tomcat single-sign-on ntlm

此处描述了类似的问题:GWT IllegalArgumentException: encodedRequest cannot be empty

我的GWT应用程序部署在Tomcat6中,它通过使用Coyote / JK2连接器与Apache链接。对于SSO,我使用mod_auth_sspi / 1.0.4。

当我使用IE8时,不显示页面,但对于Firefox,一切正常。在Tomcat日志中,我看到以下内容:

SEVERE: Exception while dispatching incoming RPC call
java.lang.IllegalArgumentException: encodedRequest cannot be empty
    at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:232)
    at org.spring4gwt.server.SpringGwtRemoteServiceServlet.processCall(SpringGwtRemoteServiceServlet.java:32)
    at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:248)
    at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:643)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at gov.department.it.server.RequestInterceptorFilter.doFilter(RequestInterceptorFilter.java:90)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190)
    at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:311)
    at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:776)
    at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:705)
    at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:898)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
    at java.lang.Thread.run(Thread.java:619)

到目前为止我尝试了什么:

1)找不到注册表项DisableNTLMPreAuth(恕我直言,这不是解决方案,因为在我的情况下IE 8被积极使用)。

2)我已经安装并配置了本机Windows身份验证框架WAFFLE

的web.xml:

...
<filter>
    <filter-name>NegotiateSecurityFilter</filter-name>
    <filter-class>waffle.servlet.NegotiateSecurityFilter</filter-class>
    <init-param>
        <param-name>waffle.servlet.spi.NegotiateSecurityFilterProvider/protocols</param-name>
        <param-value>NTLM</param-value>
    </init-param>
</filter>
...
<filter-mapping>
    <filter-name>NegotiateSecurityFilter</filter-name>
    <url-pattern>/my-app/*</url-pattern>
</filter-mapping>
...

但它没有帮助。

3)在worker.properties我设置socket_keepalive=0,但它也没有帮助 -

worker.ajp13.type=ajp13
worker.ajp13.host=localhost
worker.ajp13.port=8009
worker.ajp13.lbfactor=50
worker.ajp13.cachesize=10
worker.ajp13.cache_timeout=600
worker.ajp13.socket_keepalive=0
worker.ajp13.socket_timeout=300

我还能尝试做什么?我非常感谢这些信息。谢谢大家。

1 个答案:

答案 0 :(得分:9)

你重新发现mod_auth_sspi中的7岁bug #1已经影响了众多项目,使众多开发人员感到沮丧,并且多年来造成了无数浪费的工时。然而,由于维护者doesn't consider it a bug,它仍然没有得到解决。微软也没有针对旧浏览器解决这个问题,因为有迹象表明IE9没有这个问题。

<强>原因

这是因为IE试图成为“聪明”的。并发送一个零内容长度的POST(我将其命名为0POST以尝试使其成为一个可转位的术语,以使那些在 next 7年内重新发现它的人受益。)使用NTLM auth头期待受到服务器的挑战。 IE在此保护空间中进行身份验证后执行此操作。所以它知道它会再次受到挑战。可悲的是,mod_auth_sspi并不像IE那么聪明,所以当0POST到达时,服务器端会发生不好的事情,并且它会在没有受到质疑的情况下通过应用程序。除非有时即使对于未受保护的区域,如果它们位于需要认证的区域下,也会发生这种情况。 其他浏览器不会假装像IE一样聪明,并且在第一次往返时不会尝试节省几个字节,因此它们不会遇到这个问题。以下是此行为的Microsoft's explanation

糟糕的解决方法

在Apache httpd.conf中设置

SSPIPerRequestAuth On

这相当于您提到的DisableNTLMPreAuth IE客户端修复程序,这对于大型用户组来说是不切实际的。此外,它相当于削弱所有非Apache应用程序,可能能够处理0POST。实际上没有任何关于这个设置的例子正在讨论或者它的副作用在网上解释,所以我包括这个only link我发现它对它有所了解。无论如何,让一个服务器端改变似乎是两​​个邪恶中较小的一个。虽然现在,通过更改服务器配置,您已经削弱了访问此站点的所有其他无辜浏览器。

此解决方法的问题在于它强制每个请求执行SSPI握手,这会导致大量额外的401流量并可能影响性能。对于性能,NTLM身份验证被视为基于会话的&#39;不是基于请求的&#39;这意味着握手仅在会话开始时发生。使用此设置时,还应设置过滤器以防止日志填满401。另请注意,这需要打开KeepAlive。

我不确定您的设置是否与WAFFLE修复程序中描述的设置相同;他们像你一样使用Apache吗?我认为WAFFLE适用于Tomcat,而前面有Apache,所以Apache正在处理身份验证。您可以考虑使用该设置而不是Apache。如果您可以使用该设置,那么它可能是比此解决方案更好的选择,因为WAFFLE已明确说明了0POST和can handle it。作者与GWT一起工作时有also discovered this gem。

有趣的是,对于jcifs,a fix for this very issue was posted 9年前。作者后来还提供了excellent explanation

  

过滤器中的代码检查所有HTTP POST请求并确定   如果它们包含NTLM类型1消息。如果请求包含   NTLM类型1消息,过滤器响应虚拟类型2消息   在提交任何内容之前,要求IE重新协商NTLM   POST数据。然后,浏览器应以NTLM类型3响应   消息以及过滤器应允许的后置数据   链接到Web应用程序的其余部分。

如果您有兴趣,5年前还为mod_auth_sspi创建了simple patchSee diff在作者自己的回购中。我不确定我是否同意这种方法。它试图检测IE / 0POST,而我认为正确的修复应该是检测客户端是否正在使用NTLM Type 1标头请求auth,如jcifs过滤器。 (类型1只表示它是握手的第一条消息)

我想知道是否有人使用mod_auth_sspi的替代方案,如mod_auth_ntlm_winbind,如果他们没有表现出这种行为。如果有,请发表评论。我们已经知道WAFFLE有效,但它不是mod_auth_sspi的替代品。

另一种方法是忘记NTLM并使用Kerberos,(mod_auth_kerb)但很多人发现设置太复杂了。 IE将在任何质询 - 响应方案上以这种方式运行,因此很可能curb auth可能遇到同样的问题,因为在两种情况下都会发生类似的401序列。但作为一个不同的模块,它有可能处理这个问题。

最后,我要提一下,还有另一个问题,即每个请求的auth解决方法似乎无法修复。我还没有看到它在任何地方讨论过,但我发现有时在0POST之后,服务器会等待很长时间才会响应最终的200响应和(正确)POST的结果。这种长时间延迟仅在最后发生,而不是立即响应0POST。这很好,并且握手完成,但服务器没有响应,直到经过漫长的等待,我注意到可疑接近90秒,就像某种超时一样。实际结果是,当用户登录时,IE8有时会挂起90秒等待服务器响应。我认为KeepAlive可能导致它,但它甚至没有在我的配置中明确定义,所以我认为它是在15秒Apache默认值。但我确信这与0POST有关,因为它只是在成功的0POST授权握手之后才发生。我们的服务器位于防火墙的单独(双向)可信域中,因此可能与它有关。

此问题的各种示例

最热闹的例子是IE的智能如何影响微软自己的产品!他们自己无法理解如何处理IE的行为,导致ISA Server 2006中出现错误。