diff --git a/docker/Dockerfile b/docker/Dockerfile index 164c947..8a37ad2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,31 +1,5 @@ -FROM openjdk:11-jre as builder -WORKDIR /application -COPY maven/*.jar application.jar -RUN java -Djarmode=layertools -jar application.jar extract - -# Download dockerize and cache that layer -ARG DOCKERIZE_VERSION -ADD https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-alpine-linux-amd64-${DOCKERIZE_VERSION}.tar.gz ./dockerize.tar.gz -RUN tar xzf dockerize.tar.gz -RUN chmod +x dockerize - -FROM adoptopenjdk:16-jre-hotspot - -LABEL maintainer="zhoozhoo@yahoo.com" - -WORKDIR /application - - # Dockerize -COPY --from=builder application/dockerize ./ - -ARG EXPOSED_PORT -EXPOSE ${EXPOSED_PORT} - +FROM eclipse-temurin:21-jre-alpine +LABEL Author="zhoozhoo@yahoo.com" ENV SPRING_PROFILES_ACTIVE docker - -COPY --from=builder application/dependencies/ ./ -COPY --from=builder application/spring-boot-loader/ ./ -COPY --from=builder application/snapshot-dependencies/ ./ -COPY --from=builder application/application/ ./ - -ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"] \ No newline at end of file +COPY maven/*.jar application.jar +ENTRYPOINT ["java","-jar","/application.jar"] \ No newline at end of file diff --git a/docker/keycloak/Dockerfile b/docker/keycloak/Dockerfile index 0eb21f1..99c4c46 100644 --- a/docker/keycloak/Dockerfile +++ b/docker/keycloak/Dockerfile @@ -1,4 +1,4 @@ -FROM jboss/keycloak:latest +FROM quay.io/keycloak/keycloak:latest COPY spring-cloud-gateway-realm.json /tmp ENV KEYCLOAK_USER=user ENV KEYCLOAK_PASSWORD=password diff --git a/pom.xml b/pom.xml index 083ea41..e39227a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.springframework.boot spring-boot-starter-parent - 3.3.3 + 3.3.4 ca.zhoozhoo.spring.cloud @@ -29,14 +29,13 @@ 21 - 3.3.3 + 3.3.4 2023.0.3 3.3.3 1.7.2 - 13.0.1 + 25.0.5 zhoozhoo - v0.8.0 - 1.17.0 + 1.17.0 @@ -61,23 +60,23 @@ org.springframework.boot spring-boot-maven-plugin - - true - - true - - build-info + build-image-no-fork - ${project.build.sourceEncoding} - ${project.reporting.outputEncoding} + UTF-8 + UTF-8 ${java.version} + + + ${docker.image.prefix}/${project.artifactId}:${project.version} + eclipse-temurin:${java.version}-jre-alpine + @@ -85,45 +84,14 @@ - + docker true - - - - org.eclipse.jkube - kubernetes-maven-plugin - ${kubernetes-maven-plugin.version} - - - - ${project.artifactId} - ${docker.image.prefix}/${project.artifactId}:${project.version} - - ${project.basedir}/../docker - - ${docker.image.dockerize.version} - ${docker.image.exposed.port} - - - - - - - - - build - - - - - - - + \ No newline at end of file diff --git a/spring-cloud-api-gateway/src/main/java/ca/zhoozhoo/springcloud/api/config/SecurityConfig.java b/spring-cloud-api-gateway/src/main/java/ca/zhoozhoo/springcloud/api/config/SecurityConfig.java index 2b95e8d..a1615b9 100644 --- a/spring-cloud-api-gateway/src/main/java/ca/zhoozhoo/springcloud/api/config/SecurityConfig.java +++ b/spring-cloud-api-gateway/src/main/java/ca/zhoozhoo/springcloud/api/config/SecurityConfig.java @@ -1,38 +1,27 @@ package ca.zhoozhoo.springcloud.api.config; +import static org.springframework.security.config.Customizer.withDefaults; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; 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.oauth2.client.oidc.web.server.logout.OidcClientInitiatedServerLogoutSuccessHandler; -import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter.Mode; @Configuration -@EnableReactiveMethodSecurity @EnableWebFluxSecurity -@Profile({"docker", "kubernetes"}) +@EnableReactiveMethodSecurity public class SecurityConfig { @Bean - public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, - ReactiveClientRegistrationRepository clientRegistrationRepository) { - // Authenticate through configured OpenID Provider - http.oauth2Login(); - // Also logout at the OpenID Connect provider - http.logout(logout -> logout - .logoutSuccessHandler(new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository))); - // Allow unauthenticated actuator access - http.authorizeExchange().pathMatchers("/actuator/**").permitAll(); - // Require authentication for all requests - http.authorizeExchange().anyExchange().authenticated(); - // Allow showing /home within a frame - http.headers().frameOptions().mode(Mode.SAMEORIGIN); - // Disable CSRF in the gateway to prevent conflicts with proxied service CSRF - http.csrf().disable(); + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + http.authorizeExchange(exchanges -> exchanges + .anyExchange() + .authenticated()) + .oauth2Login(withDefaults()) + .oauth2ResourceServer((resourceServer) -> resourceServer + .jwt(withDefaults())); return http.build(); } diff --git a/spring-cloud-auth-server/pom.xml b/spring-cloud-auth-server/pom.xml index 9c4b5cc..e05555e 100644 --- a/spring-cloud-auth-server/pom.xml +++ b/spring-cloud-auth-server/pom.xml @@ -29,11 +29,6 @@ - - org.keycloak - keycloak-spring-boot-starter - ${keycloak.version} - org.keycloak keycloak-admin-client @@ -59,7 +54,7 @@ ${project.artifactId} ${docker.image.prefix}/${project.artifactId}:${project.version} - jboss/keycloak:${keycloak.version} + quay.io/keycloak/keycloak:${keycloak.version} admin admin diff --git a/spring-cloud-config-server/pom.xml b/spring-cloud-config-server/pom.xml index 6eb4829..74fefd3 100644 --- a/spring-cloud-config-server/pom.xml +++ b/spring-cloud-config-server/pom.xml @@ -23,11 +23,6 @@ org.springframework.boot spring-boot-starter-actuator - - org.springframework.boot - spring-boot-starter-test - test - @@ -39,7 +34,18 @@ spring-cloud-starter-bootstrap + + + org.jolokia + jolokia-core + + + + org.springframework.boot + spring-boot-starter-test + test + org.junit.jupiter junit-jupiter-api @@ -51,21 +57,4 @@ test - - - - docker - - true - - - - - org.eclipse.jkube - kubernetes-maven-plugin - - - - - - + \ No newline at end of file diff --git a/spring-cloud-discovery-server/pom.xml b/spring-cloud-discovery-server/pom.xml index c38294c..99f34c1 100644 --- a/spring-cloud-discovery-server/pom.xml +++ b/spring-cloud-discovery-server/pom.xml @@ -45,21 +45,4 @@ spring-retry - - - - docker - - true - - - - - org.eclipse.jkube - kubernetes-maven-plugin - - - - - diff --git a/spring-cloud-guest-service/pom.xml b/spring-cloud-guest-service/pom.xml index f18c148..00ffbbc 100644 --- a/spring-cloud-guest-service/pom.xml +++ b/spring-cloud-guest-service/pom.xml @@ -96,21 +96,4 @@ test - - - - docker - - true - - - - - org.eclipse.jkube - kubernetes-maven-plugin - - - - - diff --git a/spring-cloud-guest-service/src/main/java/ca/zhoozhoo/springcloud/guests/config/SecurityConfig.java b/spring-cloud-guest-service/src/main/java/ca/zhoozhoo/springcloud/guests/config/SecurityConfig.java index 8ea9d46..f6b4610 100644 --- a/spring-cloud-guest-service/src/main/java/ca/zhoozhoo/springcloud/guests/config/SecurityConfig.java +++ b/spring-cloud-guest-service/src/main/java/ca/zhoozhoo/springcloud/guests/config/SecurityConfig.java @@ -1,87 +1,28 @@ package ca.zhoozhoo.springcloud.guests.config; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import static org.springframework.security.config.Customizer.withDefaults; -import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.core.convert.converter.Converter; 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.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.jwt.MappedJwtClaimSetConverter; -import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; -import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; -import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders; -import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter; import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter.Mode; - -import reactor.core.publisher.Flux; @Configuration -@EnableReactiveMethodSecurity @EnableWebFluxSecurity -@Profile({"docker", "kubernetes"}) +@EnableReactiveMethodSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - // Validate tokens through configured OpenID Provider - http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter()); - // Allow unauthenticated actuator access - http.authorizeExchange().pathMatchers("/actuator/**").permitAll(); - // Require authentication for all requests - http.authorizeExchange().anyExchange().authenticated(); - // Allow showing pages within a frame - http.headers().frameOptions().mode(Mode.SAMEORIGIN); + http.authorizeExchange(exchanges -> exchanges + .anyExchange() + .authenticated()) + .oauth2Login(withDefaults()) + .oauth2ResourceServer((resourceServer) -> resourceServer + .jwt(withDefaults())); return http.build(); } - - private ReactiveJwtAuthenticationConverter jwtAuthenticationConverter() { - var jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter(); - - // Convert realm_access.roles claims to granted authorities, for use in access decisions - jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new Converter>() { - - @Override - @SuppressWarnings("unchecked") - public Flux convert(final Jwt jwt) { - return Flux.fromIterable( - ((List) ((Map) jwt.getClaims().get("realm_access")).get("roles")) - .stream().map(roleName -> "ROLE_" + roleName).map(SimpleGrantedAuthority::new) - .collect(Collectors.toList())); - } - }); - - return jwtAuthenticationConverter; - } - - @Bean - public ReactiveJwtDecoder reactiveJwtDecoderByIssuerUri(OAuth2ResourceServerProperties properties) { - var jwtDecoder = - (NimbusReactiveJwtDecoder) ReactiveJwtDecoders.fromIssuerLocation(properties.getJwt().getIssuerUri()); - - // Use preferred_username from claims as authentication name, instead of UUID subject - jwtDecoder.setClaimSetConverter(new Converter, Map>() { - - @Override - public Map convert(Map claims) { - var convertedClaims = MappedJwtClaimSetConverter.withDefaults(Collections.emptyMap()).convert(claims); - convertedClaims.put("sub", (String) convertedClaims.get("preferred_username")); - - return convertedClaims; - } - }); - - return jwtDecoder; - } } diff --git a/spring-cloud-reservation-service/pom.xml b/spring-cloud-reservation-service/pom.xml index 2872172..2bb6781 100644 --- a/spring-cloud-reservation-service/pom.xml +++ b/spring-cloud-reservation-service/pom.xml @@ -96,21 +96,4 @@ test - - - - docker - - true - - - - - org.eclipse.jkube - kubernetes-maven-plugin - - - - - diff --git a/spring-cloud-reservation-service/src/main/java/ca/zhoozhoo/springcloud/reservations/config/SecurityConfig.java b/spring-cloud-reservation-service/src/main/java/ca/zhoozhoo/springcloud/reservations/config/SecurityConfig.java index 15af7ed..7499842 100644 --- a/spring-cloud-reservation-service/src/main/java/ca/zhoozhoo/springcloud/reservations/config/SecurityConfig.java +++ b/spring-cloud-reservation-service/src/main/java/ca/zhoozhoo/springcloud/reservations/config/SecurityConfig.java @@ -1,87 +1,28 @@ package ca.zhoozhoo.springcloud.reservations.config; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import static org.springframework.security.config.Customizer.withDefaults; -import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.core.convert.converter.Converter; 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.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.jwt.MappedJwtClaimSetConverter; -import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; -import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; -import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders; -import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter; import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter.Mode; - -import reactor.core.publisher.Flux; @Configuration -@EnableReactiveMethodSecurity @EnableWebFluxSecurity -@Profile({"docker", "kubernetes"}) +@EnableReactiveMethodSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - // Validate tokens through configured OpenID Provider - http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter()); - // Allow unauthenticated actuator access - http.authorizeExchange().pathMatchers("/actuator/**").permitAll(); - // Require authentication for all requests - http.authorizeExchange().anyExchange().authenticated(); - // Allow showing pages within a frame - http.headers().frameOptions().mode(Mode.SAMEORIGIN); + http.authorizeExchange(exchanges -> exchanges + .anyExchange() + .authenticated()) + .oauth2Login(withDefaults()) + .oauth2ResourceServer((resourceServer) -> resourceServer + .jwt(withDefaults())); return http.build(); } - - private ReactiveJwtAuthenticationConverter jwtAuthenticationConverter() { - var jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter(); - - // Convert realm_access.roles claims to granted authorities, for use in access decisions - jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new Converter>() { - - @Override - @SuppressWarnings("unchecked") - public Flux convert(final Jwt jwt) { - return Flux.fromIterable( - ((List) ((Map) jwt.getClaims().get("realm_access")).get("roles")) - .stream().map(roleName -> "ROLE_" + roleName).map(SimpleGrantedAuthority::new) - .collect(Collectors.toList())); - } - }); - - return jwtAuthenticationConverter; - } - - @Bean - public ReactiveJwtDecoder reactiveJwtDecoderByIssuerUri(OAuth2ResourceServerProperties properties) { - var jwtDecoder = - (NimbusReactiveJwtDecoder) ReactiveJwtDecoders.fromIssuerLocation(properties.getJwt().getIssuerUri()); - - // Use preferred_username from claims as authentication name, instead of UUID subject - jwtDecoder.setClaimSetConverter(new Converter, Map>() { - - @Override - public Map convert(Map claims) { - var convertedClaims = MappedJwtClaimSetConverter.withDefaults(Collections.emptyMap()).convert(claims); - convertedClaims.put("sub", (String) convertedClaims.get("preferred_username")); - - return convertedClaims; - } - }); - - return jwtDecoder; - } } diff --git a/spring-cloud-room-reservation-service/pom.xml b/spring-cloud-room-reservation-service/pom.xml index 262eee2..948031e 100644 --- a/spring-cloud-room-reservation-service/pom.xml +++ b/spring-cloud-room-reservation-service/pom.xml @@ -95,21 +95,4 @@ test - - - - docker - - true - - - - - org.eclipse.jkube - kubernetes-maven-plugin - - - - - diff --git a/spring-cloud-room-reservation-service/src/main/java/ca/zhoozhoo/springcloud/roomreservation/config/SecurityConfig.java b/spring-cloud-room-reservation-service/src/main/java/ca/zhoozhoo/springcloud/roomreservation/config/SecurityConfig.java index c8502cb..81b534c 100644 --- a/spring-cloud-room-reservation-service/src/main/java/ca/zhoozhoo/springcloud/roomreservation/config/SecurityConfig.java +++ b/spring-cloud-room-reservation-service/src/main/java/ca/zhoozhoo/springcloud/roomreservation/config/SecurityConfig.java @@ -1,87 +1,28 @@ package ca.zhoozhoo.springcloud.roomreservation.config; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import static org.springframework.security.config.Customizer.withDefaults; -import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.core.convert.converter.Converter; 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.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.jwt.MappedJwtClaimSetConverter; -import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; -import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; -import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders; -import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter; import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter.Mode; - -import reactor.core.publisher.Flux; @Configuration -@EnableReactiveMethodSecurity @EnableWebFluxSecurity -@Profile({"docker", "kubernetes"}) +@EnableReactiveMethodSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - // Validate tokens through configured OpenID Provider - http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter()); - // Allow unauthenticated actuator access - http.authorizeExchange().pathMatchers("/actuator/**").permitAll(); - // Require authentication for all requests - http.authorizeExchange().anyExchange().authenticated(); - // Allow showing pages within a frame - http.headers().frameOptions().mode(Mode.SAMEORIGIN); + http.authorizeExchange(exchanges -> exchanges + .anyExchange() + .authenticated()) + .oauth2Login(withDefaults()) + .oauth2ResourceServer((resourceServer) -> resourceServer + .jwt(withDefaults())); return http.build(); } - - private ReactiveJwtAuthenticationConverter jwtAuthenticationConverter() { - var jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter(); - - // Convert realm_access.roles claims to granted authorities, for use in access decisions - jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new Converter>() { - - @Override - @SuppressWarnings("unchecked") - public Flux convert(final Jwt jwt) { - return Flux.fromIterable( - ((List) ((Map) jwt.getClaims().get("realm_access")).get("roles")) - .stream().map(roleName -> "ROLE_" + roleName).map(SimpleGrantedAuthority::new) - .collect(Collectors.toList())); - } - }); - - return jwtAuthenticationConverter; - } - - @Bean - public ReactiveJwtDecoder reactiveJwtDecoderByIssuerUri(OAuth2ResourceServerProperties properties) { - var jwtDecoder = - (NimbusReactiveJwtDecoder) ReactiveJwtDecoders.fromIssuerLocation(properties.getJwt().getIssuerUri()); - - // Use preferred_username from claims as authentication name, instead of UUID subject - jwtDecoder.setClaimSetConverter(new Converter, Map>() { - - @Override - public Map convert(Map claims) { - var convertedClaims = MappedJwtClaimSetConverter.withDefaults(Collections.emptyMap()).convert(claims); - convertedClaims.put("sub", (String) convertedClaims.get("preferred_username")); - - return convertedClaims; - } - }); - - return jwtDecoder; - } } diff --git a/spring-cloud-room-service/pom.xml b/spring-cloud-room-service/pom.xml index f24f613..393ff64 100644 --- a/spring-cloud-room-service/pom.xml +++ b/spring-cloud-room-service/pom.xml @@ -29,15 +29,19 @@ org.springframework.boot - spring-boot-starter-webflux + spring-boot-starter-data-r2dbc org.springframework.boot - spring-boot-starter-data-r2dbc + spring-boot-starter-oauth2-resource-server org.springframework.boot - spring-boot-starter-oauth2-resource-server + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-webflux @@ -49,28 +53,6 @@ org.springframework.cloud spring-cloud-config-client - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - org.springframework.cloud - spring-cloud-starter-netflix-ribbon - - - org.springframework.cloud - spring-cloud-netflix-ribbon - - - com.netflix.ribbon - ribbon-eureka - - - org.springframework.cloud - spring-cloud-netflix-hystrix - - - @@ -83,46 +65,16 @@ runtime - - - org.springframework.retry - spring-retry - - org.springframework.boot spring-boot-starter-test test + + org.springframework.security + spring-security-test + test + - - - - docker - - - - com.spotify - dockerfile-maven-plugin - - - - - - - kubernetes - - true - - - - - org.eclipse.jkube - kubernetes-maven-plugin - - - - - - + \ No newline at end of file diff --git a/spring-cloud-room-service/src/main/java/ca/zhoozhoo/springcloud/rooms/config/SecurityConfig.java b/spring-cloud-room-service/src/main/java/ca/zhoozhoo/springcloud/rooms/config/SecurityConfig.java index e24b75d..d178e6b 100644 --- a/spring-cloud-room-service/src/main/java/ca/zhoozhoo/springcloud/rooms/config/SecurityConfig.java +++ b/spring-cloud-room-service/src/main/java/ca/zhoozhoo/springcloud/rooms/config/SecurityConfig.java @@ -1,87 +1,28 @@ package ca.zhoozhoo.springcloud.rooms.config; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import static org.springframework.security.config.Customizer.withDefaults; -import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.core.convert.converter.Converter; 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.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.jwt.MappedJwtClaimSetConverter; -import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; -import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; -import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders; -import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter; import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter.Mode; - -import reactor.core.publisher.Flux; @Configuration -@EnableReactiveMethodSecurity @EnableWebFluxSecurity -@Profile({"docker", "kubernetes"}) +@EnableReactiveMethodSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { - // Validate tokens through configured OpenID Provider - http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter()); - // Allow unauthenticated actuator access - http.authorizeExchange().pathMatchers("/actuator/**").permitAll(); - // Require authentication for all requests - http.authorizeExchange().anyExchange().authenticated(); - // Allow showing pages within a frame - http.headers().frameOptions().mode(Mode.SAMEORIGIN); + http.authorizeExchange(exchanges -> exchanges + .anyExchange() + .authenticated()) + .oauth2Login(withDefaults()) + .oauth2ResourceServer((resourceServer) -> resourceServer + .jwt(withDefaults())); return http.build(); } - - private ReactiveJwtAuthenticationConverter jwtAuthenticationConverter() { - var jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter(); - - // Convert realm_access.roles claims to granted authorities, for use in access decisions - jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new Converter>() { - - @Override - @SuppressWarnings("unchecked") - public Flux convert(final Jwt jwt) { - return Flux.fromIterable( - ((List) ((Map) jwt.getClaims().get("realm_access")).get("roles")) - .stream().map(roleName -> "ROLE_" + roleName).map(SimpleGrantedAuthority::new) - .collect(Collectors.toList())); - } - }); - - return jwtAuthenticationConverter; - } - - @Bean - public ReactiveJwtDecoder reactiveJwtDecoderByIssuerUri(OAuth2ResourceServerProperties properties) { - var jwtDecoder = - (NimbusReactiveJwtDecoder) ReactiveJwtDecoders.fromIssuerLocation(properties.getJwt().getIssuerUri()); - - // Use preferred_username from claims as authentication name, instead of UUID subject - jwtDecoder.setClaimSetConverter(new Converter, Map>() { - - @Override - public Map convert(Map claims) { - var convertedClaims = MappedJwtClaimSetConverter.withDefaults(Collections.emptyMap()).convert(claims); - convertedClaims.put("sub", (String) convertedClaims.get("preferred_username")); - - return convertedClaims; - } - }); - - return jwtDecoder; - } }