session events dont work in spring session - java

My app uses http and stomp over WebSocket. So i need to refresh my httpSession when user uses WebSockets So to not invent bicycles i decided to use Spring Session, as this provides clear integration between Http and WebSockets. But i was faced with a problem. When i used TOMCAT SESSION implementation i had this listener:
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(new HttpSessionEventPublisher());
...
}
And it had worked just perfect. Session registry received a SessionDestroyEvent and destroyed a session.
Now, with Spring Session based on H2, it doesn't work.
I tried different approach like this:
#Bean
public HttpSessionEventPublisher httpSessionPublisher() {
return new HttpSessionEventPublisher();
}
#Bean
public HttpSessionListener httpSessionListener() {
return new HttpSessionListener() {
#Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("I EXIST");
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("I EXIST");
}
};
}
But it doesn't work too.
I use SpringSession with H2 storage, my config is:
#EnableJdbcHttpSession(maxInactiveIntervalInSeconds = 15)
public class H2SessionConfig {
#Bean(name = "session_dataSource")
public EmbeddedDatabase dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("org/springframework/session/jdbc/schema-h2.sql").build();
}
#Bean
public PlatformTransactionManager transactionManager(#Qualifier("session_dataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
#Bean
public HttpSessionListener httpSessionListener() {
return new HttpSessionListener() {
#Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("I EXIST");
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("I EXIST");
}
};
}
#Bean
public HttpSessionEventPublisher httpSessionPublisher() {
return new HttpSessionEventPublisher();
}
}
Thank you in advance.

Spring Session JDBC does not support publishing of session events due to obvious limitations of a RDBMS in that regard.
This limitation is documented both in reference manual and JdbcOperationsSessionRepository javadoc.

Related

How to extract claims from token in Resource Server, in Spring Boot

My authentication server is configured to retrieve check credentials against a table on my database, with a token enhancer which I use to pass additional claims - access control related stuff.
As such, I've written it like this:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Value("${security.signing-key}")
private String signingKey;
private #Autowired TokenStore tokenStore;
private #Autowired AuthenticationManager authenticationManager;
private #Autowired CustomUserDetailsService userDetailsService;
private #Autowired JwtAccessTokenConverter accessTokenConverter;
private static final Logger LOGGER = LogManager.getLogger(AuthorizationServerConfig.class);
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource oauthDataSource() {
DataSource ds = null;
try {
Context initialContex = new InitialContext();
ds = (DataSource) (initialContex.lookup("java:/jdbc/oauthdatasource"));
if (ds != null) {
ds.getConnection();
}
} catch (NamingException ex) {
LOGGER.error("Naming exception thrown: ", ex);
} catch (SQLException ex) {
LOGGER.info("SQL exception thrown: ", ex);
}
return ds;
}
#Bean
public JdbcClientDetailsService clientDetailsServices() {
return new JdbcClientDetailsService(oauthDataSource());
}
#Bean
public TokenStore tokenStore() {
return new CustomJdbcTokenStore(oauthDataSource());
}
#Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(oauthDataSource());
}
#Bean
public AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(oauthDataSource());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
CustomTokenEnhancer converter = new CustomTokenEnhancer();
converter.setSigningKey(signingKey);
return converter;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsServices());
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.accessTokenConverter(accessTokenConverter)
.userDetailsService(userDetailsService)
.reuseRefreshTokens(false);
}
}
This works very fine. When I make a call via POSTMAN, I get something like this:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsic2hhcmVwb3J0YWwiXSwiaW5mb19maXJzdCI6IlRoaXMgaXMgdGhlIGZpcnN0IEluZm8iLCJ1c2VyX25hbWUiOiJBdXRoZW50aWNhdGlvbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSIsInRydXN0Il0sImluZm9fc2Vjb25kIjoiVGhpcyBpcyB0aGUgc2Vjb25kIGluZm8iLCJleHAiOjE1ODA3MTMyOTQsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiI1MTg4MGJhZC00MGJiLTQ3ZTItODRjZS1lNDUyNGY1Y2Y3MzciLCJjbGllbnRfaWQiOiJzaGFyZXBvcnRhbC1jbGllbnQifQ.ABmBjwmVDb2acZtGSQrjKcCwfZwhw4R_rpW4y5JA1jY",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsic2hhcmVwb3J0YWwiXSwiaW5mb19maXJzdCI6IlRoaXMgaXMgdGhlIGZpcnN0IEluZm8iLCJ1c2VyX25hbWUiOiJBdXRoZW50aWNhdGlvbiIsInNjb3BlIjpbInJlYWQiLCJ3cml0ZSIsInRydXN0Il0sImF0aSI6IjUxODgwYmFkLTQwYmItNDdlMi04NGNlLWU0NTI0ZjVjZjczNyIsImluZm9fc2Vjb25kIjoiVGhpcyBpcyB0aGUgc2Vjb25kIGluZm8iLCJleHAiOjE1ODA3MTM0MzQsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiIyZDYxMDU2ZC01ZDMwLTRhZTQtOWMxZC0zZjliYjRiOWYxOGIiLCJjbGllbnRfaWQiOiJzaGFyZXBvcnRhbC1jbGllbnQifQ.qSLpJm4QxZTIVn1WYWH7EFBS8ryjF1hsD6RSRrEBZd0",
"expires_in": 359,
"scope": "read write trust"
}
The problem now is my resource server. This is how it used to be before I added a token enhancer to my authentication server:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private #Autowired CustomAuthenticationEntryPoint entryPoint;
private #Autowired TokenStore tokenStore;
private static final String RESOURCE_ID = "resourceid";
private static final Logger LOGGER = LogManager.getLogger(ResourceServerConfig.class);
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource oauthDataSource() {
DataSource ds = null;
try {
Context initialContex = new InitialContext();
ds = (DataSource) (initialContex.lookup("java:/jdbc/oauthdatasource"));
if (ds != null) {
ds.getConnection();
}
} catch (NamingException ex) {
LOGGER.error("Naming exception thrown: ", ex);
} catch (SQLException ex) {
LOGGER.info("SQL exception thrown: ", ex);
}
return ds;
}
#Bean
public TokenStore getTokenStore() {
return new JdbcTokenStore(oauthDataSource());
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')")
.antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')")
.and()
.headers().addHeaderWriter((request, response) -> {
response.addHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
}
})
.and().exceptionHandling().authenticationEntryPoint(entryPoint);
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID).tokenStore(tokenStore).authenticationEntryPoint(entryPoint);
}
}
I wish to retrieve the access control information I've placed as additional claims via the authentication server, but I don't know how to go about it.
I saw a couple of examples on the internet, including this: How to extract claims from Spring Security OAuht2 Boot in the Resource Server?, but none of them are working for me. Or maybe I'm missing something.
Please, what do I have to add to make this possible?
I had to use a third-party library to achieve this.
This is the link to the library: https://github.com/auth0/java-jwt
It works really well.
In my resource server, I can get my token value, and then using the java-jwt library, I can extract any claims I've set in my authorization server:
public Map<String, Claim> getClaims() {
Map<String, Claim> claims = new HashMap<>();
String tokenValue = ((OAuth2AuthenticationDetails)((OAuth2Authentication) authenticationFacade.getAuthentication()).getDetails()).getTokenValue();
try {
DecodedJWT jwt = JWT.decode(tokenValue);
claims = jwt.getClaims();
} catch (JWTDecodeException ex) {
LOGGER.info("Error decoding token value");
LOGGER.error("Error decoding token value", ex);
}
return claims;
}
You should look at the documentation for java-jwt to learn more.

How do you make a secure websocket conneciton with Java on the client side?

There doesn't seem to a clean and simple example of creating a secure websocket connection anywhere on the interwebs, nor instructions to set one up... any ideas?
I would provide some guidelines for websocket authentication. Since websocket is upgraded from http, the authentication is based on http too. You can equip the http connection with ssl or basic or digest auth.
I had worked with spring websocket auth before, ssl is just to upgrade http to https. I would post digest auth for spring websocket here.
1.Configure the server to user digest auth, spring security can get it:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public final static String REALM="MY_REALM";
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN")
.and().withUser("test").password("test").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().exceptionHandling().authenticationEntryPoint(getDigestEntryPoint())
.and().addFilter(getDigestAuthenticationFilter(getDigestEntryPoint()));
}
#Bean
public MyDigestAuthenticationEntryPoint getDigestEntryPoint() {
MyDigestAuthenticationEntryPoint digestAuthenticationEntryPoint = new MyDigestAuthenticationEntryPoint();
digestAuthenticationEntryPoint.setKey("mykey");
digestAuthenticationEntryPoint.setNonceValiditySeconds(120);
digestAuthenticationEntryPoint.setRealmName(REALM);
return digestAuthenticationEntryPoint;
}
public DigestAuthenticationFilter getDigestAuthenticationFilter(
MyDigestAuthenticationEntryPoint digestAuthenticationEntryPoint) throws Exception {
DigestAuthenticationFilter digestAuthenticationFilter = new DigestAuthenticationFilter();
digestAuthenticationFilter.setAuthenticationEntryPoint(digestAuthenticationEntryPoint);
digestAuthenticationFilter.setUserDetailsService(userDetailsServiceBean());
return digestAuthenticationFilter;
}
#Override
#Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
}
public class MyDigestAuthenticationEntryPoint extends DigestAuthenticationEntryPoint {
#Override
public void afterPropertiesSet() throws Exception{
super.afterPropertiesSet();
setRealmName(WebSecurityConfig.REALM);
}
}
2.Extend from AbstractSecurityWebSocketMessageBrokerConfigurer:
#Configuration
#EnableWebSocketMessageBroker
public class WssBrokerConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.nullDestMatcher().authenticated()
.simpSubscribeDestMatchers("/topic/notification").permitAll()
.simpDestMatchers("/**").authenticated()
.anyMessage().denyAll();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/ws");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hpdm-ws").setAllowedOrigins("*").withSockJS();
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
MappingJackson2HttpMessageConverter converter =
new MappingJackson2HttpMessageConverter(mapper);
return converter;
}
#Override
protected boolean sameOriginDisabled() {
return true;
}
}
3.Digest auth for client refer to this post:
spring websocket with digest authentication

Extracting Remote endpoint Object from Spring websocket session

In javax websockets we can use something like the follows
Session.getAsyncRemote().sendText(String text)
Session.getBasicRemote().sendText();
How can we send an asynchronous messages using spring websocket.
From WebSocketSession of spring webscockets can we extract RemoteEndPoint and send an async messages
PS Note: I am using Basic Spring websockets...
The configuration and code is as follows:
#Configuration
#EnableWebMvc
#EnableAspectJAutoProxy
#EnableWebSocket
public class WebMVCConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
private static final String ENDPOINT_URL = "/echo";
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(socketHandler(), ENDPOINT_URL).setAllowedOrigins("*");
}
#Bean
public WebSocketHandler socketHandler() {
return new WebSocketTestHandler();
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public DefaultHandshakeHandler handshakeHandler() {
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setInputBufferSize(8192);
policy.setIdleTimeout(600000);
return new DefaultHandshakeHandler(new JettyRequestUpgradeStrategy(new WebSocketServerFactory(policy)));
}
public class SpringMVCInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { ApplicationConfig.class, RabbitMQConfig.class, RabbitConnectionFactory.class,
WebPropertyPlaceHolderConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
}
#Configuration
public class WebSocketTestHandler extends TextWebSocketHandler {
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
log.info("Connection is established to Server....:: Session Open : {}", session.isOpen());
}
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
}
#Override
public void afterConnectionClosed(WebSocketSession curSession, CloseStatus status) throws Exception {
}
}
So inside handleTextMessage(WebSocketSession session,TextMessage message) {
Inside this method am creating multiple threads And sending same session Object and some other parameters..Inside each thread am not modifying any session object related parameters but am trying to execute
TextMessage socketMessage = new TextMessage(message);
session.sendMessage(socketMessage);
}
So each thread is trying to send messages using same session Object..But am facing the following error
java.lang.IllegalStateException: Blocking message pending 10000 for BLOCKING
at org.eclipse.jetty.websocket.common.WebSocketRemoteEndpoint.lockMsg(WebSocketRemoteEndpoint.java:130) ~[websocket-common-9.3.8.v20160314.jar:9.3.8.v20160314]
at org.eclipse.jetty.websocket.common.WebSocketRemoteEndpoint.sendString(WebSocketRemoteEndpoint.java:379) ~[websocket-common-9.3.8.v20160314.jar:9.3.8.v20160314]
at org.springframework.web.socket.adapter.jetty.JettyWebSocketSession.sendTextMessage(JettyWebSocketSession.java:188) ~[spring-websocket-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.socket.adapter.AbstractWebSocketSession.sendMessage(AbstractWebSocketSession.java:105) ~[spring-websocket-4.2.4.RELEASE.jar:4.2.4.RELEASE]
So is it possible to send asynchronous messages using spring websockets?
If yes please let me know what configuration changes are required in the above code..Or Can we extract the core AsyncRemoteEndPoint and BasicRemoteEndpoint from spring Websocket Session and can we send asynchronous messages..or if not both the above cases ..move the code to common place and put synchonized(sessionObject)
{
sendmessage
}..Sorry if the framing of question is not clear or already a duplicate question
Please note I am not using any Stomp client or anyother features over spring websocket..Am using plain spring websockets..And is it possible to do without using Future(java feature)(If yes..it would be better)?
I used ConcurrentWebSocketSessionDecorator on the session.
according to:
https://jira.spring.io/browse/SPR-13602
The decorator "enforces sending messages one at a time with a send buffer and send time limit per session. That helps quite a bit to limit the impact of slow clients"

Spring-boot jersey : resources not autodiscover

I try to use Spring-boot with jetty and jersey.
No problem with the jetty part. I can start server and spring resources are running (trace, metrics,info,beans,....) but my resources didn't run.
My configuration files are :
Launcher.java
#Configuration
#PropertySource("classpath:application.properties")
#EnableAutoConfiguration
#ComponentScan(basePackages = {"com.fdilogbox.report.serveur"})
public class Launcher extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(Launcher.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Launcher.class);
}
#Bean
public ServletRegistrationBean jerseyServlet() {
ServletRegistrationBean registration = new ServletRegistrationBean(new ServletContainer(), "/api/*");
registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, ResourcesConfiguration.class.getName());
return registration;
}
#Bean
public EmbeddedServletContainerFactory containerFactory() {
final JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory = new JettyEmbeddedServletContainerFactory() {
#Override
protected JettyEmbeddedServletContainer getJettyEmbeddedServletContainer(Server server) {
return new JettyEmbeddedServletContainer(server);
}
};
jettyEmbeddedServletContainerFactory.addServerCustomizers(new JettyConfiguration());
return jettyEmbeddedServletContainerFactory;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
JettyConfiguration.java
public class JettyConfiguration implements JettyServerCustomizer {
#Override
public void customize(Server server) {
WebAppContext webAppContext = (WebAppContext) server.getHandler();
try {
// Load configuration from resource file (standard Jetty xml configuration) and configure the context.
createConfiguration("/jetty.xml").configure(webAppContext);
createConfiguration("/jetty-rewrite.xml").configure(server);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private XmlConfiguration createConfiguration(String xml) throws IOException, SAXException {
return new XmlConfiguration(Launcher.class.getResourceAsStream(xml));
}
}
ResourcesConfiguration.java
public class ResourcesConfiguration extends ResourceConfig {
public ResourcesConfiguration() {
super();
PackageNamesScanner resourceFinder = new PackageNamesScanner(new String[]{"com.fdilogbox.report.serveur.business.resources"}, true);
registerFinder(resourceFinder);
register(JacksonFeature.class);
}
}
and my resources file :
#Path("builder")
#Component
public class ReportBuilderResource {
#Autowired
private ReportBuilderService reportBuilderService;
#GET
#Path("list")
#Produces(MediaType.APPLICATION_JSON)
public String[] findAll() {
return reportBuilderService.findAllReport();
}
}
If I try to acces "localhost:9090/api/builder/list" I get an 404 error.
But if I try "localhost:9090/bean" I get all bean on JSon format.
I think I have an error in my conf but I don't know where.
I found my mistake : management port is 9090 but the normal resources port is 8090.

How to disable ErrorPageFilter in Spring Boot?

I'm creating a SOAP service that should be running on Tomcat.
I'm using Spring Boot for my application, similar to:
#Configuration
#EnableAutoConfiguration(exclude = ErrorMvcAutoConfiguration.class)
public class AppConfig {
}
My webservice (example):
#Component
#WebService
public class MyWebservice {
#WebMethod
#WebResult
public String test() {
throw new MyException();
}
}
#WebFault
public class MyException extends Exception {
}
Problem:
Whenever I throw an exception within the webservice class, the following message is logged on the server:
ErrorPageFilter: Cannot forward to error page for request
[/services/MyWebservice] as the response has already been committed.
As a result, the response may have the wrong status code. If your
application is running on WebSphere Application Server you may be able
to resolve this problem by setting
com.ibm.ws.webcontainer.invokeFlushAfterService to false
Question:
How can I prevent this?
To disable the ErrorPageFilter in Spring Boot (tested with 1.3.0.RELEASE), add the following beans to your Spring configuration:
#Bean
public ErrorPageFilter errorPageFilter() {
return new ErrorPageFilter();
}
#Bean
public FilterRegistrationBean disableSpringBootErrorFilter(ErrorPageFilter filter) {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(filter);
filterRegistrationBean.setEnabled(false);
return filterRegistrationBean;
}
The simpliest way to disable ErrorPageFilter is:
#SpringBootApplication
public class App extends SpringBootServletInitializer {
public App() {
super();
setRegisterErrorPageFilter(false); // <- this one
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(App.class);
}
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
#SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
//set register error pagefilter false
setRegisterErrorPageFilter(false);
builder.sources(MyApplication.class);
return builder;
}
}
The best way is to tell the WebSphere container to stop ErrorPageFiltering. To achieve this we have to define a property in the server.xml file.
<webContainer throwExceptionWhenUnableToCompleteOrDispatch="false" invokeFlushAfterService="false"></webContainer>
Alternatively, you also can disable it in the spring application.properties file
logging.level.org.springframework.boot.context.web.ErrorPageFilter=off
I prefer the first way.Hope this helps.
I found in the sources that the ErrorPageFilter.java has the following code:
private void doFilter(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
ErrorWrapperResponse wrapped = new ErrorWrapperResponse(response);
try {
chain.doFilter(request, wrapped);
int status = wrapped.getStatus();
if (status >= 400) {
handleErrorStatus(request, response, status, wrapped.getMessage());
response.flushBuffer();
}
else if (!request.isAsyncStarted() && !response.isCommitted()) {
response.flushBuffer();
}
}
catch (Throwable ex) {
handleException(request, response, wrapped, ex);
response.flushBuffer();
}
}
As you can see when you throw an exception and return a response code >= 400 it will do some code. there should be some additional check if the response was already committed or not.
The way to remove the ErrorPageFilter is like this
protected WebApplicationContext run(SpringApplication application) {
application.getSources().remove(ErrorPageFilter.class);
return super.run(application);
}
Chris
public class Application extends SpringBootServletInitializer
{
private static final Logger logger = LogManager.getLogger(Application.class);
public Application()
{
super();
setRegisterErrorPageFilter(false);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}

Categories

Resources