spring-cloudspring-cloud-gatewayspring-cloud-security

TokenRelayGatewayFilterFactory protecting all URL's


I have a project https://github.com/ndrone/sample-gateway-oauth2login/tree/feature/allowAllToHealth That I am trying to allow specific URL's open to anyone that request it. In this case, it is the health endpoint of Actuator while protect all other Actuator endpoints. What I am finding is that the TokenRelayGatewayFilterFactory is being applied to all routes when though it is only set to be applied to one route. Not sure what I got wrong.

SecurityConfig in the Resource Service

@EnableWebFluxSecurity
public class SecurityConfig {

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) throws Exception {

    http.authorizeExchange().pathMatchers("/manage/health").permitAll();
    http
        .authorizeExchange()
            .pathMatchers("/resource", "/manage/**").hasAuthority("SCOPE_resource.read")
            .anyExchange().authenticated()
            .and()
        .oauth2ResourceServer()
            .jwt();
        return http.build();
        }
}

Gateway Routes

@Controller
@SpringBootApplication
public class GatewayApplication {

@Autowired
private TokenRelayGatewayFilterFactory filterFactory;

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    //@formatter:off
    return builder.routes()
            .route("resource-health", r -> r.path("/resource/manage/health")
                    .filters(f -> f.stripPrefix(1))
                    .uri("http://localhost:9000"))
            .route("resource-actuator-protected", r -> r.path("/resource/manage/**")
                    .filters(f -> f.stripPrefix(1).filter(filterFactory.apply()))
                    .uri("http://localhost:9000"))
            .route("resource", r -> r.path("/resource")
                    .filters(f -> f.filter(filterFactory.apply()))
                    .uri("http://localhost:9000"))
            .build();
    //@formatter:on
}

@GetMapping("/")
public String index(Model model,
                    @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient,
                    @AuthenticationPrincipal OAuth2User oauth2User) {
    model.addAttribute("userName", oauth2User.getName());
    model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName());
    model.addAttribute("userAttributes", oauth2User.getAttributes());
    return "index";
}

public static void main(String[] args) {
    SpringApplication.run(GatewayApplication.class, args);
}

}

Solution

  • Since I didn't have a spring security configuration detailed out in the gateway. Spring Security protected all urls. Digging into the sample more and the source of their fork from jgrandja I needed to add the following.

    /**
     * This code duplicates {@link org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration}
     * and enhances with oauth2Login() specific configuration
     *
     * and with changes defined by jgrandja @see <a href="https://github.com/jgrandja/oauth2login-gateway/commit/51a28f91b7a71d71522d14d0cb5f1fa717033f42">OAuth</a>
     *
     * @author nd26434 on 2019-06-21.
     */
    @Configuration
    @ConditionalOnClass({ EnableWebFluxSecurity.class, WebFilterChainProxy.class })
    @ConditionalOnMissingBean({ SecurityWebFilterChain.class, WebFilterChainProxy.class })
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
    @AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class)
    @AutoConfigureAfter({ HealthEndpointAutoConfiguration.class,
            InfoEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
            ReactiveOAuth2ClientAutoConfiguration.class,
            ReactiveOAuth2ResourceServerAutoConfiguration.class })
    class SecurityConfig {
    
        @Bean
        SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
            // @formatter:off
            // gateway actuator
            http.authorizeExchange()
                            .matchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class)).permitAll();
            // gateway resource actuator
            http.authorizeExchange().pathMatchers("/manage/health").permitAll();
            return http.authorizeExchange()
                            .anyExchange().authenticated()
                            .and()
                        .oauth2Login()
                            .and()
                        .exceptionHandling()
                            // NOTE:
                            // This configuration is needed to perform the auto-redirect to UAA for authentication.
                            .authenticationEntryPoint(new RedirectServerAuthenticationEntryPoint("/oauth2/authorization/login-client"))
                            .and()
                        .build();
            // @formatter:on
        }
    }
    

    The working branch: https://github.com/ndrone/sample-gateway-oauth2login/tree/feature/allowAllToHealth