Spring boot with embedded tomcat + access log with authentication user
Asked Answered
T

2

13

I'm using spring boot with embedded tomcat + spring security. My access log from tomcat seems like this

IP - - [14/Feb/2017:08:49:50 +0200] "GET /page/2 HTTP/1.1" 200 2606

So, how can i make log file to looks like

IP - - [14/Feb/2017:08:49:50 +0200] username - "GET /page/2 HTTP/1.1" 200 2606

Every request have to have the username from which is made. For security authentication i'm using spring security with database username and password info.

Thermionic answered 14/2, 2017 at 7:50 Comment(1)
Nice question, btwElrod
E
12

You probably need to change access log pattern in application properties to something like this:

server.tomcat.accesslog.pattern=%h %l %t %u "%r" %s %b

where %u is Remote user that has been authenticated (see example here).


UPD: Possibly this is not sufficient as common pattern already contains %u parameter. In this case I would recommend two additional steps:

  1. Put user's name into request session parameter, something like:

request.getSession().setAttribute("username", user.getName());

  1. Add following parameter in access log pattern: %{username}s

    server.tomcat.accesslog.pattern=%h %l %t %u %{username}s "%r" %s %b

which should take attribute named username from HttpSession as it described here.

Elrod answered 14/2, 2017 at 8:15 Comment(3)
How to deal with STATELESS session policy with this solution? Any ideas?Gyatt
above approach seems to work for stateless also if added in a request filter (ex jwt validator). Alternatively you can set the attribute in the request like request.setAttribute("username", user.getName()); and use %{username}r.Hortative
This stateless solution did not work here. As a matter of fact, the first request using session also didn't work. I can only imagine that the request came in and got registered in the accesslog before any filter could do anything. The following requests using the same session worked.Inequitable
D
1

Just to add a full example of how I managed to do this. Since the existing answer didn't provide a very detailed explanation on how to obtain this goal.

In your spring web security config type following lines.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    return http
            .csrf().disable()
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .httpBasic()
            .and()
            .addFilterAfter(usernameAccessLogFilter(), BasicAuthenticationFilter.class)
            .build();
}

@Bean
    public UsernameAccessLogFilter usernameAccessLogFilter(){
        return new UsernameAccessLogFilter();
    }

Then create a custom filter:

public class UsernameAccessLogFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = ((HttpServletRequest) servletRequest);

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if(authentication != null) {
        request.getSession().setAttribute("user", authentication.getName());
    }
    filterChain.doFilter(servletRequest, servletResponse);
}

}

In your properties file (.yml format) add following:

server:
  tomcat:
    accesslog:
      enabled: true
      directory: logs
      pattern: "%t %a %A %r %s %u %{user}s %B %T %I"
    basedir: .

This was everything I had to do to obtain the above result.

Decillion answered 25/8, 2022 at 13:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.