java 如何单元测试一个由keycloak保护的SpringBoot控制器?

qpgpyjmq  于 2023-01-29  发布在  Java
关注(0)|答案(1)|浏览(127)

我知道已经有类似的问题,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,并完成了应用运行所需的所有配置,但我在测试中未能模拟/绕过此过程。通常我会在测试中找到解决此身份验证问题的方法(未使用keycloak时),但这次没有。
是否有办法模拟适配器或过滤器进程以绕过此问题?
我已经尝试了其他问题中回答的所有问题(除了图书馆),但没有运气。如果你有任何线索,可能会有所帮助,或至少指出我正确的方向(因为这可能是由于缺乏知识的Spring安全从我的一部分),将非常感谢。

8hhllhi2

8hhllhi21#

2023更新

deprecated Keycloak adapters for Spring(其中定义了KeycloakAuthenticationToken)与spring-boot 3不兼容。“将KeycloakSpring适配器与Spring Boot 3配合使用”的可接受答案中的备选项

原始答案

正如我在对您链接的第一个问题的回答中所写的,当您的code / conf可能期望KeycloakAuthenticationToken时,@WithMockUser使用UsernamePaswordAuthenticationToken填充安全上下文。
如果你仔细阅读同样的答案,你会发现一个替代使用我的库来做这件事:在每个测试中使用KeycloakAuthenticationToken示例或mock手动填充安全上下文。

最小样本,Mockito,我添加到我的回购:

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

也许,在你衡量了这会给你的测试带来多大的混乱之后(这里几乎没有声明),你会重新考虑使用我的库(或者从它复制,因为它是开源的)。
加上我的注解,上述示例变为:

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

关于包含Keycloak的spring测试配置,您可以深入了解spring-addons-keycloak模块的测试,您会发现complete app using KeycloakAuthenticationToken包含单元测试(以及工作测试配置)。
最后(可能离题了),您可以阅读repo main README,并考虑使用比Keycloak的OIDC实现更通用的OIDC实现。我提供了一个OIDC实现,沿着测试注解,并编写了关于如何扩展它以满足您的应用特定需求的教程。

相关问题