BAEL-7704 : (CONFIGURATION)

BAEL-7704 :

Update to latest spring-addons.

Fix conf: authentication converter was no used by the security
filter-chain.

Add docker compose file for a Keycloak instance with an imported realm.
This commit is contained in:
ch4mpy
2024-04-19 23:09:30 -10:00
parent 979f4ffb2c
commit eb4996272b
18 changed files with 2065 additions and 100 deletions
@@ -12,6 +12,7 @@
<groupId>com.baeldung</groupId>
<artifactId>spring-security-oauth2-testing</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
@@ -1,7 +1,5 @@
package com.baeldung;
import static org.springframework.security.config.Customizer.withDefaults;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -16,6 +14,7 @@ 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.authentication.AbstractAuthenticationToken;
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;
@@ -48,8 +47,8 @@ public class ServletResourceServerApplication {
@EnableWebSecurity
static class SecurityConf {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.oauth2ResourceServer(resourceServer -> resourceServer.jwt(withDefaults()));
SecurityFilterChain filterChain(HttpSecurity http, Converter<Jwt, AbstractAuthenticationToken> authenticationConverter) throws Exception {
http.oauth2ResourceServer(resourceServer -> resourceServer.jwt(jwtResourceServer -> jwtResourceServer.jwtAuthenticationConverter(authenticationConverter)));
http.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
http.csrf(AbstractHttpConfigurer::disable);
http.exceptionHandling(eh -> eh.authenticationEntryPoint((request, response, authException) -> {
@@ -57,11 +56,11 @@ public class ServletResourceServerApplication {
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
}));
// @formatter:off
http.authorizeHttpRequests(req -> req
.requestMatchers(new AntPathRequestMatcher("/secured-route")).hasRole("AUTHORIZED_PERSONNEL")
.anyRequest().authenticated());
// @formatter:on
// @formatter:off
http.authorizeHttpRequests(req -> req
.requestMatchers(new AntPathRequestMatcher("/secured-route")).hasRole("AUTHORIZED_PERSONNEL")
.anyRequest().authenticated());
// @formatter:on
return http.build();
}
@@ -72,10 +71,14 @@ public class ServletResourceServerApplication {
@Bean
JwtAuthoritiesConverter 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<String>) realmRoles.getOrDefault("roles", List.of());
return roles.stream().map(SimpleGrantedAuthority::new).map(GrantedAuthority.class::cast).toList();
return roles.stream()
.map(SimpleGrantedAuthority::new)
.map(GrantedAuthority.class::cast)
.toList();
};
}
@@ -92,7 +95,8 @@ public class ServletResourceServerApplication {
public static class MessageService {
public String greet() {
final var who = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
final var who = (JwtAuthenticationToken) SecurityContextHolder.getContext()
.getAuthentication();
return "Hello %s! You are granted with %s.".formatted(who.getName(), who.getAuthorities());
}
@@ -1 +0,0 @@
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://localhost:8443/realms/master
@@ -0,0 +1,11 @@
server:
port: 8081
spring:
application:
name: servlet-resource-server
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/baeldung
@@ -0,0 +1,16 @@
${AnsiColor.GREEN} _____ _ _
${AnsiColor.GREEN} / ____| | | | |
${AnsiColor.GREEN} | (___ ___ _ ____ _| | ___| |_ _ __ ___ ___ ___ _ _ _ __ ___ ___ ___ ___ _ ____ _____ _ __
${AnsiColor.GREEN} \___ \ / _ \ '__\ \ / / |/ _ \ __| | '__/ _ \/ __|/ _ \| | | | '__/ __/ _ \ / __|/ _ \ '__\ \ / / _ \ '__|
${AnsiColor.GREEN} ____) | __/ | \ V /| | __/ |_ | | | __/\__ \ (_) | |_| | | | (_| __/ \__ \ __/ | \ V / __/ |
${AnsiColor.GREEN} |_____/ \___|_| \_/ |_|\___|\__| |_| \___||___/\___/ \__,_|_| \___\___| |___/\___|_| \_/ \___|_|
${AnsiColor.GREEN}
${AnsiColor.GREEN}
${AnsiColor.BLUE} __ __ __ ______ __ __ ______
${AnsiColor.BLUE} _____/ /_ / // / ____ ___ ____ / ____ \_____/ // / _________ / __/ /_ _________ ____ ___
${AnsiColor.BLUE} / ___/ __ \/ // /_/ __ `__ \/ __ \/ / __ `/ ___/ // /_______/ ___/ __ \/ /_/ __// ___/ __ \/ __ `__ \
${AnsiColor.BLUE}/ /__/ / / /__ __/ / / / / / /_/ / / /_/ / /__/__ __/_____(__ ) /_/ / __/ /__/ /__/ /_/ / / / / / /
${AnsiColor.BLUE}\___/_/ /_/ /_/ /_/ /_/ /_/ .___/\ \__,_/\___/ /_/ /____/\____/_/ \__(_)___/\____/_/ /_/ /_/
${AnsiColor.BLUE} /_/ \____/
${AnsiColor.RED}Spring Boot ${spring-boot.formatted-version}
${AnsiColor.BLACK}
@@ -44,9 +44,7 @@ class SpringAddonsGreetingControllerUnitTest {
}
@ParameterizedTest
@AuthenticationSource({
@WithMockAuthentication(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, name = "ch4mpy"),
@WithMockAuthentication(authorities = { "uncle", "PIRATE" }, name = "tonton-pirate") })
@AuthenticationSource({ @WithMockAuthentication(authorities = { "admin", "ROLE_AUTHORIZED_PERSONNEL" }, name = "ch4mpy"), @WithMockAuthentication(authorities = { "uncle", "PIRATE" }, name = "tonton-pirate") })
void givenUserIsAuthenticated_whenGetGreet_thenOk(@ParameterizedAuthentication Authentication auth) throws Exception {
final var greeting = "Whatever the service returns";
when(messageService.greet()).thenReturn(greeting);
@@ -3,8 +3,6 @@ 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;
@@ -17,6 +15,7 @@ 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.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.test.web.servlet.MockMvc;
import com.baeldung.ServletResourceServerApplication.GreetingController;
@@ -38,7 +37,7 @@ class SpringSecurityTestGreetingControllerUnitTest {
@Test
void givenRequestIsAnonymous_whenGetGreet_thenUnauthorized() throws Exception {
api.perform(get("/greet").with(anonymous()))
api.perform(get("/greet").with(SecurityMockMvcRequestPostProcessors.anonymous()))
.andExpect(status().isUnauthorized());
}
@@ -47,7 +46,8 @@ class SpringSecurityTestGreetingControllerUnitTest {
final var greeting = "Whatever the service returns";
when(messageService.greet()).thenReturn(greeting);
api.perform(get("/greet").with(jwt().authorities(List.of(new SimpleGrantedAuthority("admin"), new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL")))
api.perform(get("/greet").with(SecurityMockMvcRequestPostProcessors.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));
@@ -62,7 +62,7 @@ class SpringSecurityTestGreetingControllerUnitTest {
@Test
void givenRequestIsAnonymous_whenGetSecuredRoute_thenUnauthorized() throws Exception {
api.perform(get("/secured-route").with(anonymous()))
api.perform(get("/secured-route").with(SecurityMockMvcRequestPostProcessors.anonymous()))
.andExpect(status().isUnauthorized());
}
@@ -71,14 +71,16 @@ class SpringSecurityTestGreetingControllerUnitTest {
final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(secret);
api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))))
api.perform(get("/secured-route").with(SecurityMockMvcRequestPostProcessors.jwt()
.authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))))
.andExpect(status().isOk())
.andExpect(content().string(secret));
}
@Test
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredRoute_thenForbidden() throws Exception {
api.perform(get("/secured-route").with(jwt().authorities(new SimpleGrantedAuthority("admin"))))
api.perform(get("/secured-route").with(SecurityMockMvcRequestPostProcessors.jwt()
.authorities(new SimpleGrantedAuthority("admin"))))
.andExpect(status().isForbidden());
}
@@ -89,7 +91,7 @@ class SpringSecurityTestGreetingControllerUnitTest {
@Test
void givenRequestIsAnonymous_whenGetSecuredMethod_thenUnauthorized() throws Exception {
api.perform(get("/secured-method").with(anonymous()))
api.perform(get("/secured-method").with(SecurityMockMvcRequestPostProcessors.anonymous()))
.andExpect(status().isUnauthorized());
}
@@ -98,14 +100,16 @@ class SpringSecurityTestGreetingControllerUnitTest {
final var secret = "Secret!";
when(messageService.getSecret()).thenReturn(secret);
api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))))
api.perform(get("/secured-method").with(SecurityMockMvcRequestPostProcessors.jwt()
.authorities(new SimpleGrantedAuthority("ROLE_AUTHORIZED_PERSONNEL"))))
.andExpect(status().isOk())
.andExpect(content().string(secret));
}
@Test
void givenUserIsNotGrantedWithRoleAuthorizedPersonnel_whenGetSecuredMethod_thenForbidden() throws Exception {
api.perform(get("/secured-method").with(jwt().authorities(new SimpleGrantedAuthority("admin"))))
api.perform(get("/secured-method").with(SecurityMockMvcRequestPostProcessors.jwt()
.authorities(new SimpleGrantedAuthority("admin"))))
.andExpect(status().isForbidden());
}