4

Providing an AuthenticationSuccessHandler for a RememberMeAuthenticationFilter breaks the filter chain, therefore I would like to override its onSuccessfulAuthentication method by providing a custom implementation of RememberMeAuthenticationFilter. But that seems to be quite complicated or elaborate when using simple Java Config.

Providing an ApplicationEventPublisher is not a solution if one needs access to HttpServletRequest or HttpServletResponse.

I managed to do it, but it looks like a hack - is there a better way?

I've done it this way:

http.rememberMe().addObjectPostProcessor(new ObjectPostProcessor<RememberMeAuthenticationFilter>() {

    @Override
    public <O extends RememberMeAuthenticationFilter> O postProcess(O object) {

        RememberMeAuthenticationFilter newFilter = new RememberMeAuthenticationFilter(
                (AuthenticationManager) getByReflection(object, "authenticationManager"),
                (RememberMeServices) getByReflection(object, "rememberMeServices")
        ) {
            @Override
            protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) {
                // business logic
            }
        };
        return (O) newFilter;
    }

    private <O extends RememberMeAuthenticationFilter> Object getByReflection(O object, String name) {
        Field field = ReflectionUtils.findField(object.getClass(), name);
        ReflectionUtils.makeAccessible(field);
        return ReflectionUtils.getField(field, object);
    }
});

Lemmy
  • 2,437
  • 1
  • 22
  • 30
bgraves
  • 788
  • 1
  • 11
  • 23

1 Answers1

5

If you want to implement a custom behavior when authentication process (with remember me feature) is success you can try:

CustomRememberMeAuthenticationFilter

Define a new filter such as:

public class CustomRememberMeAuthenticationFilter extends RememberMeAuthenticationFilter {
  @Override
  protected void onSuccessfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final Authentication authResult) {
    super.onSuccessfulAuthentication(request, response, authResult);
    if (authResult != null) {
        // process post authentication logic here..
    }
  }
}

Set the customer filer in security chain:

@Override
protected void configure(HttpSecurity http) throws Exception {
  http
    .csrf().disable()
    .authorizeRequests()
    .antMatchers("/","/login*").permitAll()
    //...
  http
    .addFilter(rememberMeAuthenticationFilter())
    //...
}

@Bean
protected RememberMeAuthenticationFilter rememberMeAuthenticationFilter(){
    return new CustomRememberMeAuthenticationFilter(authenticationManager(),rememberMeServices());
}

Check this in order to create your (authenticationManager(),rememberMeServices()

In the previous snippet, custom filter is just added. If does not works, you must research and find the exact Filter in the chain to insert your custom filter: addFilterBefore, addFilterAfter, addFilterAt.

Check this add filter methods

Finally remove the default http.rememberMe() in order to use your own filter. Because the remember-me namespace element already inserts a RememberMeAuthenticationFilter so it will still take precedence over yours, since it comes before it in the filter chain.

References

JRichardsz
  • 14,356
  • 6
  • 59
  • 94
  • 1
    Many thanks for your detailed answer! I (already) know it's *possible* that way, but it would require much more code compared to the hack I presented above. The `RememberMeConfigurer` created by `http.rememberMe()` does so many complex things which I do not want to repeat. But probably there is no easy way to achieve that. – bgraves May 25 '20 at 16:21