Spring Security Java -集成测试GraphQL突变安全方法与来自Keycloak的@PreAuthorize角色

tnkciper  于 2023-06-23  发布在  Spring
关注(0)|答案(1)|浏览(158)

目前为止我得到的是:

  • 我有工作单元测试,它返回Spring Security拒绝的访问,这验证了我的角色是否使用Keycloak正确设置。
  • 我已经成功测试了一个没有实现Spring Security的控制器,并给出了预期的结果。
  • 我还尝试过通过Insomnia运行GraphQl突变,服务帐户没有角色,得到403禁止
  • 我还尝试通过Insomnia使用具有管理员角色和没有角色的服务帐户运行相同的GraphQl突变,两种突变都成功进行。(截图包括在内)
    目标:
  • 我正在尝试为我的Java Spring项目编写一个集成测试,该项目使用@WithMockUser来模拟Keycloak中的角色。

来自控制器的方法:

@MutationMapping
  @PreAuthorize("hasRole(admin)")
  public Entity addEntity(@Valid @Argument EntityInput input) {
    var entity =
        Entity.builder()
            .name(input.getName())
            .description(input.getDescription() != null ? input.getDescription() : "")
            .customId(input.getCustomId() != null ? input.getCustomId() : "")
            .notBefore(input.getNotBefore().toInstant())
            .expires(input.getExpires() != null ? input.getExpires().toInstant() : null)
            .entityType(input.getEntityType())
            .archived(false)
            .build();

    return entityRepository.persistAndFlush(entity);
  }

我的GraphQl Schema用于测试

mutation AddEntity($input: EntityInput!) {
  addEntityl(input: $input) {
    name
    description
    customId
    entityType
    notBefore
    expires
    archived
  }
}

我的测试

@Autowired private WebGraphQlTester graphQlTester;

@WithMockUser(username = "Test", roles={"read_only"})
@Test
void addEntity_with_readonly_role_return_403_forbidden() {
 var entityInput =
 Map.of(
  "customId",
  "Testing",
  "name",
  "Test name",
  "description",
  "Test description",
  "entityType",
  "MANUAL",
  "notBefore",
  "2023-06-28T13:37:00Z",
  "expires",
  "2023-07-04T13:37:00Z");

  graphQlTester
   .documentName("entities")
   .operationName("AddEntity")
   .variable("input", entityInput)
   .execute()
   .errors()
   .satisfy(
     errors -> {
      assertThat(errors).hasSize(1);
      assertThat(errors.get(0).getErrorType()).isEqualTo(ErrorType.FORBIDDEN);
 });
}

失眠的结果:

编辑:
我还深入研究了一下,发现WebGraphQlTester不支持@WithMockUser,因为它不更新安全上下文。如果任何人有变通方法或其他解决方案,请发布。

fzwojiic

fzwojiic1#

为了测试自定义角色(或任何高级安全设置),我采取了简单地插入Authentication的模拟/测试实现到SecurityContextHolder中。例如,我使用JWT,所以我构建令牌如下:

private fun buildAuthentication(user: User): JwtAuthenticationToken {
    val unusedAttributes = mapOf("some" to "attribute")
    val unusedHeaders = mapOf("some" to "header")
    val claims = mapOf("sub" to user.subject, "email" to user.email)
    val authorities = listOf(OAuth2UserAuthority("ROLE_CLIENT", unusedAttributes))
    val jwt = Jwt("token", null, null, unusedHeaders, claims)
    return JwtAuthenticationToken(jwt, authorities)
}

您可以将测试想要承担的任何角色而不是ROLE_CLIENT
您甚至可以创建自己的注解,从而产生与@WithMockUser类似的用法:

@WithSecurityContext(factory = TestUserSecurityContextFactory::class)
annotation class WithTestUserSecurityContext

class TestUserSecurityContextFactory : WithSecurityContextFactory<WithTestUserSecurityContext> {
    override fun createSecurityContext(annotation: WithTestUserSecurityContext) =
        SecurityContextHolder.createEmptyContext().apply { authentication = buildAuthentication(TEST_USER) }
    }
}

相关问题