Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring SecurityContext returning null authentication on error pages

I am trying to write a custom error page for errors like 403 (access denied) and 500 (internal server error). They would be rendered from Velocity template and have all messages translated using user's locale. Authentication and locale resolution works fine in the application.

I set up location in web.xml to be the desired page and in webmvc-context.xml I added requet-to-view controller via .

The problem I ran into is that SecurityContextHolder.getContext().getAuthentication() returns null in the error page view. Looking at the log I saw:

06.10 14:42:26 DEBUG - context.HttpSessionSecurityContextRepository(HttpSessionSecurityContextRepository.java:351) -  - SecurityContext stored to HttpSession: 'org.springframework.security.core.context.SecurityContextImpl@ece7b0b7: Authentication: ...
06.10 14:42:26 DEBUG - context.SecurityContextPersistenceFilter(SecurityContextPersistenceFilter.java:89) -  - SecurityContextHolder now cleared, as request processing completed
06.10 14:42:26 DEBUG - servlet.DispatcherServlet(DispatcherServlet.java:691) -  - DispatcherServlet with name 'foo' processing GET request for [/foo/app/error/403.html]

So either Spring or Tomcat redirect to an error page and the request gest finalized, thus the context is cleared. And the new "request" doesn't undergo Spring Security filters, thus not restoring the context.

The usual way doesn't work, but it seems that the authentication information is somewhere in the session, also because AbstractTemplateView logs the following:

Exposing session attribute 'SPRING_SECURITY_CONTEXT' with value [org.springframework.security.core.context.SecurityContextImpl@edfbd958: Authentication: org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken@edfbd958...

How do I properly get so that both normal and error pages would act the same?

like image 549
Infeligo Avatar asked Jun 10 '11 11:06

Infeligo


2 Answers

The problem you're running into is that the ExceptionTranslationFilter which translates exceptions into error pages comes before the SecurityContextPersistenceFilter which pulls the authentication out of the SecurityContextRepository and puts it into the SecurityContextHolder. When the request finishes the SecurityContextPersistenceFilter takes the information back out of the SecurityContextHolder.

The reason it clears the SecurityContextHolder is that the SecurityContextHolder is typically thread local and if the servlet container were to reuse a thread (most do this) they might accidentally give those credentials to someone else.

Typically the ExceptionTranslationFilter is the outermost filter to avoid the risk of any exceptions not getting translated.

Your best bet is to probably write a custom ExceptionTranslationFilter which takes in the SecurityContextRepository (often the HTTP session as you mentioned) and provides access to the Authentication via the SecurityContextRepository and not the SecurityContextHolder. Keep in mind that the Authentication will still be null if the user isn't logged in.

like image 188
Pace Avatar answered Sep 24 '22 02:09

Pace


The problem may be that springSecurityFilterChain is not intercepting ERRORS. Try changing your mapping in web.xml to be

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
like image 39
Ankur Raiyani Avatar answered Sep 20 '22 02:09

Ankur Raiyani