Search code examples
javaspringspring-securitytoggle

Exclude togglz-console from spring security


I'd like to exclude the toggle-console from being included in the spring-security auth process: I want to access it on the management port without auth. Despite adding matchers to the requestMatchers in my WebSecurityConfig the console is always blocked by the login prompt.

The SecurityFilterChain bean I have:

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
      return http
              .authorizeHttpRequests(requests -> requests
                      .requestMatchers("/actuator",
                              "/actuator/*",
                              "/togglz-console",
                              "/togglz-console/**",
                              "/togglz*",
                              "/togglz**"
                      )
                      .permitAll()
                      .anyRequest()
                      .authenticated()
              )
              .csrf(AbstractHttpConfigurer::disable)
              .formLogin(AbstractAuthenticationFilterConfigurer::permitAll)
              .logout(LogoutConfigurer::permitAll)
              .build();
  }

in application.properties I have the following:

togglz:
  enabled:
    true
  features:
    CHEEKY_GREETING:
      enabled: false
  console:
    secured: false
    use-management-port: true
  endpoint:
    enabled: true
    id: togglz
management:
  endpoints:
    web:
      exposure:
        include: 'togglz, health'
  server:
    port: 8081

My project has the following dependencies:

plugins {
    id 'org.springframework.boot' version '3.1.0'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}
ext {
    togglz_version = "4.0.1"
}
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-security'

    testImplementation('org.springframework.boot:spring-boot-starter-test')

    implementation("org.togglz:togglz-spring-boot-starter:${togglz_version}")
    implementation("org.togglz:togglz-console:${togglz_version}")
}

I tried adding the togglz-security-spring-boot-starter too, but made no change.

Code all on a branch here: https://github.com/robjwilkins/showcase/tree/add/togglz

Any suggestions what I'm doing wrong? thanks


Solution

  • The cause of this problem is that when the request for /togglz-console is checked by PathPatternMatchableHandlerMapping it looks at

    ServletRequestPathUtils.getParsedRequestPath(request).pathWithinApplication()
    

    The request path is /togglz-console, however pathWithinApplication() returns "". For some reason /togglz-console is not being considered 'part of the application' (perhaps because it's being provided as a 3rd party add-on).

    A solution to this is to add special requestMatcher, which can be configured to look at the whole request path, and ignore the pathWithinApplication.

    for example:

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.authorizeHttpRequests(requests -> 
             requests
                 .requestMatchers(customMatcher("/togglz-console"),
                                  customMatcher("/togglz-console/*"))
                 .permitAll()
                 .requestMatchers("/public")
                 .permitAll()
                 .anyRequest()
                 .authenticated()
                 .formLogin(withDefaults())
                 .build();
    }
    
    private RequestMatcher customMatcher(String pattern) {
        return request -> {
            var matcher = new PathPatternParser().parse(pattern);
            var path = ServletRequestPathUtils.parseAndCache(request);
            return matcher.matches(path);
        };
    }