Baeldung source format

This commit is contained in:
ch4mpy 2023-02-25 14:36:42 -10:00
parent 66d71f0697
commit 26e401b290
13 changed files with 384 additions and 375 deletions

View File

@ -1,7 +0,0 @@
## Spring-Security 6 OAuth2 testing samples
This module contains articles about testing spring-security 6 access-control with OAuth2
## Relevant articles:
- [Testing Spring OAuth2 Access-Control](https://drafts.baeldung.com/?p=154767&preview=true)

View File

@ -1,32 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>spring-security-oauth2-testing</artifactId> <artifactId>spring-security-oauth2-testing</artifactId>
<name>spring-security-oauth2-testing</name> <name>spring-security-oauth2-testing</name>
<packaging>pom</packaging> <packaging>pom</packaging>
<description>spring-security 6 oauth testing sample project</description> <description>spring-security 6 oauth testing sample project</description>
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>parent-boot-3</artifactId> <artifactId>parent-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-3</relativePath> <relativePath>../../parent-boot-3</relativePath>
</parent> </parent>
<properties> <properties>
<spring-addons.version>6.0.14</spring-addons.version> <spring-addons.version>6.1.0</spring-addons.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.c4-soft.springaddons</groupId> <groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-oauth2-test</artifactId> <artifactId>spring-addons-oauth2-test</artifactId>
<version>${spring-addons.version}</version> <version>${spring-addons.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
<modules> <modules>
<module>reactive-resource-server</module> <module>reactive-resource-server</module>
<module>servlet-resource-server</module> <module>servlet-resource-server</module>
</modules> </modules>
</project> </project>

View File

@ -1,58 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>spring-security-oauth2-testing</artifactId> <artifactId>spring-security-oauth2-testing</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
</parent> </parent>
<groupId>com.baeldung.spring-security-modules.testing</groupId> <groupId>com.baeldung.spring-security-modules.testing</groupId>
<artifactId>reactive-resource-server</artifactId> <artifactId>reactive-resource-server</artifactId>
<name>reactive-resource-server</name> <name>reactive-resource-server</name>
<description>Demo project for Spring Boot reactive resource-server</description> <description>Demo project for Spring Boot reactive resource-server</description>
<properties> <properties>
<java.version>17</java.version> <java.version>17</java.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId> <artifactId>spring-boot-starter-webflux</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.c4-soft.springaddons</groupId> <groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-oauth2-test</artifactId> <artifactId>spring-addons-oauth2-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <configuration>
<excludes> <excludes>
<exclude> <exclude>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
</exclude> </exclude>
</excludes> </excludes>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -49,19 +49,32 @@ public class ReactiveResourceServerApplication {
public class SecurityConfig { public class SecurityConfig {
@Bean @Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, Converter<Jwt, Mono<Collection<GrantedAuthority>>> authoritiesConverter) { SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, Converter<Jwt, Mono<Collection<GrantedAuthority>>> authoritiesConverter) {
http.oauth2ResourceServer().jwt() http.oauth2ResourceServer()
.jwtAuthenticationConverter(jwt -> authoritiesConverter.convert(jwt).map(authorities -> new JwtAuthenticationToken(jwt, authorities))); .jwt()
http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance()).csrf().disable(); .jwtAuthenticationConverter(jwt -> authoritiesConverter.convert(jwt)
http.exceptionHandling().accessDeniedHandler((var exchange, var ex) -> exchange.getPrincipal().flatMap(principal -> { .map(authorities -> new JwtAuthenticationToken(jwt, authorities)));
final var response = exchange.getResponse(); http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
response.setStatusCode(principal instanceof AnonymousAuthenticationToken ? HttpStatus.UNAUTHORIZED : HttpStatus.FORBIDDEN); .csrf()
response.getHeaders().setContentType(MediaType.TEXT_PLAIN); .disable();
final var dataBufferFactory = response.bufferFactory(); http.exceptionHandling()
final var buffer = dataBufferFactory.wrap(ex.getMessage().getBytes(Charset.defaultCharset())); .accessDeniedHandler((var exchange, var ex) -> exchange.getPrincipal()
return response.writeWith(Mono.just(buffer)).doOnError(error -> DataBufferUtils.release(buffer)); .flatMap(principal -> {
})); final var response = exchange.getResponse();
response.setStatusCode(principal instanceof AnonymousAuthenticationToken ? HttpStatus.UNAUTHORIZED : HttpStatus.FORBIDDEN);
response.getHeaders()
.setContentType(MediaType.TEXT_PLAIN);
final var dataBufferFactory = response.bufferFactory();
final var buffer = dataBufferFactory.wrap(ex.getMessage()
.getBytes(Charset.defaultCharset()));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
}));
http.authorizeExchange().pathMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL").anyExchange().authenticated(); http.authorizeExchange()
.pathMatchers("/secured-route")
.hasRole("AUTHORIZED_PERSONNEL")
.anyExchange()
.authenticated();
return http.build(); return http.build();
} }
@ -72,10 +85,14 @@ public class ReactiveResourceServerApplication {
@Bean @Bean
AuthoritiesConverter realmRoles2AuthoritiesConverter() { AuthoritiesConverter realmRoles2AuthoritiesConverter() {
return (Jwt jwt) -> { return (Jwt jwt) -> {
final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access")).orElse(Map.of()); final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access"))
.orElse(Map.of());
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final var roles = (List<String>) realmRoles.getOrDefault("roles", List.of()); final var roles = (List<String>) realmRoles.getOrDefault("roles", List.of());
return Mono.just(roles.stream().map(SimpleGrantedAuthority::new).map(GrantedAuthority.class::cast).toList()); return Mono.just(roles.stream()
.map(SimpleGrantedAuthority::new)
.map(GrantedAuthority.class::cast)
.toList());
}; };
} }
} }
@ -84,13 +101,13 @@ public class ReactiveResourceServerApplication {
public static class MessageService { public static class MessageService {
public Mono<String> greet() { public Mono<String> greet() {
return ReactiveSecurityContextHolder.getContext().map(ctx -> { return ReactiveSecurityContextHolder.getContext()
final var who = (JwtAuthenticationToken) ctx.getAuthentication(); .map(ctx -> {
final var claims = who.getTokenAttributes(); final var who = (JwtAuthenticationToken) ctx.getAuthentication();
return "Hello %s! You are granted with %s.".formatted( final var claims = who.getTokenAttributes();
claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME,claims.get(StandardClaimNames.SUB)), return "Hello %s! You are granted with %s.".formatted(claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME, claims.get(StandardClaimNames.SUB)), who.getAuthorities());
who.getAuthorities()); })
}).switchIfEmpty(Mono.error(new AuthenticationCredentialsNotFoundException("Security context is empty"))); .switchIfEmpty(Mono.error(new AuthenticationCredentialsNotFoundException("Security context is empty")));
} }
@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")
@ -106,18 +123,21 @@ public class ReactiveResourceServerApplication {
@GetMapping("/greet") @GetMapping("/greet")
public Mono<ResponseEntity<String>> greet() { public Mono<ResponseEntity<String>> greet() {
return messageService.greet().map(ResponseEntity::ok); return messageService.greet()
.map(ResponseEntity::ok);
} }
@GetMapping("/secured-route") @GetMapping("/secured-route")
public Mono<ResponseEntity<String>> securedRoute() { public Mono<ResponseEntity<String>> securedRoute() {
return messageService.getSecret().map(ResponseEntity::ok); return messageService.getSecret()
.map(ResponseEntity::ok);
} }
@GetMapping("/secured-method") @GetMapping("/secured-method")
@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")
public Mono<ResponseEntity<String>> securedMethod() { public Mono<ResponseEntity<String>> securedMethod() {
return messageService.getSecret().map(ResponseEntity::ok); return messageService.getSecret()
.map(ResponseEntity::ok);
} }
} }

View File

@ -32,25 +32,29 @@ class MessageServiceUnitTest {
@Test @Test
void givenSecurityContextIsEmpty_whenGreet_thenThrowsAuthenticationCredentialsNotFoundException() { void givenSecurityContextIsEmpty_whenGreet_thenThrowsAuthenticationCredentialsNotFoundException() {
assertThrows(AuthenticationCredentialsNotFoundException.class, () -> messageService.greet().block()); assertThrows(AuthenticationCredentialsNotFoundException.class, () -> messageService.greet()
.block());
} }
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsNotAuthenticated_whenGreet_thenThrowsClassCastException() { void givenUserIsNotAuthenticated_whenGreet_thenThrowsClassCastException() {
assertThrows(ClassCastException.class, () -> messageService.greet().block()); assertThrows(ClassCastException.class, () -> messageService.greet()
.block());
} }
@Test @Test
@WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
void givenSecurityContextIsPopulatedWithJwtAuthenticationToken_whenGreet_thenReturnGreetingWithPreferredUsernameAndAuthorities() { void givenSecurityContextIsPopulatedWithJwtAuthenticationToken_whenGreet_thenReturnGreetingWithPreferredUsernameAndAuthorities() {
assertEquals("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].", messageService.greet().block()); assertEquals("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].", messageService.greet()
.block());
} }
@Test @Test
@WithMockUser(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, username = "ch4mpy") @WithMockUser(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, username = "ch4mpy")
void givenSecurityContextIsPopulatedWithUsernamePasswordAuthenticationToken_whenGreet_thenThrowsClassCastException() { void givenSecurityContextIsPopulatedWithUsernamePasswordAuthenticationToken_whenGreet_thenThrowsClassCastException() {
assertThrows(ClassCastException.class, () -> messageService.greet().block()); assertThrows(ClassCastException.class, () -> messageService.greet()
.block());
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
@ -61,19 +65,22 @@ class MessageServiceUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsNotAuthenticated_whenGetSecret_thenThrowsAccessDeniedException() { void givenUserIsNotAuthenticated_whenGetSecret_thenThrowsAccessDeniedException() {
assertThrows(AccessDeniedException.class, () -> messageService.getSecret().block()); assertThrows(AccessDeniedException.class, () -> messageService.getSecret()
.block());
} }
@Test @Test
@WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenReturnSecret() { void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenReturnSecret() {
assertEquals("Only authorized personnel can read that", messageService.getSecret().block()); assertEquals("Only authorized personnel can read that", messageService.getSecret()
.block());
} }
@Test @Test
@WithMockJwtAuth(authorities = { "admin" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) @WithMockJwtAuth(authorities = { "admin" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenThrowsAccessDeniedException() { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenThrowsAccessDeniedException() {
assertThrows(AccessDeniedException.class, () -> messageService.getSecret().block()); assertThrows(AccessDeniedException.class, () -> messageService.getSecret()
.block());
} }
} }

View File

@ -25,22 +25,23 @@ class ReactiveResourceServerApplicationIntegrationTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception {
// @formatter:off api.get()
api.get().uri("/greet").exchange() .uri("/greet")
.expectStatus().isUnauthorized(); .exchange()
// @formatter:on .expectStatus()
.isUnauthorized();
} }
@Test @Test
@WithMockJwtAuth( @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"},
claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception {
// @formatter:off api.get()
api.get().uri("/greet").exchange() .uri("/greet")
.expectStatus().isOk() .exchange()
.expectBody(String.class).isEqualTo("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL]."); .expectStatus()
// @formatter:on .isOk()
.expectBody(String.class)
.isEqualTo("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].");
} }
/*---------------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------------*/
@ -51,29 +52,33 @@ class ReactiveResourceServerApplicationIntegrationTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception {
// @formatter:off api.get()
api.get().uri("/secured-route").exchange() .uri("/secured-route")
.expectStatus().isUnauthorized(); .exchange()
// @formatter:on .expectStatus()
.isUnauthorized();
} }
@Test @Test
@WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL")
void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception {
// @formatter:off api.get()
api.get().uri("/secured-route").exchange() .uri("/secured-route")
.expectStatus().isOk() .exchange()
.expectBody(String.class).isEqualTo("Only authorized personnel can read that"); .expectStatus()
// @formatter:on .isOk()
.expectBody(String.class)
.isEqualTo("Only authorized personnel can read that");
} }
@Test @Test
@WithMockJwtAuth("admin") @WithMockJwtAuth("admin")
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception {
// @formatter:off api.get()
api.get().uri("/secured-route").exchange() .uri("/secured-route")
.expectStatus().isForbidden(); .exchange()
// @formatter:on .expectStatus()
.isForbidden();
} }
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
@ -84,28 +89,32 @@ class ReactiveResourceServerApplicationIntegrationTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception {
// @formatter:off api.get()
api.get().uri("/secured-method").exchange() .uri("/secured-method")
.expectStatus().isUnauthorized(); .exchange()
// @formatter:on .expectStatus()
.isUnauthorized();
} }
@Test @Test
@WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL")
void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception {
// @formatter:off api.get()
api.get().uri("/secured-method").exchange() .uri("/secured-method")
.expectStatus().isOk() .exchange()
.expectBody(String.class).isEqualTo("Only authorized personnel can read that"); .expectStatus()
// @formatter:on .isOk()
.expectBody(String.class)
.isEqualTo("Only authorized personnel can read that");
} }
@Test @Test
@WithMockJwtAuth("admin") @WithMockJwtAuth("admin")
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception {
// @formatter:off api.get()
api.get().uri("/secured-method").exchange() .uri("/secured-method")
.expectStatus().isForbidden(); .exchange()
// @formatter:on .expectStatus()
.isForbidden();
} }
} }

View File

@ -35,22 +35,26 @@ class SpringAddonsGreetingControllerUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception {
api.get().uri("/greet").exchange().expectStatus().isUnauthorized(); api.get()
.uri("/greet")
.exchange()
.expectStatus()
.isUnauthorized();
} }
@Test @Test
@WithMockJwtAuth( @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"},
claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception {
final var greeting = "Whatever the service returns"; final var greeting = "Whatever the service returns";
when(messageService.greet()).thenReturn(Mono.just(greeting)); when(messageService.greet()).thenReturn(Mono.just(greeting));
// @formatter:off api.get()
api.get().uri("/greet").exchange() .uri("/greet")
.expectStatus().isOk() .exchange()
.expectBody(String.class).isEqualTo(greeting); .expectStatus()
// @formatter:on .isOk()
.expectBody(String.class)
.isEqualTo(greeting);
verify(messageService, times(1)).greet(); verify(messageService, times(1)).greet();
} }
@ -63,7 +67,11 @@ class SpringAddonsGreetingControllerUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception {
api.get().uri("/secured-route").exchange().expectStatus().isUnauthorized(); api.get()
.uri("/secured-route")
.exchange()
.expectStatus()
.isUnauthorized();
} }
@Test @Test
@ -72,20 +80,23 @@ class SpringAddonsGreetingControllerUnitTest {
final var secret = "Secret!"; final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(Mono.just(secret)); when(messageService.getSecret()).thenReturn(Mono.just(secret));
// @formatter:off api.get()
api.get().uri("/secured-route").exchange() .uri("/secured-route")
.expectStatus().isOk() .exchange()
.expectBody(String.class).isEqualTo(secret); .expectStatus()
// @formatter:on .isOk()
.expectBody(String.class)
.isEqualTo(secret);
} }
@Test @Test
@WithMockJwtAuth("admin") @WithMockJwtAuth("admin")
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception {
// @formatter:off api.get()
api.get().uri("/secured-route").exchange() .uri("/secured-route")
.expectStatus().isForbidden(); .exchange()
// @formatter:on .expectStatus()
.isForbidden();
} }
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
@ -96,7 +107,11 @@ class SpringAddonsGreetingControllerUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception {
api.get().uri("/secured-method").exchange().expectStatus().isUnauthorized(); api.get()
.uri("/secured-method")
.exchange()
.expectStatus()
.isUnauthorized();
} }
@Test @Test
@ -105,21 +120,23 @@ class SpringAddonsGreetingControllerUnitTest {
final var secret = "Secret!"; final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(Mono.just(secret)); when(messageService.getSecret()).thenReturn(Mono.just(secret));
// @formatter:off api.get()
api.get().uri("/secured-method").exchange() .uri("/secured-method")
.expectStatus().isOk() .exchange()
.expectBody(String.class).isEqualTo(secret); .expectStatus()
// @formatter:on .isOk()
.expectBody(String.class)
.isEqualTo(secret);
} }
@Test @Test
@WithMockJwtAuth("admin") @WithMockJwtAuth("admin")
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception {
// @formatter:off api.get()
api.get().uri("/secured-method").exchange() .uri("/secured-method")
.expectStatus().isForbidden(); .exchange()
// @formatter:on .expectStatus()
.isForbidden();
} }
} }

View File

@ -25,10 +25,7 @@ import reactor.core.publisher.Mono;
@WebFluxTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) @WebFluxTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" })
class SpringSecurityTestGreetingControllerUnitTest { class SpringSecurityTestGreetingControllerUnitTest {
private static final AnonymousAuthenticationToken ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken( private static final AnonymousAuthenticationToken ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken("anonymous", "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
"anonymous",
"anonymousUser",
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
@MockBean @MockBean
MessageService messageService; MessageService messageService;
@ -43,11 +40,12 @@ class SpringSecurityTestGreetingControllerUnitTest {
@Test @Test
void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception {
// @formatter:off
api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION))
.get().uri("/greet").exchange() .get()
.expectStatus().isUnauthorized(); .uri("/greet")
// @formatter:on .exchange()
.expectStatus()
.isUnauthorized();
} }
@Test @Test
@ -55,14 +53,15 @@ class SpringSecurityTestGreetingControllerUnitTest {
final var greeting = "Whatever the service returns"; final var greeting = "Whatever the service returns";
when(messageService.greet()).thenReturn(Mono.just(greeting)); when(messageService.greet()).thenReturn(Mono.just(greeting));
// @formatter:off api.mutateWith(mockJwt().authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))
api.mutateWith(mockJwt() .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy")))
.authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) .get()
.jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy"))) .uri("/greet")
.get().uri("/greet").exchange() .exchange()
.expectStatus().isOk() .expectStatus()
.expectBody(String.class).isEqualTo(greeting); .isOk()
// @formatter:on .expectBody(String.class)
.isEqualTo(greeting);
verify(messageService, times(1)).greet(); verify(messageService, times(1)).greet();
} }
@ -74,11 +73,12 @@ class SpringSecurityTestGreetingControllerUnitTest {
@Test @Test
void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception {
// @formatter:off
api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION))
.get().uri("/secured-route").exchange() .get()
.expectStatus().isUnauthorized(); .uri("/secured-route")
// @formatter:on .exchange()
.expectStatus()
.isUnauthorized();
} }
@Test @Test
@ -86,21 +86,24 @@ class SpringSecurityTestGreetingControllerUnitTest {
final var secret = "Secret!"; final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(Mono.just(secret)); when(messageService.getSecret()).thenReturn(Mono.just(secret));
// @formatter:off
api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))
.get().uri("/secured-route").exchange() .get()
.expectStatus().isOk() .uri("/secured-route")
.expectBody(String.class).isEqualTo(secret); .exchange()
// @formatter:on .expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo(secret);
} }
@Test @Test
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception {
// @formatter:off
api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin"))) api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin")))
.get().uri("/secured-route").exchange() .get()
.expectStatus().isForbidden(); .uri("/secured-route")
// @formatter:on .exchange()
.expectStatus()
.isForbidden();
} }
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
@ -110,11 +113,12 @@ class SpringSecurityTestGreetingControllerUnitTest {
@Test @Test
void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception {
// @formatter:off
api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION))
.get().uri("/secured-method").exchange() .get()
.expectStatus().isUnauthorized(); .uri("/secured-method")
// @formatter:on .exchange()
.expectStatus()
.isUnauthorized();
} }
@Test @Test
@ -122,22 +126,24 @@ class SpringSecurityTestGreetingControllerUnitTest {
final var secret = "Secret!"; final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(Mono.just(secret)); when(messageService.getSecret()).thenReturn(Mono.just(secret));
// @formatter:off
api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))
.get().uri("/secured-method").exchange() .get()
.expectStatus().isOk() .uri("/secured-method")
.expectBody(String.class).isEqualTo(secret); .exchange()
// @formatter:on .expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo(secret);
} }
@Test @Test
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception {
// @formatter:off
api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin"))) api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin")))
.get().uri("/secured-method").exchange() .get()
.expectStatus().isForbidden(); .uri("/secured-method")
// @formatter:on .exchange()
.expectStatus()
.isForbidden();
} }
} }

View File

@ -1,58 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>spring-security-oauth2-testing</artifactId> <artifactId>spring-security-oauth2-testing</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
</parent> </parent>
<groupId>com.baeldung.spring-security-modules.testing</groupId> <groupId>com.baeldung.spring-security-modules.testing</groupId>
<artifactId>servlet-resource-server</artifactId> <artifactId>servlet-resource-server</artifactId>
<name>servlet-resource-server</name> <name>servlet-resource-server</name>
<description>Demo project for Spring Boot servlet resource-server</description> <description>Demo project for Spring Boot servlet resource-server</description>
<properties> <properties>
<java.version>17</java.version> <java.version>17</java.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.c4-soft.springaddons</groupId> <groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-oauth2-test</artifactId> <artifactId>spring-addons-oauth2-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <configuration>
<excludes> <excludes>
<exclude> <exclude>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
</exclude> </exclude>
</excludes> </excludes>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -44,18 +44,25 @@ public class ServletResourceServerApplication {
static class SecurityConf { static class SecurityConf {
@Bean @Bean
SecurityFilterChain filterChain(HttpSecurity http, Converter<Jwt, Collection<GrantedAuthority>> authoritiesConverter) throws Exception { SecurityFilterChain filterChain(HttpSecurity http, Converter<Jwt, Collection<GrantedAuthority>> authoritiesConverter) throws Exception {
// @formatter:off http.oauth2ResourceServer()
http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwt -> new JwtAuthenticationToken(jwt, authoritiesConverter.convert(jwt))); .jwt()
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().csrf().disable(); .jwtAuthenticationConverter(jwt -> new JwtAuthenticationToken(jwt, authoritiesConverter.convert(jwt)));
http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> { http.sessionManagement()
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Restricted Content\""); .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase()); .and()
}); .csrf()
.disable();
http.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> {
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Restricted Content\"");
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
});
http.authorizeHttpRequests() http.authorizeHttpRequests()
.requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL") .requestMatchers("/secured-route")
.anyRequest().authenticated(); .hasRole("AUTHORIZED_PERSONNEL")
// @formatter:on .anyRequest()
.authenticated();
return http.build(); return http.build();
} }
@ -66,10 +73,14 @@ public class ServletResourceServerApplication {
@Bean @Bean
AuthoritiesConverter realmRoles2AuthoritiesConverter() { AuthoritiesConverter realmRoles2AuthoritiesConverter() {
return (Jwt jwt) -> { return (Jwt jwt) -> {
final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access")).orElse(Map.of()); final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access"))
.orElse(Map.of());
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final var roles = (List<String>) realmRoles.getOrDefault("roles", List.of()); final var roles = (List<String>) realmRoles.getOrDefault("roles", List.of());
return roles.stream().map(SimpleGrantedAuthority::new).map(GrantedAuthority.class::cast).toList(); return roles.stream()
.map(SimpleGrantedAuthority::new)
.map(GrantedAuthority.class::cast)
.toList();
}; };
} }
} }
@ -78,11 +89,10 @@ public class ServletResourceServerApplication {
public static class MessageService { public static class MessageService {
public String greet() { public String greet() {
final var who = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); final var who = (JwtAuthenticationToken) SecurityContextHolder.getContext()
.getAuthentication();
final var claims = who.getTokenAttributes(); final var claims = who.getTokenAttributes();
return "Hello %s! You are granted with %s.".formatted( return "Hello %s! You are granted with %s.".formatted(claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME, claims.get(StandardClaimNames.SUB)), who.getAuthorities());
claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME, claims.get(StandardClaimNames.SUB)),
who.getAuthorities());
} }
@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")

View File

@ -29,22 +29,16 @@ class ServletResourceServerApplicationIntegrationTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception {
// @formatter:off
api.perform(get("/greet")) api.perform(get("/greet"))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
// @formatter:on
} }
@Test @Test
@WithMockJwtAuth( @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"},
claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception {
// @formatter:off
api.perform(get("/greet")) api.perform(get("/greet"))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].")); .andExpect(content().string("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL]."));
// @formatter:on
} }
/*---------------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------------*/
@ -55,29 +49,23 @@ class ServletResourceServerApplicationIntegrationTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception {
// @formatter:off
api.perform(get("/secured-route")) api.perform(get("/secured-route"))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
// @formatter:on
} }
@Test @Test
@WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL")
void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception {
// @formatter:off
api.perform(get("/secured-route")) api.perform(get("/secured-route"))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string("Only authorized personnel can read that")); .andExpect(content().string("Only authorized personnel can read that"));
// @formatter:on
} }
@Test @Test
@WithMockJwtAuth("admin") @WithMockJwtAuth("admin")
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception {
// @formatter:off
api.perform(get("/secured-route")) api.perform(get("/secured-route"))
.andExpect(status().isForbidden()); .andExpect(status().isForbidden());
// @formatter:on
} }
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
@ -88,29 +76,23 @@ class ServletResourceServerApplicationIntegrationTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception {
// @formatter:off
api.perform(get("/secured-method")) api.perform(get("/secured-method"))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
// @formatter:on
} }
@Test @Test
@WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL")
void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception {
// @formatter:off
api.perform(get("/secured-method")) api.perform(get("/secured-method"))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string("Only authorized personnel can read that")); .andExpect(content().string("Only authorized personnel can read that"));
// @formatter:on
} }
@Test @Test
@WithMockJwtAuth("admin") @WithMockJwtAuth("admin")
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception {
// @formatter:off
api.perform(get("/secured-method")) api.perform(get("/secured-method"))
.andExpect(status().isForbidden()); .andExpect(status().isForbidden());
// @formatter:on
} }
} }

View File

@ -36,25 +36,19 @@ class SpringAddonsGreetingControllerUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception {
// @formatter:off
api.perform(get("/greet")) api.perform(get("/greet"))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
// @formatter:on
} }
@Test @Test
@WithMockJwtAuth( @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"},
claims = @OpenIdClaims(preferredUsername = "ch4mpy"))
void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception {
final var greeting = "Whatever the service returns"; final var greeting = "Whatever the service returns";
when(messageService.greet()).thenReturn(greeting); when(messageService.greet()).thenReturn(greeting);
// @formatter:off
api.perform(get("/greet")) api.perform(get("/greet"))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string(greeting)); .andExpect(content().string(greeting));
// @formatter:on
verify(messageService, times(1)).greet(); verify(messageService, times(1)).greet();
} }
@ -67,10 +61,8 @@ class SpringAddonsGreetingControllerUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception {
// @formatter:off
api.perform(get("/secured-route")) api.perform(get("/secured-route"))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
// @formatter:on
} }
@Test @Test
@ -79,20 +71,16 @@ class SpringAddonsGreetingControllerUnitTest {
final var secret = "Secret!"; final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(secret); when(messageService.getSecret()).thenReturn(secret);
// @formatter:off
api.perform(get("/secured-route")) api.perform(get("/secured-route"))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string(secret)); .andExpect(content().string(secret));
// @formatter:on
} }
@Test @Test
@WithMockJwtAuth({ "admin" }) @WithMockJwtAuth({ "admin" })
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception {
// @formatter:off
api.perform(get("/secured-route")) api.perform(get("/secured-route"))
.andExpect(status().isForbidden()); .andExpect(status().isForbidden());
// @formatter:on
} }
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
@ -103,10 +91,8 @@ class SpringAddonsGreetingControllerUnitTest {
@Test @Test
@WithAnonymousUser @WithAnonymousUser
void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception {
// @formatter:off
api.perform(get("/secured-method")) api.perform(get("/secured-method"))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
// @formatter:on
} }
@Test @Test
@ -115,20 +101,16 @@ class SpringAddonsGreetingControllerUnitTest {
final var secret = "Secret!"; final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(secret); when(messageService.getSecret()).thenReturn(secret);
// @formatter:off
api.perform(get("/secured-method")) api.perform(get("/secured-method"))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string(secret)); .andExpect(content().string(secret));
// @formatter:on
} }
@Test @Test
@WithMockJwtAuth(authorities = { "admin" }) @WithMockJwtAuth(authorities = { "admin" })
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception {
// @formatter:off
api.perform(get("/secured-method")) api.perform(get("/secured-method"))
.andExpect(status().isForbidden()); .andExpect(status().isForbidden());
// @formatter:on
} }
} }

View File

@ -38,10 +38,8 @@ class SpringSecurityTestGreetingControllerUnitTest {
@Test @Test
void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception {
// @formatter:off
api.perform(get("/greet").with(anonymous())) api.perform(get("/greet").with(anonymous()))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
// @formatter:on
} }
@Test @Test
@ -49,13 +47,10 @@ class SpringSecurityTestGreetingControllerUnitTest {
final var greeting = "Whatever the service returns"; final var greeting = "Whatever the service returns";
when(messageService.greet()).thenReturn(greeting); when(messageService.greet()).thenReturn(greeting);
// @formatter:off api.perform(get("/greet").with(jwt().authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))
api.perform(get("/greet").with(jwt() .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy"))))
.authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))
.jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy"))))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string(greeting)); .andExpect(content().string(greeting));
// @formatter:on
verify(messageService, times(1)).greet(); verify(messageService, times(1)).greet();
} }
@ -67,10 +62,8 @@ class SpringSecurityTestGreetingControllerUnitTest {
@Test @Test
void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception {
// @formatter:off
api.perform(get("/secured-route").with(anonymous())) api.perform(get("/secured-route").with(anonymous()))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
// @formatter:on
} }
@Test @Test
@ -78,19 +71,15 @@ class SpringSecurityTestGreetingControllerUnitTest {
final var secret = "Secret!"; final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(secret); when(messageService.getSecret()).thenReturn(secret);
// @formatter:off
api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))) api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string(secret)); .andExpect(content().string(secret));
// @formatter:on
} }
@Test @Test
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception {
// @formatter:off
api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("admin")))) api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("admin"))))
.andExpect(status().isForbidden()); .andExpect(status().isForbidden());
// @formatter:on
} }
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
@ -100,10 +89,8 @@ class SpringSecurityTestGreetingControllerUnitTest {
@Test @Test
void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception {
// @formatter:off
api.perform(get("/secured-method").with(anonymous())) api.perform(get("/secured-method").with(anonymous()))
.andExpect(status().isUnauthorized()); .andExpect(status().isUnauthorized());
// @formatter:on
} }
@Test @Test
@ -111,19 +98,15 @@ class SpringSecurityTestGreetingControllerUnitTest {
final var secret = "Secret!"; final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(secret); when(messageService.getSecret()).thenReturn(secret);
// @formatter:off
api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))) api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().string(secret)); .andExpect(content().string(secret));
// @formatter:on
} }
@Test @Test
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception {
// @formatter:off
api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("admin")))) api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("admin"))))
.andExpect(status().isForbidden()); .andExpect(status().isForbidden());
// @formatter:on
} }
} }