Search code examples
springamazon-web-servicesspring-websocketsockjs

Websockets fallback option streaming not working in AWS


We are facing issues to make fallback option works in AWS environment.

Setup details and background We have Spring REST web services running in the AWS cloud environment. All services are running under tomcat 8. SSL is terminated at ELB. We are working with a vendor for providing us the AWS services, who added another component(WAF) in front of ELB that is not supporting web socket. So instead of websocket we were testing streaming as a fallback option. We are using spring websocket using sockJS.

The fallback option is also not working which gives us following exception

2015-12-07 18:07:43,859 [http-nio-8080-exec-5] DEBUG - Closing due to transport error for XhrStreamingSockJsSession[id=aahouqlj]
2015-12-07 18:07:43,859 [http-nio-8080-exec-5] DEBUG - Transport error in XhrStreamingSockJsSession[id=aahouqlj]
java.lang.IllegalArgumentException: Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml. Also you must use a Servlet 3.0+ container
>---at org.springframework.util.Assert.isTrue(Assert.java:65) ~[spring-core-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.http.server.ServletServerHttpAsyncRequestControl.<init>(ServletServerHttpAsyncRequestControl.java:58) ~[spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.http.server.ServletServerHttpRequest.getAsyncRequestControl(ServletServerHttpRequest.java:213) ~[spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession.handleInitialRequest(AbstractHttpSockJsSession.java:202) [spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.transport.handler.AbstractHttpSendingTransportHandler.handleRequestInternal(AbstractHttpSendingTransportHandler.java:68) [spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.transport.handler.AbstractHttpSendingTransportHandler.handleRequest(AbstractHttpSendingTransportHandler.java:58) [spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService.handleTransportRequest(TransportHandlingSockJsService.java:272) [spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.support.AbstractSockJsService.handleRequest(AbstractSockJsService.java:407) [spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler.handleRequest(SockJsHttpRequestHandler.java:90) [spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:51) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) [servlet-api.jar:?]
>---at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) [servlet-api.jar:?]
>---at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) [catalina.jar:8.0.23]
>---at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.23]
>---at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-websocket.jar:8.0.23]
>---at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.23]
>---at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.23]
>---at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at com.company.iac.common.security.AuthenticationFilter.successfulAuthentication(AuthenticationFilter.java:184) [iac-common-0.1.jar:0.1]
>---at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:235) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at com.company.iac.common.security.AuthenticationFilter.doFilter(AuthenticationFilter.java:132) [iac-common-0.1.jar:0.1]
>---at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
-at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
>---at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) [spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) [spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.23]
>---at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.23]
>---at com.company.iac.common.filter.CloudCORSFilter.doFilter(CloudCORSFilter.java:87) [iac-common-0.1.jar:0.1]
>---at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.23]
>---at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.23]
>---at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) [catalina.jar:8.0.23]
>---at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [catalina.jar:8.0.23]
>---at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [catalina.jar:8.0.23]
>---at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [catalina.jar:8.0.23]
>---at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [catalina.jar:8.0.23]
>---at org.apache.catalina.valves.rewrite.RewriteValve.invoke(RewriteValve.java:262) [catalina.jar:8.0.23]
>---at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:617) [catalina.jar:8.0.23]
>---at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [catalina.jar:8.0.23]
>---at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) [catalina.jar:8.0.23]
>---at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) [tomcat-coyote.jar:8.0.23]
>---at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) [tomcat-coyote.jar:8.0.23]
>---at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521) [tomcat-coyote.jar:8.0.23]
>---at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478) [tomcat-coyote.jar:8.0.23]
>---at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_45]
>---at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_45]
>---at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.0.23]
>---at java.lang.Thread.run(Thread.java:745) [?:1.8.0_45]
2015-12-07 18:07:43,866 [http-nio-8080-exec-5] DEBUG - Resolving exception from handler [org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler@2cc2e2a8]: org.springframework.web.socket.sockjs.SockJsException: Uncaught failure in SockJS request, uri=https://devstaging.pr.apps.company.com:443/events/pr/664/aahouqlj/xhr_streaming?t=1449511663834; nested exception is org.springframework.web.socket.sockjs.SockJsTransportFailureException: Failed to open session; nested exception is java.lang.IllegalArgumentException: Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml. Also you must use a Servlet 3.0+ container
2015-12-07 18:07:43,866 [http-nio-8080-exec-5] DEBUG - Resolving exception from handler [org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler@2cc2e2a8]: org.springframework.web.socket.sockjs.SockJsException: Uncaught failure in SockJS request, uri=https://devstaging.pr.apps.company.com:443/events/pr/664/aahouqlj/xhr_streaming?t=1449511663834; nested exception is org.springframework.web.socket.sockjs.SockJsTransportFailureException: Failed to open session; nested exception is java.lang.IllegalArgumentException: Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml. Also you must use a Servlet 3.0+ container
Caused by: org.springframework.web.socket.sockjs.SockJsTransportFailureException: Failed to open session; nested exception is java.lang.IllegalArgumentException: Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml. Also you must use a Servlet 3.0+ container
>---at org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession.handleInitialRequest(AbstractHttpSockJsSession.java:220) ~[spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.transport.handler.AbstractHttpSendingTransportHandler.handleRequestInternal(AbstractHttpSendingTransportHandler.java:68) ~[spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.transport.handler.AbstractHttpSendingTransportHandler.handleRequest(AbstractHttpSendingTransportHandler.java:58) ~[spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService.handleTransportRequest(TransportHandlingSockJsService.java:272) ~[spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.support.AbstractSockJsService.handleRequest(AbstractSockJsService.java:407) ~[spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---at org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler.handleRequest(SockJsHttpRequestHandler.java:90) ~[spring-websocket-4.1.7.RELEASE.jar:4.1.7.RELEASE]
>---... 63 more

We are using spring version 4.1.7. I could see filterchain and servlet has by default async support enabled. spring security config looks like this

   protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable().logout().disable().anonymous().disable().authorizeRequests()
        .anyRequest().permitAll().and().addFilterBefore(authenticationFilter() , ExceptionTranslationFilter.class).
        sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

The auth Filter extends AbstractAuthenticationProcessingFilter

public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public AuthenticationFilter(AuthenticationManager authenticationManager) {
        super(new DummyRequestMatcher());
        this.setAuthenticationManager(authenticationManager);
    }

Does authFilter has to have async support enabled? If yes then I have not found the way to do it. I am assuming that springsecurityfilters has by default async flag set to true.

Do you see anything else that I am missing?


Solution

  • There were multiple issues. First issue was with the valve we introduced. That acts as a filter so we need to set the async flag to true(). Tomcat documentation doesnt talk about it but found this from stackoverflow valve is also a filter Second issue was with Authentication Object from spring security. We missed to implement the equals method and hence before connecting(xhr_send) the call was failing with 404 error.