diff --git a/servlet/spring-boot/java/oauth2/resource-server/hello-security/src/test/java/example/OAuth2ResourceServerControllerTests.java b/servlet/spring-boot/java/oauth2/resource-server/hello-security/src/test/java/example/OAuth2ResourceServerControllerTests.java index 4943af6..94b854c 100644 --- a/servlet/spring-boot/java/oauth2/resource-server/hello-security/src/test/java/example/OAuth2ResourceServerControllerTests.java +++ b/servlet/spring-boot/java/oauth2/resource-server/hello-security/src/test/java/example/OAuth2ResourceServerControllerTests.java @@ -16,12 +16,31 @@ package example; +import java.io.InputStream; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.context.annotation.Import; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.security.test.context.support.WithSecurityContext; +import org.springframework.security.test.context.support.WithSecurityContextFactory; import org.springframework.test.web.servlet.MockMvc; import static org.hamcrest.CoreMatchers.is; @@ -102,4 +121,62 @@ public class OAuth2ResourceServerControllerTests { // @formatter:on } + @Test + @WithMockJwt("classpath:validjwt.json") + void indexGreetsAuthenticatedUserWithMockJwt() throws Exception { + this.mockMvc.perform(get("/")).andExpect(content().string(is("Hello, ch4mpy!"))); + } + + @Test + @WithMockJwt(value = "classpath:validjwt.json", authorities = "SCOPE_message:read") + void messageCanBeReadWithScopeMessageReadAuthorityWithMockJwt() throws Exception { + // @formatter:off + this.mockMvc.perform(get("/message")).andExpect(content().string(is("secret message"))); + // @formatter:on + } + + @Test + @WithMockJwt(value = "classpath:validjwt.json", authorities = "SCOPE_message:read") + void messageCanNotBeCreatedWithScopeMessageReadAuthorityWithMockJwt() throws Exception { + // @formatter:off + this.mockMvc.perform(post("/message") + .content("Hello message")) + .andExpect(status().isForbidden()); + // @formatter:on + } + + @Retention(RetentionPolicy.RUNTIME) + @WithSecurityContext(factory = JwtFactory.class) + @interface WithMockJwt { + + String value(); + + String[] authorities() default {}; + + } + + static class JwtFactory implements WithSecurityContextFactory { + + private final ResourceLoader resourceLoader = new DefaultResourceLoader(); + + private final ObjectMapper mapper = new ObjectMapper(); + + @Override + public SecurityContext createSecurityContext(WithMockJwt annotation) { + Resource jwtString = this.resourceLoader.getResource(annotation.value()); + try (InputStream in = jwtString.getInputStream()) { + Map claims = (Map) this.mapper.readValue(in, Map.class); + Jwt jwt = Jwt.withTokenValue("token").header("alg", "none").claims((c) -> c.putAll(claims)).build(); + Collection authorities = Stream.of(annotation.authorities()) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + return new SecurityContextImpl(new JwtAuthenticationToken(jwt, authorities)); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + } + } diff --git a/servlet/spring-boot/java/oauth2/resource-server/hello-security/src/test/resources/validjwt.json b/servlet/spring-boot/java/oauth2/resource-server/hello-security/src/test/resources/validjwt.json new file mode 100644 index 0000000..fe73b5f --- /dev/null +++ b/servlet/spring-boot/java/oauth2/resource-server/hello-security/src/test/resources/validjwt.json @@ -0,0 +1 @@ +{ "sub" : "ch4mpy" } \ No newline at end of file