skip to Main Content

Im creating a project with spring using spring security but i am having problem only with my api(all controllers are working correctly with csrf). But seems like the csrf is causing problem to my api, because when i make a request to my api i get:

{"id":41,"titulo":"vineta3","creationdate":1489421003000,"URL":"http://i2.kym-cdn.com/photos/images/facebook/000/125/918/RMUBQ.png","likes":0,"dislikes":0,"descripcion":"des3"}{"timestamp":1489421218765,"status":200,"error":"OK","exception":"java.lang.IllegalStateException","message":"Cannot create a session after the response has been committed","path":"/api/vineta/41/"}

The last info:

{"timestamp":1489421218765,"status":200,"error":"OK","exception":"java.lang.IllegalStateException","message":"Cannot create a session after the response has been committed","path":"/api/vineta/41/"}

is not returning when my project has not spring secutiry. Im using the next code for my security configuration.

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
public UserRepositoryAuthenticationProvider authenticationProvider;

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

    // Public pages
    http.authorizeRequests().antMatchers("/").permitAll();
    http.authorizeRequests().antMatchers("/login").permitAll();
    http.authorizeRequests().antMatchers("/loginerror").permitAll();
    http.authorizeRequests().antMatchers("/registro").permitAll();
    http.authorizeRequests().antMatchers("/signup").permitAll();
    http.authorizeRequests().antMatchers(HttpMethod.GET, "/api/**").permitAll();        


    // Private pages (all other pages)
    http.authorizeRequests().antMatchers("/home").hasAnyRole("USER");
    //http.authorizeRequests().antMatchers("/crearComentario/vineta/{id}").hasAnyRole("USER");

    // Login form
    http.formLogin().loginPage("/login");
    http.formLogin().usernameParameter("username");
    http.formLogin().passwordParameter("password");
    http.formLogin().defaultSuccessUrl("/home");
    http.formLogin().failureUrl("/loginerror");

    // Logout
    http.logout().logoutUrl("/logout");
    http.logout().logoutSuccessUrl("/");

}

@Override
protected void configure(AuthenticationManagerBuilder auth)
        throws Exception {
    // Database authentication provider
    auth.authenticationProvider(authenticationProvider);
}

}

and the next for my csrf:

@Configuration
public class CSRFHandlerConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CSRFHandlerInterceptor());
    }
}

class CSRFHandlerInterceptor extends HandlerInterceptorAdapter {

    @Override
    public void postHandle(final HttpServletRequest request,
            final HttpServletResponse response, final Object handler,
            final ModelAndView modelAndView) throws Exception {

        CsrfToken token = (CsrfToken) request.getAttribute("_csrf"); 
        modelAndView.addObject("token", token.getToken());      
    }
}

In the console, i can see the follow logs:
at

org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.32.jar:8.0.32]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
Caused by: java.lang.IllegalStateException: Cannot create a session after the response has been committed
    at org.apache.catalina.connector.Request.doGetSession(Request.java:2928) ~[tomcat-embed-core-8.0.32.jar:8.0.32]

Im not using SingleTransactionsController, this can be the problem?

4

Answers


  1. I don’t understand why you use CSRFHandlerInterceptor, but if you want to disable CRSF only for API, I have two solutions:

    1. You can inject a requireCsrfProtectionMatcher to CSRF filter, for example:

       http
           .csrf()
               .requireCsrfProtectionMatcher(newAndRequestMatcher(CsrfFilter.DEFAULT_CSRF_MATCHER, new RegexRequestMatcher("^(?!/api/)", null)));
      

      The default matcher is method matcher, and the second matcher is used for not /api/ request.

    2. You can create a new Spring Security config only for /api, and set the order before default Spring Security config, match the API URL without CSRF:

      http.requestMatcher(new AntPathRequestMatcher("/api/**")).csrf().disable();
      
    Login or Signup to reply.
  2. Csrf settings are global in Spring Security

    This can help:

    http.csrf().requireCsrfProtectionMatcher(new RequestMatcher() {
    
            private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
           // regex to match your api url 
            private RegexRequestMatcher apiMatcher = new RegexRequestMatcher("/v[0-9]*/.*", null);
    
            @Override
            public boolean matches(HttpServletRequest request) {
                // No CSRF due to allowedMethod
                if(allowedMethods.matcher(request.getMethod()).matches())
                    return false;
    
                // No CSRF due to api call
                if(request.getRequestURI().equals("/view/cpanel/Login.jsp");
                    return false;
    
                // CSRF for everything else that is not an API call or an allowedMethod
                return true;
            }
        });
    
    Login or Signup to reply.
  3. If your API uses something other than a session cookie for authentication, like basic auth or an API token, then a simple way to allow just those requests through is:

    .csrf()
        .requireCsrfProtectionMatcher(new AndRequestMatcher(
            CsrfFilter.DEFAULT_CSRF_MATCHER,
            new RequestHeaderRequestMatcher(HttpHeaders.COOKIE)));
    
    Login or Signup to reply.
  4. Another way to enable security for both API and Web is to include this in your SecurityConfig class:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
                http
                .authorizeRequests()
                .antMatchers(....)
                //form login etc
                .and().csrf().ignoringAntMatchers("/api/**");
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search