From b4d18fd2274269addc96a0084a8dd22eb6cd1519 Mon Sep 17 00:00:00 2001 From: ch4mpy Date: Thu, 16 Feb 2023 08:47:54 -1000 Subject: [PATCH 1/6] https://jira.baeldung.com/browse/BAEL-6223 --- pom.xml | 1 + .../spring-security-oauth2-testing/README.md | 7 + .../spring-security-oauth2-testing/pom.xml | 32 ++++ .../reactive-resource-server/pom.xml | 58 ++++++++ .../ReactiveResourceServerApplication.java | 124 ++++++++++++++++ .../src/main/resources/application.yaml | 6 + .../com/baeldung/MessageServiceUnitTest.java | 79 ++++++++++ ...ourceServerApplicationIntegrationTest.java | 109 ++++++++++++++ ...pringAddonsGreetingControllerUnitTest.java | 123 ++++++++++++++++ ...ecurityTestGreetingControllerUnitTest.java | 138 ++++++++++++++++++ .../servlet-resource-server/pom.xml | 58 ++++++++ .../ServletResourceServerApplication.java | 116 +++++++++++++++ .../src/main/resources/application.properties | 1 + .../com/baeldung/MessageServiceUnitTest.java | 79 ++++++++++ ...ourceServerApplicationIntegrationTest.java | 114 +++++++++++++++ ...pringAddonsGreetingControllerUnitTest.java | 131 +++++++++++++++++ ...ecurityTestGreetingControllerUnitTest.java | 124 ++++++++++++++++ 17 files changed, 1300 insertions(+) create mode 100644 spring-security-modules/spring-security-oauth2-testing/README.md create mode 100644 spring-security-modules/spring-security-oauth2-testing/pom.xml create mode 100644 spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml create mode 100644 spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java create mode 100644 spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/resources/application.yaml create mode 100644 spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java create mode 100644 spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java create mode 100644 spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java create mode 100644 spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java create mode 100644 spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml create mode 100644 spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java create mode 100644 spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/resources/application.properties create mode 100644 spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java create mode 100644 spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java create mode 100644 spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java create mode 100644 spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java diff --git a/pom.xml b/pom.xml index 0ec9e9efdd..345cd7979a 100644 --- a/pom.xml +++ b/pom.xml @@ -1023,6 +1023,7 @@ spring-kafka spring-native + spring-security-modules/spring-security-oauth2-testing spring-protobuf spring-quartz diff --git a/spring-security-modules/spring-security-oauth2-testing/README.md b/spring-security-modules/spring-security-oauth2-testing/README.md new file mode 100644 index 0000000000..82728ff450 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/README.md @@ -0,0 +1,7 @@ +## 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) diff --git a/spring-security-modules/spring-security-oauth2-testing/pom.xml b/spring-security-modules/spring-security-oauth2-testing/pom.xml new file mode 100644 index 0000000000..f634b6105c --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + spring-security-oauth2-testing + spring-security-oauth2-testing + pom + spring-security 6 oauth testing sample project + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + 6.0.14 + + + + + com.c4-soft.springaddons + spring-addons-oauth2-test + ${spring-addons.version} + + + + + reactive-resource-server + servlet-resource-server + + \ No newline at end of file diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml new file mode 100644 index 0000000000..c1fa6b7c6d --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + com.baeldung + spring-security-oauth2-testing + 0.0.1-SNAPSHOT + + com.baeldung.spring-security-modules.testing + reactive-resource-server + reactive-resource-server + Demo project for Spring Boot reactive resource-server + + 17 + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-webflux + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.c4-soft.springaddons + spring-addons-oauth2-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + \ No newline at end of file diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java new file mode 100644 index 0000000000..608038331a --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java @@ -0,0 +1,124 @@ +package com.baeldung; + +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.security.oauth2.core.oidc.StandardClaimNames; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import lombok.RequiredArgsConstructor; +import reactor.core.publisher.Mono; + +@SpringBootApplication +public class ReactiveResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(ReactiveResourceServerApplication.class, args); + } + + @Configuration + @EnableWebFluxSecurity + @EnableReactiveMethodSecurity + public class SecurityConfig { + @Bean + SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, Converter>> authoritiesConverter) { + http.oauth2ResourceServer().jwt() + .jwtAuthenticationConverter(jwt -> authoritiesConverter.convert(jwt).map(authorities -> new JwtAuthenticationToken(jwt, authorities))); + http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance()).csrf().disable(); + http.exceptionHandling().accessDeniedHandler((var exchange, var ex) -> exchange.getPrincipal().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(); + + return http.build(); + } + + static interface AuthoritiesConverter extends Converter>> { + } + + @Bean + AuthoritiesConverter realmRoles2AuthoritiesConverter() { + return (Jwt jwt) -> { + final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access")).orElse(Map.of()); + @SuppressWarnings("unchecked") + final var roles = (List) realmRoles.getOrDefault("roles", List.of()); + return Mono.just(roles.stream().map(SimpleGrantedAuthority::new).map(GrantedAuthority.class::cast).toList()); + }; + } + } + + @Service + public static class MessageService { + + public Mono greet() { + return ReactiveSecurityContextHolder.getContext().map(ctx -> { + final var who = (JwtAuthenticationToken) ctx.getAuthentication(); + final var claims = who.getTokenAttributes(); + return "Hello %s! You are granted with %s.".formatted( + claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME,claims.get(StandardClaimNames.SUB)), + who.getAuthorities()); + }).switchIfEmpty(Mono.error(new AuthenticationCredentialsNotFoundException("Security context is empty"))); + } + + @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") + public Mono getSecret() { + return Mono.just("Only authorized personnel can read that"); + } + } + + @RestController + @RequiredArgsConstructor + public class GreetingController { + private final MessageService messageService; + + @GetMapping("/greet") + public Mono> greet() { + return messageService.greet().map(ResponseEntity::ok); + } + + @GetMapping("/secured-route") + public Mono> securedRoute() { + return messageService.getSecret().map(ResponseEntity::ok); + } + + @GetMapping("/secured-method") + @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") + public Mono> securedMethod() { + return messageService.getSecret().map(ResponseEntity::ok); + } + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/resources/application.yaml b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/resources/application.yaml new file mode 100644 index 0000000000..01e655e1b3 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/resources/application.yaml @@ -0,0 +1,6 @@ +spring: + security: + oauth2: + resourceserver: + jwt: + issuer-uri: https://localhost:8443/realms/master diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java new file mode 100644 index 0000000000..92896754ef --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.baeldung.ReactiveResourceServerApplication.MessageService; +import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; + +@Import({ MessageService.class }) +@ExtendWith(SpringExtension.class) +@EnableReactiveMethodSecurity +class MessageServiceUnitTest { + @Autowired + MessageService messageService; + + /*----------------------------------------------------------------------------*/ + /* greet() */ + /* Expects a JwtAuthenticationToken to be retrieved from the security-context */ + /*----------------------------------------------------------------------------*/ + + @Test + void givenSecurityContextIsEmpty_whenGreet_thenThrowsAuthenticationCredentialsNotFoundException() { + assertThrows(AuthenticationCredentialsNotFoundException.class, () -> messageService.greet().block()); + } + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGreet_thenThrowsClassCastException() { + assertThrows(ClassCastException.class, () -> messageService.greet().block()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenSecurityContextIsPopulatedWithJwtAuthenticationToken_whenGreet_thenReturnGreetingWithPreferredUsernameAndAuthorities() { + assertEquals("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].", messageService.greet().block()); + } + + @Test + @WithMockUser(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, username = "ch4mpy") + void givenSecurityContextIsPopulatedWithUsernamePasswordAuthenticationToken_whenGreet_thenThrowsClassCastException() { + assertThrows(ClassCastException.class, () -> messageService.greet().block()); + } + + /*--------------------------------------------------------------------*/ + /* getSecret() */ + /* is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" */ + /*--------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecret_thenThrowsAccessDeniedException() { + assertThrows(AccessDeniedException.class, () -> messageService.getSecret().block()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenReturnSecret() { + assertEquals("Only authorized personnel can read that", messageService.getSecret().block()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenThrowsAccessDeniedException() { + assertThrows(AccessDeniedException.class, () -> messageService.getSecret().block()); + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java new file mode 100644 index 0000000000..e3c45883c2 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java @@ -0,0 +1,109 @@ +package com.baeldung; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; + +@SpringBootTest(webEnvironment = WebEnvironment.MOCK) +@AutoConfigureWebTestClient +class ReactiveResourceServerApplicationIntegrationTest { + @Autowired + WebTestClient api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + // @formatter:off + api.get().uri("/greet").exchange() + .expectStatus().isUnauthorized(); + // @formatter:on + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + // @formatter:off + api.get().uri("/greet").exchange() + .expectStatus().isOk() + .expectBody(String.class).isEqualTo("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL]."); + // @formatter:on + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /secured-route */ + /* This end-point is secured with ".requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL")" in SecurityConf */ + /*---------------------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + // @formatter:off + api.get().uri("/secured-route").exchange() + .expectStatus().isUnauthorized(); + // @formatter:on + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + // @formatter:off + api.get().uri("/secured-route").exchange() + .expectStatus().isOk() + .expectBody(String.class).isEqualTo("Only authorized personnel can read that"); + // @formatter:on + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + // @formatter:off + api.get().uri("/secured-route").exchange() + .expectStatus().isForbidden(); + // @formatter:on + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + // @formatter:off + api.get().uri("/secured-method").exchange() + .expectStatus().isUnauthorized(); + // @formatter:on + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + // @formatter:off + api.get().uri("/secured-method").exchange() + .expectStatus().isOk() + .expectBody(String.class).isEqualTo("Only authorized personnel can read that"); + // @formatter:on + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + // @formatter:off + api.get().uri("/secured-method").exchange() + .expectStatus().isForbidden(); + // @formatter:on + } +} diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java new file mode 100644 index 0000000000..e28136dd25 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -0,0 +1,123 @@ +package com.baeldung; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.baeldung.ReactiveResourceServerApplication.GreetingController; +import com.baeldung.ReactiveResourceServerApplication.MessageService; +import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; + +import reactor.core.publisher.Mono; + +@WebFluxTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) +class SpringAddonsGreetingControllerUnitTest { + + @MockBean + MessageService messageService; + + @Autowired + WebTestClient api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + api.get().uri("/greet").exchange().expectStatus().isUnauthorized(); + } + + @Test + @WithMockJwtAuth(claims = @OpenIdClaims(preferredUsername = "Tonton Pirate")) + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + final var greeting = "Whatever the service returns"; + when(messageService.greet()).thenReturn(Mono.just(greeting)); + + // @formatter:off + api.get().uri("/greet").exchange() + .expectStatus().isOk() + .expectBody(String.class).isEqualTo(greeting); + // @formatter:on + + verify(messageService, times(1)).greet(); + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /secured-route */ + /* This end-point is secured with ".requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL")" in SecurityConf */ + /*---------------------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + api.get().uri("/secured-route").exchange().expectStatus().isUnauthorized(); + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(Mono.just(secret)); + + // @formatter:off + api.get().uri("/secured-route").exchange() + .expectStatus().isOk() + .expectBody(String.class).isEqualTo(secret); + // @formatter:on + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + // @formatter:off + api.get().uri("/secured-route").exchange() + .expectStatus().isForbidden(); + // @formatter:on + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + api.get().uri("/secured-method").exchange().expectStatus().isUnauthorized(); + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(Mono.just(secret)); + + // @formatter:off + api.get().uri("/secured-method").exchange() + .expectStatus().isOk() + .expectBody(String.class).isEqualTo(secret); + // @formatter:on + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + // @formatter:off + api.get().uri("/secured-method").exchange() + .expectStatus().isForbidden(); + // @formatter:on + } + +} + diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java new file mode 100644 index 0000000000..291a405e29 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -0,0 +1,138 @@ +package com.baeldung; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockAuthentication; +import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockJwt; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.baeldung.ReactiveResourceServerApplication.GreetingController; +import com.baeldung.ReactiveResourceServerApplication.MessageService; + +import reactor.core.publisher.Mono; + +@WebFluxTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) +class SpringSecurityTestGreetingControllerUnitTest { + private static final AnonymousAuthenticationToken ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken( + "anonymous", + "anonymousUser", + AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")); + + @MockBean + MessageService messageService; + + @Autowired + WebTestClient api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + // @formatter:off + api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) + .get().uri("/greet").exchange() + .expectStatus().isUnauthorized(); + // @formatter:on + } + + @Test + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + final var greeting = "Whatever the service returns"; + when(messageService.greet()).thenReturn(Mono.just(greeting)); + + // @formatter:off + api.mutateWith(mockJwt()) + .get().uri("/greet").exchange() + .expectStatus().isOk() + .expectBody(String.class).isEqualTo(greeting); + // @formatter:on + + verify(messageService, times(1)).greet(); + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /secured-route */ + /* This end-point is secured with ".requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL")" in SecurityConf */ + /*---------------------------------------------------------------------------------------------------------------------*/ + + @Test + void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + // @formatter:off + api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) + .get().uri("/secured-route").exchange() + .expectStatus().isUnauthorized(); + // @formatter:on + } + + @Test + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(Mono.just(secret)); + + // @formatter:off + api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .get().uri("/secured-route").exchange() + .expectStatus().isOk() + .expectBody(String.class).isEqualTo(secret); + // @formatter:on + } + + @Test + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + // @formatter:off + api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin"))) + .get().uri("/secured-route").exchange() + .expectStatus().isForbidden(); + // @formatter:on + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + // @formatter:off + api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) + .get().uri("/secured-method").exchange() + .expectStatus().isUnauthorized(); + // @formatter:on + } + + @Test + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(Mono.just(secret)); + + // @formatter:off + api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .get().uri("/secured-method").exchange() + .expectStatus().isOk() + .expectBody(String.class).isEqualTo(secret); + // @formatter:on + } + + @Test + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + // @formatter:off + api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin"))) + .get().uri("/secured-method").exchange() + .expectStatus().isForbidden(); + // @formatter:on + } + +} + diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml new file mode 100644 index 0000000000..8de154b934 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + com.baeldung + spring-security-oauth2-testing + 0.0.1-SNAPSHOT + + com.baeldung.spring-security-modules.testing + servlet-resource-server + servlet-resource-server + Demo project for Spring Boot servlet resource-server + + 17 + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.c4-soft.springaddons + spring-addons-oauth2-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java new file mode 100644 index 0000000000..ba55944c29 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java @@ -0,0 +1,116 @@ +package com.baeldung; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.core.oidc.StandardClaimNames; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import lombok.RequiredArgsConstructor; + +@SpringBootApplication +public class ServletResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(ServletResourceServerApplication.class, args); + } + + @Configuration + @EnableMethodSecurity + @EnableWebSecurity + static class SecurityConf { + @Bean + SecurityFilterChain filterChain(HttpSecurity http, Converter> authoritiesConverter) throws Exception { + // @formatter:off + http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwt -> new JwtAuthenticationToken(jwt, authoritiesConverter.convert(jwt))); + http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).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() + .requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL") + .anyRequest().authenticated(); + // @formatter:on + + return http.build(); + } + + static interface AuthoritiesConverter extends Converter> { + } + + @Bean + AuthoritiesConverter realmRoles2AuthoritiesConverter() { + return (Jwt jwt) -> { + final var realmRoles = Optional.of(jwt.getClaimAsMap("realm_access")).orElse(Map.of()); + @SuppressWarnings("unchecked") + final var roles = (List) realmRoles.getOrDefault("roles", List.of()); + return roles.stream().map(SimpleGrantedAuthority::new).map(GrantedAuthority.class::cast).toList(); + }; + } + } + + @Service + public static class MessageService { + + public String greet() { + final var who = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + final var claims = who.getTokenAttributes(); + return "Hello %s! You are granted with %s.".formatted( + claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME, claims.get(StandardClaimNames.SUB)), + who.getAuthorities()); + } + + @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") + public String getSecret() { + return "Only authorized personnel can read that"; + } + } + + @RestController + @RequiredArgsConstructor + public static class GreetingController { + private final MessageService messageService; + + @GetMapping("/greet") + public ResponseEntity greet() { + return ResponseEntity.ok(messageService.greet()); + } + + @GetMapping("/secured-route") + public ResponseEntity securedRoute() { + return ResponseEntity.ok(messageService.getSecret()); + } + + @GetMapping("/secured-method") + @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") + public ResponseEntity securedMethod() { + return ResponseEntity.ok(messageService.getSecret()); + } + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/resources/application.properties b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/resources/application.properties new file mode 100644 index 0000000000..998f6303aa --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.security.oauth2.resourceserver.jwt.issuer-uri=https://localhost:8443/realms/master diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java new file mode 100644 index 0000000000..36be2df331 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java @@ -0,0 +1,79 @@ +package com.baeldung; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.baeldung.ServletResourceServerApplication.MessageService; +import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; + +@Import({ MessageService.class }) +@ExtendWith(SpringExtension.class) +@EnableMethodSecurity +class MessageServiceUnitTest { + @Autowired + MessageService messageService; + + /*----------------------------------------------------------------------------*/ + /* greet() */ + /* Expects a JwtAuthenticationToken to be retrieved from the security-context */ + /*----------------------------------------------------------------------------*/ + + @Test + void givenSecurityContextIsNotSet_whenGreet_thenThrowsAuthenticationCredentialsNotFoundException() { + assertThrows(AuthenticationCredentialsNotFoundException.class, () -> messageService.getSecret()); + } + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGreet_thenThrowsAccessDeniedException() { + assertThrows(AccessDeniedException.class, () -> messageService.getSecret()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenSecurityContextIsPopulatedWithJwtAuthenticationToken_whenGreet_thenReturnGreetingWithPreferredUsernameAndAuthorities() { + assertEquals("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].", messageService.greet()); + } + + @Test + @WithMockUser(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, username = "ch4mpy") + void givenSecurityContextIsPopulatedWithUsernamePasswordAuthenticationToken_whenGreet_thenThrowsClassCastException() { + assertThrows(ClassCastException.class, () -> messageService.greet()); + } + + /*--------------------------------------------------------------------*/ + /* getSecret() */ + /* is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" */ + /*--------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecret_thenThrowsAccessDeniedException() { + assertThrows(AccessDeniedException.class, () -> messageService.getSecret()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenReturnSecret() { + assertEquals("Only authorized personnel can read that", messageService.getSecret()); + } + + @Test + @WithMockJwtAuth(authorities = { "admin" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenThrowsAccessDeniedException() { + assertThrows(AccessDeniedException.class, () -> messageService.getSecret()); + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java new file mode 100644 index 0000000000..0c6504bff0 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java @@ -0,0 +1,114 @@ +package com.baeldung; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.test.web.servlet.MockMvc; + +import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; + +@SpringBootTest(webEnvironment = WebEnvironment.MOCK) +@AutoConfigureMockMvc +class ServletResourceServerApplicationIntegrationTest { + @Autowired + MockMvc api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + // @formatter:off + api.perform(get("/greet")) + .andExpect(status().isUnauthorized()); + // @formatter:on + } + + @Test + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + // @formatter:off + api.perform(get("/greet")) + .andExpect(status().isOk()) + .andExpect(content().string("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].")); + // @formatter:on + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /secured-route */ + /* This end-point is secured with ".requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL")" in SecurityConf */ + /*---------------------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + // @formatter:off + api.perform(get("/secured-route")) + .andExpect(status().isUnauthorized()); + // @formatter:on + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + // @formatter:off + api.perform(get("/secured-route")) + .andExpect(status().isOk()) + .andExpect(content().string("Only authorized personnel can read that")); + // @formatter:on + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + // @formatter:off + api.perform(get("/secured-route")) + .andExpect(status().isForbidden()); + // @formatter:on + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + // @formatter:off + api.perform(get("/secured-method")) + .andExpect(status().isUnauthorized()); + // @formatter:on + } + + @Test + @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + // @formatter:off + api.perform(get("/secured-method")) + .andExpect(status().isOk()) + .andExpect(content().string("Only authorized personnel can read that")); + // @formatter:on + } + + @Test + @WithMockJwtAuth("admin") + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + // @formatter:off + api.perform(get("/secured-method")) + .andExpect(status().isForbidden()); + // @formatter:on + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java new file mode 100644 index 0000000000..76902bb9b7 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -0,0 +1,131 @@ +package com.baeldung; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +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.boot.test.mock.mockito.MockBean; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.test.web.servlet.MockMvc; + +import com.baeldung.ServletResourceServerApplication.GreetingController; +import com.baeldung.ServletResourceServerApplication.MessageService; +import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; + +@WebMvcTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) +class SpringAddonsGreetingControllerUnitTest { + + @MockBean + MessageService messageService; + + @Autowired + MockMvc api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + // @formatter:off + api.perform(get("/greet")) + .andExpect(status().isUnauthorized()); + // @formatter:on + } + + @Test + @WithMockJwtAuth + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + final var greeting = "Whatever the service returns"; + when(messageService.greet()).thenReturn(greeting); + + // @formatter:off + api.perform(get("/greet")) + .andExpect(status().isOk()) + .andExpect(content().string(greeting)); + // @formatter:on + + verify(messageService, times(1)).greet(); + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /secured-route */ + /* This end-point is secured with ".requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL")" in SecurityConf */ + /*---------------------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + // @formatter:off + api.perform(get("/secured-route")) + .andExpect(status().isUnauthorized()); + // @formatter:on + } + + @Test + @WithMockJwtAuth({ "admin", "ROLE_AUTHORIZED_PERSONNEL" }) + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(secret); + + // @formatter:off + api.perform(get("/secured-route")) + .andExpect(status().isOk()) + .andExpect(content().string(secret)); + // @formatter:on + } + + @Test + @WithMockJwtAuth({ "admin" }) + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + // @formatter:off + api.perform(get("/secured-route")) + .andExpect(status().isForbidden()); + // @formatter:on + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + @WithAnonymousUser + void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + // @formatter:off + api.perform(get("/secured-method")) + .andExpect(status().isUnauthorized()); + // @formatter:on + } + + @Test + @WithMockJwtAuth({ "admin", "ROLE_AUTHORIZED_PERSONNEL" }) + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(secret); + + // @formatter:off + api.perform(get("/secured-method")) + .andExpect(status().isOk()) + .andExpect(content().string(secret)); + // @formatter:on + } + + @Test + @WithMockJwtAuth(authorities = { "admin" }) + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + // @formatter:off + api.perform(get("/secured-method")) + .andExpect(status().isForbidden()); + // @formatter:on + } + +} diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java new file mode 100644 index 0000000000..aa53dd7531 --- /dev/null +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -0,0 +1,124 @@ +package com.baeldung; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.anonymous; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +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.boot.test.mock.mockito.MockBean; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.test.web.servlet.MockMvc; + +import com.baeldung.ServletResourceServerApplication.GreetingController; +import com.baeldung.ServletResourceServerApplication.MessageService; + +@WebMvcTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) +class SpringSecurityTestGreetingControllerUnitTest { + + @MockBean + MessageService messageService; + + @Autowired + MockMvc api; + + /*-----------------------------------------------------------------------------*/ + /* /greet */ + /* This end-point secured with ".anyRequest().authenticated()" in SecurityConf */ + /*-----------------------------------------------------------------------------*/ + + @Test + void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + // @formatter:off + api.perform(get("/greet").with(anonymous())) + .andExpect(status().isUnauthorized()); + // @formatter:on + } + + @Test + void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { + final var greeting = "Whatever the service returns"; + when(messageService.greet()).thenReturn(greeting); + + // @formatter:off + api.perform(get("/greet").with(jwt())) + .andExpect(status().isOk()) + .andExpect(content().string(greeting)); + // @formatter:on + + verify(messageService, times(1)).greet(); + } + + /*---------------------------------------------------------------------------------------------------------------------*/ + /* /secured-route */ + /* This end-point is secured with ".requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL")" in SecurityConf */ + /*---------------------------------------------------------------------------------------------------------------------*/ + + @Test + void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + // @formatter:off + api.perform(get("/secured-route").with(anonymous())) + .andExpect(status().isUnauthorized()); + // @formatter:on + } + + @Test + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(secret); + + // @formatter:off + api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))) + .andExpect(status().isOk()) + .andExpect(content().string(secret)); + // @formatter:on + } + + @Test + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { + // @formatter:off + api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("admin")))) + .andExpect(status().isForbidden()); + // @formatter:on + } + + /*---------------------------------------------------------------------------------------------------------*/ + /* /secured-method */ + /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ + /*---------------------------------------------------------------------------------------------------------*/ + + @Test + void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + // @formatter:off + api.perform(get("/secured-method").with(anonymous())) + .andExpect(status().isUnauthorized()); + // @formatter:on + } + + @Test + void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { + final var secret = "Secret!"; + when(messageService.getSecret()).thenReturn(secret); + + // @formatter:off + api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))) + .andExpect(status().isOk()) + .andExpect(content().string(secret)); + // @formatter:on + } + + @Test + void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { + // @formatter:off + api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("admin")))) + .andExpect(status().isForbidden()); + // @formatter:on + } + +} From 66d71f0697a10aaabb74c90228870b6563e8d88a Mon Sep 17 00:00:00 2001 From: ch4mpy Date: Fri, 17 Feb 2023 12:18:02 -1000 Subject: [PATCH 2/6] Improve anonymous tests readability --- ...iveResourceServerApplicationIntegrationTest.java | 10 ++++++---- .../SpringAddonsGreetingControllerUnitTest.java | 10 ++++++---- ...pringSecurityTestGreetingControllerUnitTest.java | 13 +++++++++---- ...letResourceServerApplicationIntegrationTest.java | 4 +++- .../SpringAddonsGreetingControllerUnitTest.java | 5 ++++- ...pringSecurityTestGreetingControllerUnitTest.java | 7 ++++++- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java index e3c45883c2..d464aa37ad 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java @@ -24,7 +24,7 @@ class ReactiveResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { // @formatter:off api.get().uri("/greet").exchange() .expectStatus().isUnauthorized(); @@ -32,7 +32,9 @@ class ReactiveResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + @WithMockJwtAuth( + authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"}, + claims = @OpenIdClaims(preferredUsername = "ch4mpy")) void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { // @formatter:off api.get().uri("/greet").exchange() @@ -48,7 +50,7 @@ class ReactiveResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { // @formatter:off api.get().uri("/secured-route").exchange() .expectStatus().isUnauthorized(); @@ -81,7 +83,7 @@ class ReactiveResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { // @formatter:off api.get().uri("/secured-method").exchange() .expectStatus().isUnauthorized(); diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java index e28136dd25..38bbb4d0bd 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -34,12 +34,14 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { api.get().uri("/greet").exchange().expectStatus().isUnauthorized(); } @Test - @WithMockJwtAuth(claims = @OpenIdClaims(preferredUsername = "Tonton Pirate")) + @WithMockJwtAuth( + authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"}, + claims = @OpenIdClaims(preferredUsername = "ch4mpy")) void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { final var greeting = "Whatever the service returns"; when(messageService.greet()).thenReturn(Mono.just(greeting)); @@ -60,7 +62,7 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { api.get().uri("/secured-route").exchange().expectStatus().isUnauthorized(); } @@ -93,7 +95,7 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { api.get().uri("/secured-method").exchange().expectStatus().isUnauthorized(); } diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java index 291a405e29..40ba700c21 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -6,6 +6,8 @@ import static org.mockito.Mockito.when; import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockAuthentication; import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockJwt; +import java.util.List; + import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; @@ -13,6 +15,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.core.oidc.StandardClaimNames; import org.springframework.test.web.reactive.server.WebTestClient; import com.baeldung.ReactiveResourceServerApplication.GreetingController; @@ -39,7 +42,7 @@ class SpringSecurityTestGreetingControllerUnitTest { /*-----------------------------------------------------------------------------*/ @Test - void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { // @formatter:off api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) .get().uri("/greet").exchange() @@ -53,7 +56,9 @@ class SpringSecurityTestGreetingControllerUnitTest { when(messageService.greet()).thenReturn(Mono.just(greeting)); // @formatter:off - api.mutateWith(mockJwt()) + api.mutateWith(mockJwt() + .authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy"))) .get().uri("/greet").exchange() .expectStatus().isOk() .expectBody(String.class).isEqualTo(greeting); @@ -68,7 +73,7 @@ class SpringSecurityTestGreetingControllerUnitTest { /*---------------------------------------------------------------------------------------------------------------------*/ @Test - void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { // @formatter:off api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) .get().uri("/secured-route").exchange() @@ -104,7 +109,7 @@ class SpringSecurityTestGreetingControllerUnitTest { /*---------------------------------------------------------------------------------------------------------*/ @Test - void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { // @formatter:off api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) .get().uri("/secured-method").exchange() diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java index 0c6504bff0..eba908da75 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java @@ -36,7 +36,9 @@ class ServletResourceServerApplicationIntegrationTest { } @Test - @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + @WithMockJwtAuth( + authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"}, + claims = @OpenIdClaims(preferredUsername = "ch4mpy")) void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { // @formatter:off api.perform(get("/greet")) diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java index 76902bb9b7..f18ad85832 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -16,6 +16,7 @@ import org.springframework.test.web.servlet.MockMvc; import com.baeldung.ServletResourceServerApplication.GreetingController; import com.baeldung.ServletResourceServerApplication.MessageService; +import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims; import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth; @WebMvcTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) @@ -42,7 +43,9 @@ class SpringAddonsGreetingControllerUnitTest { } @Test - @WithMockJwtAuth + @WithMockJwtAuth( + authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"}, + claims = @OpenIdClaims(preferredUsername = "ch4mpy")) void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { final var greeting = "Whatever the service returns"; when(messageService.greet()).thenReturn(greeting); diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java index aa53dd7531..83a95cf508 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -9,11 +9,14 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.util.List; + 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.boot.test.mock.mockito.MockBean; import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.core.oidc.StandardClaimNames; import org.springframework.test.web.servlet.MockMvc; import com.baeldung.ServletResourceServerApplication.GreetingController; @@ -47,7 +50,9 @@ class SpringSecurityTestGreetingControllerUnitTest { when(messageService.greet()).thenReturn(greeting); // @formatter:off - api.perform(get("/greet").with(jwt())) + api.perform(get("/greet").with(jwt() + .authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy")))) .andExpect(status().isOk()) .andExpect(content().string(greeting)); // @formatter:on From 26e401b2904ba4b2fcddada1b7e8a72ce185bfe2 Mon Sep 17 00:00:00 2001 From: ch4mpy Date: Sat, 25 Feb 2023 14:36:42 -1000 Subject: [PATCH 3/6] Baeldung source format --- .../spring-security-oauth2-testing/README.md | 7 -- .../spring-security-oauth2-testing/pom.xml | 58 ++++----- .../reactive-resource-server/pom.xml | 110 +++++++++--------- .../ReactiveResourceServerApplication.java | 68 +++++++---- .../com/baeldung/MessageServiceUnitTest.java | 21 ++-- ...ourceServerApplicationIntegrationTest.java | 87 +++++++------- ...pringAddonsGreetingControllerUnitTest.java | 79 ++++++++----- ...ecurityTestGreetingControllerUnitTest.java | 100 ++++++++-------- .../servlet-resource-server/pom.xml | 110 +++++++++--------- .../ServletResourceServerApplication.java | 44 ++++--- ...ourceServerApplicationIntegrationTest.java | 30 +---- ...pringAddonsGreetingControllerUnitTest.java | 22 +--- ...ecurityTestGreetingControllerUnitTest.java | 23 +--- 13 files changed, 384 insertions(+), 375 deletions(-) delete mode 100644 spring-security-modules/spring-security-oauth2-testing/README.md diff --git a/spring-security-modules/spring-security-oauth2-testing/README.md b/spring-security-modules/spring-security-oauth2-testing/README.md deleted file mode 100644 index 82728ff450..0000000000 --- a/spring-security-modules/spring-security-oauth2-testing/README.md +++ /dev/null @@ -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) diff --git a/spring-security-modules/spring-security-oauth2-testing/pom.xml b/spring-security-modules/spring-security-oauth2-testing/pom.xml index f634b6105c..93348cb48c 100644 --- a/spring-security-modules/spring-security-oauth2-testing/pom.xml +++ b/spring-security-modules/spring-security-oauth2-testing/pom.xml @@ -1,32 +1,32 @@ - 4.0.0 - spring-security-oauth2-testing - spring-security-oauth2-testing - pom - spring-security 6 oauth testing sample project - - com.baeldung - parent-boot-3 - 0.0.1-SNAPSHOT - ../../parent-boot-3 - - - 6.0.14 - - - - - com.c4-soft.springaddons - spring-addons-oauth2-test - ${spring-addons.version} - - - - - reactive-resource-server - servlet-resource-server - + 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"> + 4.0.0 + spring-security-oauth2-testing + spring-security-oauth2-testing + pom + spring-security 6 oauth testing sample project + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + 6.1.0 + + + + + com.c4-soft.springaddons + spring-addons-oauth2-test + ${spring-addons.version} + + + + + reactive-resource-server + servlet-resource-server + \ No newline at end of file diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml index c1fa6b7c6d..86f73cfdbf 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/pom.xml @@ -1,58 +1,58 @@ - 4.0.0 - - com.baeldung - spring-security-oauth2-testing - 0.0.1-SNAPSHOT - - com.baeldung.spring-security-modules.testing - reactive-resource-server - reactive-resource-server - Demo project for Spring Boot reactive resource-server - - 17 - - - - org.springframework.boot - spring-boot-starter-oauth2-resource-server - - - org.springframework.boot - spring-boot-starter-webflux - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - com.c4-soft.springaddons - spring-addons-oauth2-test - test - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + com.baeldung + spring-security-oauth2-testing + 0.0.1-SNAPSHOT + + com.baeldung.spring-security-modules.testing + reactive-resource-server + reactive-resource-server + Demo project for Spring Boot reactive resource-server + + 17 + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-webflux + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.c4-soft.springaddons + spring-addons-oauth2-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + \ No newline at end of file diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java index 608038331a..500d876bc4 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/main/java/com/baeldung/ReactiveResourceServerApplication.java @@ -49,19 +49,32 @@ public class ReactiveResourceServerApplication { public class SecurityConfig { @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, Converter>> authoritiesConverter) { - http.oauth2ResourceServer().jwt() - .jwtAuthenticationConverter(jwt -> authoritiesConverter.convert(jwt).map(authorities -> new JwtAuthenticationToken(jwt, authorities))); - http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance()).csrf().disable(); - http.exceptionHandling().accessDeniedHandler((var exchange, var ex) -> exchange.getPrincipal().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.oauth2ResourceServer() + .jwt() + .jwtAuthenticationConverter(jwt -> authoritiesConverter.convert(jwt) + .map(authorities -> new JwtAuthenticationToken(jwt, authorities))); + http.securityContextRepository(NoOpServerSecurityContextRepository.getInstance()) + .csrf() + .disable(); + http.exceptionHandling() + .accessDeniedHandler((var exchange, var ex) -> exchange.getPrincipal() + .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(); } @@ -72,10 +85,14 @@ public class ReactiveResourceServerApplication { @Bean AuthoritiesConverter realmRoles2AuthoritiesConverter() { 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") final var roles = (List) 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 Mono greet() { - return ReactiveSecurityContextHolder.getContext().map(ctx -> { - final var who = (JwtAuthenticationToken) ctx.getAuthentication(); - final var claims = who.getTokenAttributes(); - return "Hello %s! You are granted with %s.".formatted( - claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME,claims.get(StandardClaimNames.SUB)), - who.getAuthorities()); - }).switchIfEmpty(Mono.error(new AuthenticationCredentialsNotFoundException("Security context is empty"))); + return ReactiveSecurityContextHolder.getContext() + .map(ctx -> { + final var who = (JwtAuthenticationToken) ctx.getAuthentication(); + final var claims = who.getTokenAttributes(); + return "Hello %s! You are granted with %s.".formatted(claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME, claims.get(StandardClaimNames.SUB)), who.getAuthorities()); + }) + .switchIfEmpty(Mono.error(new AuthenticationCredentialsNotFoundException("Security context is empty"))); } @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") @@ -106,18 +123,21 @@ public class ReactiveResourceServerApplication { @GetMapping("/greet") public Mono> greet() { - return messageService.greet().map(ResponseEntity::ok); + return messageService.greet() + .map(ResponseEntity::ok); } @GetMapping("/secured-route") public Mono> securedRoute() { - return messageService.getSecret().map(ResponseEntity::ok); + return messageService.getSecret() + .map(ResponseEntity::ok); } @GetMapping("/secured-method") @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") public Mono> securedMethod() { - return messageService.getSecret().map(ResponseEntity::ok); + return messageService.getSecret() + .map(ResponseEntity::ok); } } diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java index 92896754ef..ecaf270f10 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java @@ -32,25 +32,29 @@ class MessageServiceUnitTest { @Test void givenSecurityContextIsEmpty_whenGreet_thenThrowsAuthenticationCredentialsNotFoundException() { - assertThrows(AuthenticationCredentialsNotFoundException.class, () -> messageService.greet().block()); + assertThrows(AuthenticationCredentialsNotFoundException.class, () -> messageService.greet() + .block()); } @Test @WithAnonymousUser void givenUserIsNotAuthenticated_whenGreet_thenThrowsClassCastException() { - assertThrows(ClassCastException.class, () -> messageService.greet().block()); + assertThrows(ClassCastException.class, () -> messageService.greet() + .block()); } @Test @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) 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 @WithMockUser(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, username = "ch4mpy") void givenSecurityContextIsPopulatedWithUsernamePasswordAuthenticationToken_whenGreet_thenThrowsClassCastException() { - assertThrows(ClassCastException.class, () -> messageService.greet().block()); + assertThrows(ClassCastException.class, () -> messageService.greet() + .block()); } /*--------------------------------------------------------------------*/ @@ -61,19 +65,22 @@ class MessageServiceUnitTest { @Test @WithAnonymousUser void givenUserIsNotAuthenticated_whenGetSecret_thenThrowsAccessDeniedException() { - assertThrows(AccessDeniedException.class, () -> messageService.getSecret().block()); + assertThrows(AccessDeniedException.class, () -> messageService.getSecret() + .block()); } @Test @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) 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 @WithMockJwtAuth(authorities = { "admin" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecret_thenThrowsAccessDeniedException() { - assertThrows(AccessDeniedException.class, () -> messageService.getSecret().block()); + assertThrows(AccessDeniedException.class, () -> messageService.getSecret() + .block()); } } diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java index d464aa37ad..dd64eb2109 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java @@ -25,22 +25,23 @@ class ReactiveResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { - // @formatter:off - api.get().uri("/greet").exchange() - .expectStatus().isUnauthorized(); - // @formatter:on + api.get() + .uri("/greet") + .exchange() + .expectStatus() + .isUnauthorized(); } @Test - @WithMockJwtAuth( - authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"}, - claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { - // @formatter:off - api.get().uri("/greet").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL]."); - // @formatter:on + api.get() + .uri("/greet") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL]."); } /*---------------------------------------------------------------------------------------------------------------------*/ @@ -51,31 +52,35 @@ class ReactiveResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { - // @formatter:off - api.get().uri("/secured-route").exchange() - .expectStatus().isUnauthorized(); - // @formatter:on + api.get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isUnauthorized(); } @Test @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { - // @formatter:off - api.get().uri("/secured-route").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("Only authorized personnel can read that"); - // @formatter:on + api.get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Only authorized personnel can read that"); } @Test @WithMockJwtAuth("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { - // @formatter:off - api.get().uri("/secured-route").exchange() - .expectStatus().isForbidden(); - // @formatter:on + api.get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isForbidden(); } - + /*---------------------------------------------------------------------------------------------------------*/ /* /secured-method */ /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ @@ -84,28 +89,32 @@ class ReactiveResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { - // @formatter:off - api.get().uri("/secured-method").exchange() - .expectStatus().isUnauthorized(); - // @formatter:on + api.get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isUnauthorized(); } @Test @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { - // @formatter:off - api.get().uri("/secured-method").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo("Only authorized personnel can read that"); - // @formatter:on + api.get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Only authorized personnel can read that"); } @Test @WithMockJwtAuth("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { - // @formatter:off - api.get().uri("/secured-method").exchange() - .expectStatus().isForbidden(); - // @formatter:on + api.get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isForbidden(); } } diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java index 38bbb4d0bd..0da6701781 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -35,22 +35,26 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { - api.get().uri("/greet").exchange().expectStatus().isUnauthorized(); + api.get() + .uri("/greet") + .exchange() + .expectStatus() + .isUnauthorized(); } @Test - @WithMockJwtAuth( - authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"}, - claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { final var greeting = "Whatever the service returns"; when(messageService.greet()).thenReturn(Mono.just(greeting)); - // @formatter:off - api.get().uri("/greet").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo(greeting); - // @formatter:on + api.get() + .uri("/greet") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo(greeting); verify(messageService, times(1)).greet(); } @@ -63,7 +67,11 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { - api.get().uri("/secured-route").exchange().expectStatus().isUnauthorized(); + api.get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isUnauthorized(); } @Test @@ -72,22 +80,25 @@ class SpringAddonsGreetingControllerUnitTest { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(Mono.just(secret)); - // @formatter:off - api.get().uri("/secured-route").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo(secret); - // @formatter:on + api.get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo(secret); } @Test @WithMockJwtAuth("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { - // @formatter:off - api.get().uri("/secured-route").exchange() - .expectStatus().isForbidden(); - // @formatter:on + api.get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isForbidden(); } - + /*---------------------------------------------------------------------------------------------------------*/ /* /secured-method */ /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ @@ -96,7 +107,11 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { - api.get().uri("/secured-method").exchange().expectStatus().isUnauthorized(); + api.get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isUnauthorized(); } @Test @@ -105,21 +120,23 @@ class SpringAddonsGreetingControllerUnitTest { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(Mono.just(secret)); - // @formatter:off - api.get().uri("/secured-method").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo(secret); - // @formatter:on + api.get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo(secret); } @Test @WithMockJwtAuth("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { - // @formatter:off - api.get().uri("/secured-method").exchange() - .expectStatus().isForbidden(); - // @formatter:on + api.get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isForbidden(); } } - diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java index 40ba700c21..b15c1304e6 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -25,10 +25,7 @@ import reactor.core.publisher.Mono; @WebFluxTest(controllers = GreetingController.class, properties = { "server.ssl.enabled=false" }) class SpringSecurityTestGreetingControllerUnitTest { - private static final AnonymousAuthenticationToken ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken( - "anonymous", - "anonymousUser", - AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")); + private static final AnonymousAuthenticationToken ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken("anonymous", "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")); @MockBean MessageService messageService; @@ -43,11 +40,12 @@ class SpringSecurityTestGreetingControllerUnitTest { @Test void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { - // @formatter:off api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) - .get().uri("/greet").exchange() - .expectStatus().isUnauthorized(); - // @formatter:on + .get() + .uri("/greet") + .exchange() + .expectStatus() + .isUnauthorized(); } @Test @@ -55,14 +53,15 @@ class SpringSecurityTestGreetingControllerUnitTest { final var greeting = "Whatever the service returns"; when(messageService.greet()).thenReturn(Mono.just(greeting)); - // @formatter:off - api.mutateWith(mockJwt() - .authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) - .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy"))) - .get().uri("/greet").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo(greeting); - // @formatter:on + api.mutateWith(mockJwt().authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy"))) + .get() + .uri("/greet") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo(greeting); verify(messageService, times(1)).greet(); } @@ -74,35 +73,39 @@ class SpringSecurityTestGreetingControllerUnitTest { @Test void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { - // @formatter:off api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) - .get().uri("/secured-route").exchange() - .expectStatus().isUnauthorized(); - // @formatter:on + .get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isUnauthorized(); } - + @Test void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(Mono.just(secret)); - - // @formatter:off + api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) - .get().uri("/secured-route").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo(secret); - // @formatter:on + .get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo(secret); } - + @Test void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { - // @formatter:off api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin"))) - .get().uri("/secured-route").exchange() - .expectStatus().isForbidden(); - // @formatter:on + .get() + .uri("/secured-route") + .exchange() + .expectStatus() + .isForbidden(); } - + /*---------------------------------------------------------------------------------------------------------*/ /* /secured-method */ /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ @@ -110,11 +113,12 @@ class SpringSecurityTestGreetingControllerUnitTest { @Test void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { - // @formatter:off api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) - .get().uri("/secured-method").exchange() - .expectStatus().isUnauthorized(); - // @formatter:on + .get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isUnauthorized(); } @Test @@ -122,22 +126,24 @@ class SpringSecurityTestGreetingControllerUnitTest { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(Mono.just(secret)); - // @formatter:off api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) - .get().uri("/secured-method").exchange() - .expectStatus().isOk() - .expectBody(String.class).isEqualTo(secret); - // @formatter:on + .get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo(secret); } @Test void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { - // @formatter:off api.mutateWith(mockJwt().authorities(new SimpleGrantedAuthority("admin"))) - .get().uri("/secured-method").exchange() - .expectStatus().isForbidden(); - // @formatter:on + .get() + .uri("/secured-method") + .exchange() + .expectStatus() + .isForbidden(); } } - diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml index 8de154b934..271cc7dc18 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/pom.xml @@ -1,58 +1,58 @@ - 4.0.0 - - com.baeldung - spring-security-oauth2-testing - 0.0.1-SNAPSHOT - - com.baeldung.spring-security-modules.testing - servlet-resource-server - servlet-resource-server - Demo project for Spring Boot servlet resource-server - - 17 - - - - org.springframework.boot - spring-boot-starter-oauth2-resource-server - - - org.springframework.boot - spring-boot-starter-web - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - com.c4-soft.springaddons - spring-addons-oauth2-test - test - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + com.baeldung + spring-security-oauth2-testing + 0.0.1-SNAPSHOT + + com.baeldung.spring-security-modules.testing + servlet-resource-server + servlet-resource-server + Demo project for Spring Boot servlet resource-server + + 17 + + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.c4-soft.springaddons + spring-addons-oauth2-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java index ba55944c29..a30c60eab0 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/main/java/com/baeldung/ServletResourceServerApplication.java @@ -44,18 +44,25 @@ public class ServletResourceServerApplication { static class SecurityConf { @Bean SecurityFilterChain filterChain(HttpSecurity http, Converter> authoritiesConverter) throws Exception { - // @formatter:off - http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwt -> new JwtAuthenticationToken(jwt, authoritiesConverter.convert(jwt))); - http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).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.oauth2ResourceServer() + .jwt() + .jwtAuthenticationConverter(jwt -> new JwtAuthenticationToken(jwt, authoritiesConverter.convert(jwt))); + http.sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .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() - .requestMatchers("/secured-route").hasRole("AUTHORIZED_PERSONNEL") - .anyRequest().authenticated(); - // @formatter:on + .requestMatchers("/secured-route") + .hasRole("AUTHORIZED_PERSONNEL") + .anyRequest() + .authenticated(); return http.build(); } @@ -66,10 +73,14 @@ public class ServletResourceServerApplication { @Bean AuthoritiesConverter realmRoles2AuthoritiesConverter() { 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") final var roles = (List) 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 String greet() { - final var who = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + final var who = (JwtAuthenticationToken) SecurityContextHolder.getContext() + .getAuthentication(); final var claims = who.getTokenAttributes(); - return "Hello %s! You are granted with %s.".formatted( - claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME, claims.get(StandardClaimNames.SUB)), - who.getAuthorities()); + return "Hello %s! You are granted with %s.".formatted(claims.getOrDefault(StandardClaimNames.PREFERRED_USERNAME, claims.get(StandardClaimNames.SUB)), who.getAuthorities()); } @PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')") diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java index eba908da75..60b74e93be 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java @@ -29,22 +29,16 @@ class ServletResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { - // @formatter:off api.perform(get("/greet")) .andExpect(status().isUnauthorized()); - // @formatter:on } @Test - @WithMockJwtAuth( - authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"}, - claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { - // @formatter:off api.perform(get("/greet")) - .andExpect(status().isOk()) - .andExpect(content().string("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].")); - // @formatter:on + .andExpect(status().isOk()) + .andExpect(content().string("Hello ch4mpy! You are granted with [admin, ROLE_AUTHORIZED_PERSONNEL].")); } /*---------------------------------------------------------------------------------------------------------------------*/ @@ -55,31 +49,25 @@ class ServletResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { - // @formatter:off api.perform(get("/secured-route")) .andExpect(status().isUnauthorized()); - // @formatter:on } @Test @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenOk() throws Exception { - // @formatter:off api.perform(get("/secured-route")) - .andExpect(status().isOk()) - .andExpect(content().string("Only authorized personnel can read that")); - // @formatter:on + .andExpect(status().isOk()) + .andExpect(content().string("Only authorized personnel can read that")); } @Test @WithMockJwtAuth("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { - // @formatter:off api.perform(get("/secured-route")) .andExpect(status().isForbidden()); - // @formatter:on } - + /*---------------------------------------------------------------------------------------------------------*/ /* /secured-method */ /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ @@ -88,29 +76,23 @@ class ServletResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { - // @formatter:off api.perform(get("/secured-method")) .andExpect(status().isUnauthorized()); - // @formatter:on } @Test @WithMockJwtAuth("ROLE_AUTHORIZED_PERSONNEL") void givenUserIsGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenOk() throws Exception { - // @formatter:off api.perform(get("/secured-method")) .andExpect(status().isOk()) .andExpect(content().string("Only authorized personnel can read that")); - // @formatter:on } @Test @WithMockJwtAuth("admin") void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { - // @formatter:off api.perform(get("/secured-method")) .andExpect(status().isForbidden()); - // @formatter:on } } diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java index f18ad85832..949a8aa04c 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -36,25 +36,19 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { - // @formatter:off api.perform(get("/greet")) .andExpect(status().isUnauthorized()); - // @formatter:on } @Test - @WithMockJwtAuth( - authorities = {"admin", "ROLE_AUTHORIZED_PERSONNEL"}, - claims = @OpenIdClaims(preferredUsername = "ch4mpy")) + @WithMockJwtAuth(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, claims = @OpenIdClaims(preferredUsername = "ch4mpy")) void givenUserIsAuthenticated_whenGetGreet_thenOk() throws Exception { final var greeting = "Whatever the service returns"; when(messageService.greet()).thenReturn(greeting); - // @formatter:off api.perform(get("/greet")) .andExpect(status().isOk()) .andExpect(content().string(greeting)); - // @formatter:on verify(messageService, times(1)).greet(); } @@ -67,10 +61,8 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { - // @formatter:off api.perform(get("/secured-route")) .andExpect(status().isUnauthorized()); - // @formatter:on } @Test @@ -79,22 +71,18 @@ class SpringAddonsGreetingControllerUnitTest { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(secret); - // @formatter:off api.perform(get("/secured-route")) .andExpect(status().isOk()) .andExpect(content().string(secret)); - // @formatter:on } @Test @WithMockJwtAuth({ "admin" }) void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { - // @formatter:off api.perform(get("/secured-route")) .andExpect(status().isForbidden()); - // @formatter:on } - + /*---------------------------------------------------------------------------------------------------------*/ /* /secured-method */ /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ @@ -103,10 +91,8 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { - // @formatter:off api.perform(get("/secured-method")) .andExpect(status().isUnauthorized()); - // @formatter:on } @Test @@ -115,20 +101,16 @@ class SpringAddonsGreetingControllerUnitTest { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(secret); - // @formatter:off api.perform(get("/secured-method")) .andExpect(status().isOk()) .andExpect(content().string(secret)); - // @formatter:on } @Test @WithMockJwtAuth(authorities = { "admin" }) void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { - // @formatter:off api.perform(get("/secured-method")) .andExpect(status().isForbidden()); - // @formatter:on } } diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java index 83a95cf508..2bbd294401 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -38,10 +38,8 @@ class SpringSecurityTestGreetingControllerUnitTest { @Test void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { - // @formatter:off api.perform(get("/greet").with(anonymous())) .andExpect(status().isUnauthorized()); - // @formatter:on } @Test @@ -49,13 +47,10 @@ class SpringSecurityTestGreetingControllerUnitTest { final var greeting = "Whatever the service returns"; when(messageService.greet()).thenReturn(greeting); - // @formatter:off - api.perform(get("/greet").with(jwt() - .authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) - .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy")))) + api.perform(get("/greet").with(jwt().authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))) + .jwt(jwt -> jwt.claim(StandardClaimNames.PREFERRED_USERNAME, "ch4mpy")))) .andExpect(status().isOk()) .andExpect(content().string(greeting)); - // @formatter:on verify(messageService, times(1)).greet(); } @@ -67,10 +62,8 @@ class SpringSecurityTestGreetingControllerUnitTest { @Test void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { - // @formatter:off api.perform(get("/secured-route").with(anonymous())) .andExpect(status().isUnauthorized()); - // @formatter:on } @Test @@ -78,21 +71,17 @@ class SpringSecurityTestGreetingControllerUnitTest { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(secret); - // @formatter:off api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))) .andExpect(status().isOk()) .andExpect(content().string(secret)); - // @formatter:on } @Test void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception { - // @formatter:off api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("admin")))) .andExpect(status().isForbidden()); - // @formatter:on } - + /*---------------------------------------------------------------------------------------------------------*/ /* /secured-method */ /* This end-point is secured with "@PreAuthorize("hasRole('AUTHORIZED_PERSONNEL')")" on @Controller method */ @@ -100,10 +89,8 @@ class SpringSecurityTestGreetingControllerUnitTest { @Test void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { - // @formatter:off api.perform(get("/secured-method").with(anonymous())) .andExpect(status().isUnauthorized()); - // @formatter:on } @Test @@ -111,19 +98,15 @@ class SpringSecurityTestGreetingControllerUnitTest { final var secret = "Secret!"; when(messageService.getSecret()).thenReturn(secret); - // @formatter:off api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))) .andExpect(status().isOk()) .andExpect(content().string(secret)); - // @formatter:on } @Test void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception { - // @formatter:off api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("admin")))) .andExpect(status().isForbidden()); - // @formatter:on } } From 5679db5cb82e15eec0b4240bddaae45f04cdbdc9 Mon Sep 17 00:00:00 2001 From: ch4mpy Date: Wed, 1 Mar 2023 14:20:41 -1000 Subject: [PATCH 4/6] BAEL-6223 : ul (CONFIGURATION) Move spring-security-oauth2-testing module declaration --- pom.xml | 1 - spring-security-modules/pom.xml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 345cd7979a..0ec9e9efdd 100644 --- a/pom.xml +++ b/pom.xml @@ -1023,7 +1023,6 @@ spring-kafka spring-native - spring-security-modules/spring-security-oauth2-testing spring-protobuf spring-quartz diff --git a/spring-security-modules/pom.xml b/spring-security-modules/pom.xml index 223f0894d5..6fb9f8ea0b 100644 --- a/spring-security-modules/pom.xml +++ b/spring-security-modules/pom.xml @@ -26,6 +26,7 @@ spring-security-oauth2-sso spring-security-oidc spring-security-okta + spring-security-oauth2-testing spring-security-saml spring-security-social-login spring-security-web-angular From 052dd5e64fa414114d30d965390d67b4872725fa Mon Sep 17 00:00:00 2001 From: ch4mpy Date: Wed, 1 Mar 2023 14:53:01 -1000 Subject: [PATCH 5/6] BAEL-6223 : ul (CONFIGURATION) Anonymous test methods naming --- .../src/test/java/com/baeldung/MessageServiceUnitTest.java | 4 ++-- .../ReactiveResourceServerApplicationIntegrationTest.java | 6 +++--- .../baeldung/SpringAddonsGreetingControllerUnitTest.java | 6 +++--- .../SpringSecurityTestGreetingControllerUnitTest.java | 6 +++--- .../src/test/java/com/baeldung/MessageServiceUnitTest.java | 4 ++-- .../ServletResourceServerApplicationIntegrationTest.java | 6 +++--- .../baeldung/SpringAddonsGreetingControllerUnitTest.java | 6 +++--- .../SpringSecurityTestGreetingControllerUnitTest.java | 6 +++--- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java index ecaf270f10..97893bc1fb 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java @@ -38,7 +38,7 @@ class MessageServiceUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGreet_thenThrowsClassCastException() { + void givenUserIsAnonymous_whenGreet_thenThrowsClassCastException() { assertThrows(ClassCastException.class, () -> messageService.greet() .block()); } @@ -64,7 +64,7 @@ class MessageServiceUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecret_thenThrowsAccessDeniedException() { + void givenUserIsAnonymous_whenGetSecret_thenThrowsAccessDeniedException() { assertThrows(AccessDeniedException.class, () -> messageService.getSecret() .block()); } diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java index dd64eb2109..1ee6fc7e87 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/ReactiveResourceServerApplicationIntegrationTest.java @@ -24,7 +24,7 @@ class ReactiveResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser - void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { api.get() .uri("/greet") .exchange() @@ -51,7 +51,7 @@ class ReactiveResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser - void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { api.get() .uri("/secured-route") .exchange() @@ -88,7 +88,7 @@ class ReactiveResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser - void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { api.get() .uri("/secured-method") .exchange() diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java index 0da6701781..6f55f287d8 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -34,7 +34,7 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser - void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { api.get() .uri("/greet") .exchange() @@ -66,7 +66,7 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser - void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { api.get() .uri("/secured-route") .exchange() @@ -106,7 +106,7 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser - void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { api.get() .uri("/secured-method") .exchange() diff --git a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java index b15c1304e6..e048481ce4 100644 --- a/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/reactive-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -39,7 +39,7 @@ class SpringSecurityTestGreetingControllerUnitTest { /*-----------------------------------------------------------------------------*/ @Test - void givenUserIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) .get() .uri("/greet") @@ -72,7 +72,7 @@ class SpringSecurityTestGreetingControllerUnitTest { /*---------------------------------------------------------------------------------------------------------------------*/ @Test - void givenUserIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) .get() .uri("/secured-route") @@ -112,7 +112,7 @@ class SpringSecurityTestGreetingControllerUnitTest { /*---------------------------------------------------------------------------------------------------------*/ @Test - void givenUserIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { api.mutateWith(mockAuthentication(ANONYMOUS_AUTHENTICATION)) .get() .uri("/secured-method") diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java index 36be2df331..3c608d226e 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/MessageServiceUnitTest.java @@ -37,7 +37,7 @@ class MessageServiceUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGreet_thenThrowsAccessDeniedException() { + void givenUserIsAnonymous_whenGreet_thenThrowsAccessDeniedException() { assertThrows(AccessDeniedException.class, () -> messageService.getSecret()); } @@ -60,7 +60,7 @@ class MessageServiceUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecret_thenThrowsAccessDeniedException() { + void givenUserIsAnonymous_whenGetSecret_thenThrowsAccessDeniedException() { assertThrows(AccessDeniedException.class, () -> messageService.getSecret()); } diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java index 60b74e93be..5bb539741f 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/ServletResourceServerApplicationIntegrationTest.java @@ -28,7 +28,7 @@ class ServletResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { api.perform(get("/greet")) .andExpect(status().isUnauthorized()); } @@ -48,7 +48,7 @@ class ServletResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { api.perform(get("/secured-route")) .andExpect(status().isUnauthorized()); } @@ -75,7 +75,7 @@ class ServletResourceServerApplicationIntegrationTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { api.perform(get("/secured-method")) .andExpect(status().isUnauthorized()); } diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java index 949a8aa04c..9162768930 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringAddonsGreetingControllerUnitTest.java @@ -35,7 +35,7 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { api.perform(get("/greet")) .andExpect(status().isUnauthorized()); } @@ -60,7 +60,7 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { api.perform(get("/secured-route")) .andExpect(status().isUnauthorized()); } @@ -90,7 +90,7 @@ class SpringAddonsGreetingControllerUnitTest { @Test @WithAnonymousUser - void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { api.perform(get("/secured-method")) .andExpect(status().isUnauthorized()); } diff --git a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java index 2bbd294401..0e710bcc9f 100644 --- a/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java +++ b/spring-security-modules/spring-security-oauth2-testing/servlet-resource-server/src/test/java/com/baeldung/SpringSecurityTestGreetingControllerUnitTest.java @@ -37,7 +37,7 @@ class SpringSecurityTestGreetingControllerUnitTest { /*-----------------------------------------------------------------------------*/ @Test - void givenUserIsNotAuthenticated_whenGetGreet_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception { api.perform(get("/greet").with(anonymous())) .andExpect(status().isUnauthorized()); } @@ -61,7 +61,7 @@ class SpringSecurityTestGreetingControllerUnitTest { /*---------------------------------------------------------------------------------------------------------------------*/ @Test - void givenUserIsNotAuthenticated_whenGetSecuredRoute_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception { api.perform(get("/secured-route").with(anonymous())) .andExpect(status().isUnauthorized()); } @@ -88,7 +88,7 @@ class SpringSecurityTestGreetingControllerUnitTest { /*---------------------------------------------------------------------------------------------------------*/ @Test - void givenUserIsNotAuthenticated_whenGetSecuredMethod_thenUnauthorized() throws Exception { + void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception { api.perform(get("/secured-method").with(anonymous())) .andExpect(status().isUnauthorized()); } From 769ca1793720209eea37b3d2f59099c4f10454eb Mon Sep 17 00:00:00 2001 From: ch4mpy Date: Wed, 1 Mar 2023 14:53:35 -1000 Subject: [PATCH 6/6] BAEL-6223 : ul (CONFIGURATION) Revert move spring-security-oauth2-testing module declaration --- pom.xml | 1 + spring-security-modules/pom.xml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0ec9e9efdd..345cd7979a 100644 --- a/pom.xml +++ b/pom.xml @@ -1023,6 +1023,7 @@ spring-kafka spring-native + spring-security-modules/spring-security-oauth2-testing spring-protobuf spring-quartz diff --git a/spring-security-modules/pom.xml b/spring-security-modules/pom.xml index 6fb9f8ea0b..223f0894d5 100644 --- a/spring-security-modules/pom.xml +++ b/spring-security-modules/pom.xml @@ -26,7 +26,6 @@ spring-security-oauth2-sso spring-security-oidc spring-security-okta - spring-security-oauth2-testing spring-security-saml spring-security-social-login spring-security-web-angular