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.
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