4

I have a springboot micro service. This is called by a React client. The react client authenticates the user via a login form and logs her in. It uses our custom Authentication service for that. After a successful login, a JWT kind of token is issued and saved in browser's local storage which then is submitted by the client in HTTP Authorization header when calling the microservice. Here's a code snippet from my implementation.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // ...  
    @Override
    protected void configure(HttpSecurity http) throws Exception {
      super.configure(http);
      http.csrf().disable().headers().frameOptions().disable()
      .and().sessionManagement()
      .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
      .and().authorizeRequests().antMatchers("/api/**").authenticated()
      .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
      .antMatchers("/swagger-resources/configuration/ui").permitAll()
      .antMatchers("/health/**").permitAll()
      .and()
      .addFilterBefore(new JWTAuthorizationFilter(new MyAuthenticationProvider()),
                        UsernamePasswordAuthenticationFilter.class);
    }
}

I have my own AuthenticationProvider implementation for doing the actual authentication against our internal auth service. Here's my filter class. I have removed unnecessary code for the sake of simplicity.

public class JWTAuthorizationFilter extends OncePerRequestFilter {
    private static final String UNAUTHORIZED_ERROR = "UNAUTHORIZED";
    public static final String X_AUTHORIZATION_HEADER = "X-Authorization";
    private static final String BEARER = "Bearer ";
    private final Logger log = LoggerFactory.getLogger(JWTAuthorizationFilter.class);
    private final AuthenticationProvider authenticationProvider;

    public JWTAuthorizationFilter(AuthenticationProvider authProvider) {
        super();
        this.authenticationProvider = authProvider;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        try {
            String token = resolveToken(request);
            Authentication authentication = this.authenticationProvider
                    .authenticate(new UsernamePasswordAuthenticationToken(null, token));
            SecurityContextHolder.getContext().setAuthentication(authentication);
            // invoking the next chain in the filter.
            filterChain.doFilter(request, response);
        } catch (AuthenticationException e) {
            log.error("Security exception for user {} - {}", e.getMessage());
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, UNAUTHORIZED_ERROR);
        }
    }

    private String resolveToken(HttpServletRequest request) {
        return request.getHeader(X_AUTHORIZATION_HEADER);
    }
}

Everything works fine. Then I had a code review and at that moment a coulegue asked me to use AbstractAuthenticationProcessingFilter instead of OncePerRequestFilter/GenericFilterBean. I checked the documentation [1], and it says that the AbstractAuthenticationProcessingFilter is mainly used for browser-based HTTP-based authentication requests.

By the way I tried implementing that by moving around my currently working logic there, and hooked it up with my springboot microservice. But unfortunately when I send a request it gives me 301 moved permanently HTTP status code with some HTML for a login form.

Here's my question.

  1. Can I use AbstractAuthenticationProcessingFilter for this token authentication. If so how it can be done?
  2. Why I am getting 301 moved permanently ERROR after hooking it up with my service.
  3. Are there any possible errors, vulnerabilities, or performance issues that might occur with my current approach?
  4. What other ways are there for token based authentication, and what are their pros and cons?

I checked out the spring security reference guide, but could not find concrete answers to the above questions.

Unfortunately I can't share my code, since it uses some proprietary libraries which are internal to the organization. My apologies for that. Any help is appreciated.

[1] https://docs.spring.io/autorepo/docs/spring-security/4.0.3.RELEASE/apidocs/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html

diginoise
  • 7,352
  • 2
  • 31
  • 39
Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
  • It's a strange thing you get 301 and not 403. Are you sure you go in the filter and it refuses access ? It seems more like the microservice config got messed up and it stopped working. – Veselin Davidov Oct 19 '17 at 14:28
  • Yes, that should be the reason. But why it is happening? I just need to know whether that suggested approach is correct or are they suggesting the wrong tool for this purpose? `GenericFilterBean` works perfectly with the same security config. – Ravindra Ranwala Oct 19 '17 at 14:30
  • I would say it depends on what you want. If you want service with guaranteed singleton execution per any request (as stated in OncePerRequestFilter) you can use that - no problem. The other one is more standard and often given in the examples - check https://auth0.com/blog/securing-spring-boot-with-jwts/ – Veselin Davidov Oct 19 '17 at 14:38
  • @VeselinDavidov They still have used `AbstractAuthenticationProcessingFilter` for form based login, if you check it very carefully. See the `JWTLoginFilter`, all it does is collect username and password, create the token and return it in response header. That is not what I need. Also I don't need to guaranteed singleton execution per any request, the reason I used that subtype since it directly gives me `HttpServletRequest` instead of `ServletRequest` so I can get rid of casting when I get the token here `final String bearerToken = request.getHeader(AUTHORIZATION_HEADER)` – Ravindra Ranwala Oct 19 '17 at 14:44
  • @araknoid The OP's questions 1 and especially 2 would make it off-topic for Code Review, as they don't write new code or explain how to change/fix behaviors. If the OP wish to post their __working__ code to CR for general review they are welcome to. – Phrancis Oct 19 '17 at 14:55
  • I could find a solution by following this post https://stackoverflow.com/questions/21779967/spring-security-with-java-configuration-how-to-handle-badcredentialsexception-f But still I doubt which is the best approach? – Ravindra Ranwala Oct 20 '17 at 05:28

0 Answers0