Document how to use this if Keycloak is on the classpath
See original GitHub issueThank you for this project. It is just what I needed for my @WebMvcTest
tests in my Spring Boot project. I am using Spring Boot 2.2.6 with keycloak-spring-boot-starter
9.0.0.
After adding:
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-security-oauth2-test-webmvc-addons</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
to my project, I also had to do the following things:
- Create a custom meta-annotation for all my webmvc tests:
@Retention(RetentionPolicy.RUNTIME)
@WebMvcTest
@ContextConfiguration(classes = MyProjectRestControllerTestConfiguration.class)
@ActiveProfiles("webmvc-test")
public @interface MyProjectRestControllerTest {
/**
* @see WebMvcTest#value
*/
@AliasFor(annotation = WebMvcTest.class, attribute = "value")
Class<?>[] value() default {};
/**
* @see WebMvcTest#controllers
*/
@AliasFor(annotation = WebMvcTest.class, attribute = "controllers")
Class<?>[] controllers() default {};
}
- I created a custom
@TestConfiguration
for my test:
@TestConfiguration
@Import({KeycloakAutoConfiguration.class, WebSecurityConfiguration.class})
public class MyProjectRestControllerTestConfiguration {
@Bean
public KeycloakSpringBootConfigResolver keycloakSpringBootConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
Where WebSecurityConfiguration
is my actual production security config class:
@KeycloakConfiguration
public class WebSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder builder) {
KeycloakAuthenticationProvider provider = new KeycloakAuthenticationProvider();
provider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
builder.authenticationProvider(provider);
}
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.antMatchers("/actuator/info", "/actuator/health").permitAll()
.anyRequest()
.hasRole("user");
}
}
- Next, I added
application-webmvc-test.properties
insrc/test/resources
:
# Properties are here for proper startup. Keycloak is not actually used in @WebMvcTest tests
keycloak.auth-server-url=http://localhost:8180/auth
keycloak.realm=pegus-digital-test
keycloak.resource=springboot-app
keycloak.public-client=true
keycloak.principal-attribute=preferred_username
- Finally my test self:
@MyProjectRestControllerTest(UserRestController.class)
class UserRestControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void testOwnUserDetails() throws Exception {
KeycloakAuthRequestPostProcessor keycloakAuthRequestPostProcessor = new KeycloakAuthRequestPostProcessor()
.roles("user", "admin")
.name("wim.deblauwe@example.com")
.idToken(idToken -> {
idToken.setSubject("aac53545-5d5b-4e1f-8c94-0c593d22b5a2");
idToken.setGivenName("Wim");
idToken.setFamilyName("Deblauwe");
});
mockMvc.perform(get("/api/users/me")
.with(keycloakAuthRequestPostProcessor))
.andExpect(status().isOk())
.andExpect(jsonPath("authorizationServerUserId").value("aac53545-5d5b-4e1f-8c94-0c593d22b5a2"))
.andExpect(jsonPath("firstName").value("Wim"))
.andExpect(jsonPath("lastName").value("Deblauwe"))
.andExpect(jsonPath("email").value("wim.deblauwe@example.com"))
.andExpect(jsonPath("userRole").value("ADMIN"))
;
}
}
Might be good to add something similar to the documentation, as most people will have Keycloak on the classpath in their project (unlike the example in your repo currently).
Issue Analytics
- State:
- Created 3 years ago
- Comments:14 (8 by maintainers)
Top Results From Across the Web
Securing Applications and Services Guide - Keycloak
There are really two types of use cases when using OIDC. The first is an application that asks the Keycloak server to authenticate...
Read more >Adding external jar dependency in JAR file - Stack Overflow
The keycloak can read the custom provider when I put the jar in the relevant path. I can also see keycloak is showing...
Read more >Include a third party library in custom authenticator
I am creating plugins (providers) for keycloak using the Service ... However, the library is not found in the classpath when I deploy...
Read more >Spring Security and Keycloak to Secure Spring Boot - A First ...
xml if using Maven). buildscript { ext { springBootVersion = '2.1.9.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.
Read more >Keycloak Reference Guide
A client is a service that is secured by a realm. You will often use Client for every Application secured by Keycloak. When...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I’ll try some investigation and maybe open a Keykloak ticket.
@ch4mpy @wimdeblauwe
I have created controller tests similar to the sample project and all works fine!
However … when running integration tests that use the full application context I found that one change proposed by @wimdeblauwe is essential which is moving the bean definition of
KeyloakSpringBootConfigResolver
to a class separate from the projects central KeycloakConfig.This change involves creating a dedicated class that imports the central config and annotating the bean witrh @Primary, like so:
If I do this both unit and integration tests run fine. I have no clue why this is any different from the unit level tests.
It would be nice to somehow document this or integrate this into the sample project, just to prevent this problem. B.t.w. for reference the exception thrown when not implementing this is: