3

I try building a minimal openid secured cloud environment. Following more or less https://developer.okta.com/blog/2019/08/28/reactive-microservices-spring-cloud-gateway .

I have a spring cloud gateway, a consul registry, an application registered on okta and a simple test app with just one controller returning a string. Both the gateway and the test application depend on 'com.okta.spring', name: 'okta-spring-boot-starter', version: '1.4.0'.

The gateway is configured like so (skipping ssl here for brevity):

spring:
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    gateway:
      default-filters: 
        - TokenRelay
      discovery:
        locator:
          enabled: true
okta:
  oauth2:
    issuer: ${OKTA_OAUTH2_ISSUER}
    client-id: ${OKTA_OAUTH2_CLIENT_ID}
    client-secret: ${OKTA_OAUTH2_CLIENT_SECRET}

and i added a minimal security configuration:

private final ReactiveClientRegistrationRepository clientRegistrationRepository;

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
    http
            .redirectToHttps()
            .and()
            .authorizeExchange()
            .pathMatchers("/login").permitAll()
            .pathMatchers("/actuator/**").permitAll()
            .anyExchange().authenticated()
            .and()
            .oauth2Login()
            .and()
            .logout(logout -> logout.logoutSuccessHandler(oidcLogoutSuccessHandler()))
            .oauth2ResourceServer()
            .jwt();
    return http.build();
}

private ServerLogoutSuccessHandler oidcLogoutSuccessHandler() {
    OidcClientInitiatedServerLogoutSuccessHandler oidcLogoutSuccessHandler =
            new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository);

    oidcLogoutSuccessHandler.setPostLogoutRedirectUri(URI.create("https://<my-uri>"));

    return oidcLogoutSuccessHandler;
}

The test application also has okta openid configured in the application.yml as in the gateway plus:

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
    http
            .authorizeExchange()
            .pathMatchers("/actuator/**").permitAll()
            .anyExchange().authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt();

    Okta.configureResourceServer401ResponseBody(http);

    return http.build();
}

My problem is:

When I remove the token relay and keep the test application un-secure the gateway will successfully do the authorization and the response contains a set-cookie header that can be used in subsequent requests to provide from running through all the authorization flow again.

However, adding token relay by means of 'org.springframework.cloud:spring-cloud-starter-security' (and configured as a default-filter as shown above), returns an empty set-cookie header and thus each and every request as to run throw the whole authorization flow.

I tried different solution approaches, like manually configuring ReactiveOAuth2AuthorizedClientService. My approaches all felt more like guessing.

PeMa
  • 1,559
  • 18
  • 44
  • FYI... I'm the author of the Okta blog post. I'm having a similar issue when configuring the token relay filter in YAML for JHipster. https://stackoverflow.com/questions/60251863/spring-cloud-gateway-and-tokenrelay-filter – Matt Raible Feb 16 '20 at 22:17
  • @Matt Raible Thanks for this hint. But I doubt your solution will help in my case since I’m facing the issue upstream. I’ll have to check the TCP dump but I’d guess the response header is even send to the gateway. I think there also needs to be some kind of relay for the `set-cookie` header. – PeMa Feb 17 '20 at 06:42

1 Answers1

3

It turned out, the solution is to remove the cookie header from the downstream request. This can be achieved by adding another default filter to the gateway:

spring:
  cloud:
    gateway:
      default-filters: 
        - TokenRelay=
        - RemoveRequestHeader=Cookie
PeMa
  • 1,559
  • 18
  • 44