3

We are facing an issue with SpringSecurity ignoring a method. We tried to skip authentication for a few urls (acutator/health) and resources. Authentication is being taken care externally and we are having one custom filter to extract the principle for authorization.

We override the configured method as shown below:

public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**", "/actuator/health");
}
protected void configure(HttpSecurity http) throws Exception {
         http.addFilter(cutstomFilter).authorizeRequests()
        .antMatchers("/add","/update","/upload").hasAuthority("ADMIN").anyRequest().authenticated()
        .and().logout().logoutSuccessUrl("/logoutUser").and()
        .exceptionHandling().accessDeniedPage("/accessDenied").and().csrf().disable();
    }

With the given implementation, our customFilter is being called for resources and health url. This is causing reauthenticating due to principle change.

We tried adding this code but customFilter gets called for health url as well.

http.authorizeRequests().antMatchers("/actuator/health").permitAll() 

Note: Checked the @Rob Winch answer but did not understand why we need a custom filer if we are putting those url in the ignore list. https://stackoverflow.com/a/19985323/2138633

ManojP
  • 6,113
  • 2
  • 37
  • 49
  • Code example to add a custom security filter in spring boot: https://stackoverflow.com/questions/24364436/ (Add a FilterRegistrationBean for each custom security filter in your application). A request to add an annotation is pending to make it easier, see https://github.com/spring-projects/spring-boot/issues/16500. – Ritesh Dec 26 '20 at 14:19

3 Answers3

5

UPDATE: Please see comment from @dur in question, it will probably solve the issue without major changes.

To make it clear, your first security configuration is correct. Your problem 
is that your filter is used as a servlet filter not only as a security chain 
filter. Spring Boot does this autmatically, if you expose your filter.

https://stackoverflow.com/a/39314867/14072498


OP is mentioning that actuator end-points are involved. Let's have a look in doc: https://spring.io/guides/topicals/spring-security-architecture

Doc says:

If you want your application security rules to apply to the actuator 
endpoints, you can add a filter chain that is ordered earlier than the 
actuator one and that has a request matcher that includes all actuator 
endpoints.

Doc is suggesting to divide config into multiple implementations of WebSecurityConfigurerAdapter.

In the example config below, you should apply what you refer to as custom filter to the MainAppConfigurerAdapter.

Example on "Multiple Spring Boot Security Configuration": https://medium.com/@igor.bonny/multiple-spring-boot-security-configuration-c876f1b6061e

In order to skip authentication for other end-points, add

.and()
.authorizeRequests().anyRequest().permitAll();

to end of app chain shown below.

To verify security settings, add integration tests for all end-points.

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {

  @Configuration
  @Order(ManagementServerProperties.BASIC_AUTH_ORDER - 1)
  public class ActuatorConfigurerAdapter extends WebSecurityConfigurerAdapter {
    @Override
      protected void configure(HttpSecurity http) {
          http.antMatcher("/actuator/**")
          ...
      }
  }

  @Configuration
  @Order(SecurityProperties.DEFAULT_FILTER_ORDER)
  public class MainAppConfigurerAdapter extends WebSecurityConfigurerAdapter {
      @Override
      protected void configure(HttpSecurity http) {
          http.antMatcher("/api/**")
          ...
      }
  }
}
Roar S.
  • 8,103
  • 1
  • 15
  • 37
  • @RoarS. I tried this configuration but its not working as we are adding filter to extract principle before authorizing request. So ignoring url should work to skip the filter invocation. – ManojP Dec 24 '20 at 13:04
  • 1
    This security configuration would make the new routes unsecured by default It is usually better to use anyRequest().authenticated(), or event anyRequest().denyAll() to avoid any unwanted side effect. – Raphael Dec 24 '20 at 13:47
  • @Raphael: Your statement is true (upvoted your comment); the config in this example requires that all end-points that requires security, are specified. With proper test coverage, it should not make any problems though. BR – Roar S. Dec 24 '20 at 20:20
0

Following https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-endpoints-security, you should :

  • Add to your properties file

    management.endpoints.web.exposure.include=*

  • Update your security configuration to look like

      @Configuration(proxyBeanMethods = false)
      public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
    
    
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests((requests) ->
              requests.anyRequest().permitAll());
          }
      }
    
Raphael
  • 375
  • 2
  • 12
0

One way to do it is to use patterns in both security config and in your custom filter that extracts the principal from the authentication. You can do it as follows:

  1. Declare ignore patterns:

     static final String[] IGNORE_PATTERNS = new String[] { "**/*.js", "**/*.css", "/resources/**"};
    
  2. Declare permit all patterns:

     static final String[] PERMIT_ALL_PATTERNS = new String[] { "/login", "/logout", "/health"};
    
  3. Use ignored patterns in WebSecurity:

     web.ignoring().antMatchers(IGNORE_PATTERNS);
    
  4. Use permit-all patterns in HttpSecurity:

     http.authorizeRequests().antMatchers(PERMIT_ALL_PATTERNS).permitAll().anyRequest().authenticated().and() ...
    
  5. Declare a RequestMatcher in your filter:

     List<RequestMatcher> matchers = new ArrayList<>();
     for (String pattern : IGNORE_PATTERNS) {
         matchers.add(new AntPathRequestMatcher(pattern));
     }
     for (String pattern : PERMIT_ALL_PATTERNS) {
         matchers.add(new AntPathRequestMatcher(pattern));
     }
    
     RequestMatcher ignoreRequestMatcher = new OrRequestMatcher(matchers);  
    
  6. Use the request matcher in the doFilter method of the filter:

     if (ignoreRequestMatcher.matches((HttpServletRequest) request)) {
     /* skip this filter */
     chain.doFilter(request, response);
     return;  } /* rest of the filter code below */
    
Ritesh
  • 7,472
  • 2
  • 39
  • 43