2

We're using Spring Security to secure our Spring web application. In fact we're using a Spring Social authentication filter. It was not easy to get it working, but it works now and everything is great.

The only thing missing is that the user name doesn't appear in the Tomcat logs. In Tomcat, if I use good old fashioned BASIC authentication, the logged in user appears nicely in the logs. That is very helpful. I want to know which authorized user is doing certain things, for analytics etc.

I know that Tomcat logs the user based on httpServletRequest.getRemoteUser(). Spring stores user info as SecurityContextHolder.getSecurityContext().getPrincipal().

I looked around at the Spring documentation and it looks like I need to add the SecurityContextHolderAwareRequestFilter to the chain, which will wrap the HttpServletRequest and provide useful implementations of getSecurityContext() and other methods.

I tried to add that to my Java SecurityConfiguration class, like this:

@Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .addFilter(new SecurityContextHolderAwareRequestFilter())

but when I do that, I get an exception:

java.lang.NullPointerException
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)

I can see clearly what is going on. At that line in SecurityContextHolderAwareRequestFilter, it is:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {
chain.doFilter(requestFactory.create((HttpServletRequest)req, (HttpServletResponse) res), res);
}

Either the chain parameter is null (not likely) or the requestFactory member is null.

Looking at the code some more, it looks like the requestFactory member is created by calling afterPropertiesSet(). When is the right spot for making that call? Is this whole approach even the right approach?

Can anyone tell me what's the right way to do this? Surely there's some correct way to get the user name to show up in Tomcat logs?

Thanks

user2959589
  • 362
  • 1
  • 9
  • 23

1 Answers1

3

If you're talking about Tomcat's access log valve, this won't work, since Tomcat is unaware of Spring Security, which operates entirely within your application.

SecurityContextHolderAwareRequestFilter is usually enabled by default, but its effects don't apply to parts of the call stack above where it lies in the filter chain. This should be obvious from the doFilter method you've posted above. The wrapped request created by requestFactory is only visible below that point in the filter chain.

The easiest option would be to just add your own filter (e.g. in web.xml) after Spring Security, and dump the information you want to a log. Or you can use it to set the username in the MDC for a logging package such as log4j or logback, which will allow you you to add it to your logging pattern. See the UserServletFilter in the above link for an example.

Shaun the Sheep
  • 22,353
  • 1
  • 72
  • 100