From 0b49a55177802588fc263764ff8355d92cde2494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szrnka?= Date: Tue, 19 Dec 2023 16:16:26 +0100 Subject: [PATCH] GMS-85 Redis configuration fix + Security config fix + exception handler updated --- .../redis-cache/start-local-redis-stack.bat | 1 + code/gms-backend/pom.xml | 1310 +++++++++-------- .../java/io/github/gms/GmsApplication.java | 4 +- .../io/github/gms/GmsExceptionHandler.java | 53 +- .../gms/auth/config/SecurityConfig.java | 21 +- .../gms/common/config/RedisCacheConfig.java | 13 + .../filter/SecureHeaderInitializerFilter.java | 28 +- .../src/main/resources/application.properties | 5 +- .../github/gms/GmsExceptionHandlerTest.java | 80 +- .../abstraction/AbstractIntegrationTest.java | 17 +- .../api/controller/ApiIntegrationTest.java | 3 + 11 files changed, 780 insertions(+), 755 deletions(-) create mode 100644 batch-files/redis-cache/start-local-redis-stack.bat diff --git a/batch-files/redis-cache/start-local-redis-stack.bat b/batch-files/redis-cache/start-local-redis-stack.bat new file mode 100644 index 00000000..57bb43a5 --- /dev/null +++ b/batch-files/redis-cache/start-local-redis-stack.bat @@ -0,0 +1 @@ +docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest \ No newline at end of file diff --git a/code/gms-backend/pom.xml b/code/gms-backend/pom.xml index d3cc71eb..594cf43b 100644 --- a/code/gms-backend/pom.xml +++ b/code/gms-backend/pom.xml @@ -1,657 +1,667 @@ - - 4.0.0 - - io.github.gms - give-my-secret - 1.0.0-SNAPSHOT - - gms-backend - - 21 - 21 - 21 - UTF-8 - gms-app - 3.2.0 - 32.0.0-jre - 3.0.0-M4 - 9.8.1 - - 5.8.2 - 4.6.1 - 0.8.11 - false - 0.90 - peter-szrnka - https://sonarcloud.io - **/enums/**, - **/abstraction/**, - **/dto/**, - **/model/**, - **/config/**, - **/entity/**, - **/util/**, - **/exception/**, - **/types/**, - **/event/**, - **/*Entity.java, - **/*Application.java - - true - - - - szrnka.peter@gmail.com - Péter Szrnka - https://github.com/peter-szrnka - - Architect - Technical lead - Developer - - - - - - - - org.springframework.boot - spring-boot-dependencies - ${spring-boot.version} - pom - import - - - - - - - org.springframework.boot - spring-boot-starter-web - - - org.yaml - snakeyaml - - - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-data-ldap - - - org.springframework.boot - spring-boot-starter-aop - - - org.springframework.boot - spring-boot-starter-cache - - - org.springframework.boot - spring-boot-starter-data-redis - - - jakarta.persistence - jakarta.persistence-api - - - jakarta.servlet - jakarta.servlet-api - - + + 4.0.0 + + io.github.gms + give-my-secret + 1.0.0-SNAPSHOT + + gms-backend + + 21 + 21 + 21 + UTF-8 + gms-app + 3.2.0 + 32.0.0-jre + 3.0.0-M4 + 9.22.3 + + 5.9.2 + 5.2.0 + 0.8.9 + false + 0.90 + peter-szrnka + https://sonarcloud.io + **/enums/**, + **/abstraction/**, + **/dto/**, + **/model/**, + **/config/**, + **/entity/**, + **/util/**, + **/exception/**, + **/types/**, + **/event/**, + **/*Entity.java, + **/*Application.java + + true + + + + szrnka.peter@gmail.com + Péter Szrnka + https://github.com/peter-szrnka + + Architect + Technical lead + Developer + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-web + + + org.yaml + snakeyaml + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-data-ldap + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-cache + + + org.springframework.boot + spring-boot-starter-data-redis + + + jakarta.persistence + jakarta.persistence-api + + + jakarta.servlet + jakarta.servlet-api + + ch.qos.logback logback-classic 1.4.12 - - ch.qos.logback - logback-core - 1.4.12 - - - - org.springframework.ldap - spring-ldap-core - 3.2.0 - - - com.unboundid - unboundid-ldapsdk - 6.0.10 - - - org.springframework.boot - spring-boot-devtools - true - runtime - - - org.springframework - spring-context-indexer - true - - - - org.mariadb.jdbc - mariadb-java-client - - - com.mysql - mysql-connector-j - + + ch.qos.logback + logback-core + 1.4.12 + + + + org.springframework.ldap + spring-ldap-core + 3.2.0 + + + com.unboundid + unboundid-ldapsdk + 6.0.10 + + + org.springframework.boot + spring-boot-devtools + true + runtime + + + org.springframework + spring-context-indexer + true + + + + org.mariadb.jdbc + mariadb-java-client + + + com.mysql + mysql-connector-j + - - org.postgresql - postgresql - - - com.microsoft.sqlserver - mssql-jdbc - - - com.oracle.database.jdbc - ojdbc10 - 19.16.0.0 - - - org.flywaydb - flyway-core - ${flyway.version} - - - org.flywaydb - flyway-mysql - ${flyway.version} - - - org.flywaydb - flyway-sqlserver - ${flyway.version} - - - - org.yaml - snakeyaml - 2.0 - - - org.bouncycastle - bcprov-jdk18on - 1.76 - - - org.bouncycastle - bcpkix-jdk18on - 1.76 - - - io.jsonwebtoken - jjwt-api - 0.11.1 - - - io.jsonwebtoken - jjwt-impl - 0.11.1 - runtime - - - io.jsonwebtoken - jjwt-jackson - 0.11.1 - runtime - - - org.projectlombok - lombok - 1.18.30 - - - com.google.guava - guava - ${guava.version} - - - dev.samstevens.totp - totp - 1.7.1 - - - - com.h2database - h2 - test - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.jupiter - junit-jupiter-engine - ${junit.jupiter.version} - test - - - org.junit.jupiter - junit-jupiter-api - ${junit.jupiter.version} - test - - - org.junit.jupiter - junit-jupiter-params - ${junit.jupiter.version} - test - - - org.mockito - mockito-core - ${mockito.version} - test - - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - - - org.mockito - mockito-inline - ${mockito.version} - test - - - org.assertj - assertj-core - test - - - - - default - - true - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${java.version} - ${java.version} - - -parameters - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.1.1 - - UTF-8 - src/main/resources/checkstyle.xml - true - true - true - true - true - true - - - - validate - clean - - check - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - - build-info - - build-info - - - - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - !IntegrationTest,!SecurityTest - - - - - - - codecov - - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - true - - - - org.jacoco - jacoco-maven-plugin - ${jacoco-maven-plugin.version} - - ${skip.jacoco-check-execution} - - **/*Application.class - **/**/DemoDataProviderService.class - **/Abstract*.class - **/**/*Exception.class - **/TestDataProviderService.class - **/model/*.class - **/config/*.class - **/dto/*.class - **/enums/*.class - **/entity/*.class - **/types/*.class - **/event/*.class - - - - - - prepare-agent - - - - jacoco-report - package - - report - - - - jacoco-check - test - - check - - - ${skip.jacoco-check-execution} - - - BUNDLE - - - INSTRUCTION - COVEREDRATIO - ${test.minimum.coverage} - - - BRANCH - COVEREDRATIO - ${test.minimum.coverage} - - - - - - - - - - - - - mutation-test - - false - - - - - org.pitest - pitest-maven - 1.7.3 - - - pit-report - test - - mutationCoverage - - - - - - org.pitest - pitest-junit5-plugin - 0.15 - - - - 95 - 95 - 2 - - io.github.gms.* - - - io.github.gms.* - - - *.*Application - *.*Config - *.*Dto - *.*Entity - *.config.* - *.dto.* - *.entity.* - *.enums.* - *.event.* - *.exception.* - *.model.* - *.repository.* - - - io.github.gms.**IntegrationTest - - - java.util.logging - org.apache.log4j - org.slf4j - org.apache.commons.logging - - - - - - - - build-prod - - false - - - gms-app - - - - maven-resources-plugin - 3.0.2 - - - copy-javascript-resources - prepare-package - - copy-resources - - - ${basedir}/target/classes/static - - - ${basedir}/../gms-frontend/dist/gms-frontend - false - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - io.github.gms.GmsApplication - - - - - repackage - - - - build-info - - build-info - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.1.0 - - - - - - build-prod-docker-image-local - - false - - - gms-app - - - maven-resources-plugin - 3.0.2 - - - copy-javascript-resources - prepare-package - - copy-resources - - - ${basedir}/target/classes/static - - - ${basedir}/../gms-frontend/dist/gms-frontend - false - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - ${java.version} - ${java.version} - - - - io.github.gms - gms-frontend - 0.0.1-SNAPSHOT - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - io.github.gms.GmsApplication - - - - - repackage - - - - build-info - - build-info - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.1.0 - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - true - - - - com.spotify - dockerfile-maven-plugin - - false - gms-app-local - latest - gms-app-local - - target/${project.build.finalName}.jar - - - - - default - - build - - - - - - - - + + org.postgresql + postgresql + + + com.microsoft.sqlserver + mssql-jdbc + + + com.oracle.database.jdbc + ojdbc10 + 19.18.0.0 + + + org.flywaydb + flyway-core + ${flyway.version} + + + org.flywaydb + flyway-mysql + ${flyway.version} + + + org.flywaydb + flyway-sqlserver + ${flyway.version} + + + + org.yaml + snakeyaml + 2.0 + + + org.bouncycastle + bcprov-jdk18on + 1.76 + + + org.bouncycastle + bcpkix-jdk18on + 1.76 + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + + + org.projectlombok + lombok + 1.18.30 + + + com.google.guava + guava + ${guava.version} + + + dev.samstevens.totp + totp + 1.7.1 + + + com.beust + jcommander + + + + + com.beust + jcommander + 1.82 + + + + com.h2database + h2 + test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-params + ${junit.jupiter.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + + + org.mockito + mockito-inline + ${mockito.version} + test + + + org.assertj + assertj-core + test + + + + + default + + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + ${java.version} + + -parameters + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.1 + + UTF-8 + src/main/resources/checkstyle.xml + true + true + true + true + true + true + + + + validate + clean + + check + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + build-info + + build-info + + + + + + + + + + codecov + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + true + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + ${skip.jacoco-check-execution} + + **/*Application.class + **/**/DemoDataProviderService.class + **/Abstract*.class + **/**/*Exception.class + **/TestDataProviderService.class + **/model/*.class + **/config/*.class + **/dto/*.class + **/enums/*.class + **/entity/*.class + **/types/*.class + **/event/*.class + + + + + + prepare-agent + + + + jacoco-report + package + + report + + + + jacoco-check + test + + check + + + ${skip.jacoco-check-execution} + + + BUNDLE + + + INSTRUCTION + COVEREDRATIO + ${test.minimum.coverage} + + + BRANCH + COVEREDRATIO + ${test.minimum.coverage} + + + + + + + + + + + + + mutation-test + + false + + + + + org.pitest + pitest-maven + 1.14.1 + + + pit-report + test + + mutationCoverage + + + + + + org.pitest + pitest-junit5-plugin + 0.15 + + + + 95 + 95 + 2 + + io.github.gms.**.* + + + io.github.gms.**.*Test + + + *.*Application + *.*Config + *.*Dto + *.*Entity + *.config.* + *.dto.* + *.entity.* + *.enums.* + *.event.* + *.exception.* + *.model.* + *.repository.* + + + io.github.gms.**.*IntegrationTest + + + + + + + + build-prod + + false + + + gms-app + + + + maven-resources-plugin + 3.0.2 + + + copy-javascript-resources + prepare-package + + copy-resources + + + ${basedir}/target/classes/static + + + ${basedir}/../gms-frontend/dist/gms-frontend + false + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + io.github.gms.GmsApplication + + + + + repackage + + + + build-info + + build-info + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + + + + build-prod-docker-image-local + + false + + + gms-app + + + maven-resources-plugin + 3.0.2 + + + copy-javascript-resources + prepare-package + + copy-resources + + + ${basedir}/target/classes/static + + + ${basedir}/../gms-frontend/dist/gms-frontend + false + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + io.github.gms + gms-frontend + 0.0.1-SNAPSHOT + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + io.github.gms.GmsApplication + + + + + repackage + + + + build-info + + build-info + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + true + + + + com.spotify + dockerfile-maven-plugin + + false + gms-app-local + latest + gms-app-local + + target/${project.build.finalName}.jar + + + + + default + + build + + + + + + + + diff --git a/code/gms-backend/src/main/java/io/github/gms/GmsApplication.java b/code/gms-backend/src/main/java/io/github/gms/GmsApplication.java index 3e0f00b4..3cd60152 100644 --- a/code/gms-backend/src/main/java/io/github/gms/GmsApplication.java +++ b/code/gms-backend/src/main/java/io/github/gms/GmsApplication.java @@ -3,6 +3,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; /** @@ -13,7 +14,8 @@ */ @SpringBootApplication(exclude = { LdapRepositoriesAutoConfiguration.class, - JacksonAutoConfiguration.class + JacksonAutoConfiguration.class, + RedisAutoConfiguration.class }) public class GmsApplication { diff --git a/code/gms-backend/src/main/java/io/github/gms/GmsExceptionHandler.java b/code/gms-backend/src/main/java/io/github/gms/GmsExceptionHandler.java index 8dcaebe0..59fd65cb 100644 --- a/code/gms-backend/src/main/java/io/github/gms/GmsExceptionHandler.java +++ b/code/gms-backend/src/main/java/io/github/gms/GmsExceptionHandler.java @@ -1,26 +1,21 @@ package io.github.gms; -import java.time.Clock; -import java.time.ZonedDateTime; - +import com.google.common.base.Throwables; +import io.github.gms.common.dto.ErrorResponseDto; +import io.github.gms.common.enums.MdcParameter; +import io.github.gms.common.exception.GmsException; +import lombok.extern.slf4j.Slf4j; import org.slf4j.MDC; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.web.bind.MissingRequestHeaderException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; - -import com.google.common.base.Throwables; +import org.springframework.web.context.request.WebRequest; -import io.github.gms.common.dto.ErrorResponseDto; -import io.github.gms.common.enums.MdcParameter; -import io.github.gms.common.exception.GmsException; -import jakarta.servlet.http.HttpServletRequest; -import lombok.extern.slf4j.Slf4j; +import java.time.Clock; +import java.time.ZonedDateTime; /** * @author Peter Szrnka @@ -28,7 +23,7 @@ */ @Slf4j @ControllerAdvice -public class GmsExceptionHandler extends ResponseEntityExceptionHandler { +public class GmsExceptionHandler { private final Clock clock; @@ -37,28 +32,32 @@ public GmsExceptionHandler(Clock clock) { } @ExceptionHandler(GmsException.class) - @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) - public @ResponseBody ErrorResponseDto handleOtherException(HttpServletRequest request, HandlerMethod handlerMethod, GmsException ex) { + public ResponseEntity handleOtherException(GmsException ex, WebRequest request) { log.error("GmsException handled", ex); - return new ErrorResponseDto(Throwables.getRootCause(ex).getMessage(), MDC.get(MdcParameter.CORRELATION_ID.getDisplayName()), ZonedDateTime.now(clock)); + return getResponse(ex, HttpStatus.INTERNAL_SERVER_ERROR); } @ExceptionHandler(AccessDeniedException.class) - @ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "Access forbidden") - public @ResponseBody ErrorResponseDto handleOtherException(HttpServletRequest request, HandlerMethod handlerMethod, AccessDeniedException ex) { - return new ErrorResponseDto(Throwables.getRootCause(ex).getMessage(), MDC.get(MdcParameter.CORRELATION_ID.getDisplayName()), ZonedDateTime.now(clock)); + public ResponseEntity handleOtherException(AccessDeniedException ex, WebRequest request) { + return getResponse(ex, HttpStatus.FORBIDDEN); } @ExceptionHandler(MissingRequestHeaderException.class) - @ResponseStatus(value = HttpStatus.BAD_REQUEST) - public @ResponseBody ErrorResponseDto handleOtherException(HttpServletRequest request, HandlerMethod handlerMethod, MissingRequestHeaderException ex) { - return new ErrorResponseDto(Throwables.getRootCause(ex).getMessage(), MDC.get(MdcParameter.CORRELATION_ID.getDisplayName()), ZonedDateTime.now(clock)); + public ResponseEntity handleOtherException(MissingRequestHeaderException ex, WebRequest request) { + return getResponse(ex, HttpStatus.BAD_REQUEST); } @ExceptionHandler(Exception.class) - @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) - public @ResponseBody ErrorResponseDto handleOtherException(HttpServletRequest request, HandlerMethod handlerMethod, Exception ex) { + public ResponseEntity handleOtherException(Exception ex, WebRequest request) { log.error("Exception handled", ex); - return new ErrorResponseDto(Throwables.getRootCause(ex).getMessage(), MDC.get(MdcParameter.CORRELATION_ID.getDisplayName()), ZonedDateTime.now(clock)); + return getResponse(ex, HttpStatus.INTERNAL_SERVER_ERROR); + } + + private ResponseEntity getResponse(Exception ex, HttpStatus httpStatus) { + return new ResponseEntity<>(new ErrorResponseDto( + Throwables.getRootCause(ex).getMessage(), + MDC.get(MdcParameter.CORRELATION_ID.getDisplayName()), + ZonedDateTime.now(clock) + ), httpStatus); } } \ No newline at end of file diff --git a/code/gms-backend/src/main/java/io/github/gms/auth/config/SecurityConfig.java b/code/gms-backend/src/main/java/io/github/gms/auth/config/SecurityConfig.java index c5140d5c..7e276511 100644 --- a/code/gms-backend/src/main/java/io/github/gms/auth/config/SecurityConfig.java +++ b/code/gms-backend/src/main/java/io/github/gms/auth/config/SecurityConfig.java @@ -1,9 +1,12 @@ package io.github.gms.auth.config; -import static io.github.gms.common.util.Constants.PASSWORD_ENCODER; - -import java.util.List; - +import dev.samstevens.totp.code.CodeGenerator; +import dev.samstevens.totp.code.CodeVerifier; +import dev.samstevens.totp.code.DefaultCodeGenerator; +import dev.samstevens.totp.code.DefaultCodeVerifier; +import dev.samstevens.totp.time.SystemTimeProvider; +import dev.samstevens.totp.time.TimeProvider; +import io.github.gms.common.filter.SecureHeaderInitializerFilter; import org.springframework.boot.autoconfigure.security.servlet.PathRequest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -28,13 +31,9 @@ import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import dev.samstevens.totp.code.CodeGenerator; -import dev.samstevens.totp.code.CodeVerifier; -import dev.samstevens.totp.code.DefaultCodeGenerator; -import dev.samstevens.totp.code.DefaultCodeVerifier; -import dev.samstevens.totp.time.SystemTimeProvider; -import dev.samstevens.totp.time.TimeProvider; -import io.github.gms.common.filter.SecureHeaderInitializerFilter; +import java.util.List; + +import static io.github.gms.common.util.Constants.PASSWORD_ENCODER; /** * @author Peter Szrnka diff --git a/code/gms-backend/src/main/java/io/github/gms/common/config/RedisCacheConfig.java b/code/gms-backend/src/main/java/io/github/gms/common/config/RedisCacheConfig.java index cb412233..247d556a 100644 --- a/code/gms-backend/src/main/java/io/github/gms/common/config/RedisCacheConfig.java +++ b/code/gms-backend/src/main/java/io/github/gms/common/config/RedisCacheConfig.java @@ -1,6 +1,7 @@ package io.github.gms.common.config; import io.github.gms.common.config.cache.ApiCacheKeyGenerator; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.CacheManager; @@ -13,6 +14,7 @@ import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; @@ -31,6 +33,17 @@ @ConditionalOnProperty(name = "config.cache.redis.enabled", havingValue = "true") public class RedisCacheConfig { + @Value("${config.cache.redis.host}") + private String host; + + @Value("${config.cache.redis.port}") + private Integer port; + + @Bean + public LettuceConnectionFactory lettuceConnectionFactory() { + return new LettuceConnectionFactory(host, port); + } + @Primary @Bean public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { diff --git a/code/gms-backend/src/main/java/io/github/gms/common/filter/SecureHeaderInitializerFilter.java b/code/gms-backend/src/main/java/io/github/gms/common/filter/SecureHeaderInitializerFilter.java index 02a62a9a..84584632 100644 --- a/code/gms-backend/src/main/java/io/github/gms/common/filter/SecureHeaderInitializerFilter.java +++ b/code/gms-backend/src/main/java/io/github/gms/common/filter/SecureHeaderInitializerFilter.java @@ -1,21 +1,6 @@ package io.github.gms.common.filter; -import java.io.IOException; -import java.util.Set; -import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.slf4j.MDC; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatus; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; - import com.google.common.collect.Sets; - import io.github.gms.auth.AuthorizationService; import io.github.gms.auth.model.AuthorizationResponse; import io.github.gms.common.enums.JwtConfigType; @@ -28,6 +13,19 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.Set; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * A custom Spring filter used to authorize user by parsing JWT token. diff --git a/code/gms-backend/src/main/resources/application.properties b/code/gms-backend/src/main/resources/application.properties index 157b6b72..49b23a27 100644 --- a/code/gms-backend/src/main/resources/application.properties +++ b/code/gms-backend/src/main/resources/application.properties @@ -65,5 +65,6 @@ spring.flyway.locations=classpath:db/${SELECTED_DB}/migration # Cache (Redis) config.cache.redis.enabled=${ENABLE_REDIS_CACHE:false} -spring.redis.host=${REDIS_HOST} -spring.redis.port=${REDIS_PORT} \ No newline at end of file +spring.data.redis.repositories.enabled=${ENABLE_REDIS_CACHE:false} +config.cache.redis.host=${REDIS_HOST} +config.cache.redis.port=${REDIS_PORT} \ No newline at end of file diff --git a/code/gms-backend/src/test/java/io/github/gms/GmsExceptionHandlerTest.java b/code/gms-backend/src/test/java/io/github/gms/GmsExceptionHandlerTest.java index a96a44a4..3599a8f3 100644 --- a/code/gms-backend/src/test/java/io/github/gms/GmsExceptionHandlerTest.java +++ b/code/gms-backend/src/test/java/io/github/gms/GmsExceptionHandlerTest.java @@ -1,35 +1,33 @@ package io.github.gms; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.lang.reflect.Method; -import java.time.Clock; -import java.time.Instant; -import java.time.ZoneOffset; - +import io.github.gms.abstraction.AbstractUnitTest; +import io.github.gms.common.dto.ErrorResponseDto; +import io.github.gms.common.enums.MdcParameter; +import io.github.gms.common.exception.GmsException; import org.jboss.logging.MDC; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.core.MethodParameter; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.web.bind.MissingRequestHeaderException; -import org.springframework.web.method.HandlerMethod; +import org.springframework.web.context.request.WebRequest; -import io.github.gms.abstraction.AbstractUnitTest; -import io.github.gms.common.dto.ErrorResponseDto; -import io.github.gms.common.enums.MdcParameter; -import io.github.gms.common.exception.GmsException; -import jakarta.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneOffset; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * @author Peter Szrnka * @since 1.0 */ -@Disabled class GmsExceptionHandlerTest extends AbstractUnitTest { private static final String CORRELATION_ID = "CORRELATION_ID"; @@ -48,64 +46,66 @@ public void setup() { @Test void shouldHandleGmsException() { // arrange - HttpServletRequest request = mock(HttpServletRequest.class); - HandlerMethod handlerMethod = mock(HandlerMethod.class); + WebRequest webRequest = mock(WebRequest.class); // act - ErrorResponseDto response = handler.handleOtherException(request, handlerMethod, new GmsException("Oops!")); + ResponseEntity response = handler.handleOtherException(new GmsException("Oops!"), webRequest); // assert assertNotNull(response); - assertEquals(CORRELATION_ID, response.getCorrelationId()); - assertEquals("Oops!", response.getMessage()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertNotNull(response.getBody()); + assertEquals(CORRELATION_ID, response.getBody().getCorrelationId()); + assertEquals("Oops!", response.getBody().getMessage()); } @Test void shouldHandleAccessDeniedException() { // arrange - HttpServletRequest request = mock(HttpServletRequest.class); - HandlerMethod handlerMethod = mock(HandlerMethod.class); + WebRequest webRequest = mock(WebRequest.class); // act - ErrorResponseDto response = handler.handleOtherException(request, handlerMethod, - new AccessDeniedException("Oops!")); + ResponseEntity response = handler.handleOtherException(new AccessDeniedException("Oops!"), webRequest); // assert assertNotNull(response); - assertEquals(CORRELATION_ID, response.getCorrelationId()); - assertEquals("Oops!", response.getMessage()); + assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); + assertNotNull(response.getBody()); + assertEquals(CORRELATION_ID, response.getBody().getCorrelationId()); + assertEquals("Oops!", response.getBody().getMessage()); } @Test void shouldHandleOtherException() { // arrange - HttpServletRequest request = mock(HttpServletRequest.class); - HandlerMethod handlerMethod = mock(HandlerMethod.class); + WebRequest webRequest = mock(WebRequest.class); // act - ErrorResponseDto response = handler.handleOtherException(request, handlerMethod, new RuntimeException("Oops!")); + ResponseEntity response = handler.handleOtherException(new RuntimeException("Oops!"), webRequest); // assert assertNotNull(response); - assertEquals(CORRELATION_ID, response.getCorrelationId()); - assertEquals("Oops!", response.getMessage()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertNotNull(response.getBody()); + assertEquals(CORRELATION_ID, response.getBody().getCorrelationId()); + assertEquals("Oops!", response.getBody().getMessage()); } @Test void shouldHandleMissingRequestHeaderException() { // arrange - HttpServletRequest request = mock(HttpServletRequest.class); - HandlerMethod handlerMethod = mock(HandlerMethod.class); Method mockMethod = mock(Method.class); MethodParameter mockMethodParameter = new MethodParameter(mockMethod, -1, 2); + WebRequest webRequest = mock(WebRequest.class); // act - ErrorResponseDto response = handler.handleOtherException(request, handlerMethod, - new MissingRequestHeaderException("x-api-key", mockMethodParameter)); + ResponseEntity response = handler.handleOtherException(new MissingRequestHeaderException("x-api-key", mockMethodParameter), webRequest); // assert assertNotNull(response); - assertEquals(CORRELATION_ID, response.getCorrelationId()); - assertEquals("Required request header 'x-api-key' for method parameter type Object is not present", response.getMessage()); + assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); + assertNotNull(response.getBody()); + assertEquals(CORRELATION_ID, response.getBody().getCorrelationId()); + assertEquals("Required request header 'x-api-key' for method parameter type Object is not present", response.getBody().getMessage()); } } diff --git a/code/gms-backend/src/test/java/io/github/gms/abstraction/AbstractIntegrationTest.java b/code/gms-backend/src/test/java/io/github/gms/abstraction/AbstractIntegrationTest.java index d56b0777..9b94d477 100644 --- a/code/gms-backend/src/test/java/io/github/gms/abstraction/AbstractIntegrationTest.java +++ b/code/gms-backend/src/test/java/io/github/gms/abstraction/AbstractIntegrationTest.java @@ -1,7 +1,12 @@ package io.github.gms.abstraction; -import static io.github.gms.common.util.Constants.CONFIG_AUTH_TYPE_DB; - +import io.github.gms.auth.model.GmsUserDetails; +import io.github.gms.secure.repository.ApiKeyRepository; +import io.github.gms.secure.repository.KeystoreRepository; +import io.github.gms.secure.repository.SecretRepository; +import io.github.gms.secure.repository.UserRepository; +import io.github.gms.secure.service.JwtService; +import io.github.gms.util.TestUtils; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -13,13 +18,7 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.web.client.RestTemplate; -import io.github.gms.auth.model.GmsUserDetails; -import io.github.gms.secure.repository.ApiKeyRepository; -import io.github.gms.secure.repository.KeystoreRepository; -import io.github.gms.secure.repository.SecretRepository; -import io.github.gms.secure.repository.UserRepository; -import io.github.gms.secure.service.JwtService; -import io.github.gms.util.TestUtils; +import static io.github.gms.common.util.Constants.CONFIG_AUTH_TYPE_DB; /** * @author Peter Szrnka diff --git a/code/gms-backend/src/test/java/io/github/gms/api/controller/ApiIntegrationTest.java b/code/gms-backend/src/test/java/io/github/gms/api/controller/ApiIntegrationTest.java index 73cc4006..b8e7b8e0 100644 --- a/code/gms-backend/src/test/java/io/github/gms/api/controller/ApiIntegrationTest.java +++ b/code/gms-backend/src/test/java/io/github/gms/api/controller/ApiIntegrationTest.java @@ -4,6 +4,7 @@ import io.github.gms.secure.repository.KeystoreAliasRepository; import io.github.gms.util.DemoData; import io.github.gms.util.TestUtils; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; @@ -12,12 +13,14 @@ import java.util.Map; +import static io.github.gms.util.TestConstants.TAG_INTEGRATION_TEST; import static org.junit.jupiter.api.Assertions.assertEquals; /** * @author Peter Szrnka * @since 1.0 */ +@Tag(TAG_INTEGRATION_TEST) class ApiIntegrationTest extends AbstractIntegrationTest { @Autowired