0

I am securing a REST API with Spring Security and JWT (i'm not using Spring Boot).

When i try to send an authentication request (/login) to my REST API i got Could not get any response on Postman

enter image description here

Here is my JWT filter

public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    ...

    public AuthenticationFilter(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            ... // getting the credentials from the request
            return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(credentials.login, credentials.password));
        } 
        catch (IOException e) { throw new RuntimeException(e); }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
            Authentication authResult) throws IOException, ServletException {

        ... // generating the jwtToken;

        response.setHeader("Authorization", jwtToken);
    }
}

When i am debugging my app everything works fine and the successfulAuthentication method is executed and i get the right token inserted in the header request response.setHeader("Authorization", jwtToken);.

But after that it's like my REST API (or Spring Security or Tomcat) don't send any response back !

Here is the security config :

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
                .anyRequest().authenticated()
            .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager()));
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    }

    ...
}

For other HTTP requests other than /login i got a (403) HTML response in Postman and NOT a JSON response.

<!doctype html>
<html lang="en">

<head>
    <title>HTTP Status 403 – Forbidden</title>
    ...

So Why my server is not responding at /login request ? and why Spring security is not sending JSON response for all the http requests ?

Logs after /login request :

DEBUG o.s.security.web.FilterChainProxy - /login at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG o.s.security.web.FilterChainProxy - /login at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG o.s.security.web.FilterChainProxy - /login at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG o.s.security.web.FilterChainProxy - /login at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', GET]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Request 'POST /login' doesn't match 'GET /logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', POST]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', PUT]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Request 'POST /login' doesn't match 'PUT /logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', DELETE]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Request 'POST /login' doesn't match 'DELETE /logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - No matches found
DEBUG o.s.security.web.FilterChainProxy - /login at position 5 of 11 in additional filter chain; firing Filter: 'JwtAuthenticationFilter'
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/login'
DEBUG security.JwtAuthenticationFilter - Request is to process authentication
DEBUG o.s.security.authentication.ProviderManager - Authentication attempt using o.s.security.authentication.dao.DaoAuthenticationProvider
DEBUG o.s.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation
Hibernate: select ... 
DEBUG o.s.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher o.s.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5b319bff
DEBUG o.s.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
Hayi
  • 6,972
  • 26
  • 80
  • 139

2 Answers2

0

The very first things, I will talk about the response the that you get is not in Json(For all other requests). See, first the method at the url endpoint should be assigned to produce the content that you're requesting. And the content that you want, you can mention in the headers in postman for json it should be Accepts : Application/json

The other thing is why the server is not responding to your login request is that, best configuration should be in your case.

http.csrf().disable()
             //You can give the request that you want to allow
         .anyRequest().authenticated()
            .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager()));
Amit Mishra
  • 498
  • 5
  • 16
0

For the issue with the server not responding it was stupid mistake, In my properties file i have put the Authorization header name with double quote

security.token.header-string="Authorization"

Instead of

security.token.header-string=Authorization

For the part which the server not responding with JSON format i follow this answer

So i had to implement a custom authenticationEntryPoint, accessDeniedHandler, authenticationSuccessHandler and authenticationFailureHandler like bellow :

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.csrf().disable();
    http.
        authorizeRequests()
            .anyRequest().authenticated()
        .and()
        .addFilter(getJwtAuthenticationFilter())
        .exceptionHandling()
            .authenticationEntryPoint((request, response, exception) -> {
                response.setStatus(401);
            })  
            .accessDeniedHandler((request, response, exception) -> {
                response.setStatus(403);
            })
        ;

    http.
        sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

}

With the JwtAuthenticationFilter

@Bean
private JwtAuthenticationFilter getJwtAuthenticationFilter() throws Exception {

    JwtAuthenticationFilter filter = new JwtAuthenticationFilter(authenticationManager());

    filter.setFilterProcessesUrl("/api/login");

    //filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
    //    response.setStatus(200);
    //});

    filter.setAuthenticationFailureHandler((request, response, exception) -> {
        response.setStatus(401);
    });

    return filter;
}

I have comment the line filter.setAuthenticationSuccessHandler(...) because it will not be invoked since i already override the successfulAuthentication method on my JwtAuthenticationFilter class.

Hayi
  • 6,972
  • 26
  • 80
  • 139