Spring security - Custom filter and entry point for rest service

Viewed 3225

I need to develop the security of a rest service wirh Spring Security (version 4.0.3. RELEASE).

The scenario is:

  1. authenticate the client performing the request (client id + client token on custom header)
  2. in case of errors, a JSON response needs to be sent

I created a custom OncePerRequestFilter that does the job of reading a custom token just as if it was a basic auth token.

public class MyClientAuthorizationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // omitting implementation
    }

}

Then I created my own AuthenticationEntryPoint that does the job of writing the JSON error in the response.

public class MyAuthorizationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        // omitting implementation
    }

}

Then I wired them up like that:

@Configuration
@EnableWebSecurity
public class WebApiSecurityConfig extends WebSecurityConfigurerAdapter implements TogatherWebApiCostants {

    private static final Logger log = LoggerFactory.getLogger(WebApiSecurityConfig.class);

    private @Inject Environment environment;

    @Bean
    protected AuthenticationEntryPoint clientAuthorizationEntryPoint() {
        return new MyAuthorizationEntryPoint();
    }

    @Bean
    protected Filter clientAuthorizationFilter() {
        return new MyAuthorizationFilter();
    }

    /**
     * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        log.debug("Configuring HTTP security");

        // @formatter:on
        http
            .addFilterBefore(clientAuthorizationFilter(), BasicAuthenticationFilter.class)
            .exceptionHandling().authenticationEntryPoint(clientAuthorizationEntryPoint());
        // @formatter:off
    }

}

Everything works, except the custom entry point. It doesn't get fired and it seems Spring is still using the default one. I've also tried to switch to XML config (I'm much more used to it rather than with JavaConfig approach) but the behavior remains the same.

Can anyone tell me what I'm doing wrong?

NOTE: I tried to debug Spring Security by adding a logger org.springframework.security with level set to debug, but I dont see any log message

~~~~~~~~~~~~~~

EDIT: Adding current workaround

As of now, lacking an elegant solution, I just explicitly called the entry point from the filter.

public class MyClientAuthorizationFilter extends OncePerRequestFilter {

    ...
    private @Inject AuthenticationEntryPoint entryPoint;
    ...

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            // omitting logic
        } catch(AuthenticationException ae) {
            SecurityContextHolder.clearContext();
            entryPoint.commence(request, response, ae);
            return;         
        }
    }

}
2 Answers

It looks that you are passing wrong object in authenticationEntryPoint() of WebApiSecurityConfig implementation class, pass AuthenticationEntryPoint implementation class object which is here TogatherWebApiClientAuthorizationEntryPoint and check if you are getting custom error.

You should paste your filter after ExceptionTranslationFilter

@Override
protected void configure(HttpSecurity http) throws Exception {
    log.debug("Configuring HTTP security");

    // @formatter:on
    http
        .addFilterAfter(clientAuthorizationFilter(), ExceptionTranslationFilter.class)
        .exceptionHandling().authenticationEntryPoint(clientAuthorizationEntryPoint());
    // @formatter:off
}
Related