Reputation: 41
I am upgrading to Java 8, Spring 4 and Spring Security 4 (from Java 7, Spring/Security 3 where everything worked). After the upgrade, everything but ability to download/stream from server to the browser works fine.
For the UI, we use Vaadin. In one instance, I create a frame in the browser that should display a PDF and provide data of type application/pdf in the input stream. In other instances, a stream goes back to the browser to be saved as a file
Debugging in Java, I see an open InputStream that contains data to be downloaded in the browser. Data are read from the input stream and written to the response.OutputStream which is also open. However, when Tomcat tries to write the output stream data into the socket it throws the exception you can see below (Tomcat 8.5 throws an exception trying to write data, Tomcat 7 throws an exception when trying to flush data - different implementations). It seems the connection to the browser has been terminated. It only happens when the app is secured with Spring Security. If I remove security everything works (and it also worked with with Spring Security 3)
Any help resolving this is greatly appreciated! Please let me know if I can provide any additional information to shed light on this issue.
web.xml
:
<filter>
<filter-name>MultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>MultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Security configuration:
<context:property-placeholder ignore-resource-not-found="true" location="classpath:CALC.properties" />
<security:global-method-security pre-post-annotations="enabled" secured-annotations="enabled" />
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<constructor-arg value=".." />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="${service.calc.security.service}">
<security:password-encoder ref="passwordEncoder" />
</security:authentication-provider>
</security:authentication-manager>
<security:http pattern="/VAADIN/**" security="none" />
<security:http pattern="/loggedout*" security="none" />
<security:http auto-config='true' use-expressions="true" realm="Illustration System">
<security:intercept-url pattern="/**" access="isFullyAuthenticated()" />
<security:http-basic />
<security:csrf disabled="true"/>
<security:anonymous granted-authority="ROLE_USER" />
</security:http>
<bean id="logoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
<property name="invalidateHttpSession" value="true" />
</bean>
Stack trace:
org.apache.catalina.connector.ClientAbortException: java.io.IOException: An established connection was aborted by the software in your host machine
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:356) ~[catalina.jar:8.5.13]
at org.apache.catalina.connector.OutputBuffer.appendByteArray(OutputBuffer.java:778) ~[catalina.jar:8.5.13]
at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:707) ~[catalina.jar:8.5.13]
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:391) ~[catalina.jar:8.5.13]
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:369) ~[catalina.jar:8.5.13]
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:96) ~[catalina.jar:8.5.13]
at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextServletOutputStream.write(OnCommittedResponseWrapper.java:639) ~[spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at com.vaadin.server.DownloadStream.writeResponse(DownloadStream.java:307) ~[vaadin-server-7.7.8.jar:7.7.8]
at com.vaadin.server.AbstractClientConnector.handleConnectorRequest(AbstractClientConnector.java:682) ~[vaadin-server-7.7.8.jar:7.7.8]
at com.vaadin.server.ConnectorResourceHandler.handleRequest(ConnectorResourceHandler.java:90) [vaadin-server-7.7.8.jar:7.7.8]
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1422) [vaadin-server-7.7.8.jar:7.7.8]
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:380) [vaadin-server-7.7.8.jar:7.7.8]
at com.calcfocus.webui.util.CalcFocusServlet.service(CalcFocusServlet.java:21) [webui-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [servlet-api.jar:?]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) [catalina.jar:8.5.13]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [catalina.jar:8.5.13]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-websocket.jar:8.5.13]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [catalina.jar:8.5.13]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [catalina.jar:8.5.13]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:215) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:177) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) [spring-security-web-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [catalina.jar:8.5.13]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [catalina.jar:8.5.13]
at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:122) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [catalina.jar:8.5.13]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [catalina.jar:8.5.13]
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71) [log4j-web-2.3.jar:2.3]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [catalina.jar:8.5.13]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [catalina.jar:8.5.13]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [catalina.jar:8.5.13]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [catalina.jar:8.5.13]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [catalina.jar:8.5.13]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [catalina.jar:8.5.13]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [catalina.jar:8.5.13]
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624) [catalina.jar:8.5.13]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [catalina.jar:8.5.13]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) [catalina.jar:8.5.13]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-coyote.jar:8.5.13]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-coyote.jar:8.5.13]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) [tomcat-coyote.jar:8.5.13]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-coyote.jar:8.5.13]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-coyote.jar:8.5.13]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_121]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_121]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.5.13]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_121]
Caused by: java.io.IOException: An established connection was aborted by the software in your host machine
at sun.nio.ch.SocketDispatcher.write0(Native Method) ~[?:1.8.0_121]
at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51) ~[?:1.8.0_121]
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93) ~[?:1.8.0_121]
at sun.nio.ch.IOUtil.write(IOUtil.java:65) ~[?:1.8.0_121]
at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471) ~[?:1.8.0_121]
at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:134) ~[tomcat-coyote.jar:8.5.13]
at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101) ~[tomcat-coyote.jar:8.5.13]
at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:157) ~[tomcat-coyote.jar:8.5.13]
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1259) ~[tomcat-coyote.jar:8.5.13]
at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:670) ~[tomcat-coyote.jar:8.5.13]
at org.apache.tomcat.util.net.SocketWrapperBase.writeBlocking(SocketWrapperBase.java:450) ~[tomcat-coyote.jar:8.5.13]
at org.apache.tomcat.util.net.SocketWrapperBase.write(SocketWrapperBase.java:388) ~[tomcat-coyote.jar:8.5.13]
at org.apache.coyote.http11.Http11OutputBuffer$SocketOutputBuffer.doWrite(Http11OutputBuffer.java:644) ~[tomcat-coyote.jar:8.5.13]
at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:123) ~[tomcat-coyote.jar:8.5.13]
at org.apache.coyote.http11.Http11OutputBuffer.doWrite(Http11OutputBuffer.java:235) ~[tomcat-coyote.jar:8.5.13]
at org.apache.coyote.Response.doWrite(Response.java:518) ~[tomcat-coyote.jar:8.5.13]
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:351) ~[catalina.jar:8.5.13]
... 79 more
Upvotes: 2
Views: 1628
Reputation: 633
Had the same problem in Spring Boot with spring security. I could not stream a video in HttpServletResponse outputStream. Solved it with Java configuration.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers().disable()
.authorizeRequests()
.antMatchers("/").permitAll() // home page
.anyRequest().authenticated();
}
//... other methods
}
Upvotes: 2
Reputation: 41
Found the answer in the Spring 3 to 4 migration guide
Migrating from Spring Security 3.x to 4.x (XML Configuration)
Section 6.6 Migrating headers
As Spring Security 4.0+ Security HTTP Response Headers is now enabled by default.
Presence of the headers was (somehow) blocking the download stream.
Suggestion: start the migration by adding the csrf and headers tags to the configuration to get it running and then try to understand whether disabling these features is acceptable or not. Also, read the guide, it may save you some time... strangely :-)
<security:http auto-config='true' use-expressions="true" realm="Illustration System">
<security:intercept-url pattern="/**" access="isFullyAuthenticated()" />
<security:http-basic />
<security:csrf disabled="true"/>
<security:headers disabled="true"/>
</security:http>
Upvotes: 2