question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Document how to use this if Keycloak is on the classpath

See original GitHub issue

Thank 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:

  1. 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 {};

}
  1. 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");
    }
}
  1. Next, I added application-webmvc-test.properties in src/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
  1. 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:closed
  • Created 3 years ago
  • Comments:14 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
ch4mpycommented, Apr 29, 2020

I’ll try some investigation and maybe open a Keykloak ticket.

0reactions
pvannieropcommented, Apr 30, 2020

@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:

@TestConfiguration
@Import({KeycloakAutoConfiguration.class, KeycloakConfig.class})
public class KeycloakTestConfiguration {
    @Bean
    @Primary
    public KeycloakSpringBootConfigResolver testKeycloakSpringBootConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }
}

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:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'keycloakConfigResolver': Requested bean is currently in creation: Is there an unresolvable circular reference?
Read more comments on GitHub >

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

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found