Disable Spring Security for OPTIONS Http Method

87,857

Solution 1

Have you tried this

You can use multiple elements to define different access requirements for different sets of URLs, but they will be evaluated in the order listed and the first match will be used. So you must put the most specific matches at the top. You can also add a method attribute to limit the match to a particular HTTP method (GET, POST, PUT etc.).

<http auto-config="true">
    <intercept-url pattern="/client/edit" access="isAuthenticated" method="GET" />
    <intercept-url pattern="/client/edit" access="hasRole('EDITOR')" method="POST" />
</http>

Above means you need to select the url pattern to intercept and what methods you want

Solution 2

If you're using an annotation based security config file (@EnableWebSecurity & @Configuration) you can do something like the following in the configure() method to allow for the OPTION requests to be permitted by Spring Security without authentication for a given path:

@Override
protected void configure(HttpSecurity http) throws Exception
{
     http
    .csrf().disable()
    .authorizeRequests()
      .antMatchers(HttpMethod.OPTIONS,"/path/to/allow").permitAll()//allow CORS option calls
      .antMatchers("/resources/**").permitAll()
      .anyRequest().authenticated()
    .and()
    .formLogin()
    .and()
    .httpBasic();
}

Solution 3

Allow all OPTIONS in context:

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }

Solution 4

In case someone is looking for an easy solution using Spring Boot. Just add an additional bean:

   @Bean
   public IgnoredRequestCustomizer optionsIgnoredRequestsCustomizer() {
      return configurer -> {
         List<RequestMatcher> matchers = new ArrayList<>();
         matchers.add(new AntPathRequestMatcher("/**", "OPTIONS"));
         configurer.requestMatchers(new OrRequestMatcher(matchers));
      };
   }

Please note that depending on your application this may open it for potential exploits.

Opened issue for a better solution: https://github.com/spring-projects/spring-security/issues/4448

Solution 5

The accepted answer is not recommended and you shold not do that.
Below is the correct way for CORS setup of Spring Security and jQuery's ajax.

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
   
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(userAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors() // <-- This let it use "corsConfigurationSource" bean.
                .and()
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            ...
    }

    @Bean
    protected CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
        configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));

        // NOTE: setAllowCredentials(true) is important,
        // otherwise, the value of the 'Access-Control-Allow-Origin' header in the response
        // must not be the wildcard '*' when the request's credentials mode is 'include'.
        configuration.setAllowCredentials(true);

        // NOTE: setAllowedHeaders is important!
        // Without it, OPTIONS preflight request will fail with 403 Invalid CORS request
        configuration.setAllowedHeaders(Arrays.asList(
                "Authorization",
                "Accept",
                "Cache-Control",
                "Content-Type",
                "Origin",
                "ajax", // <-- This is needed for jQuery's ajax request.
                "x-csrf-token",
                "x-requested-with"
        ));

        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

And from jQuery side.

$.ajaxSetup({
    // NOTE: Necessary for CORS
    crossDomain: true,
    xhrFields: {
        withCredentials: true
    }
});
Share:
87,857
Dhanush Gopinath
Author by

Dhanush Gopinath

I am CTO &amp; Co-founder at Geektrust, an online recruitment marketplace. I code in Go, Javascript and Python and used to work on Java before I started Geektrust. I have been programming for about 16 years now and love to explore new programming languages and technology.

Updated on July 05, 2022

Comments

  • Dhanush Gopinath
    Dhanush Gopinath almost 2 years

    Is it possible to disable Spring Security for a type of HTTP Method?

    We have a Spring REST application with services that require Authorization token to be attached in the header of http request. I am writing a JS client for it and using JQuery to send the GET/POST requests. The application is CORS enabled with this filter code.

    doFilter(....) {
    
      HttpServletResponse httpResp = (HttpServletResponse) response;
      httpResp.setHeader("Access-Control-Allow-Origin", "*");
      httpResp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
      httpResp.setHeader("Access-Control-Max-Age", "3600");
      Enumeration<String> headersEnum = ((HttpServletRequest) request).getHeaders("Access-Control-Request-Headers");
      StringBuilder headers = new StringBuilder();
      String delim = "";
      while (headersEnum.hasMoreElements()) {
        headers.append(delim).append(headersEnum.nextElement());
        delim = ", ";
      }
      httpResp.setHeader("Access-Control-Allow-Headers", headers.toString());
    }
    

    But when JQuery sends in the OPTIONS request for CORS, the server responds with Authorization Failed token. Clearly the OPTIONS request, lacks Authorization token. So is it possible to let the OPTIONS escape the Security Layer from the Spring Security Configuration?

  • Dhanush Gopinath
    Dhanush Gopinath over 10 years
    But I guess we cant have some thing like <intercept-url pattern="/client/edit" access="hasRole('EDITOR')" method="POST, OPTIONS" /> . Right ?
  • Koitoer
    Koitoer over 10 years
  • Dormouse
    Dormouse over 9 years
    +1 Exactly what we did to enable CORS OPTIONS requests.
  • Dipanshu Verma
    Dipanshu Verma over 8 years
    How would this work in case of @PreAuthorize annotation, I want Put methods to have Admin access and Post methods to have User access
  • Ravi Kumar
    Ravi Kumar over 8 years
    What will be it's equivalent in java config
  • Saurav Wahid
    Saurav Wahid over 8 years
    it's works fine Thanks for your tips i searching and debug lot but can't fixed now i fixed it to use this tips
  • jaseeey
    jaseeey over 8 years
    This seemed to be the only way to allow OPTIONS requests without requiring auhorization.
  • CodeMed
    CodeMed about 8 years
    I found your answer while researching a similar problem which does not yet respond to your solution in its present form. Are you willing to take a look? Here is the link: stackoverflow.com/questions/36705874/…
  • Dr4gon
    Dr4gon over 7 years
    This might help for a general understanding: docs.spring.io/spring-security/site/docs/4.1.3.RELEASE/…
  • Kunok
    Kunok over 6 years
    I am not Java Spring user myself, I am having same issue on my end using different language on backend. Does Java/Spring bring any additional abstraction in security or it is mostly safe to ignore authentication middleware method for all OPTIONS requests?
  • Tim
    Tim over 6 years
    If you then create an Options endpoint you want to secure, you'll forget about the exclusion in your config and everyone can access it. You should consider using the filter to allow cors option requests to be excluded from spring-security: docs.spring.io/spring-security/site/docs/4.2.x/reference/htm‌​l/…
  • Ena
    Ena about 6 years
    With HttpSecurity is http.authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/registrybrain/**").permitAll()
  • dnvsp
    dnvsp about 6 years
    Not working for me. Here is my problem, could you please have a look.
  • dnvsp
    dnvsp about 6 years
  • dnvsp
    dnvsp about 6 years
    please have a look on my problem. stackoverflow.com/questions/50579277/…
  • Angelo
    Angelo almost 6 years
    That works for me. Remember the difference from one asterisk and double asterisk regards to paths. antMatchers(HttpMethod.OPTIONS,"/rest/auth/**").permitAll() stackoverflow.com/questions/12569308/…
  • Waqas
    Waqas almost 6 years
    Spent more than 2 hours trying and finding solution- only this worked.
  • Maksim Gumerov
    Maksim Gumerov over 5 years
    "If you then create an Options endpoint you want to secure" @Tim why would anyone need that?
  • Mukarram Ali
    Mukarram Ali over 5 years
    Dude you saved me. Thanks a ton
  • Oleksii Kyslytsyn
    Oleksii Kyslytsyn about 5 years
    In order to open a POST endpoint for client requests it is available the following security configuration: .antMatchers(HttpMethod.POST,"/path/to/post/request")
  • bvdb
    bvdb about 4 years
    IgnoredRequestCustomizer is deprecated since spring boot 2.
  • wonsuc
    wonsuc over 3 years
    This is not recommended and don't do this.
  • singhpradeep
    singhpradeep over 2 years
    Simple solution in spring security just add http.cors(). You are done.