如何对由keycloak保护的SpringBoot控制器进行单元测试?

时间:2020-06-04 16:01:35

标签: java spring-boot keycloak

我知道关于这个问题已经有类似的问题,herehere,但是提出的每一个解决方案都无法帮助我。在大多数答案中也都提到了this库,但是(出于所有应有的尊重)我想避免依赖外部库只是为了测试一个简单的控制器。

因此,我有一个非常简单的api,可以使用keycloak生成的承载令牌来访问它,我想测试控制器。遵循以下原则:

@Test
@DisplayName("Should be ok")
@WithMockUser
void whenCalled_shouldBeOk() throws Exception {
    SecurityContext context = SecurityContextHolder.getContext();
    Authentication authentication = context.getAuthentication();
    mockMvc.perform(
        post("/api/url/something")
            .content("{}")
            .contentType(APPLICATION_JSON)
            .with(authentication(authentication))
    ).andExpect(status().isOk());
}

问题是我总是会收到KeycloakDeploymentBuilder抛出的空指针异常,因为它缺少适配器配置。在我们的SecurityConfig中,我们扩展了KeycloakWebSecurityConfigurerAdapter并完成了应用程序运行所需的所有必需配置,但是我无法在测试中模拟/绕过此过程。通常,我会在带有@WithMockUser批注的测试中找到解决身份验证问题的方法(当不使用keycloak时),但是这次却没有。

不是要模拟适配器或过滤器过程来绕过此问题的方法吗?

我尝试了在其他问题(图书馆除外)中回答的所有问题,但是没有运气。如果您有任何帮助的线索,或者至少可以为我指明正确的方向(因为这可能是由于我缺乏对弹簧安全性的了解),那么将不胜感激。

1 个答案:

答案 0 :(得分:0)

正如我在回答您所链接的第一个问题的答案中所写的那样,当您的代码/ conf可能期望使用@WithMockUser时,UsernamePaswordAuthenticationTokenKeycloakAuthenticationToken填充安全上下文。

如果您仔细阅读了相同的答案,您将找到使用我的lib的替代方法:使用KeycloakAuthenticationToken实例手动填充安全上下文或在每个测试中模拟。

最小样本与Mockito I added to my repo

    @Test
    public void test() {
        final var principal = mock(Principal.class);
        when(principal.getName()).thenReturn("user");

        final var account = mock(OidcKeycloakAccount.class);
        when(account.getRoles()).thenReturn(Set.of("offline_access", "uma_authorization"));
        when(account.getPrincipal()).thenReturn(principal);

        final var authentication = mock(KeycloakAuthenticationToken.class);
        when(authentication.getAccount()).thenReturn(account);

        // post(...).with(authentication(authentication))
        // limits to testing secured @Controller with MockMvc
        // I prefer to set security context directly instead:
        SecurityContextHolder.getContext().setAuthentication(authentication);

        //TODO: invoque mockmvc to test @Controller or test any other type of @Component as usual
    }

也许,在您确定这会使您的测试杂乱无章(此处设置的声明很少)后,您将重新考虑使用我的lib(或从它的开源版本复制它)。

使用我的注释,上面的示例变为:

    @Test
    @WithMockKeycloakAuth
    public void test() throws Exception {
        //TODO: invoque mockmvc to test @Controller or test any other type of @Component as usual
    }

关于涉及Keycloak的弹簧测试配置,您可以深入研究spring-security-oauth2-test-webmvc-addons模块的测试。您会发现一个complete app using KeycloakAuthenticationToken带有单元测试(和有效的测试配置)