I wanted to add integration tests for my spring cloud gateway. I found test containers and using that I spin up two services, keycloak container and gateway. Now I can already get the access token using keycloak getauthServerUrl method but I can’t seem authenticate. My security config looks like:
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.csrf(ServerHttpSecurity.CsrfSpec::disable);
http.authorizeExchange(auth -> auth.anyExchange().authenticated()).oauth2Login(withDefaults())
.oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}
I think I know why I cannot authenticate in tests because my security config expects to login through a login page and in my test I add access token as a header. What can I change in my config that it works both with login page and without?
I wanted to add integration tests for my spring cloud gateway. I found test containers and using that I spin up two services, keycloak container and gateway. Now I can already get the access token using keycloak getauthServerUrl method but I can’t seem authenticate. My security config looks like:
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.csrf(ServerHttpSecurity.CsrfSpec::disable);
http.authorizeExchange(auth -> auth.anyExchange().authenticated()).oauth2Login(withDefaults())
.oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}
I think I know why I cannot authenticate in tests because my security config expects to login through a login page and in my test I add access token as a header. What can I change in my config that it works both with login page and without?
Testing with Keycloak in a container is end-to-end testing (which is slow). If using the authorization code flow, you'll need an end-to-end test framework like Protractor to manipulate the UI as if users were actually logging in.
You can write integration tests for your Spring backend without a test container and, more importantly, without the need to manipulate a UI. For that, use:
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureWebTestClient
(would be @AutoConfigureMockMvc
in a servlet)WebTestClient
to query an oauth2ResourceServer
configured with a JWT decoder and the default authentication converter, you can mock the JwtAuthenticationToken
in the test's security context with SecurityMockServerConfigurers.mockJwt()
(would be SecurityMockMvcRequestPostProcessors.jwt()
with MockMvc
). But as there are quite some limitations to WebTestClient
mutators (and the MockMvc
post-processors) I created in spring-security-tests
for OAuth2, I also created test annotations in spring-addons-oauth2-tests.I described that in details in this Baeldung article.
If your aim is to test access control, you should consider writing unit tests with @WebFluxTest
or WebMvcTest
.
@SpringBootTest
integration tests and end-to-end tests are slower than unit tests and should be used for testing no more than things wirering correctly together (not all possible access attempts for instance).
oauth2Login
or no security at allOn a gateway, I would not configure the security filter chain for routes to downstream resource servers with oauth2ResourceServer
. Instead:
oauth2Login
and the routes with the TokenRelay=
filterTokenRelay=
filter) for "routes" to downstream services, or I have OAuth2 clients query the downstream services directly (skip the gateway)In both cases: