From 1b97824c67ad51e52f9464edbdaed31100f99f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krystian=20Kie=C5=82basa?= Date: Mon, 18 Nov 2024 04:05:02 +0100 Subject: [PATCH] feat: #185 new tests --- .../security/JwtAuthorizationFilter.java | 11 +- .../configuration/JwtConfiguration.java | 5 + kodemy-auth/build.gradle | 7 +- .../configuration/SecurityConfiguration.java | 60 +---- .../configuration/WebConfiguration.java | 29 ++- .../module/auth/LogoutService.java | 4 +- .../module/auth/RefreshTokensService.java | 11 +- .../auth/handler/LogoutRequestHandler.java | 2 + .../auth/handler/LogoutSuccessHandler.java | 9 +- .../module/common/rest/UserDetails.java | 15 -- .../oauth2/OAuth2AuthenticationProvider.java | 18 -- .../OAuth2AuthorizationRequestRepository.java | 21 +- .../oauth2/OAuth2BeanConfiguration.java | 32 --- .../module/oauth2/OAuth2ProviderService.java | 13 +- .../module/oauth2/OAuth2Service.java | 31 +-- .../configuration/OAuth2ModuleConfig.java | 34 --- .../handler/OAuth2LoginFailureHandler.java | 15 ++ .../handler/OAuth2LoginSuccessHandler.java | 22 +- .../oauth2/provider/OAuth2Provider.java | 41 +--- .../oauth2/provider/OAuth2ProviderResult.java | 22 ++ .../provider/OAuth2ProviderSuperclass.java | 29 +++ .../module/oauth2/provider/OAuth2Stage.java | 35 --- .../provider/github/GithubOAuth2Provider.java | 74 +++--- .../github/GithubOAuth2ProviderResult.java | 36 +++ .../provider/github/GithubOAuth2Stage.java | 47 ---- ...perations.java => OAuth2RestTemplate.java} | 19 +- .../module/user/ChangeUserRoleService.java | 6 +- .../module/user/UserService.java | 14 +- .../module/user/UsersBriefService.java | 6 +- .../infrastructure/store/AuthRedisStore.java | 36 +++ .../RefreshTokenStore.java} | 6 +- .../RoleDao.java => store/RoleStore.java} | 4 +- .../UserDao.java => store/UserStore.java} | 14 +- .../java/pl/sknikod/kodemyauth/BaseTest.java | 41 ---- .../java/pl/sknikod/kodemyauth/MvcTest.java | 24 -- .../pl/sknikod/kodemyauth/SuperclassTest.java | 36 +++ .../sknikod/kodemyauth/WithUserPrincipal.java | 17 -- ...ithUserPrincipalTestExecutionListener.java | 52 ---- .../configuration/TestSecurityConfig.java | 51 ---- .../configuration/TestWebConfig.java | 20 -- .../exception/RestExceptionHandlerTest.java | 161 ------------- .../kodemyauth/factory/OAuth2Factory.java | 21 -- .../kodemyauth/factory/ProviderFactory.java | 16 -- .../kodemyauth/factory/RoleFactory.java | 18 -- .../kodemyauth/factory/TokenFactory.java | 45 ---- .../kodemyauth/factory/UserFactory.java | 33 --- .../database/handler/RefreshTokenDaoTest.java | 127 ---------- .../database/handler/RoleDaoTest.java | 54 ----- .../database/handler/UserDaoTest.java | 223 ------------------ .../module/RefreshTokensServiceTest.java | 63 ----- .../oauth2/OAuth2ProviderServiceTest.java | 6 - .../OAuth2LoginFailureHandlerTest.java | 70 ------ .../src/test/resources/application-test.yml | 7 + .../src/test/resources/application.yml | 5 - kodemy-backend/build.gradle | 7 +- .../configuration/RabbitConfiguration.java | 68 ------ .../configuration/SecurityConfiguration.java | 13 +- .../configuration/WebConfiguration.java | 26 +- .../rabbit/RabbitDlqErrorSwitch.java | 86 +++++++ .../infrastructure/mapper/GradeMapper.java | 5 +- .../infrastructure/model/UserDetails.java | 15 -- .../module/grade/GradeService.java | 5 +- .../material/MaterialStatusService.java | 4 +- .../material}/model/MaterialStatusUtil.java | 2 +- .../model/SingleMaterialResponse.java | 10 +- .../src/main/resources/application.yml | 9 +- .../kodemybackend/MvcSuperclassTest.java | 17 ++ .../sknikod/kodemybackend/SuperclassTest.java | 69 ++++++ .../producer/MaterialCreatedProducerTest.java | 40 ++++ .../category/CategoryControllerTest.java | 17 ++ .../module/category/CategoryServiceTest.java | 38 +++ .../store/CategoryStoreTest.java | 36 +++ .../store/MaterialStoreTest.java | 97 ++++++++ .../src/test/resources/application-test.yml | 7 + .../src/test/resources/application.yml | 5 - kodemy-search/build.gradle | 4 + .../configuration/RabbitConfiguration.java | 68 ------ .../configuration/SecurityConfiguration.java | 13 +- .../configuration/WebConfiguration.java | 21 ++ .../rabbit/RabbitDlqErrorSwitch.java | 86 +++++++ .../consumer/MaterialCreatedConsumer.java | 2 +- .../MaterialStatusUpdatedConsumer.java | 2 +- .../consumer/MaterialTagsUpdatedConsumer.java | 2 +- .../consumer/MaterialUpdatedConsumer.java | 2 +- .../module/ModuleBeanConfiguration.java | 18 -- .../material/MaterialAddUpdateService.java | 12 +- .../material/MaterialSearchService.java | 8 +- .../material/MaterialUpdateStatusService.java | 12 +- .../MaterialSearchStore.java} | 6 +- .../data/{SearchDao.java => SearchStore.java} | 2 +- .../pl/sknikod/kodemysearch/BaseTest.java | 21 -- .../java/pl/sknikod/kodemysearch/MvcTest.java | 25 -- .../sknikod/kodemysearch/SuperclassTest.java | 19 ++ .../kodemysearch/WithUserPrincipal.java | 17 -- ...ithUserPrincipalTestExecutionListener.java | 52 ---- .../configuration/TestOpenSearchConfig.java | 14 -- .../configuration/TestSecurityConfig.java | 27 --- .../kodemysearch/factory/TokenFactory.java | 32 --- .../module/TestModuleConfig.java | 20 -- .../src/test/resources/application-test.yml | 5 + .../src/test/resources/application.yml | 3 - 101 files changed, 966 insertions(+), 1921 deletions(-) delete mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/common/rest/UserDetails.java delete mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2AuthenticationProvider.java delete mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2BeanConfiguration.java delete mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/configuration/OAuth2ModuleConfig.java create mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2ProviderResult.java create mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2ProviderSuperclass.java delete mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2Stage.java create mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2ProviderResult.java delete mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2Stage.java rename kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/util/{OAuth2RestOperations.java => OAuth2RestTemplate.java} (75%) create mode 100644 kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/AuthRedisStore.java rename kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/{dao/RefreshTokenDao.java => store/RefreshTokenStore.java} (97%) rename kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/{dao/RoleDao.java => store/RoleStore.java} (92%) rename kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/{dao/UserDao.java => store/UserStore.java} (92%) delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/BaseTest.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/MvcTest.java create mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/SuperclassTest.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/WithUserPrincipal.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/WithUserPrincipalTestExecutionListener.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/configuration/TestSecurityConfig.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/configuration/TestWebConfig.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/exception/RestExceptionHandlerTest.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/OAuth2Factory.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/ProviderFactory.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/RoleFactory.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/TokenFactory.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/UserFactory.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/RefreshTokenDaoTest.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/RoleDaoTest.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/UserDaoTest.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/RefreshTokensServiceTest.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2ProviderServiceTest.java delete mode 100644 kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginFailureHandlerTest.java create mode 100644 kodemy-auth/src/test/resources/application-test.yml delete mode 100644 kodemy-auth/src/test/resources/application.yml create mode 100644 kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/rabbit/RabbitDlqErrorSwitch.java delete mode 100644 kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/model/UserDetails.java rename kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/{ => module/material}/model/MaterialStatusUtil.java (98%) create mode 100644 kodemy-backend/src/test/java/pl/sknikod/kodemybackend/MvcSuperclassTest.java create mode 100644 kodemy-backend/src/test/java/pl/sknikod/kodemybackend/SuperclassTest.java create mode 100644 kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/event/producer/MaterialCreatedProducerTest.java create mode 100644 kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/module/category/CategoryControllerTest.java create mode 100644 kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/module/category/CategoryServiceTest.java create mode 100644 kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/store/CategoryStoreTest.java create mode 100644 kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/store/MaterialStoreTest.java create mode 100644 kodemy-backend/src/test/resources/application-test.yml delete mode 100644 kodemy-backend/src/test/resources/application.yml create mode 100644 kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/rabbit/RabbitDlqErrorSwitch.java rename kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/{module/material => event}/consumer/MaterialCreatedConsumer.java (90%) rename kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/{module/material => event}/consumer/MaterialStatusUpdatedConsumer.java (90%) rename kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/{module/material => event}/consumer/MaterialTagsUpdatedConsumer.java (85%) rename kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/{module/material => event}/consumer/MaterialUpdatedConsumer.java (90%) rename kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/{dao/MaterialSearchDao.java => store/MaterialSearchStore.java} (95%) rename kodemy-search/src/main/java/pl/sknikod/kodemysearch/util/data/{SearchDao.java => SearchStore.java} (84%) delete mode 100644 kodemy-search/src/test/java/pl/sknikod/kodemysearch/BaseTest.java delete mode 100644 kodemy-search/src/test/java/pl/sknikod/kodemysearch/MvcTest.java create mode 100644 kodemy-search/src/test/java/pl/sknikod/kodemysearch/SuperclassTest.java delete mode 100644 kodemy-search/src/test/java/pl/sknikod/kodemysearch/WithUserPrincipal.java delete mode 100644 kodemy-search/src/test/java/pl/sknikod/kodemysearch/WithUserPrincipalTestExecutionListener.java delete mode 100644 kodemy-search/src/test/java/pl/sknikod/kodemysearch/configuration/TestOpenSearchConfig.java delete mode 100644 kodemy-search/src/test/java/pl/sknikod/kodemysearch/configuration/TestSecurityConfig.java delete mode 100644 kodemy-search/src/test/java/pl/sknikod/kodemysearch/factory/TokenFactory.java delete mode 100644 kodemy-search/src/test/java/pl/sknikod/kodemysearch/infrastructure/module/TestModuleConfig.java create mode 100644 kodemy-search/src/test/resources/application-test.yml delete mode 100644 kodemy-search/src/test/resources/application.yml diff --git a/commons/src/main/java/pl/sknikod/kodemycommons/security/JwtAuthorizationFilter.java b/commons/src/main/java/pl/sknikod/kodemycommons/security/JwtAuthorizationFilter.java index bc4acb6a..7747fc5a 100644 --- a/commons/src/main/java/pl/sknikod/kodemycommons/security/JwtAuthorizationFilter.java +++ b/commons/src/main/java/pl/sknikod/kodemycommons/security/JwtAuthorizationFilter.java @@ -7,11 +7,14 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.NonNull; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import pl.sknikod.kodemycommons.security.configuration.JwtConfiguration; @@ -26,14 +29,14 @@ public class JwtAuthorizationFilter extends OncePerRequestFilter { public JwtAuthorizationFilter( List permitPaths, - JwtConfiguration.JwtProperties jwtProperties + JwtProvider jwtProvider ) { this.notFilterMatchers = permitPaths.stream().map(AntPathRequestMatcher::new).toList(); - this.jwtProvider = new JwtProvider(jwtProperties); + this.jwtProvider = jwtProvider; } - public JwtAuthorizationFilter(JwtConfiguration.JwtProperties jwtProperties) { - this(Collections.emptyList(), jwtProperties); + public JwtAuthorizationFilter(JwtProvider jwtProvider) { + this(Collections.emptyList(), jwtProvider); } @Override diff --git a/commons/src/main/java/pl/sknikod/kodemycommons/security/configuration/JwtConfiguration.java b/commons/src/main/java/pl/sknikod/kodemycommons/security/configuration/JwtConfiguration.java index 337ca541..7c0993cb 100644 --- a/commons/src/main/java/pl/sknikod/kodemycommons/security/configuration/JwtConfiguration.java +++ b/commons/src/main/java/pl/sknikod/kodemycommons/security/configuration/JwtConfiguration.java @@ -2,13 +2,18 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Configuration +@Getter +@RequiredArgsConstructor public class JwtConfiguration { + private final JwtProperties jwtProperties; + @Getter @Setter @Component diff --git a/kodemy-auth/build.gradle b/kodemy-auth/build.gradle index 53fb7945..a31aa55f 100644 --- a/kodemy-auth/build.gradle +++ b/kodemy-auth/build.gradle @@ -66,13 +66,16 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' - testImplementation 'org.testcontainers:junit-jupiter:1.19.8' + testImplementation 'org.springframework.cloud:spring-cloud-contract-wiremock' + testImplementation 'org.springframework.cloud:spring-cloud-stream' + testImplementation 'org.springframework.cloud:spring-cloud-stream-test-binder' + testImplementation 'org.testcontainers:junit-jupiter:1.20.0' constraints { testImplementation('org.apache.commons:commons-compress:1.26.2') { because '<1.25.x vulnerability' } } - testImplementation 'org.testcontainers:postgresql:1.19.8' + testImplementation 'org.testcontainers:postgresql:1.20.0' testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/configuration/SecurityConfiguration.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/configuration/SecurityConfiguration.java index 4b69d479..36684975 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/configuration/SecurityConfiguration.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/configuration/SecurityConfiguration.java @@ -21,7 +21,7 @@ import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.stereotype.Component; -import pl.sknikod.kodemyauth.infrastructure.dao.RefreshTokenDao; +import pl.sknikod.kodemyauth.infrastructure.store.RefreshTokenStore; import pl.sknikod.kodemyauth.infrastructure.module.auth.LogoutService; import pl.sknikod.kodemyauth.infrastructure.module.auth.handler.LogoutRequestHandler; import pl.sknikod.kodemyauth.infrastructure.module.auth.handler.LogoutSuccessHandler; @@ -97,71 +97,21 @@ public ServletExceptionHandler servletExceptionHandler(ObjectMapper objectMapper return new ServletExceptionHandler(objectMapper); } - @Bean - public JwtConfiguration.JwtProperties jwtProperties() { - return new JwtConfiguration.JwtProperties(); - } - @Bean public JwtAuthorizationFilter jwtAuthorizationFilter( OAuth2EndpointsProperties oAuth2EndpointsProperties, - JwtConfiguration.JwtProperties jwtProperties + JwtProvider jwtProvider ) { final var permitPaths = List.of( oAuth2EndpointsProperties.authorize + OAuth2Constant.OAUTH2_PROVIDER_SUFFIX, oAuth2EndpointsProperties.callback + OAuth2Constant.OAUTH2_PROVIDER_SUFFIX ); - return new JwtAuthorizationFilter(permitPaths, jwtProperties); - } - - @Bean - public OAuth2AuthorizationRequestRepository oAuth2AuthorizeRequestResolver( - StringRedisTemplate stringRedisTemplate - ) { - return new OAuth2AuthorizationRequestRepository(stringRedisTemplate); - } - - @Bean - public JwtProvider jwtProvider(JwtConfiguration.JwtProperties jwtProperties) { - return new JwtProvider(jwtProperties); - } - - @Bean - public OAuth2LoginSuccessHandler oAuth2SuccessProcessHandler( - JwtProvider jwtProvider, - @Value("${app.security.oauth2.route.front}") String frontRoute, - @Value("${app.security.oauth2.endpoints.redirect}") String redirectEndpoint, - RefreshTokenDao refreshTokenRepositoryHandler, - RouteRedirectStrategy routeRedirectStrategy - ) { - var redirectPath = (frontRoute.equals("/") ? null : frontRoute) + redirectEndpoint; - final var handler = new OAuth2LoginSuccessHandler(jwtProvider, redirectPath, refreshTokenRepositoryHandler); - handler.setRedirectStrategy(routeRedirectStrategy); - return handler; - } - - @Bean - public OAuth2LoginFailureHandler oAuth2FailureProcessHandler( - RouteRedirectStrategy routeRedirectStrategy, - @Value("${app.security.oauth2.route.front}") String frontRoute, - @Value("${app.security.oauth2.endpoints.redirect}") String redirectEndpoint - ) { - var redirectPath = (frontRoute.equals("/") ? null : frontRoute) + redirectEndpoint; - final var handler = new OAuth2LoginFailureHandler(redirectPath); - handler.setRedirectStrategy(routeRedirectStrategy); - return handler; - } - - @Bean - public LogoutRequestHandler logoutRequestHandler( - LogoutService logoutService, JwtProvider jwtProvider) { - return new LogoutRequestHandler(logoutService, jwtProvider); + return new JwtAuthorizationFilter(permitPaths, jwtProvider); } @Bean - public LogoutSuccessHandler logoutSuccessHandler( - @Value("${network.route.gateway}") String gatewayRoute) { - return new LogoutSuccessHandler(gatewayRoute); + public JwtProvider jwtProvider(JwtConfiguration jwtConfiguration) { + return new JwtProvider(jwtConfiguration.getJwtProperties()); } @Getter diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/configuration/WebConfiguration.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/configuration/WebConfiguration.java index 7158bca8..fdd0b109 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/configuration/WebConfiguration.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/configuration/WebConfiguration.java @@ -4,29 +4,34 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; +import org.zalando.logbook.spring.LogbookClientHttpRequestInterceptor; +import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2RestTemplate; + +import java.util.Collections; @Configuration @Slf4j public class WebConfiguration { - @Getter - @Setter - @Component - @NoArgsConstructor - @ConfigurationProperties(prefix = "network.databus") - public static class LanNetworkProperties { - private int connectTimeoutMs; - private int readTimeoutMs; - } - @Bean @LoadBalanced - public RestTemplate restTemplate() { - return new RestTemplate(); + public RestTemplate restTemplate( + RestTemplateBuilder restTemplateBuilder, LogbookClientHttpRequestInterceptor logbookInterceptor + ) { + restTemplateBuilder.requestFactory(() -> { + var requestFactory = new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build()); + return new BufferingClientHttpRequestFactory(requestFactory); + }); + restTemplateBuilder.additionalInterceptors(Collections.singletonList(logbookInterceptor)); + return restTemplateBuilder.build(); } } diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/LogoutService.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/LogoutService.java index 5f3904d0..a6fc0090 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/LogoutService.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/LogoutService.java @@ -3,7 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import pl.sknikod.kodemyauth.infrastructure.dao.RefreshTokenDao; +import pl.sknikod.kodemyauth.infrastructure.store.RefreshTokenStore; import pl.sknikod.kodemycommons.exception.InternalError500Exception; import pl.sknikod.kodemycommons.security.UserPrincipal; @@ -13,7 +13,7 @@ @Component @RequiredArgsConstructor public class LogoutService { - private final RefreshTokenDao refreshTokenRepositoryHandler; + private final RefreshTokenStore refreshTokenRepositoryHandler; public Boolean logout(UserPrincipal userPrincipal, UUID bearerJti) { return refreshTokenRepositoryHandler.invalidateByUserIdAnfBearerJti(userPrincipal.getId(), bearerJti) diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/RefreshTokensService.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/RefreshTokensService.java index 7e0dc1d3..0d77739d 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/RefreshTokensService.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/RefreshTokensService.java @@ -8,12 +8,12 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Component; import pl.sknikod.kodemyauth.configuration.SecurityConfiguration; -import pl.sknikod.kodemyauth.infrastructure.dao.RefreshTokenDao; import pl.sknikod.kodemyauth.infrastructure.database.RefreshToken; import pl.sknikod.kodemyauth.infrastructure.database.Role; import pl.sknikod.kodemyauth.infrastructure.database.RoleRepository; import pl.sknikod.kodemyauth.infrastructure.database.User; import pl.sknikod.kodemyauth.infrastructure.module.auth.model.RefreshTokensResponse; +import pl.sknikod.kodemyauth.infrastructure.store.RefreshTokenStore; import pl.sknikod.kodemycommons.exception.InternalError500Exception; import pl.sknikod.kodemycommons.security.JwtProvider; @@ -26,12 +26,11 @@ @RequiredArgsConstructor public class RefreshTokensService { private final RoleRepository roleRepository; - private final RefreshTokenDao refreshTokenDao; + private final RefreshTokenStore refreshTokenStore; private final JwtProvider jwtProvider; - private final SecurityConfiguration.RoleProperties roleProperties; public RefreshTokensResponse refresh(UUID refresh, UUID bearerJti) { - return refreshTokenDao.findByTokenAndBearerJti(refresh, bearerJti) + return refreshTokenStore.findByTokenAndBearerJti(refresh, bearerJti) .flatMapTry(this::generateTokensAndInvalidate) .map(tokens -> new RefreshTokensResponse( tokens._2.getToken().toString(), tokens._1.value())) @@ -40,11 +39,11 @@ public RefreshTokensResponse refresh(UUID refresh, UUID bearerJti) { private Try> generateTokensAndInvalidate(RefreshToken refreshToken) { return Try.of(() -> jwtProvider.generateUserToken(map(refreshToken.getUser()))) - .flatMapTry(bearerToken -> refreshTokenDao + .flatMapTry(bearerToken -> refreshTokenStore .createAndGet(refreshToken.getUser(), bearerToken.id()) .map(newRefreshToken -> Tuple.of(bearerToken, newRefreshToken)) .onFailure(th -> log.error("Error during tokens generation", th))) - .peek(unused -> refreshTokenDao.invalidate(refreshToken)); + .peek(unused -> refreshTokenStore.invalidate(refreshToken)); } private JwtProvider.Input map(User user) { diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/handler/LogoutRequestHandler.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/handler/LogoutRequestHandler.java index e3a70f51..53c89997 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/handler/LogoutRequestHandler.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/handler/LogoutRequestHandler.java @@ -9,6 +9,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutHandler; +import org.springframework.stereotype.Component; import pl.sknikod.kodemyauth.infrastructure.module.auth.LogoutService; import pl.sknikod.kodemycommons.exception.InternalError500Exception; import pl.sknikod.kodemycommons.security.AuthFacade; @@ -16,6 +17,7 @@ import java.util.UUID; +@Component @Slf4j @RequiredArgsConstructor public class LogoutRequestHandler implements LogoutHandler { diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/handler/LogoutSuccessHandler.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/handler/LogoutSuccessHandler.java index fb95af97..3b9de553 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/handler/LogoutSuccessHandler.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/auth/handler/LogoutSuccessHandler.java @@ -3,16 +3,21 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.Null; -import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; +import org.springframework.stereotype.Component; import java.io.IOException; -@RequiredArgsConstructor +@Component public class LogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler { private final String gatewayRoute; + public LogoutSuccessHandler(@Value("${network.route.gateway}") String gatewayRoute) { + this.gatewayRoute = gatewayRoute; + } + @Override public void onLogoutSuccess( HttpServletRequest request, diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/common/rest/UserDetails.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/common/rest/UserDetails.java deleted file mode 100644 index cf30d057..00000000 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/common/rest/UserDetails.java +++ /dev/null @@ -1,15 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.module.common.rest; - -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.ToString; - -@Getter -@AllArgsConstructor -@ToString -@EqualsAndHashCode -public class UserDetails { - Long id; - String username; -} diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2AuthenticationProvider.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2AuthenticationProvider.java deleted file mode 100644 index c78b5cda..00000000 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2AuthenticationProvider.java +++ /dev/null @@ -1,18 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.module.oauth2; - -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; - -public class OAuth2AuthenticationProvider implements AuthenticationProvider { - @Override - public Authentication authenticate(Authentication authentication) throws AuthenticationException { - return authentication; - } - - @Override - public boolean supports(Class authentication) { - return (OAuth2AuthenticationToken.class.isAssignableFrom(authentication)); - } -} diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2AuthorizationRequestRepository.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2AuthorizationRequestRepository.java index 839e4df1..96f6a53d 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2AuthorizationRequestRepository.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2AuthorizationRequestRepository.java @@ -1,6 +1,5 @@ package pl.sknikod.kodemyauth.infrastructure.module.oauth2; -import io.vavr.control.Try; import jakarta.annotation.Nullable; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -9,23 +8,23 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.SerializationUtils; -import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository; import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.stereotype.Component; +import pl.sknikod.kodemyauth.infrastructure.store.AuthRedisStore; import java.io.Serializable; -import java.time.Duration; import java.util.Base64; @Slf4j +@Component @RequiredArgsConstructor public class OAuth2AuthorizationRequestRepository implements AuthorizationRequestRepository { private static final String AUTH_REQ_PREFIX = "oauth2_auth_request"; - private static final Duration SESSION_STORE_DURATION = Duration.ofMinutes(5); - private final StringRedisTemplate redisTemplate; + private final AuthRedisStore authRedisStore; private final HttpSessionOAuth2AuthorizationRequestRepository delegate = new HttpSessionOAuth2AuthorizationRequestRepository(); @@ -33,8 +32,7 @@ public class OAuth2AuthorizationRequestRepository implements @Override @Nullable public OAuth2AuthorizationRequest loadAuthorizationRequest(HttpServletRequest request) { - return Try.of(() -> redisTemplate.opsForValue().get(getRedisKey(getStateParam(request)))) - .onFailure(th -> log.error("Problem with getting {} redis key value", AUTH_REQ_PREFIX, th)) + return authRedisStore.findByKey(getRedisKey(getStateParam(request))) .mapTry(encodedReq -> (OAuth2AuthorizationRequest) Base64Coder.decode(encodedReq)) .getOrNull(); } @@ -57,11 +55,7 @@ public void saveAuthorizationRequest( } var state = authorizationRequest.getState(); if (state != null) { - Try.of(() -> { - var encodedReq = Base64Coder.encode(authorizationRequest); - redisTemplate.opsForValue().set(getRedisKey(state), encodedReq, SESSION_STORE_DURATION); - return true; - }).onFailure(th -> log.error("Problem with store {} redis key", AUTH_REQ_PREFIX, th)); + authRedisStore.save(getRedisKey(state), Base64Coder.encode(authorizationRequest)); } } @@ -70,8 +64,7 @@ public void saveAuthorizationRequest( public OAuth2AuthorizationRequest removeAuthorizationRequest(HttpServletRequest request, HttpServletResponse response) { OAuth2AuthorizationRequest authorizationRequest = loadAuthorizationRequest(request); if (authorizationRequest != null) { - Try.of(() -> redisTemplate.delete(getRedisKey(getStateParam(request)))) - .onFailure(th -> log.warn("Cannot delete redis {} key", AUTH_REQ_PREFIX, th)); + authRedisStore.delete(getRedisKey(getStateParam(request))); } return authorizationRequest; } diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2BeanConfiguration.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2BeanConfiguration.java deleted file mode 100644 index 079cf0d8..00000000 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2BeanConfiguration.java +++ /dev/null @@ -1,32 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.module.oauth2; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; -import pl.sknikod.kodemyauth.infrastructure.dao.UserDao; -import pl.sknikod.kodemyauth.infrastructure.database.RoleRepository; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Provider; - -import java.util.List; - -@Configuration -public class OAuth2BeanConfiguration { - @Bean - public OAuth2Service oAuth2Service( - RoleRepository roleRepository, - RestTemplate oAuth2RestTemplate, - List oAuth2Providers, - UserDao userDao - ) { - return new OAuth2Service(roleRepository, oAuth2RestTemplate, oAuth2Providers, userDao); - } - - @Bean - public OAuth2ProviderService oauth2ProviderService( - List oAuth2Providers, - @Value("${app.security.oauth2.endpoints.authorize}") String authorizeEndpoint - ) { - return new OAuth2ProviderService(oAuth2Providers, authorizeEndpoint); - } -} diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2ProviderService.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2ProviderService.java index 9f37ee53..03da10a6 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2ProviderService.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2ProviderService.java @@ -1,15 +1,24 @@ package pl.sknikod.kodemyauth.infrastructure.module.oauth2; -import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Provider; import java.util.List; -@RequiredArgsConstructor +@Service public class OAuth2ProviderService { private final List oAuth2Providers; private final String authorizeEndpoint; + public OAuth2ProviderService( + List oAuth2Providers, + @Value("${app.security.oauth2.endpoints.authorize}") String authorizeEndpoint + ) { + this.oAuth2Providers = oAuth2Providers; + this.authorizeEndpoint = authorizeEndpoint; + } + public List getProviders() { return oAuth2Providers .stream() diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2Service.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2Service.java index baecfd97..3a5dbf10 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2Service.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2Service.java @@ -10,57 +10,58 @@ import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.web.client.RestTemplate; -import pl.sknikod.kodemyauth.infrastructure.dao.UserDao; +import org.springframework.stereotype.Service; import pl.sknikod.kodemyauth.infrastructure.database.Permission; import pl.sknikod.kodemyauth.infrastructure.database.Role; import pl.sknikod.kodemyauth.infrastructure.database.RoleRepository; import pl.sknikod.kodemyauth.infrastructure.database.User; import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Provider; +import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderResult; import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2UserPrincipal; +import pl.sknikod.kodemyauth.infrastructure.store.UserStore; import java.util.*; @Slf4j +@Service @RequiredArgsConstructor public class OAuth2Service implements OAuth2UserService { private final RoleRepository roleRepository; - private final RestTemplate oAuth2RestTemplate; private final List oAuth2Providers; - private final UserDao userDao; + private final UserStore userStore; @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { - return retrieveProviderUser(userRequest, oAuth2Providers.iterator()) + return retrieveUser(userRequest, oAuth2Providers.iterator()) .map(this::createOrLoadUser) .map(this::toUserPrincipal) .orElse(null); } - private Optional retrieveProviderUser(OAuth2UserRequest userRequest, Iterator iterator) { + private Optional retrieveUser(OAuth2UserRequest userRequest, Iterator iterator) { if (!iterator.hasNext()) { - log.info("No OAuth2Provider found for registration ID: {}", userRequest.getClientRegistration().getRegistrationId()); + log.info("No processable provider for registration ID: {}", userRequest.getClientRegistration().getRegistrationId()); return Optional.empty(); } OAuth2Provider provider = iterator.next(); - if (provider.supports(userRequest.getClientRegistration().getRegistrationId())) { + if (provider.isApply(userRequest.getClientRegistration().getRegistrationId())) { log.info("Process {} provider class", provider.getClass().getSimpleName()); - return Optional.of(provider.retrieveUser(oAuth2RestTemplate, userRequest)); + return Optional.of(provider.retrieve(userRequest)); } - return retrieveProviderUser(userRequest, iterator); // check another one + return retrieveUser(userRequest, iterator); // check another one } - private Tuple2 createOrLoadUser(OAuth2Provider.User providerUser) { - return userDao.findByProviderUser(providerUser) + private Tuple2 createOrLoadUser(OAuth2ProviderResult providerUser) { + return userStore.findByProviderUser(providerUser) .fold(unused -> Tuple.of(this.createNewUser(providerUser), providerUser), user -> Tuple.of(user, providerUser)); } - private User createNewUser(OAuth2Provider.User providerUser) { - return userDao.save(providerUser) + private User createNewUser(OAuth2ProviderResult providerUser) { + return userStore.save(providerUser) .orElse(null); } - private OAuth2UserPrincipal toUserPrincipal(Tuple2 userTuple2) { + private OAuth2UserPrincipal toUserPrincipal(Tuple2 userTuple2) { return Try.of(() -> roleRepository.findById(userTuple2._1.getRole().getId())) .filter(Optional::isPresent) .map(Optional::get) diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/configuration/OAuth2ModuleConfig.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/configuration/OAuth2ModuleConfig.java deleted file mode 100644 index 74293c35..00000000 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/configuration/OAuth2ModuleConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.module.oauth2.configuration; - -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.BufferingClientHttpRequestFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.web.client.RestTemplate; -import org.zalando.logbook.spring.LogbookClientHttpRequestInterceptor; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2RestOperations; - -import java.util.Collections; - -@Configuration -public class OAuth2ModuleConfig { - @Bean - public RestTemplate oAuth2RestTemplate( - RestTemplateBuilder restTemplateBuilder, - LogbookClientHttpRequestInterceptor logbookInterceptor - ) { - restTemplateBuilder.requestFactory(() -> { - var requestFactory = new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build()); - return new BufferingClientHttpRequestFactory(requestFactory); - }); - restTemplateBuilder.additionalInterceptors(Collections.singletonList(logbookInterceptor)); - return restTemplateBuilder.build(); - } - - @Bean - public OAuth2RestOperations oAuth2RestOperations(RestTemplate oAuth2RestTemplate) { - return new OAuth2RestOperations(oAuth2RestTemplate); - } -} diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginFailureHandler.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginFailureHandler.java index 7c44c38f..416694dd 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginFailureHandler.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginFailureHandler.java @@ -5,18 +5,33 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import org.springframework.stereotype.Component; import pl.sknikod.kodemyauth.util.route.RouteRedirectStrategy; import java.util.Map; @Slf4j +@Component @RequiredArgsConstructor public class OAuth2LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler { private final String redirectPath; private static final Map GENERAL_ERROR_PARAMS = Map.of("error", "authentication_error"); + @Autowired + public OAuth2LoginFailureHandler( + RouteRedirectStrategy routeRedirectStrategy, + @Value("${app.security.oauth2.route.front}") String frontRoute, + @Value("${app.security.oauth2.endpoints.redirect}") String redirectEndpoint + ) { + this((frontRoute.equals("/") ? null : frontRoute) + redirectEndpoint); + this.setRedirectStrategy(routeRedirectStrategy); + } + @Override public void onAuthenticationFailure( HttpServletRequest request, HttpServletResponse response, AuthenticationException exception diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginSuccessHandler.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginSuccessHandler.java index 83244ea0..85a60e28 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginSuccessHandler.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginSuccessHandler.java @@ -7,10 +7,13 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; -import pl.sknikod.kodemyauth.infrastructure.dao.RefreshTokenDao; +import org.springframework.stereotype.Component; import pl.sknikod.kodemyauth.infrastructure.database.RefreshToken; +import pl.sknikod.kodemyauth.infrastructure.store.RefreshTokenStore; import pl.sknikod.kodemyauth.util.route.RouteRedirectStrategy; import pl.sknikod.kodemycommons.exception.InternalError500Exception; import pl.sknikod.kodemycommons.security.AuthFacade; @@ -20,11 +23,24 @@ import java.util.Map; @Slf4j +@Component @RequiredArgsConstructor public class OAuth2LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private final JwtProvider jwtProvider; private final String redirectPath; - private final RefreshTokenDao refreshTokenRepositoryHandler; + private final RefreshTokenStore refreshTokenStore; + + @Autowired + public OAuth2LoginSuccessHandler( + JwtProvider jwtProvider, + @Value("${app.security.oauth2.route.front}") String frontRoute, + @Value("${app.security.oauth2.endpoints.redirect}") String redirectEndpoint, + RefreshTokenStore refreshTokenStore, + RouteRedirectStrategy routeRedirectStrategy + ) { + this(jwtProvider, (frontRoute.equals("/") ? null : frontRoute) + redirectEndpoint, refreshTokenStore); + this.setRedirectStrategy(routeRedirectStrategy); + } @Override public void onAuthenticationSuccess( @@ -49,7 +65,7 @@ private Try> postProcess(Authentication private Try> generateTokens(UserPrincipal userPrincipal) { return Try.of(() -> jwtProvider.generateUserToken(map(userPrincipal))) - .flatMapTry(bearerToken -> refreshTokenRepositoryHandler + .flatMapTry(bearerToken -> refreshTokenStore .createAndGet(userPrincipal.getId(), bearerToken.id()) .map(refreshToken -> Tuple.of(bearerToken, refreshToken))) .onFailure(th -> log.error("Error during tokens generation", th)); diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2Provider.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2Provider.java index 9551d5af..69364087 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2Provider.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2Provider.java @@ -1,42 +1,9 @@ package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; -import org.springframework.web.client.RestTemplate; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.github.GithubOAuth2Provider; -import java.util.Map; - -@RequiredArgsConstructor -public abstract class OAuth2Provider { - protected final Stage oAuth2Stage; - - public abstract String getRegistrationId(); - - public abstract boolean supports(String registrationId); - - public abstract GithubOAuth2Provider.GithubUser retrieveUser(RestTemplate oAuth2RestTemplate, OAuth2UserRequest userRequest); - - @Getter - @AllArgsConstructor - public static abstract class User { - protected final Map attributes; - - public abstract String getProvider(); - - public abstract String getPrincipalId(); - - public abstract String getUsername(); - - public abstract String getEmail(); - - public abstract String getPhoto(); - } - - public interface Stage { - Map retrieveAttributes(@NonNull OAuth2UserRequest userRequest); - } +public interface OAuth2Provider { + String getRegistrationId(); + boolean isApply(String registrationId); + OAuth2ProviderResult retrieve(OAuth2UserRequest userRequest); } diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2ProviderResult.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2ProviderResult.java new file mode 100644 index 00000000..149f81ae --- /dev/null +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2ProviderResult.java @@ -0,0 +1,22 @@ +package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Map; + +@Getter +@AllArgsConstructor +public abstract class OAuth2ProviderResult { + protected final Map attributes; + + public abstract String getRegistrationId(); + + public abstract String getPrincipalId(); + + public abstract String getUsername(); + + public abstract String getEmail(); + + public abstract String getPhoto(); +} \ No newline at end of file diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2ProviderSuperclass.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2ProviderSuperclass.java new file mode 100644 index 00000000..7948f031 --- /dev/null +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2ProviderSuperclass.java @@ -0,0 +1,29 @@ +package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider; + +import io.vavr.control.Try; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +@RequiredArgsConstructor +@Slf4j +public abstract class OAuth2ProviderSuperclass { + protected final OAuth2RestTemplate oAuth2RestTemplate; + private final Map attributes = new HashMap<>(); + private boolean isInitialized = false; + + protected Map getAttributes(@NonNull OAuth2UserRequest userRequest) { + if (!isInitialized) { + Try.of(() -> this.oAuth2RestTemplate.exchange(userRequest).getBody()) + .onSuccess(attrs -> log.info("Successfully retrieved {} user attributes", attrs.size())) + .peek(this.attributes::putAll); + this.isInitialized = true; + } + return attributes; + } +} diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2Stage.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2Stage.java deleted file mode 100644 index fa56aca3..00000000 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/OAuth2Stage.java +++ /dev/null @@ -1,35 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider; - -import io.vavr.control.Try; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2RestOperations; - -import java.util.HashMap; -import java.util.Map; - -@Slf4j -@RequiredArgsConstructor -public abstract class OAuth2Stage implements OAuth2Provider.Stage { - protected final OAuth2RestOperations oAuth2RestOperations; - protected final Map attributes = new HashMap<>(); - - public final Map retrieveAttributes(@NonNull OAuth2UserRequest userRequest) { - attributes.clear(); - processBaseAttributes(userRequest); - addSubProcesses(userRequest); - return attributes; - } - - private void processBaseAttributes(@NonNull OAuth2UserRequest userRequest) { - Try.of(() -> this.oAuth2RestOperations.exchange(userRequest).getBody()) - .onSuccess(attrs -> log.info("Successfully retrieved {} user attributes", attrs.size())) - .peek(this.attributes::putAll); - } - - protected void addSubProcesses(@NonNull OAuth2UserRequest userRequest) { - // placeholder to children - } -} \ No newline at end of file diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2Provider.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2Provider.java index 22fc639e..8523fda5 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2Provider.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2Provider.java @@ -1,18 +1,27 @@ package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.github; +import io.vavr.control.Try; +import lombok.Data; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Provider; +import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderResult; +import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderSuperclass; +import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2RestTemplate; +import java.util.List; import java.util.Map; @Component -public class GithubOAuth2Provider extends OAuth2Provider { +@Slf4j +public class GithubOAuth2Provider extends OAuth2ProviderSuperclass implements OAuth2Provider { private static final String REGISTRATION_ID = "github"; - public GithubOAuth2Provider(GithubOAuth2Stage githubOAuth2Stage) { - super(githubOAuth2Stage); + public GithubOAuth2Provider(OAuth2RestTemplate oAuth2RestTemplate) { + super(oAuth2RestTemplate); } @Override @@ -21,44 +30,37 @@ public String getRegistrationId() { } @Override - public boolean supports(String registrationId) { - return REGISTRATION_ID.equals(registrationId); + public boolean isApply(String registrationId) { + return getRegistrationId().equals(registrationId); } @Override - public GithubUser retrieveUser(RestTemplate oAuth2RestTemplate, OAuth2UserRequest userRequest) { - Map attributes = oAuth2Stage.retrieveAttributes(userRequest); - return new GithubUser(attributes); + public OAuth2ProviderResult retrieve(OAuth2UserRequest userRequest) { + Map attributes = super.getAttributes(userRequest); + attributes.put("registrationId", REGISTRATION_ID); + fixEmailNull(attributes, userRequest); + return new GithubOAuth2ProviderResult(attributes); } - public static class GithubUser extends User { - public GithubUser(Map attributes) { - super(attributes); - } + private void fixEmailNull(Map attributes, OAuth2UserRequest userRequest) { + final var userInfoUri = userRequest + .getClientRegistration() + .getProviderDetails() + .getUserInfoEndpoint() + .getUri(); - @Override - public String getProvider() { - return REGISTRATION_ID; - } - - @Override - public String getPrincipalId() { - return attributes.get("id").toString(); - } - - @Override - public String getUsername() { - return attributes.get("login").toString(); - } - - @Override - public String getEmail() { - return attributes.get("email").toString(); - } + final var typeReference = new ParameterizedTypeReference>() { + }; + Try.of(() -> this.oAuth2RestTemplate.exchange(userInfoUri + "/emails", typeReference, userRequest).getBody()) + .onSuccess(unused -> log.info("Successfully retrieved emails")) + .map(emails -> emails.stream().filter(e -> e.primary).findFirst().orElse(null)) + .peek(e -> attributes.put("email", e.email)); + } - @Override - public String getPhoto() { - return attributes.get("avatar_url").toString(); - } + @Data + private static class Email { + private String email; + private boolean primary; + private boolean verified; } } diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2ProviderResult.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2ProviderResult.java new file mode 100644 index 00000000..b7315497 --- /dev/null +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2ProviderResult.java @@ -0,0 +1,36 @@ +package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.github; + +import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderResult; + +import java.util.Map; + +public class GithubOAuth2ProviderResult extends OAuth2ProviderResult { + public GithubOAuth2ProviderResult(Map attributes) { + super(attributes); + } + + @Override + public String getRegistrationId() { + return attributes.get("registration_id").toString(); + } + + @Override + public String getPrincipalId() { + return attributes.get("id").toString(); + } + + @Override + public String getUsername() { + return attributes.get("login").toString(); + } + + @Override + public String getEmail() { + return attributes.get("email").toString(); + } + + @Override + public String getPhoto() { + return attributes.get("avatar_url").toString(); + } +} diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2Stage.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2Stage.java deleted file mode 100644 index 33c9c975..00000000 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/provider/github/GithubOAuth2Stage.java +++ /dev/null @@ -1,47 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.github; - -import io.vavr.control.Try; -import lombok.Data; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; -import org.springframework.stereotype.Component; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Stage; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.util.OAuth2RestOperations; - -import java.util.List; - -@Slf4j -@Component -public class GithubOAuth2Stage extends OAuth2Stage { - public GithubOAuth2Stage(OAuth2RestOperations oAuth2RestOperations) { - super(oAuth2RestOperations); - } - - @Override - protected void addSubProcesses(@NonNull OAuth2UserRequest userRequest) { - processFixEmailNull(userRequest); - } - - private void processFixEmailNull(OAuth2UserRequest userRequest) { - final var userInfoUri = userRequest - .getClientRegistration() - .getProviderDetails() - .getUserInfoEndpoint() - .getUri(); - - Try.of(() -> this.oAuth2RestOperations.exchange(userInfoUri + "/emails", new ParameterizedTypeReference>() { - }, userRequest).getBody()) - .onSuccess(unused -> log.info("Successfully retrieved emails")) - .map(emails -> emails.stream().filter(e -> e.primary).findFirst().orElse(null)) - .peek(e -> this.attributes.put("email", e.email)); - } - - @Data - private static class Email { - private String email; - private boolean primary; - private boolean verified; - } -} \ No newline at end of file diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/util/OAuth2RestOperations.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/util/OAuth2RestTemplate.java similarity index 75% rename from kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/util/OAuth2RestOperations.java rename to kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/util/OAuth2RestTemplate.java index 3219f678..1389daf6 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/util/OAuth2RestOperations.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/util/OAuth2RestTemplate.java @@ -5,6 +5,7 @@ import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.*; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; @@ -12,12 +13,16 @@ import java.util.Collections; import java.util.Map; +@Component @RequiredArgsConstructor -public class OAuth2RestOperations { - private static final ParameterizedTypeReference> PARAMETERIZED_RESPONSE_TYPE = new ParameterizedTypeReference<>() { - }; +public class OAuth2RestTemplate { + private final RestTemplate restTemplate; + private static final ParameterizedTypeReference> PARAMETERIZED_RESPONSE_TYPE; - private final RestTemplate oAuth2RestTemplate; + static { + PARAMETERIZED_RESPONSE_TYPE = new ParameterizedTypeReference<>() { + }; + } public RequestEntity map(@NonNull String url, @NonNull OAuth2UserRequest userRequest) { URI uri = UriComponentsBuilder.fromUriString(url) @@ -34,7 +39,7 @@ public ResponseEntity> exchange(@NonNull OAuth2UserRequest u .getProviderDetails() .getUserInfoEndpoint() .getUri(); - return this.oAuth2RestTemplate.exchange(map(userInfoUri, userRequest), PARAMETERIZED_RESPONSE_TYPE); + return this.restTemplate.exchange(map(userInfoUri, userRequest), PARAMETERIZED_RESPONSE_TYPE); } public ResponseEntity exchange( @@ -42,7 +47,7 @@ public ResponseEntity exchange( @NonNull Class responseType, @NonNull OAuth2UserRequest userRequest ) { - return this.oAuth2RestTemplate.exchange(map(url, userRequest), responseType); + return this.restTemplate.exchange(map(url, userRequest), responseType); } public ResponseEntity exchange( @@ -50,6 +55,6 @@ public ResponseEntity exchange( @NonNull ParameterizedTypeReference responseType, @NonNull OAuth2UserRequest userRequest ) { - return this.oAuth2RestTemplate.exchange(map(url, userRequest), responseType); + return this.restTemplate.exchange(map(url, userRequest), responseType); } } diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/ChangeUserRoleService.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/ChangeUserRoleService.java index fae9fb53..74ae2a8d 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/ChangeUserRoleService.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/ChangeUserRoleService.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import pl.sknikod.kodemyauth.infrastructure.dao.UserDao; +import pl.sknikod.kodemyauth.infrastructure.store.UserStore; import pl.sknikod.kodemyauth.infrastructure.database.User; import pl.sknikod.kodemycommons.exception.InternalError500Exception; import pl.sknikod.kodemycommons.exception.content.ExceptionMsgPattern; @@ -11,10 +11,10 @@ @Component @RequiredArgsConstructor public class ChangeUserRoleService { - private final UserDao userDao; + private final UserStore userStore; public void change(Long userId, String roleName) { - userDao.updateRole(userId, roleName) + userStore.updateRole(userId, roleName) .onFailure(th -> { throw new InternalError500Exception(ExceptionMsgPattern.PROCESS_FAILED_ENTITY, User.class); }) diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/UserService.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/UserService.java index 0566f6bd..4095e096 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/UserService.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/UserService.java @@ -9,8 +9,8 @@ import org.springframework.data.domain.PageRequest; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Service; -import pl.sknikod.kodemyauth.infrastructure.dao.RoleDao; -import pl.sknikod.kodemyauth.infrastructure.dao.UserDao; +import pl.sknikod.kodemyauth.infrastructure.store.RoleStore; +import pl.sknikod.kodemyauth.infrastructure.store.UserStore; import pl.sknikod.kodemyauth.infrastructure.database.Role; import pl.sknikod.kodemyauth.infrastructure.database.User; import pl.sknikod.kodemyauth.infrastructure.module.auth.AuthService; @@ -26,8 +26,8 @@ @RequiredArgsConstructor public class UserService { private final UserMapper userMapper; - private final RoleDao roleDao; - private final UserDao userDao; + private final RoleStore roleStore; + private final UserStore userStore; private final AuthService.AuthMapper authMapper; public static boolean checkPrivilege(String privilege) { @@ -40,7 +40,7 @@ public static boolean checkPrivilege(String privilege) { @Transactional public UserInfoResponse getUserInfo(Long userId) { - return userDao.findById(userId) + return userStore.findById(userId) .map(userMapper::map) .getOrElseThrow(th -> th instanceof InternalError500Exception ex ? ex : new InternalError500Exception()); @@ -49,13 +49,13 @@ public UserInfoResponse getUserInfo(Long userId) { public UserInfoResponse getCurrentUserInfo() { return AuthFacade.getCurrentUserPrincipal() .map(UserPrincipal::getId) - .map(id -> userDao.findById(id).getOrNull()) + .map(id -> userStore.findById(id).getOrNull()) .map(userMapper::map) .orElseThrow(InternalError500Exception::new); } public Page searchUsers(PageRequest pageRequest, FilterSearchParams filterSearchParams) { - Page users = userDao.findByUsernameOrEmailOrRole( + Page users = userStore.findByUsernameOrEmailOrRole( filterSearchParams.getUsername(), filterSearchParams.getEmail(), filterSearchParams.getRoleName() != null ? filterSearchParams.getRoleName() : null, diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/UsersBriefService.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/UsersBriefService.java index 12d18ef6..a542cd53 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/UsersBriefService.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/module/user/UsersBriefService.java @@ -3,7 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import pl.sknikod.kodemyauth.infrastructure.dao.UserDao; +import pl.sknikod.kodemyauth.infrastructure.store.UserStore; import pl.sknikod.kodemyauth.infrastructure.module.user.model.SimpleUserResponse; import pl.sknikod.kodemycommons.exception.content.ExceptionUtil; @@ -14,10 +14,10 @@ @Component @RequiredArgsConstructor public class UsersBriefService { - private final UserDao userDao; + private final UserStore userStore; public List getUserBrief(Set ids) { - return userDao.findByIds(ids) + return userStore.findByIds(ids) .map(list -> list .stream() .map(obj -> new SimpleUserResponse((Long) obj[0], (String) obj[1])) diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/AuthRedisStore.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/AuthRedisStore.java new file mode 100644 index 00000000..ed00cfc2 --- /dev/null +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/AuthRedisStore.java @@ -0,0 +1,36 @@ +package pl.sknikod.kodemyauth.infrastructure.store; + +import io.vavr.control.Try; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +@Component +@Slf4j +@RequiredArgsConstructor +public class AuthRedisStore { + private final StringRedisTemplate redisTemplate; + + private ValueOperations opsForValue() { + return redisTemplate.opsForValue(); + } + + public Try findByKey(String key) { + return Try.of(() -> opsForValue().get(key)) + .onFailure(th -> log.error("Problem with getting {} redis key value", key, th)); + } + + public void save(String key, String object) { + Try.run(() -> opsForValue().set(key, object, Duration.ofMinutes(5))) + .onFailure(th -> log.error("Problem with store {} redis key", key, th)); + } + + public void delete(String key) { + Try.run(() -> redisTemplate.delete(key)) + .onFailure(th -> log.warn("Cannot delete redis {} key", key, th)); + } +} diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/dao/RefreshTokenDao.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/RefreshTokenStore.java similarity index 97% rename from kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/dao/RefreshTokenDao.java rename to kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/RefreshTokenStore.java index e579c923..1b059b9f 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/dao/RefreshTokenDao.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/RefreshTokenStore.java @@ -1,4 +1,4 @@ -package pl.sknikod.kodemyauth.infrastructure.dao; +package pl.sknikod.kodemyauth.infrastructure.store; import io.vavr.control.Option; import io.vavr.control.Try; @@ -19,12 +19,12 @@ @Slf4j @Component -public class RefreshTokenDao { +public class RefreshTokenStore { private final RefreshTokenRepository refreshTokenRepository; private final Integer refreshTokenExpirationMin; private final UserRepository userRepository; - public RefreshTokenDao( + public RefreshTokenStore( RefreshTokenRepository refreshTokenRepository, @Value("${jwt.refresh.expiration-min:1440}") Integer refreshTokenExpirationMin, UserRepository userRepository diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/dao/RoleDao.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/RoleStore.java similarity index 92% rename from kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/dao/RoleDao.java rename to kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/RoleStore.java index 379d0728..6c729ac9 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/dao/RoleDao.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/RoleStore.java @@ -1,4 +1,4 @@ -package pl.sknikod.kodemyauth.infrastructure.dao; +package pl.sknikod.kodemyauth.infrastructure.store; import io.vavr.control.Try; import lombok.RequiredArgsConstructor; @@ -14,7 +14,7 @@ @Slf4j @Component @RequiredArgsConstructor -public class RoleDao { +public class RoleStore { private final RoleRepository roleRepository; public Try findByRoleName(String roleName) throws RuntimeException { diff --git a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/dao/UserDao.java b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/UserStore.java similarity index 92% rename from kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/dao/UserDao.java rename to kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/UserStore.java index d39993ec..ff1d7561 100644 --- a/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/dao/UserDao.java +++ b/kodemy-auth/src/main/java/pl/sknikod/kodemyauth/infrastructure/store/UserStore.java @@ -1,4 +1,4 @@ -package pl.sknikod.kodemyauth.infrastructure.dao; +package pl.sknikod.kodemyauth.infrastructure.store; import io.vavr.control.Option; import io.vavr.control.Try; @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; import pl.sknikod.kodemyauth.configuration.SecurityConfiguration; import pl.sknikod.kodemyauth.infrastructure.database.*; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Provider; +import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2ProviderResult; import pl.sknikod.kodemycommons.exception.InternalError500Exception; import pl.sknikod.kodemycommons.exception.NotFound404Exception; import pl.sknikod.kodemycommons.exception.content.ExceptionMsgPattern; @@ -21,19 +21,19 @@ @Component @RequiredArgsConstructor @Slf4j -public class UserDao { +public class UserStore { private final UserRepository userRepository; private final RoleRepository roleRepository; private final SecurityConfiguration.RoleProperties roleProperties; - public Optional save(OAuth2Provider.User providerUser) { + public Optional save(OAuth2ProviderResult providerUser) { return this.fetchRole(roleProperties.getPrimary()) .map(role -> new User( providerUser.getUsername(), providerUser.getEmail(), providerUser.getPhoto(), role)) .map(user -> { var provider = new Provider( - providerUser.getPrincipalId(), providerUser.getProvider(), + providerUser.getPrincipalId(), providerUser.getRegistrationId(), providerUser.getEmail(), providerUser.getPhoto(), user ); user.setProviders(Set.of(provider)); @@ -52,9 +52,9 @@ private Try fetchRole(String roleName) { .onFailure(th -> log.error(th.getMessage())); } - public Try findByProviderUser(OAuth2Provider.User providerUser) { + public Try findByProviderUser(OAuth2ProviderResult providerUser) { return Option.of(userRepository.findUserByPrincipalIdAndAuthProvider( - providerUser.getPrincipalId(), providerUser.getProvider() + providerUser.getPrincipalId(), providerUser.getRegistrationId() )) .toTry(() -> new NotFound404Exception(ExceptionMsgPattern.ENTITY_NOT_FOUND, User.class)); } diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/BaseTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/BaseTest.java deleted file mode 100644 index 16cdf398..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/BaseTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package pl.sknikod.kodemyauth; - -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.DynamicPropertyRegistry; -import org.springframework.test.context.DynamicPropertySource; -import org.springframework.test.context.TestExecutionListeners; -import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; -import pl.sknikod.kodemyauth.configuration.TestSecurityConfig; -import pl.sknikod.kodemyauth.configuration.TestWebConfig; - -@SpringBootTest -@Testcontainers -@ImportAutoConfiguration(value = { - TestSecurityConfig.class, - TestWebConfig.class -}) -@TestExecutionListeners( - listeners = {WithUserPrincipalTestExecutionListener.class}, - mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS -) -public abstract class BaseTest { - @Container - private static final PostgreSQLContainer postgreSQLContainer; - - static { - postgreSQLContainer = new PostgreSQLContainer<>("postgres:14.1-alpine") - .withDatabaseName("kodemy") - .withUsername("postgres") - .withPassword("postgres"); - } - - @DynamicPropertySource - private static void containerProperties(DynamicPropertyRegistry registry) { - registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl); - registry.add("spring.datasource.username", postgreSQLContainer::getUsername); - registry.add("spring.datasource.password", postgreSQLContainer::getPassword); - } -} diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/MvcTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/MvcTest.java deleted file mode 100644 index f3e8fe84..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/MvcTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package pl.sknikod.kodemyauth; - -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.http.HttpHeaders; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.ResultActions; -import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; - -@SpringBootTest -@AutoConfigureMockMvc -public abstract class MvcTest extends BaseTest { - @Autowired - protected MockMvc mockMvc; - - protected final ResultActions mvcPerform(MockHttpServletRequestBuilder request) throws Exception { - return mockMvc.perform(request); - } - - protected final ResultActions mvcPerformWithBearerAuth(MockHttpServletRequestBuilder request) throws Exception { - return this.mvcPerform(request.header(HttpHeaders.AUTHORIZATION, "Bearer ")); - } -} diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/SuperclassTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/SuperclassTest.java new file mode 100644 index 00000000..2311ff41 --- /dev/null +++ b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/SuperclassTest.java @@ -0,0 +1,36 @@ +package pl.sknikod.kodemyauth; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import pl.sknikod.kodemycommons.security.configuration.JwtConfiguration; + +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.MOCK +) +@ContextConfiguration(classes = KodemyAuthApplication.class) +@ImportAutoConfiguration(value = TestChannelBinderConfiguration.class) +@Import({JwtConfiguration.class}) +@Testcontainers +public class SuperclassTest { + @Container + private static final PostgreSQLContainer dataSource; + + static { + dataSource = new PostgreSQLContainer<>("postgres:14.1-alpine"); + } + + @DynamicPropertySource + private static void containerProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", dataSource::getJdbcUrl); + registry.add("spring.datasource.username", dataSource::getUsername); + registry.add("spring.datasource.password", dataSource::getPassword); + } +} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/WithUserPrincipal.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/WithUserPrincipal.java deleted file mode 100644 index 7ac169b2..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/WithUserPrincipal.java +++ /dev/null @@ -1,17 +0,0 @@ -package pl.sknikod.kodemyauth; - -import java.lang.annotation.*; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@Documented -public @interface WithUserPrincipal { - long id() default 1L; - - String username() default "username"; - - String[] authorities() default {}; - - boolean authenticated() default true; -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/WithUserPrincipalTestExecutionListener.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/WithUserPrincipalTestExecutionListener.java deleted file mode 100644 index f60bbc1c..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/WithUserPrincipalTestExecutionListener.java +++ /dev/null @@ -1,52 +0,0 @@ -package pl.sknikod.kodemyauth; - -import org.springframework.lang.NonNull; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.test.context.TestContext; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; -import pl.sknikod.kodemycommons.security.UserPrincipal; - -import java.util.Arrays; -import java.util.Collection; - -public class WithUserPrincipalTestExecutionListener extends DependencyInjectionTestExecutionListener { - @Override - public void beforeTestMethod(@NonNull TestContext testContext) throws Exception { - super.beforeTestMethod(testContext); - var withUserPrincipal = testContext.getTestMethod().getAnnotation(WithUserPrincipal.class); - if (withUserPrincipal == null) - withUserPrincipal = testContext.getTestClass().getAnnotation(WithUserPrincipal.class); - - if (withUserPrincipal != null) { - final var userPrincipal = toUserPrincipal(withUserPrincipal); - final var authenticationToken = withUserPrincipal.authenticated() ? - new UsernamePasswordAuthenticationToken(userPrincipal, null, userPrincipal.getAuthorities()) : - new UsernamePasswordAuthenticationToken(userPrincipal, null); - SecurityContextHolder.getContext().setAuthentication(authenticationToken); - } - } - - private UserPrincipal toUserPrincipal(WithUserPrincipal withUserPrincipal) { - return new UserPrincipal( - withUserPrincipal.id(), - withUserPrincipal.username(), - toAuthorities(withUserPrincipal.authorities()) - ); - } - - private Collection toAuthorities(String[] authorities) { - return Arrays.stream(authorities).map(SimpleGrantedAuthority::new).toList(); - } - - @Override - public void afterTestMethod(@NonNull TestContext testContext) throws Exception { - super.afterTestMethod(testContext); - var isAnnotation = testContext.getTestMethod().isAnnotationPresent(WithUserPrincipal.class); - if (!isAnnotation) - isAnnotation = testContext.getTestClass().isAnnotationPresent(WithUserPrincipal.class); - if (isAnnotation) - SecurityContextHolder.clearContext(); - } -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/configuration/TestSecurityConfig.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/configuration/TestSecurityConfig.java deleted file mode 100644 index d93ad279..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/configuration/TestSecurityConfig.java +++ /dev/null @@ -1,51 +0,0 @@ -package pl.sknikod.kodemyauth.configuration; - -import org.mockito.Mockito; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.OAuth2AuthorizationRequestRepository; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.handler.OAuth2LoginFailureHandler; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.handler.OAuth2LoginSuccessHandler; -import pl.sknikod.kodemycommons.exception.handler.ServletExceptionHandler; -import pl.sknikod.kodemycommons.security.JwtAuthorizationFilter; -import pl.sknikod.kodemycommons.security.JwtProvider; - -@TestConfiguration -public class TestSecurityConfig { - @Bean - public ClientRegistrationRepository clientRegistrationRepository() { - return Mockito.mock(ClientRegistrationRepository.class); - } - - @Bean - public ServletExceptionHandler servletExceptionHandler() { - return Mockito.mock(ServletExceptionHandler.class); - } - - @Bean - public JwtAuthorizationFilter jwtAuthorizationFilter( - ) { - return Mockito.mock(JwtAuthorizationFilter.class); - } - - @Bean - public JwtProvider jwtProvider() { - return Mockito.mock(JwtProvider.class); - } - - @Bean - public OAuth2AuthorizationRequestRepository oAuth2SessionAuthRequestRepository() { - return Mockito.mock(OAuth2AuthorizationRequestRepository.class); - } - - @Bean - public OAuth2LoginSuccessHandler oAuth2SuccessProcessHandler() { - return Mockito.mock(OAuth2LoginSuccessHandler.class); - } - - @Bean - public OAuth2LoginFailureHandler oAuth2FailureProcessHandler() { - return Mockito.mock(OAuth2LoginFailureHandler.class); - } -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/configuration/TestWebConfig.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/configuration/TestWebConfig.java deleted file mode 100644 index aca62196..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/configuration/TestWebConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package pl.sknikod.kodemyauth.configuration; - -import org.mockito.Mockito; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@TestConfiguration -public class TestWebConfig { - @Bean - public WebMvcConfigurer webSecurityConfigurer() { - return Mockito.mock(WebMvcConfigurer.class); - } - - @Bean - public RestTemplate restTemplate() { - return Mockito.mock(RestTemplate.class); - } -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/exception/RestExceptionHandlerTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/exception/RestExceptionHandlerTest.java deleted file mode 100644 index d1fe5296..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/exception/RestExceptionHandlerTest.java +++ /dev/null @@ -1,161 +0,0 @@ -package pl.sknikod.kodemyauth.exception; - -import jakarta.validation.ConstraintViolationException; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.springframework.context.MessageSource; -import org.springframework.context.MessageSourceResolvable; -import org.springframework.context.NoSuchMessageException; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.HttpStatusCode; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.authentication.InsufficientAuthenticationException; -import org.springframework.validation.BindingResult; -import org.springframework.validation.FieldError; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.context.request.WebRequest; -import pl.sknikod.kodemyauth.BaseTest; -import pl.sknikod.kodemycommons.exception.InternalError500Exception; -import pl.sknikod.kodemycommons.exception.content.ExceptionBody; -import pl.sknikod.kodemycommons.exception.handler.RestExceptionHandler; - -import java.util.List; -import java.util.Locale; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.Mockito.when; - -class RestExceptionHandlerTest extends BaseTest { - @Mock - WebRequest request; - - @Mock - BindingResult bindingResult; - - MessageSource messageSource = new MessageSourceImpl(); - - RestExceptionHandler restExceptionHandler = new RestExceptionHandler(); - - @BeforeEach - void setUp() { - restExceptionHandler.setMessageSource(messageSource); - } - - @Test - void handleConstraintViolationException_shouldBadRequest() { - // given - ConstraintViolationException ex = new ConstraintViolationException("Validation failed", null); - // when - ResponseEntity result = restExceptionHandler.handleConstraintViolationException(ex, request); - // then - assertNotNull(result.getBody()); - assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); - assertEquals("Validation failed", ((ExceptionBody) result.getBody()).getMessage()); - } - - @Test - void handleAccessDeniedException_shouldForbidden() { - // given - AccessDeniedException ex = new AccessDeniedException("Access denied"); - - // when - ResponseEntity result = restExceptionHandler.handleAccessDeniedException(ex, request); - - // then - assertNotNull(result.getBody()); - assertEquals(HttpStatus.FORBIDDEN, result.getStatusCode()); - assertEquals("Access denied", ((ExceptionBody) result.getBody()).getMessage()); - } - - @Test - void handleInsufficientAuthenticationException_shouldUnauthorized() { - // given - InsufficientAuthenticationException ex = new InsufficientAuthenticationException("Insufficient authentication"); - // when - ResponseEntity result = restExceptionHandler.handleInsufficientAuthenticationException(ex, request); - // then - assertNotNull(result.getBody()); - assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode()); - assertEquals("Insufficient authentication", ((ExceptionBody) result.getBody()).getMessage()); - } - - @Test - void handleServerProcessingException_shouldServerProcessing() { - // given - var ex = new InternalError500Exception(); - // when - ResponseEntity result = restExceptionHandler.handleServerProcessingException(ex, request); - // then - assertNotNull(result.getBody()); - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, result.getStatusCode()); - assertEquals("Internal error", ((ExceptionBody) result.getBody()).getMessage()); - } - - @Test - void handleMethodArgumentNotValid_shouldBadRequest() { - // given - MethodArgumentNotValidException ex = new MethodArgumentNotValidException(null, bindingResult); - when(bindingResult.getFieldErrors()).thenReturn(List.of( - new FieldError("objectName", "field1", "must not be null"), - new FieldError("objectName", "field2", "must be a valid email") - )); - - // when - ResponseEntity result = restExceptionHandler.handleMethodArgumentNotValid( - ex, new HttpHeaders(), HttpStatus.BAD_REQUEST, request - ); - - // then - assertNotNull(result); - assertNotNull(result.getBody()); - assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); - assertEquals("[field1: must not be null, field2: must be a valid email]", ((ExceptionBody) result.getBody()).getMessage()); - } - - @Test - void handleExceptionInternal_shouldCorrectResponse() { - // given - Exception ex = new Exception("Internal error"); - HttpHeaders headers = new HttpHeaders(); - HttpStatusCode statusCode = HttpStatus.INTERNAL_SERVER_ERROR; - - // when - ResponseEntity result = restExceptionHandler.handleExceptionInternal( - ex, null, headers, statusCode, request - ); - - // then - assertNotNull(result); - assertNotNull(result.getBody()); - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, result.getStatusCode()); - assertEquals("Internal error", ((ExceptionBody) result.getBody()).getMessage()); - } - - private static class MessageSourceImpl implements MessageSource { - @Override - public String getMessage( - @NotNull String code, Object[] args, String defaultMessage, @NotNull Locale locale) { - return ""; - } - - @Override - @NotNull - public String getMessage( - @NotNull String code, Object[] args, @NotNull Locale locale) throws NoSuchMessageException { - return ""; - } - - @Override - @NotNull - public String getMessage( - @NotNull MessageSourceResolvable resolvable, @NotNull Locale locale) throws NoSuchMessageException { - return ""; - } - } - -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/OAuth2Factory.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/OAuth2Factory.java deleted file mode 100644 index cd00123a..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/OAuth2Factory.java +++ /dev/null @@ -1,21 +0,0 @@ -package pl.sknikod.kodemyauth.factory; - -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.OAuth2Provider; -import pl.sknikod.kodemyauth.infrastructure.module.oauth2.provider.github.GithubOAuth2Provider; - -import java.util.Map; - -public class OAuth2Factory { - private OAuth2Factory() { - - } - - public static OAuth2Provider.User oAuth2GithubUser() { - return new GithubOAuth2Provider.GithubUser(Map.of( - "id", 1L, - "login", "username", - "email", "email@email.com", - "avatar_url", "photo" - )); - } -} diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/ProviderFactory.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/ProviderFactory.java deleted file mode 100644 index 741d28d3..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/ProviderFactory.java +++ /dev/null @@ -1,16 +0,0 @@ -package pl.sknikod.kodemyauth.factory; - -import pl.sknikod.kodemyauth.infrastructure.database.Provider; - -public class ProviderFactory { - private ProviderFactory() { - } - - public static Provider provider(String providerType) { - var provider = new Provider(); - provider.setId(1L); - provider.setProviderType(providerType); - provider.setUser(UserFactory.user(RoleFactory.role("ROLE_USER"))); - return provider; - } -} diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/RoleFactory.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/RoleFactory.java deleted file mode 100644 index d3d71e72..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/RoleFactory.java +++ /dev/null @@ -1,18 +0,0 @@ -package pl.sknikod.kodemyauth.factory; - -import pl.sknikod.kodemyauth.infrastructure.database.Role; - -public class RoleFactory { - private RoleFactory() { - } - - public static Role roleUser = role("ROLE_USER"); - public static Role roleAdmin = role("ROLE_ADMIN"); - - public static Role role(String roleName) { - Role role = new Role(); - role.setId(1L); - role.setName(roleName); - return role; - } -} diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/TokenFactory.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/TokenFactory.java deleted file mode 100644 index ec938693..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/TokenFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -package pl.sknikod.kodemyauth.factory; - -import pl.sknikod.kodemyauth.infrastructure.database.RefreshToken; -import pl.sknikod.kodemycommons.security.JwtProvider; - -import java.util.Collections; -import java.util.Date; -import java.util.UUID; - -public class TokenFactory { - private TokenFactory() { - } - - public static RefreshToken refreshToken = refreshToken(); - public static JwtProvider.Token jwtProviderToken = jwtProviderToken(); - public static JwtProvider.Token.Deserialize jwtProviderTokenDeserialize = jwtProviderTokenDeserialize(); - - public static RefreshToken refreshToken() { - var token = new RefreshToken( - UUID.randomUUID(), - null, - null, - UserFactory.user(RoleFactory.role("ROLE_USER")) - ); - token.setId(1L); - return token; - } - - private static JwtProvider.Token jwtProviderToken() { - return new JwtProvider.Token( - UUID.randomUUID(), - "header.payload.signature", - new Date() - ); - } - - private static JwtProvider.Token.Deserialize jwtProviderTokenDeserialize() { - return new JwtProvider.Token.Deserialize( - 1L, - "username", - 1, - Collections.emptySet() - ); - } -} diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/UserFactory.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/UserFactory.java deleted file mode 100644 index 481d336c..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/factory/UserFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -package pl.sknikod.kodemyauth.factory; - -import pl.sknikod.kodemyauth.infrastructure.database.Role; -import pl.sknikod.kodemyauth.infrastructure.database.User; -import pl.sknikod.kodemycommons.security.UserPrincipal; - -import java.util.Collections; - -public class UserFactory { - private UserFactory() { - } - - public static User userUser = user(RoleFactory.roleUser); - public static User userAdmin = user(RoleFactory.roleAdmin); - public static UserPrincipal userPrincipal = userPrincipal(); - - public static User user(Role role) { - var user = new User("username", "email@email.com", "photo", role); - user.setId(1L); - user.setUsername("user"); - return user; - } - - - private static UserPrincipal userPrincipal() { - return new UserPrincipal( - 1L, "username", - false, false, false, true, - Collections.emptySet() - ); - } - -} diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/RefreshTokenDaoTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/RefreshTokenDaoTest.java deleted file mode 100644 index 33603f72..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/RefreshTokenDaoTest.java +++ /dev/null @@ -1,127 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.database.handler; - -import io.vavr.control.Try; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.springframework.dao.OptimisticLockingFailureException; -import pl.sknikod.kodemyauth.BaseTest; -import pl.sknikod.kodemyauth.factory.TokenFactory; -import pl.sknikod.kodemyauth.factory.UserFactory; -import pl.sknikod.kodemyauth.infrastructure.dao.RefreshTokenDao; -import pl.sknikod.kodemyauth.infrastructure.database.RefreshToken; -import pl.sknikod.kodemyauth.infrastructure.database.RefreshTokenRepository; -import pl.sknikod.kodemyauth.infrastructure.database.UserRepository; -import pl.sknikod.kodemycommons.exception.InternalError500Exception; - -import java.util.Optional; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.when; - -class RefreshTokenDaoTest extends BaseTest { - @Mock - RefreshTokenRepository refreshTokenRepository; - Integer refreshTokenExpirationMin = 1440; - @Mock - UserRepository userRepository; - - RefreshTokenDao refreshTokenRepositoryHandler; - - @BeforeEach - void setUp() { - refreshTokenRepositoryHandler = new RefreshTokenDao( - refreshTokenRepository, refreshTokenExpirationMin, userRepository); - } - - @Test - void createAndGet_shouldSucceed() { - //given - var id = 1L; - var uuid = UUID.randomUUID(); - when(userRepository.findById(id)) - .thenReturn(Optional.of(UserFactory.userUser)); - when(refreshTokenRepository.save(any())) - .thenReturn(TokenFactory.refreshToken); - //when - Try result = refreshTokenRepositoryHandler.createAndGet(id, uuid); - //then - assertTrue(result.isSuccess()); - assertEquals(TokenFactory.refreshToken.getId(), result.get().getId()); - assertEquals(TokenFactory.refreshToken.getBearerId(), result.get().getBearerId()); - } - - @Test - void createAndGet_shouldFailure_whenUserNotFound() { - //given - var id = 1L; - var uuid = UUID.randomUUID(); - when(userRepository.findById(id)) - .thenReturn(null); - //when - Try result = refreshTokenRepositoryHandler.createAndGet(id, uuid); - //then - assertTrue(result.isFailure()); - assertInstanceOf(InternalError500Exception.class, result.getCause()); - } - - @Test - void createAndGet_shouldFailure_whenSaveFails() { - //given - var id = 1L; - var uuid = UUID.randomUUID(); - when(userRepository.findById(id)) - .thenReturn(Optional.of(UserFactory.userUser)); - when(refreshTokenRepository.save(any())) - .thenThrow(new OptimisticLockingFailureException("")); - //when - Try result = refreshTokenRepositoryHandler.createAndGet(id, uuid); - //then - assertTrue(result.isFailure()); - assertInstanceOf(InternalError500Exception.class, result.getCause()); - } - - @Test - void createAndGet2_shouldSucceed() { - //given - var uuid = UUID.randomUUID(); - when(refreshTokenRepository.save(any())) - .thenReturn(TokenFactory.refreshToken); - //when - Try result = refreshTokenRepositoryHandler.createAndGet(UserFactory.userUser, uuid); - //then - assertTrue(result.isSuccess()); - assertEquals(TokenFactory.refreshToken.getId(), result.get().getId()); - assertEquals(TokenFactory.refreshToken.getBearerId(), result.get().getBearerId()); - } - - @Test - void createAndGet2_shouldFailure_whenUserHasIdNull() { - //given - var uuid = UUID.randomUUID(); - var user = UserFactory.userUser; - user.setId(null); - when(refreshTokenRepository.save(any())) - .thenThrow(new RuntimeException("")); - //when - Try result = refreshTokenRepositoryHandler.createAndGet(UserFactory.userUser, uuid); - //then - assertTrue(result.isFailure()); - assertInstanceOf(InternalError500Exception.class, result.getCause()); - } - - @Test - void createAndGet2_shouldFailure_whenSaveFails() { - //given - var uuid = UUID.randomUUID(); - when(refreshTokenRepository.save(any())) - .thenThrow(new OptimisticLockingFailureException("")); - //when - Try result = refreshTokenRepositoryHandler.createAndGet(UserFactory.userUser, uuid); - //then - assertTrue(result.isFailure()); - assertInstanceOf(InternalError500Exception.class, result.getCause()); - } -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/RoleDaoTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/RoleDaoTest.java deleted file mode 100644 index adb117c6..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/RoleDaoTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.database.handler; - -import io.vavr.control.Try; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import pl.sknikod.kodemyauth.BaseTest; -import pl.sknikod.kodemyauth.factory.RoleFactory; -import pl.sknikod.kodemyauth.infrastructure.dao.RoleDao; -import pl.sknikod.kodemyauth.infrastructure.database.Role; -import pl.sknikod.kodemyauth.infrastructure.database.RoleRepository; -import pl.sknikod.kodemycommons.exception.NotFound404Exception; - -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -class RoleDaoTest extends BaseTest { - @Mock - private RoleRepository roleRepository; - - private RoleDao roleDao; - - @BeforeEach - void setUp() { - roleDao = new RoleDao(roleRepository); - } - - @Test - void findByRoleName_shouldSucceed() { - // given - when(roleRepository.findByName(any())) - .thenReturn(Optional.of(RoleFactory.roleUser)); - // when - Try result = roleDao.findByRoleName("ROLE_ADMIN"); - // then - assertTrue(result.isSuccess()); - assertEquals(RoleFactory.roleUser.getName(), result.get().getName()); - } - - @Test - void findByRoleName_shouldFailure_whenRoleNotFound() { - // given - when(roleRepository.findByName(any())) - .thenReturn(Optional.empty()); - // when - Try result = roleDao.findByRoleName("ROLE_ADMIN"); - // then - assertTrue(result.isFailure()); - assertInstanceOf(NotFound404Exception.class, result.getCause()); - } -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/UserDaoTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/UserDaoTest.java deleted file mode 100644 index 7170fec5..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/database/handler/UserDaoTest.java +++ /dev/null @@ -1,223 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.database.handler; - -import io.vavr.control.Try; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.springframework.dao.OptimisticLockingFailureException; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import pl.sknikod.kodemyauth.BaseTest; -import pl.sknikod.kodemyauth.configuration.SecurityConfiguration; -import pl.sknikod.kodemyauth.factory.OAuth2Factory; -import pl.sknikod.kodemyauth.factory.RoleFactory; -import pl.sknikod.kodemyauth.factory.UserFactory; -import pl.sknikod.kodemyauth.infrastructure.dao.UserDao; -import pl.sknikod.kodemyauth.infrastructure.database.RoleRepository; -import pl.sknikod.kodemyauth.infrastructure.database.User; -import pl.sknikod.kodemyauth.infrastructure.database.UserRepository; -import pl.sknikod.kodemycommons.exception.InternalError500Exception; -import pl.sknikod.kodemycommons.exception.NotFound404Exception; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.when; - -class UserDaoTest extends BaseTest { - @Mock - private UserRepository userRepository; - @Mock - private RoleRepository roleRepository; - @Mock - private SecurityConfiguration.RoleProperties roleProperties; - - private UserDao userDao; - - @BeforeEach - void setUp() { - userDao = new UserDao(userRepository, roleRepository, roleProperties); - } - - @Test - void save_shouldSucceed() { - // given - when(roleProperties.getPrimary()) - .thenReturn("ROLE_USER"); - when(roleRepository.findByName(any())) - .thenReturn(Optional.of(RoleFactory.roleUser)); - when(userRepository.save(any())) - .thenReturn(UserFactory.userUser); - // when - Optional result = userDao.save(OAuth2Factory.oAuth2GithubUser()); - // then - assertTrue(result.isPresent()); - assertEquals(UserFactory.userUser.getUsername(), result.get().getUsername()); - } - - @Test - void save_shouldEmpty_whenRoleNotFound() { - // given - when(roleProperties.getPrimary()) - .thenReturn("ROLE_USER"); - when(roleRepository.findByName(any())) - .thenReturn(Optional.empty()); - // when - Optional result = userDao.save(OAuth2Factory.oAuth2GithubUser()); - // then - assertTrue(result.isEmpty()); - } - - @Test - void save_shouldEmpty_whenSaveFails() { - // given - when(roleProperties.getPrimary()) - .thenReturn("ROLE_USER"); - when(roleRepository.findByName(any())) - .thenReturn(Optional.of(RoleFactory.roleUser)); - when(userRepository.save(any())) - .thenThrow(new OptimisticLockingFailureException("")); - // when - Optional result = userDao.save(OAuth2Factory.oAuth2GithubUser()); - // then - assertTrue(result.isEmpty()); - } - - @Test - void findByProviderUser_shouldSucceed() { - // given - when(userRepository.findUserByPrincipalIdAndAuthProvider(any(), any())) - .thenReturn(UserFactory.userUser); - // when - Try result = userDao.findByProviderUser(OAuth2Factory.oAuth2GithubUser()); - // then - assertTrue(result.isSuccess()); - assertEquals(UserFactory.userUser.getUsername(), result.get().getUsername()); - } - - @Test - void findUserByProvider_shouldFailure_whenUserNotFound() { - // given - when(userRepository.findUserByPrincipalIdAndAuthProvider(any(), any())) - .thenReturn(null); - // when - Try result = userDao.findByProviderUser(OAuth2Factory.oAuth2GithubUser()); - // then - assertTrue(result.isFailure()); - assertInstanceOf(NotFound404Exception.class, result.getCause()); - } - - @Test - void findById_shouldSucceed() { - // given - when(userRepository.findById(UserFactory.userUser.getId())) - .thenReturn(Optional.of(UserFactory.userUser)); - // when - Try result = userDao.findById(UserFactory.userUser.getId()); - // then - assertTrue(result.isSuccess()); - assertEquals(UserFactory.userUser.getUsername(), result.get().getUsername()); - } - - @Test - void findById_shouldFailure_whenUserNotFound() { - // given - when(userRepository.findById(UserFactory.userUser.getId())) - .thenReturn(Optional.empty()); - // when - Try result = userDao.findById(UserFactory.userUser.getId()); - // then - assertTrue(result.isFailure()); - assertInstanceOf(NotFound404Exception.class, result.getCause()); - } - - @Test - void updateRole_shouldSucceed() { - // given - when(roleRepository.findByName(any())) - .thenReturn(Optional.of(RoleFactory.roleAdmin)); - when(userRepository.findById(any())) - .thenReturn(Optional.of(UserFactory.userUser)); - when(userRepository.save(any())) - .thenReturn(UserFactory.userAdmin); - // when - Try result = userDao.updateRole(UserFactory.userUser.getId(), "ROLE_ADMIN"); - // then - assertTrue(result.isSuccess()); - assertEquals(RoleFactory.roleAdmin, result.get().getRole()); - } - - @Test - void updateRole_shouldFailure_whenRoleNotFound() { - // given - when(roleRepository.findByName(any())) - .thenReturn(Optional.empty()); - // when - Try result = userDao.updateRole(UserFactory.userUser.getId(), "ROLE_ADMIN"); - // then - assertTrue(result.isFailure()); - assertInstanceOf(InternalError500Exception.class, result.getCause()); - } - - @Test - void updateRole_shouldFailure_whenUserNotFound() { - // given - when(roleRepository.findByName(any())) - .thenReturn(Optional.of(RoleFactory.roleAdmin)); - when(userRepository.findById(any())) - .thenReturn(Optional.empty()); - // when - Try result = userDao.updateRole(UserFactory.userUser.getId(), "ROLE_ADMIN"); - // then - assertTrue(result.isFailure()); - assertInstanceOf(InternalError500Exception.class, result.getCause()); - } - - @Test - void updateRole_shouldFailure_whenSaveFails() { - // given - when(roleRepository.findByName(any())) - .thenReturn(Optional.of(RoleFactory.roleAdmin)); - when(userRepository.findById(any())) - .thenReturn(Optional.of(UserFactory.userUser)); - when(userRepository.save(any())) - .thenThrow(new OptimisticLockingFailureException("")); - // when - Try result = userDao.updateRole(UserFactory.userUser.getId(), "ROLE_ADMIN"); - // then - assertTrue(result.isFailure()); - assertInstanceOf(InternalError500Exception.class, result.getCause()); - } - - @Test - void findByUsernameOrEmailOrRole_shouldSucceed() { - // given - Page pageOfUser = new PageImpl<>(List.of(UserFactory.userUser), Pageable.unpaged(), 1); - when(userRepository.findByUsernameOrEmailOrRole(any(), any(), any(), any())) - .thenReturn(pageOfUser); - // when - Page result = userDao.findByUsernameOrEmailOrRole(any(), any(), any(), any()); - // then - assertNotNull(result); - assertEquals(pageOfUser.getTotalPages(), result.getTotalPages()); - assertEquals(UserFactory.userUser.getUsername(), result.getContent().get(0).getUsername()); - } - - @Test - void findByUsernameOrEmailOrRole_shouldSucceed_whenPageEmpty() { - // given - Page pageOfUser = new PageImpl<>(Collections.emptyList(), Pageable.unpaged(), 0); - when(userRepository.findByUsernameOrEmailOrRole(any(), any(), any(), any())) - .thenReturn(pageOfUser); - // when - Page result = userDao.findByUsernameOrEmailOrRole(any(), any(), any(), any()); - // then - assertNotNull(result); - assertEquals(pageOfUser.getTotalPages(), result.getTotalPages()); - assertEquals(pageOfUser.getContent().size(), result.getContent().size()); - } -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/RefreshTokensServiceTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/RefreshTokensServiceTest.java deleted file mode 100644 index 942a3640..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/RefreshTokensServiceTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.module; - -import io.vavr.control.Try; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import pl.sknikod.kodemyauth.BaseTest; -import pl.sknikod.kodemyauth.configuration.SecurityConfiguration; -import pl.sknikod.kodemyauth.factory.TokenFactory; -import pl.sknikod.kodemyauth.infrastructure.dao.RefreshTokenDao; -import pl.sknikod.kodemyauth.infrastructure.database.RoleRepository; -import pl.sknikod.kodemyauth.infrastructure.module.auth.RefreshTokensService; -import pl.sknikod.kodemycommons.security.JwtProvider; - -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.*; - -class RefreshTokensServiceTest extends BaseTest { - private final RefreshTokenDao refreshTokenRepositoryHandler = - Mockito.mock(RefreshTokenDao.class); - private final JwtProvider jwtProvider = - Mockito.mock(JwtProvider.class); - private final SecurityConfiguration.RoleProperties roleProperties = - Mockito.mock(SecurityConfiguration.RoleProperties.class); - private final RoleRepository roleRepository = - Mockito.mock(RoleRepository.class); - - private final RefreshTokensService refreshTokensService = - new RefreshTokensService(roleRepository, refreshTokenRepositoryHandler, jwtProvider, roleProperties); - - private static final UUID refresh; - private static final UUID bearerJti; - - static { - refresh = UUID.randomUUID(); - bearerJti = UUID.randomUUID(); - } - - @BeforeEach - void setUp() { - /*when(roleProperties.getAuthorities(any())) - .thenReturn(Collections.emptySet());*/ - } - - @Test - void refresh_shouldReturnNewTokens() { - // given - var refreshToken = TokenFactory.refreshToken(); - when(refreshTokenRepositoryHandler.findByTokenAndBearerJti(eq(refresh), eq(bearerJti))) - .thenReturn(Try.success(refreshToken)); - when(jwtProvider.generateUserToken(any())) - .thenReturn(TokenFactory.jwtProviderToken); - when(refreshTokenRepositoryHandler.createAndGet(any(), any())) - .thenReturn(Try.success(refreshToken)); - // when - var result = refreshTokensService.refresh(refresh, bearerJti); - // then - assertEquals(TokenFactory.jwtProviderToken.value(), result.token()); - assertEquals(refreshToken.getToken().toString(), result.refresh()); - } -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2ProviderServiceTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2ProviderServiceTest.java deleted file mode 100644 index 7b4cf77d..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/OAuth2ProviderServiceTest.java +++ /dev/null @@ -1,6 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.module.oauth2; - -import pl.sknikod.kodemyauth.BaseTest; - -class OAuth2ProviderServiceTest extends BaseTest { -} \ No newline at end of file diff --git a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginFailureHandlerTest.java b/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginFailureHandlerTest.java deleted file mode 100644 index 0fddeb9b..00000000 --- a/kodemy-auth/src/test/java/pl/sknikod/kodemyauth/infrastructure/module/oauth2/handler/OAuth2LoginFailureHandlerTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package pl.sknikod.kodemyauth.infrastructure.module.oauth2.handler; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import pl.sknikod.kodemyauth.BaseTest; -import pl.sknikod.kodemyauth.util.route.RouteRedirectStrategy; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.*; - -class OAuth2LoginFailureHandlerTest extends BaseTest { - @Mock - HttpServletRequest request; - @Mock - HttpServletResponse response; - - @Mock - RouteRedirectStrategy redirectStrategy; - private static final String frontRouteBaseUrl = "http://localhost:8080"; - - OAuth2LoginFailureHandler failureHandler; - - @SuppressWarnings("unchecked") - @Captor - ArgumentCaptor> paramsCaptor = ArgumentCaptor.forClass(Map.class); - - @BeforeEach - void setUp() { - failureHandler = new OAuth2LoginFailureHandler(frontRouteBaseUrl); - failureHandler.setRedirectStrategy(redirectStrategy); - } - - @Test - void onAuthenticationFailure_shouldFailure_whenAuthenticationException() { - // given - AuthenticationException exception = mock(AuthenticationException.class); - // when - failureHandler.onAuthenticationFailure(request, response, exception); - // then - verify(redirectStrategy, times(1)) - .sendRedirect(eq(request), eq(response), eq(frontRouteBaseUrl), paramsCaptor.capture()); - - var params = paramsCaptor.getValue(); - assertEquals("authentication_error", params.get("error")); - } - - @Test - void onAuthenticationFailure_shouldFailure_whenOAuth2AuthenticationException() { - // given - OAuth2AuthenticationException exception = mock(OAuth2AuthenticationException.class); - // when - failureHandler.onAuthenticationFailure(request, response, exception); - // then - verify(redirectStrategy, times(1)) - .sendRedirect(eq(request), eq(response), eq(frontRouteBaseUrl), paramsCaptor.capture()); - - var params = paramsCaptor.getValue(); - assertEquals("authentication_error", params.get("error")); - } - -} \ No newline at end of file diff --git a/kodemy-auth/src/test/resources/application-test.yml b/kodemy-auth/src/test/resources/application-test.yml new file mode 100644 index 00000000..e8bfed70 --- /dev/null +++ b/kodemy-auth/src/test/resources/application-test.yml @@ -0,0 +1,7 @@ +spring: + main: + allow-bean-definition-overriding: true + liquibase: + change-log: classpath:/db/changelog/db.changelog-test.xml + profiles: + active: test \ No newline at end of file diff --git a/kodemy-auth/src/test/resources/application.yml b/kodemy-auth/src/test/resources/application.yml deleted file mode 100644 index 102c7c90..00000000 --- a/kodemy-auth/src/test/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -spring: - main: - allow-bean-definition-overriding: true - liquibase: - change-log: classpath:/db/changelog/db.changelog-test.xml \ No newline at end of file diff --git a/kodemy-backend/build.gradle b/kodemy-backend/build.gradle index b04b3d3f..37cdb354 100644 --- a/kodemy-backend/build.gradle +++ b/kodemy-backend/build.gradle @@ -75,13 +75,16 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' - testImplementation 'org.testcontainers:junit-jupiter:1.19.8' + testImplementation 'org.springframework.cloud:spring-cloud-contract-wiremock' + testImplementation 'org.springframework.cloud:spring-cloud-stream' + testImplementation 'org.springframework.cloud:spring-cloud-stream-test-binder' + testImplementation 'org.testcontainers:junit-jupiter:1.20.0' constraints { testImplementation('org.apache.commons:commons-compress:1.26.2') { because '<1.25.x vulnerability' } } - testImplementation 'org.testcontainers:postgresql:1.19.8' + testImplementation 'org.testcontainers:postgresql:1.20.0' testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/RabbitConfiguration.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/RabbitConfiguration.java index f0828e21..75befda3 100644 --- a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/RabbitConfiguration.java +++ b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/RabbitConfiguration.java @@ -75,72 +75,4 @@ public RabbitTemplate rabbitTemplate( rabbitTemplate.setMessageConverter(messageConverter); return rabbitTemplate; } - - @Component - @DependsOn("rabbitConfiguration") - @RequiredArgsConstructor - public static class RabbitDlqErrorSwitch implements RabbitListenerConfigurer { - public static final String DLQ_SUFFIX = ".dlq"; - private final RabbitTemplate rabbitTemplate; - private final BindingServiceProperties bindingServiceProperties; - - @Override - public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) { - registrar.registerEndpoint(new DlqRabbitListenerEndpoint()); - } - - private class DlqRabbitListenerEndpoint extends AbstractRabbitListenerEndpoint { - @Override - @NonNull - protected MessageListener createMessageListener(@NonNull MessageListenerContainer container) { - final var queueNames = bindingServiceProperties - .getBindings().entrySet().stream() - .filter(binding -> binding.getKey().matches("[A-Za-z]+-in-\\d+")) - .map(Map.Entry::getValue) - .map(binding -> String.format("%s.%s%s", binding.getDestination(), binding.getGroup(), DLQ_SUFFIX)) - .toArray(String[]::new); - container.setQueueNames(queueNames); - return new DlqMessageListener(rabbitTemplate); - } - - @Override - @NonNull - public String getId() { - return getClass().getName(); - } - } - - @RequiredArgsConstructor - private static class DlqMessageListener implements MessageListener { - private static final String RETRY_HEADER = "x-dead-letter-retry"; - private static final String MAX_LENGTH_HEADER = "x-max-length"; - private final RabbitTemplate rabbitTemplate; - - @Override - public void onMessage(Message message) { - final var headers = message.getMessageProperties().getHeaders(); - final var routingKey = message.getMessageProperties().getReceivedRoutingKey(); - final var retry = (int) headers.getOrDefault(RETRY_HEADER, 0); - final var maxLength = (int) headers.getOrDefault(MAX_LENGTH_HEADER, 3); - if (retry >= maxLength) { - redirect(routingKey, RedirectTarget.PARKING_LOT, message); - return; - } - headers.put(RETRY_HEADER, retry + 1); - redirect(routingKey, RedirectTarget.ORIGINAL, message); - } - - private void redirect(String routingKey, RedirectTarget redirectTarget, Message message) { - String newRoutingKey = routingKey.replace(DLQ_SUFFIX, "") + redirectTarget.suffix; - rabbitTemplate.send("", newRoutingKey, message); - } - - @AllArgsConstructor - private enum RedirectTarget { - ORIGINAL(""), - PARKING_LOT(PARKING_LOT_SUFFIX); - private final String suffix; - } - } - } } diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/SecurityConfiguration.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/SecurityConfiguration.java index 5ea2845a..597fd578 100644 --- a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/SecurityConfiguration.java +++ b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/SecurityConfiguration.java @@ -58,17 +58,12 @@ public ServletExceptionHandler servletExceptionHandler(ObjectMapper objectMapper } @Bean - public JwtConfiguration.JwtProperties jwtProperties() { - return new JwtConfiguration.JwtProperties(); + public JwtProvider jwtProvider(JwtConfiguration jwtConfiguration) { + return new JwtProvider(jwtConfiguration.getJwtProperties()); } @Bean - public JwtProvider jwtProvider(JwtConfiguration.JwtProperties jwtProperties) { - return new JwtProvider(jwtProperties); - } - - @Bean - public JwtAuthorizationFilter jwtAuthorizationFilter(JwtConfiguration.JwtProperties jwtProperties) { - return new JwtAuthorizationFilter(jwtProperties); + public JwtAuthorizationFilter jwtAuthorizationFilter(JwtProvider jwtProvider) { + return new JwtAuthorizationFilter(jwtProvider); } } \ No newline at end of file diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/WebConfiguration.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/WebConfiguration.java index 89f11506..f1879f3f 100644 --- a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/WebConfiguration.java +++ b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/WebConfiguration.java @@ -1,13 +1,9 @@ package pl.sknikod.kodemybackend.configuration; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.FormHttpMessageConverter; -import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import pl.sknikod.kodemycommons.exception.handler.RestExceptionHandler; import pl.sknikod.kodemycommons.network.LanRestTemplate; @@ -17,7 +13,7 @@ public class WebConfiguration { @Bean - public RestExceptionHandler restExceptionHandler(){ + public RestExceptionHandler restExceptionHandler() { return new RestExceptionHandler(); } @@ -29,19 +25,9 @@ public RestTemplate restTemplate() { } @Bean - public LanRestTemplate lanRestTemplate(LanNetworkProperties lanNetworkProperties, JwtProvider jwtProvider) { - return new LanRestTemplate(lanNetworkProperties.connectTimeoutMs, lanNetworkProperties.readTimeoutMs, jwtProvider); - } - - @Getter - @Setter - @Component - @NoArgsConstructor - @ConfigurationProperties(prefix = "network.lan") - public static class LanNetworkProperties { - private String username; - private String password; - private int connectTimeoutMs; - private int readTimeoutMs; + public LanRestTemplate lanRestTemplate( + @Value("${network.connect-timeout-ms}") int connectTimeoutMs, @Value("${network.read-timeout-ms}") int readTimeoutMs, JwtProvider jwtProvider + ) { + return new LanRestTemplate(connectTimeoutMs, readTimeoutMs, jwtProvider); } } diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/rabbit/RabbitDlqErrorSwitch.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/rabbit/RabbitDlqErrorSwitch.java new file mode 100644 index 00000000..7dab7850 --- /dev/null +++ b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/configuration/rabbit/RabbitDlqErrorSwitch.java @@ -0,0 +1,86 @@ +package pl.sknikod.kodemybackend.configuration.rabbit; + +import lombok.AllArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageListener; +import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.AbstractRabbitListenerEndpoint; +import org.springframework.amqp.rabbit.listener.MessageListenerContainer; +import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar; +import org.springframework.cloud.stream.config.BindingServiceProperties; +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; +import pl.sknikod.kodemybackend.configuration.RabbitConfiguration; + +import java.util.Map; + +@Component +@DependsOn("rabbitConfiguration") +@RequiredArgsConstructor +public class RabbitDlqErrorSwitch implements RabbitListenerConfigurer { + public static final String DLQ_SUFFIX = ".dlq"; + private final RabbitTemplate rabbitTemplate; + private final BindingServiceProperties bindingServiceProperties; + + @Override + public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) { + registrar.registerEndpoint(new DlqRabbitListenerEndpoint()); + } + + private class DlqRabbitListenerEndpoint extends AbstractRabbitListenerEndpoint { + @Override + @NonNull + protected MessageListener createMessageListener(@NonNull MessageListenerContainer container) { + final var queueNames = bindingServiceProperties + .getBindings().entrySet().stream() + .filter(binding -> binding.getKey().matches("[A-Za-z]+-in-\\d+")) + .map(Map.Entry::getValue) + .map(binding -> String.format("%s.%s%s", binding.getDestination(), binding.getGroup(), DLQ_SUFFIX)) + .toArray(String[]::new); + container.setQueueNames(queueNames); + return new DlqMessageListener(rabbitTemplate); + } + + @Override + @NonNull + public String getId() { + return getClass().getName(); + } + } + + @RequiredArgsConstructor + private static class DlqMessageListener implements MessageListener { + private static final String RETRY_HEADER = "x-dead-letter-retry"; + private static final String MAX_LENGTH_HEADER = "x-max-length"; + private final RabbitTemplate rabbitTemplate; + + @Override + public void onMessage(Message message) { + final var headers = message.getMessageProperties().getHeaders(); + final var routingKey = message.getMessageProperties().getReceivedRoutingKey(); + final var retry = (int) headers.getOrDefault(RETRY_HEADER, 0); + final var maxLength = (int) headers.getOrDefault(MAX_LENGTH_HEADER, 3); + if (retry >= maxLength) { + redirect(routingKey, DlqMessageListener.RedirectTarget.PARKING_LOT, message); + return; + } + headers.put(RETRY_HEADER, retry + 1); + redirect(routingKey, DlqMessageListener.RedirectTarget.ORIGINAL, message); + } + + private void redirect(String routingKey, DlqMessageListener.RedirectTarget redirectTarget, Message message) { + String newRoutingKey = routingKey.replace(DLQ_SUFFIX, "") + redirectTarget.suffix; + rabbitTemplate.send("", newRoutingKey, message); + } + + @AllArgsConstructor + private enum RedirectTarget { + ORIGINAL(""), + PARKING_LOT(RabbitConfiguration.PARKING_LOT_SUFFIX); + private final String suffix; + } + } +} diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/mapper/GradeMapper.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/mapper/GradeMapper.java index 571f169a..fb8cbedf 100644 --- a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/mapper/GradeMapper.java +++ b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/mapper/GradeMapper.java @@ -2,19 +2,16 @@ import org.mapstruct.Mapper; import org.mapstruct.MappingConstants; -import pl.sknikod.kodemybackend.infrastructure.model.UserDetails; import pl.sknikod.kodemybackend.infrastructure.database.Grade; import pl.sknikod.kodemybackend.infrastructure.module.grade.GradeService; -import java.util.Set; - @Mapper(componentModel = MappingConstants.ComponentModel.SPRING) public interface GradeMapper { default GradeService.GradePageable map(Grade grade, String username) { return new GradeService.GradePageable( grade.getId(), grade.getValue(), - new UserDetails( + new GradeService.GradePageable.AuthorDetails( grade.getUserId(), username ) diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/model/UserDetails.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/model/UserDetails.java deleted file mode 100644 index 621d90bd..00000000 --- a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/model/UserDetails.java +++ /dev/null @@ -1,15 +0,0 @@ -package pl.sknikod.kodemybackend.infrastructure.model; - -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.ToString; - -@Getter -@AllArgsConstructor -@ToString -@EqualsAndHashCode -public class UserDetails { - Long id; - String username; -} diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/grade/GradeService.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/grade/GradeService.java index b45cd364..6d03af44 100644 --- a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/grade/GradeService.java +++ b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/grade/GradeService.java @@ -11,7 +11,6 @@ import pl.sknikod.kodemybackend.infrastructure.database.Grade; import pl.sknikod.kodemybackend.infrastructure.database.GradeRepository; import pl.sknikod.kodemybackend.infrastructure.mapper.GradeMapper; -import pl.sknikod.kodemybackend.infrastructure.model.UserDetails; import pl.sknikod.kodemybackend.infrastructure.module.grade.model.GradeMaterialFilterSearchParams; import pl.sknikod.kodemybackend.infrastructure.store.GradeStore; import pl.sknikod.kodemybackend.infrastructure.store.MaterialStore; @@ -55,7 +54,9 @@ public static class MaterialAddGradeRequest { private String grade; } - public record GradePageable(Long id, Double value, UserDetails author) { + public record GradePageable(Long id, Double value, AuthorDetails author) { + public record AuthorDetails(Long id, String username) { + } } } diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/MaterialStatusService.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/MaterialStatusService.java index a8c93072..627b2543 100644 --- a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/MaterialStatusService.java +++ b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/MaterialStatusService.java @@ -10,8 +10,8 @@ import pl.sknikod.kodemycommons.security.AuthFacade; import pl.sknikod.kodemycommons.security.UserPrincipal; -import static pl.sknikod.kodemybackend.infrastructure.model.MaterialStatusUtil.getAuthorityForStatusChange; -import static pl.sknikod.kodemybackend.infrastructure.model.MaterialStatusUtil.getPossibleStatuses; +import static pl.sknikod.kodemybackend.infrastructure.module.material.model.MaterialStatusUtil.getAuthorityForStatusChange; +import static pl.sknikod.kodemybackend.infrastructure.module.material.model.MaterialStatusUtil.getPossibleStatuses; @Service @AllArgsConstructor diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/model/MaterialStatusUtil.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/model/MaterialStatusUtil.java similarity index 98% rename from kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/model/MaterialStatusUtil.java rename to kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/model/MaterialStatusUtil.java index f6d8e4b9..a367a8fc 100644 --- a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/model/MaterialStatusUtil.java +++ b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/model/MaterialStatusUtil.java @@ -1,4 +1,4 @@ -package pl.sknikod.kodemybackend.infrastructure.model; +package pl.sknikod.kodemybackend.infrastructure.module.material.model; import org.springframework.security.core.authority.SimpleGrantedAuthority; import pl.sknikod.kodemybackend.infrastructure.database.Material; diff --git a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/model/SingleMaterialResponse.java b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/model/SingleMaterialResponse.java index def9715d..ff2c6937 100644 --- a/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/model/SingleMaterialResponse.java +++ b/kodemy-backend/src/main/java/pl/sknikod/kodemybackend/infrastructure/module/material/model/SingleMaterialResponse.java @@ -2,11 +2,9 @@ import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.Hidden; -import io.vavr.control.Try; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import lombok.*; -import pl.sknikod.kodemybackend.infrastructure.model.UserDetails; import pl.sknikod.kodemybackend.infrastructure.database.Material; import java.time.LocalDateTime; @@ -28,12 +26,10 @@ public class SingleMaterialResponse { @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") LocalDateTime createdDate; - @EqualsAndHashCode(callSuper = true) @Value - public static class AuthorDetails extends UserDetails { - public AuthorDetails(Long id, String username) { - super(id, username); - } + public static class AuthorDetails { + Long id; + String username; } @Value diff --git a/kodemy-backend/src/main/resources/application.yml b/kodemy-backend/src/main/resources/application.yml index 9d8c3bf6..02b58bd2 100644 --- a/kodemy-backend/src/main/resources/application.yml +++ b/kodemy-backend/src/main/resources/application.yml @@ -63,15 +63,12 @@ management: network: route: auth: http://kodemy-auth:8080 - lan: - username: user - password: password - connect-timeout-ms: 3000 - read-timeout-ms: 5000 + connect-timeout-ms: 3000 + read-timeout-ms: 5000 jwt: secret-key: YWJjZGVmZ2hjvbwjrW5vcHFyc3R1dnd4eXoxMjM0NTY3OnDMTIzNDU2Nzg5MDEyMzQ1Njc4OTAf= - + eureka: client: serviceUrl: diff --git a/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/MvcSuperclassTest.java b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/MvcSuperclassTest.java new file mode 100644 index 00000000..ad796e1a --- /dev/null +++ b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/MvcSuperclassTest.java @@ -0,0 +1,17 @@ +package pl.sknikod.kodemybackend; + +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.context.annotation.Import; +import org.springframework.test.web.servlet.MockMvc; +import pl.sknikod.kodemybackend.configuration.SecurityConfiguration; +import pl.sknikod.kodemycommons.security.configuration.JwtConfiguration; + +@SpringBootTest +@AutoConfigureMockMvc +@Import({SecurityConfiguration.class, JwtConfiguration.class}) +public class MvcSuperclassTest extends SuperclassTest { + @Autowired + protected MockMvc mockMvc; +} diff --git a/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/SuperclassTest.java b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/SuperclassTest.java new file mode 100644 index 00000000..e8da5c61 --- /dev/null +++ b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/SuperclassTest.java @@ -0,0 +1,69 @@ +package pl.sknikod.kodemybackend; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.platform.commons.logging.LoggerFactory; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import pl.sknikod.kodemycommons.security.configuration.JwtConfiguration; + +import java.util.logging.Logger; + +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.MOCK +) +@ContextConfiguration(classes = KodemyBackendApplication.class) +@ImportAutoConfiguration(value = TestChannelBinderConfiguration.class) +@Import({JwtConfiguration.class}) +@Testcontainers +public class SuperclassTest { + @Container + private static final PostgreSQLContainer dataSource; + private static final WireMockServer wireMockServer; + + static { + dataSource = new PostgreSQLContainer<>("postgres:14.1-alpine"); + wireMockServer = new WireMockServer(WireMockConfiguration.options().dynamicPort()); + } + + @BeforeAll + public static void startWireMock() { + if (wireMockServer.isRunning()) { + return; + } + wireMockServer.start(); + } + + @AfterAll + public static void stopWireMock() { + if (!wireMockServer.isRunning()) { + return; + } + wireMockServer.stop(); + } + + @DynamicPropertySource + private static void containerProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", dataSource::getJdbcUrl); + registry.add("spring.datasource.username", dataSource::getUsername); + registry.add("spring.datasource.password", dataSource::getPassword); + + registry.add("network.route.auth", () -> "http://localhost:" + wireMockServer.port()); + } + + @DynamicPropertySource + private static void wireMockProperties(DynamicPropertyRegistry registry) { + registry.add("network.route.auth", () -> "http://localhost:8080"); + } +} \ No newline at end of file diff --git a/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/event/producer/MaterialCreatedProducerTest.java b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/event/producer/MaterialCreatedProducerTest.java new file mode 100644 index 00000000..36a34a32 --- /dev/null +++ b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/event/producer/MaterialCreatedProducerTest.java @@ -0,0 +1,40 @@ +package pl.sknikod.kodemybackend.infrastructure.event.producer; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.cloud.stream.function.StreamBridge; +import pl.sknikod.kodemybackend.SuperclassTest; +import pl.sknikod.kodemybackend.infrastructure.database.Category; +import pl.sknikod.kodemybackend.infrastructure.database.Material; +import pl.sknikod.kodemybackend.infrastructure.database.Section; + +import java.time.LocalDateTime; + +class MaterialCreatedProducerTest extends SuperclassTest { + + private final StreamBridge streamBridge = Mockito.mock(StreamBridge.class); + + private final MaterialCreatedProducer materialCreatedProducer = new MaterialCreatedProducer(streamBridge); + + private final ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Object.class); + + @Test + void publish_success() { + var material = new Material(); + material.setId(1L); + material.setCreatedDate(LocalDateTime.now()); + var category = new Category(); + category.setSection(new Section()); + material.setCategory(category); + + materialCreatedProducer.publish(MaterialCreatedProducer.Message.map(material, "username")); + + Mockito.verify(streamBridge, Mockito.times(1)) + .send(Mockito.any(), messageCaptor.capture()); + Assertions.assertEquals(((MaterialCreatedProducer.Message) messageCaptor.getValue()).getId(), material.getId()); + } +} \ No newline at end of file diff --git a/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/module/category/CategoryControllerTest.java b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/module/category/CategoryControllerTest.java new file mode 100644 index 00000000..90b0b994 --- /dev/null +++ b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/module/category/CategoryControllerTest.java @@ -0,0 +1,17 @@ +package pl.sknikod.kodemybackend.infrastructure.module.category; + +import org.junit.jupiter.api.Test; +import pl.sknikod.kodemybackend.MvcSuperclassTest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class CategoryControllerTest extends MvcSuperclassTest { + @Test + void getCategoryDetails_success() throws Exception { + mockMvc.perform(get("/api/categories/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(1)); + } +} \ No newline at end of file diff --git a/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/module/category/CategoryServiceTest.java b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/module/category/CategoryServiceTest.java new file mode 100644 index 00000000..117f265d --- /dev/null +++ b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/module/category/CategoryServiceTest.java @@ -0,0 +1,38 @@ +package pl.sknikod.kodemybackend.infrastructure.module.category; + +import io.vavr.control.Try; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import pl.sknikod.kodemybackend.SuperclassTest; +import pl.sknikod.kodemybackend.infrastructure.database.Category; +import pl.sknikod.kodemybackend.infrastructure.database.Section; +import pl.sknikod.kodemybackend.infrastructure.mapper.CategoryMapper; +import pl.sknikod.kodemybackend.infrastructure.store.CategoryStore; + +class CategoryServiceTest extends SuperclassTest { + + @MockBean + private CategoryStore categoryStore; + + @Autowired + private CategoryService categoryService; + + @Test + void showCategoryInfo_success() { + var category = new Category(); + category.setId(1L); + category.setSection(new Section()); + category.setName("name"); + + Mockito.when(categoryStore.findById(Mockito.eq(category.getId()))).thenReturn(Try.success(category)); + + var result = categoryService.showCategoryInfo(category.getId()); + + Assertions.assertNotNull(result); + Assertions.assertEquals(category.getId(), result.id()); + Assertions.assertEquals(category.getName(), result.name()); + } +} \ No newline at end of file diff --git a/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/store/CategoryStoreTest.java b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/store/CategoryStoreTest.java new file mode 100644 index 00000000..619b4acb --- /dev/null +++ b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/store/CategoryStoreTest.java @@ -0,0 +1,36 @@ +package pl.sknikod.kodemybackend.infrastructure.store; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import pl.sknikod.kodemybackend.infrastructure.database.Category; +import pl.sknikod.kodemybackend.infrastructure.database.CategoryRepository; +import pl.sknikod.kodemycommons.exception.NotFound404Exception; + +import java.util.Optional; + +class CategoryStoreTest { + + private final CategoryRepository repo = Mockito.mock(CategoryRepository.class); + private final CategoryStore store = new CategoryStore(repo); + + @Test + void findById_success() { + Mockito.when(repo.findById(Mockito.any(Long.class))).thenReturn(Optional.of(new Category())); + + var result = store.findById(1L); + + Assertions.assertFalse(result.isEmpty()); + } + + @Test + void findById_notFound() { + Mockito.when(repo.findById(Mockito.any(Long.class))).thenReturn(Optional.empty()); + + var result = store.findById(1L); + + Assertions.assertTrue(result.isEmpty()); + Assertions.assertInstanceOf(NotFound404Exception.class, result.getCause()); + } +} \ No newline at end of file diff --git a/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/store/MaterialStoreTest.java b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/store/MaterialStoreTest.java new file mode 100644 index 00000000..dc0a5570 --- /dev/null +++ b/kodemy-backend/src/test/java/pl/sknikod/kodemybackend/infrastructure/store/MaterialStoreTest.java @@ -0,0 +1,97 @@ +package pl.sknikod.kodemybackend.infrastructure.store; + +import io.vavr.control.Try; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import pl.sknikod.kodemybackend.infrastructure.database.Material; +import pl.sknikod.kodemybackend.infrastructure.database.MaterialRepository; +import pl.sknikod.kodemybackend.infrastructure.module.material.model.FilterSearchParams; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +class MaterialStoreTest { + + private final MaterialRepository repo = Mockito.mock(MaterialRepository.class); + private final UserStore userStore = Mockito.mock(UserStore.class); + private final GradeStore gradeStore = Mockito.mock(GradeStore.class); + + private final MaterialStore store = new MaterialStore(repo, userStore, gradeStore); + + private final Long ID = 1L; + private final Material.MaterialStatus NEW_STATUS = Material.MaterialStatus.APPROVED; + + @BeforeEach + void setUp() { + var material = new Material(); + material.setId(ID); + material.setUserId(ID); + material.setStatus(Material.MaterialStatus.PENDING); + + var user = new UserStore.User(); + user.setId(ID); + user.setUsername("username"); + + Mockito.when(repo.findById(Mockito.eq(ID))).thenReturn(Optional.of(material)); + Mockito.when(userStore.findById(Mockito.eq(ID))).thenReturn(Try.success(user)); + Mockito.when(gradeStore.findAvgGradeByMaterial(Mockito.eq(ID))).thenReturn(Try.success(1.0)); + Mockito.when(gradeStore.getGradeStats(Mockito.eq(ID))).thenReturn(Try.success(Collections.emptyList())); + + Mockito.when(repo.save(Mockito.any(Material.class))).thenReturn(material); + + Mockito.when(repo.searchMaterialsWithAvgGrades( + Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), + Mockito.any(), Mockito.any(), Mockito.any(), Mockito.eq(ID), + Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any() + )).thenReturn(new PageImpl<>(List.of(new Object[]{material, 1.0}), Pageable.ofSize(1), 1)); + + Mockito.doNothing().when(repo).updateStatus(Mockito.eq(ID), Mockito.eq(Material.MaterialStatus.PENDING)); + } + + + @Test + void findById_success() { + var result1 = store.findById(ID, true); + var result2 = store.findById(ID); + + Assertions.assertTrue(result1.isSuccess()); + Assertions.assertEquals(ID, result1.get().getMaterial().getId()); + Assertions.assertTrue(result2.isSuccess()); + Assertions.assertEquals(ID, result2.get().getMaterial().getId()); + } + + @Test + void save_success() { + var result = store.save(new Material()); + + Assertions.assertTrue(result.isSuccess()); + Assertions.assertNotEquals(null, result.get().getId()); + } + + @Test + void update_success() { + var result = store.update(new Material()); + + Assertions.assertTrue(result.isSuccess()); + Assertions.assertNotEquals(null, result.get().getId()); + } + + @Test + void findAll_success() { + var result = store.findAll(new FilterSearchParams(), null, ID, null); + + Assertions.assertFalse(result.isEmpty()); + } + + @Test + void changeStatus_success() { + var result = store.changeStatus(ID, NEW_STATUS); + + Assertions.assertTrue(result.isSuccess()); + } +} \ No newline at end of file diff --git a/kodemy-backend/src/test/resources/application-test.yml b/kodemy-backend/src/test/resources/application-test.yml new file mode 100644 index 00000000..e8bfed70 --- /dev/null +++ b/kodemy-backend/src/test/resources/application-test.yml @@ -0,0 +1,7 @@ +spring: + main: + allow-bean-definition-overriding: true + liquibase: + change-log: classpath:/db/changelog/db.changelog-test.xml + profiles: + active: test \ No newline at end of file diff --git a/kodemy-backend/src/test/resources/application.yml b/kodemy-backend/src/test/resources/application.yml deleted file mode 100644 index 102c7c90..00000000 --- a/kodemy-backend/src/test/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -spring: - main: - allow-bean-definition-overriding: true - liquibase: - change-log: classpath:/db/changelog/db.changelog-test.xml \ No newline at end of file diff --git a/kodemy-search/build.gradle b/kodemy-search/build.gradle index 58185953..cc6083be 100755 --- a/kodemy-search/build.gradle +++ b/kodemy-search/build.gradle @@ -71,6 +71,10 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + testImplementation 'org.springframework.cloud:spring-cloud-contract-wiremock' + testImplementation 'org.springframework.cloud:spring-cloud-stream' + testImplementation 'org.springframework.cloud:spring-cloud-stream-test-binder' + testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' } diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/RabbitConfiguration.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/RabbitConfiguration.java index f8065302..3197b44b 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/RabbitConfiguration.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/RabbitConfiguration.java @@ -78,72 +78,4 @@ public RabbitTemplate rabbitTemplate( rabbitTemplate.setMessageConverter(messageConverter); return rabbitTemplate; } - - @Component - @DependsOn("rabbitConfiguration") - @RequiredArgsConstructor - public static class DlqRabbitSwitch implements RabbitListenerConfigurer { - public static final String DLQ_SUFFIX = ".dlq"; - private final RabbitTemplate rabbitTemplate; - private final BindingServiceProperties bindingServiceProperties; - - @Override - public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) { - registrar.registerEndpoint(new DlqRabbitListenerEndpoint()); - } - - private class DlqRabbitListenerEndpoint extends AbstractRabbitListenerEndpoint { - @Override - @NonNull - protected MessageListener createMessageListener(@NonNull MessageListenerContainer container) { - final var queueNames = bindingServiceProperties - .getBindings().entrySet().stream() - .filter(binding -> binding.getKey().matches("[A-Za-z]+-in-\\d+")) - .map(Map.Entry::getValue) - .map(binding -> String.format("%s.%s%s", binding.getDestination(), binding.getGroup(), DLQ_SUFFIX)) - .toArray(String[]::new); - container.setQueueNames(queueNames); - return new DlqMessageListener(rabbitTemplate); - } - - @Override - @NonNull - public String getId() { - return getClass().getName(); - } - } - - @RequiredArgsConstructor - private static class DlqMessageListener implements MessageListener { - private static final String RETRY_HEADER = "x-retries"; - private static final String MAX_LENGTH_HEADER = "x-max-length"; - private final RabbitTemplate rabbitTemplate; - - @Override - public void onMessage(Message message) { - final var headers = message.getMessageProperties().getHeaders(); - final var routingKey = message.getMessageProperties().getReceivedRoutingKey(); - final var retry = (int) headers.getOrDefault(RETRY_HEADER, 0); - final var maxLength = (int) headers.getOrDefault(MAX_LENGTH_HEADER, 3); - if (retry >= maxLength) { - redirect(routingKey, RedirectTarget.PARKING_LOT, message); - return; - } - headers.put(RETRY_HEADER, retry + 1); - redirect(routingKey, RedirectTarget.ORIGINAL, message); - } - - private void redirect(String routingKey, RedirectTarget redirectTarget, Message message) { - String newRoutingKey = routingKey.replace(DLQ_SUFFIX, "") + redirectTarget.suffix; - rabbitTemplate.send("", newRoutingKey, message); - } - - @AllArgsConstructor - private enum RedirectTarget { - ORIGINAL(""), - PARKING_LOT(PARKING_LOT_SUFFIX); - private final String suffix; - } - } - } } diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/SecurityConfiguration.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/SecurityConfiguration.java index c23ad098..534166ec 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/SecurityConfiguration.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/SecurityConfiguration.java @@ -57,17 +57,12 @@ public ServletExceptionHandler servletExceptionHandler(ObjectMapper objectMapper } @Bean - public JwtConfiguration.JwtProperties jwtProperties() { - return new JwtConfiguration.JwtProperties(); + public JwtProvider jwtProvider(JwtConfiguration jwtConfiguration) { + return new JwtProvider(jwtConfiguration.getJwtProperties()); } @Bean - public JwtProvider jwtProvider(JwtConfiguration.JwtProperties jwtProperties) { - return new JwtProvider(jwtProperties); - } - - @Bean - public JwtAuthorizationFilter jwtAuthorizationFilter(JwtConfiguration.JwtProperties jwtProperties) { - return new JwtAuthorizationFilter(jwtProperties); + public JwtAuthorizationFilter jwtAuthorizationFilter(JwtProvider jwtProvider) { + return new JwtAuthorizationFilter(jwtProvider); } } \ No newline at end of file diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/WebConfiguration.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/WebConfiguration.java index e4258ae1..5812b281 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/WebConfiguration.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/WebConfiguration.java @@ -2,14 +2,22 @@ import io.vavr.control.Try; import jakarta.validation.ValidationException; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.converter.Converter; import org.springframework.format.FormatterRegistry; +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.lang.NonNull; +import org.springframework.web.client.RestTemplate; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.zalando.logbook.spring.LogbookClientHttpRequestInterceptor; import java.text.SimpleDateFormat; +import java.util.Collections; import java.util.Date; @Configuration @@ -31,4 +39,17 @@ public Date convert(@NonNull String source) { } }; } + + @Bean + @LoadBalanced + public RestTemplate restTemplate( + RestTemplateBuilder restTemplateBuilder, LogbookClientHttpRequestInterceptor logbookInterceptor + ) { + restTemplateBuilder.requestFactory(() -> { + var requestFactory = new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build()); + return new BufferingClientHttpRequestFactory(requestFactory); + }); + restTemplateBuilder.additionalInterceptors(Collections.singletonList(logbookInterceptor)); + return restTemplateBuilder.build(); + } } diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/rabbit/RabbitDlqErrorSwitch.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/rabbit/RabbitDlqErrorSwitch.java new file mode 100644 index 00000000..a72d830c --- /dev/null +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/configuration/rabbit/RabbitDlqErrorSwitch.java @@ -0,0 +1,86 @@ +package pl.sknikod.kodemysearch.configuration.rabbit; + +import lombok.AllArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageListener; +import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.AbstractRabbitListenerEndpoint; +import org.springframework.amqp.rabbit.listener.MessageListenerContainer; +import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar; +import org.springframework.cloud.stream.config.BindingServiceProperties; +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; +import pl.sknikod.kodemysearch.configuration.RabbitConfiguration; + +import java.util.Map; + +@Component +@DependsOn("rabbitConfiguration") +@RequiredArgsConstructor +public class RabbitDlqErrorSwitch implements RabbitListenerConfigurer { + public static final String DLQ_SUFFIX = ".dlq"; + private final RabbitTemplate rabbitTemplate; + private final BindingServiceProperties bindingServiceProperties; + + @Override + public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) { + registrar.registerEndpoint(new DlqRabbitListenerEndpoint()); + } + + private class DlqRabbitListenerEndpoint extends AbstractRabbitListenerEndpoint { + @Override + @NonNull + protected MessageListener createMessageListener(@NonNull MessageListenerContainer container) { + final var queueNames = bindingServiceProperties + .getBindings().entrySet().stream() + .filter(binding -> binding.getKey().matches("[A-Za-z]+-in-\\d+")) + .map(Map.Entry::getValue) + .map(binding -> String.format("%s.%s%s", binding.getDestination(), binding.getGroup(), DLQ_SUFFIX)) + .toArray(String[]::new); + container.setQueueNames(queueNames); + return new DlqMessageListener(rabbitTemplate); + } + + @Override + @NonNull + public String getId() { + return getClass().getName(); + } + } + + @RequiredArgsConstructor + private static class DlqMessageListener implements MessageListener { + private static final String RETRY_HEADER = "x-retries"; + private static final String MAX_LENGTH_HEADER = "x-max-length"; + private final RabbitTemplate rabbitTemplate; + + @Override + public void onMessage(Message message) { + final var headers = message.getMessageProperties().getHeaders(); + final var routingKey = message.getMessageProperties().getReceivedRoutingKey(); + final var retry = (int) headers.getOrDefault(RETRY_HEADER, 0); + final var maxLength = (int) headers.getOrDefault(MAX_LENGTH_HEADER, 3); + if (retry >= maxLength) { + redirect(routingKey, DlqMessageListener.RedirectTarget.PARKING_LOT, message); + return; + } + headers.put(RETRY_HEADER, retry + 1); + redirect(routingKey, DlqMessageListener.RedirectTarget.ORIGINAL, message); + } + + private void redirect(String routingKey, DlqMessageListener.RedirectTarget redirectTarget, Message message) { + String newRoutingKey = routingKey.replace(DLQ_SUFFIX, "") + redirectTarget.suffix; + rabbitTemplate.send("", newRoutingKey, message); + } + + @AllArgsConstructor + private enum RedirectTarget { + ORIGINAL(""), + PARKING_LOT(RabbitConfiguration.PARKING_LOT_SUFFIX); + private final String suffix; + } + } +} diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialCreatedConsumer.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialCreatedConsumer.java similarity index 90% rename from kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialCreatedConsumer.java rename to kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialCreatedConsumer.java index 8a9138eb..6d60601e 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialCreatedConsumer.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialCreatedConsumer.java @@ -1,4 +1,4 @@ -package pl.sknikod.kodemysearch.infrastructure.module.material.consumer; +package pl.sknikod.kodemysearch.infrastructure.event.consumer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialStatusUpdatedConsumer.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialStatusUpdatedConsumer.java similarity index 90% rename from kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialStatusUpdatedConsumer.java rename to kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialStatusUpdatedConsumer.java index 8b3e95df..06a39093 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialStatusUpdatedConsumer.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialStatusUpdatedConsumer.java @@ -1,4 +1,4 @@ -package pl.sknikod.kodemysearch.infrastructure.module.material.consumer; +package pl.sknikod.kodemysearch.infrastructure.event.consumer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialTagsUpdatedConsumer.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialTagsUpdatedConsumer.java similarity index 85% rename from kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialTagsUpdatedConsumer.java rename to kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialTagsUpdatedConsumer.java index bcd17af8..889174ef 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialTagsUpdatedConsumer.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialTagsUpdatedConsumer.java @@ -1,4 +1,4 @@ -package pl.sknikod.kodemysearch.infrastructure.module.material.consumer; +package pl.sknikod.kodemysearch.infrastructure.event.consumer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialUpdatedConsumer.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialUpdatedConsumer.java similarity index 90% rename from kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialUpdatedConsumer.java rename to kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialUpdatedConsumer.java index cff3ac79..4dfdd1c8 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/consumer/MaterialUpdatedConsumer.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/event/consumer/MaterialUpdatedConsumer.java @@ -1,4 +1,4 @@ -package pl.sknikod.kodemysearch.infrastructure.module.material.consumer; +package pl.sknikod.kodemysearch.infrastructure.event.consumer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/ModuleBeanConfiguration.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/ModuleBeanConfiguration.java index 38f72604..c3d228e4 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/ModuleBeanConfiguration.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/ModuleBeanConfiguration.java @@ -5,9 +5,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; -import pl.sknikod.kodemysearch.infrastructure.dao.MaterialSearchDao; -import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialAddUpdateService; -import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialSearchService; @Configuration public class ModuleBeanConfiguration { @@ -18,19 +15,4 @@ public ObjectMapper objectMapper() { objectMapper.registerModule(new JavaTimeModule()); return objectMapper; } - - @Bean - public MaterialAddUpdateService materialAddUpdateService( - MaterialSearchDao materialSearchDao, - ObjectMapper objectMapper, - MaterialAddUpdateService.MaterialIndexDataMapper materialIndexDataMapper - ) { - return new MaterialAddUpdateService(materialSearchDao, objectMapper, materialIndexDataMapper); - } - - @Bean - public MaterialSearchService materialSearchService( - MaterialSearchDao materialSearchDao, MaterialSearchService.MaterialSearchMapper materialSearchMapper) { - return new MaterialSearchService(materialSearchDao, materialSearchMapper); - } } diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialAddUpdateService.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialAddUpdateService.java index b630d2cf..07ba716e 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialAddUpdateService.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialAddUpdateService.java @@ -8,18 +8,18 @@ import org.mapstruct.MappingConstants; import org.opensearch.client.opensearch._types.WriteResponseBase; import org.springframework.context.annotation.DependsOn; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import pl.sknikod.kodemycommons.exception.content.ExceptionUtil; -import pl.sknikod.kodemysearch.infrastructure.dao.MaterialSearchDao; +import pl.sknikod.kodemysearch.infrastructure.store.MaterialSearchStore; import pl.sknikod.kodemysearch.infrastructure.module.material.model.MaterialIndexData; import pl.sknikod.kodemysearch.infrastructure.module.material.model.MaterialIndexEvent; @Slf4j -@Component +@Service @RequiredArgsConstructor @DependsOn("rabbitConfiguration") public class MaterialAddUpdateService { - private final MaterialSearchDao materialSearchDao; + private final MaterialSearchStore materialSearchStore; private final ObjectMapper objectMapper; private final MaterialIndexDataMapper mapper; @@ -31,14 +31,14 @@ private Try mapToMaterialIndexData(String msg) { public String index(String msg) { return mapToMaterialIndexData(msg) - .flatMap(materialSearchDao::save) + .flatMap(materialSearchStore::save) .map(WriteResponseBase::id) .getOrElseThrow(ExceptionUtil::throwIfFailure); } public String reindex(String msg) { return mapToMaterialIndexData(msg) - .flatMap(materialSearchDao::update) + .flatMap(materialSearchStore::update) .map(WriteResponseBase::id) .getOrElseThrow(ExceptionUtil::throwIfFailure); } diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialSearchService.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialSearchService.java index 84ac3b1f..4dcd621c 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialSearchService.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialSearchService.java @@ -11,8 +11,9 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; import pl.sknikod.kodemycommons.exception.content.ExceptionUtil; -import pl.sknikod.kodemysearch.infrastructure.dao.MaterialSearchDao; +import pl.sknikod.kodemysearch.infrastructure.store.MaterialSearchStore; import pl.sknikod.kodemysearch.infrastructure.module.material.model.MaterialFilterSearchParams; import pl.sknikod.kodemysearch.infrastructure.module.material.model.MaterialIndexData; import pl.sknikod.kodemysearch.infrastructure.module.material.model.MaterialPageable; @@ -20,14 +21,15 @@ import java.util.List; import java.util.Objects; +@Service @RequiredArgsConstructor @Slf4j public class MaterialSearchService { - private final MaterialSearchDao materialSearchDao; + private final MaterialSearchStore materialSearchStore; private final MaterialSearchMapper mapper; public Page search(MaterialFilterSearchParams filterSearchParams, Pageable pageRequest) { - return materialSearchDao.search(mapToSearchCriteria(filterSearchParams, pageRequest)) + return materialSearchStore.search(mapToSearchCriteria(filterSearchParams, pageRequest)) .map(page -> new PageImpl<>(mapper.map(page.getContent()), page.getPageable(), page.getTotalElements())) .getOrElseThrow(ExceptionUtil::throwIfFailure); } diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialUpdateStatusService.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialUpdateStatusService.java index 9a02ccf3..8ea8185b 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialUpdateStatusService.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/module/material/MaterialUpdateStatusService.java @@ -5,18 +5,16 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.opensearch.client.opensearch._types.WriteResponseBase; -import org.springframework.context.annotation.DependsOn; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import pl.sknikod.kodemycommons.exception.content.ExceptionUtil; -import pl.sknikod.kodemysearch.infrastructure.dao.MaterialSearchDao; +import pl.sknikod.kodemysearch.infrastructure.store.MaterialSearchStore; import pl.sknikod.kodemysearch.infrastructure.module.material.model.MaterialStatusChangeData; @Slf4j -@Component +@Service @RequiredArgsConstructor -@DependsOn("rabbitConfiguration") public class MaterialUpdateStatusService { - private final MaterialSearchDao materialSearchDao; + private final MaterialSearchStore materialSearchStore; private final ObjectMapper objectMapper; private Try mapToMaterialStatusChangeData(String msg) { @@ -26,7 +24,7 @@ private Try mapToMaterialStatusChangeData(String msg) public String updateStatus(String msg) { return mapToMaterialStatusChangeData(msg) - .flatMap(d -> materialSearchDao.update(d.getId(), d.getStatus())) + .flatMap(d -> materialSearchStore.update(d.getId(), d.getStatus())) .map(WriteResponseBase::id) .getOrElseThrow(ExceptionUtil::throwIfFailure); } diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/dao/MaterialSearchDao.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/store/MaterialSearchStore.java similarity index 95% rename from kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/dao/MaterialSearchDao.java rename to kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/store/MaterialSearchStore.java index 4f21aaa3..bc59f158 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/dao/MaterialSearchDao.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/infrastructure/store/MaterialSearchStore.java @@ -1,4 +1,4 @@ -package pl.sknikod.kodemysearch.infrastructure.dao; +package pl.sknikod.kodemysearch.infrastructure.store; import io.vavr.control.Try; import lombok.RequiredArgsConstructor; @@ -15,7 +15,7 @@ import pl.sknikod.kodemysearch.infrastructure.module.material.SearchRequestBuilder; import pl.sknikod.kodemysearch.infrastructure.module.material.model.MaterialIndexData; import pl.sknikod.kodemysearch.infrastructure.module.material.model.MaterialStatus; -import pl.sknikod.kodemysearch.util.data.SearchDao; +import pl.sknikod.kodemysearch.util.data.SearchStore; import java.util.Map; import java.util.Set; @@ -23,7 +23,7 @@ @Slf4j @Component @RequiredArgsConstructor -public class MaterialSearchDao implements SearchDao { +public class MaterialSearchStore implements SearchStore { private final String INDEX = "materials"; private final OpenSearchClient openSearchClient; diff --git a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/util/data/SearchDao.java b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/util/data/SearchStore.java similarity index 84% rename from kodemy-search/src/main/java/pl/sknikod/kodemysearch/util/data/SearchDao.java rename to kodemy-search/src/main/java/pl/sknikod/kodemysearch/util/data/SearchStore.java index afb4f1b6..608df4a0 100644 --- a/kodemy-search/src/main/java/pl/sknikod/kodemysearch/util/data/SearchDao.java +++ b/kodemy-search/src/main/java/pl/sknikod/kodemysearch/util/data/SearchStore.java @@ -4,7 +4,7 @@ import org.opensearch.client.opensearch.core.IndexResponse; import org.opensearch.client.opensearch.core.UpdateResponse; -public interface SearchDao { +public interface SearchStore { Try save(T object); Try> update(T object); diff --git a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/BaseTest.java b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/BaseTest.java deleted file mode 100644 index 7b4ea254..00000000 --- a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/BaseTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package pl.sknikod.kodemysearch; - -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.TestExecutionListeners; -import pl.sknikod.kodemysearch.configuration.TestOpenSearchConfig; -import pl.sknikod.kodemysearch.configuration.TestSecurityConfig; -import pl.sknikod.kodemysearch.infrastructure.module.TestModuleConfig; - -@SpringBootTest -@ImportAutoConfiguration(value = { - TestSecurityConfig.class, - TestOpenSearchConfig.class, - TestModuleConfig.class -}) -@TestExecutionListeners( - listeners = {WithUserPrincipalTestExecutionListener.class}, - mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS -) -public abstract class BaseTest { -} diff --git a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/MvcTest.java b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/MvcTest.java deleted file mode 100644 index fc8b3c0b..00000000 --- a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/MvcTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package pl.sknikod.kodemysearch; - - -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.http.HttpHeaders; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.ResultActions; -import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; - -@SpringBootTest -@AutoConfigureMockMvc -public abstract class MvcTest extends BaseTest { - @Autowired - protected MockMvc mockMvc; - - protected final ResultActions mvcPerform(MockHttpServletRequestBuilder request) throws Exception { - return mockMvc.perform(request); - } - - protected final ResultActions mvcPerformWithBearerAuth(MockHttpServletRequestBuilder request) throws Exception { - return this.mvcPerform(request.header(HttpHeaders.AUTHORIZATION, "Bearer ")); - } -} diff --git a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/SuperclassTest.java b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/SuperclassTest.java new file mode 100644 index 00000000..5061516e --- /dev/null +++ b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/SuperclassTest.java @@ -0,0 +1,19 @@ +package pl.sknikod.kodemysearch; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import pl.sknikod.kodemycommons.security.configuration.JwtConfiguration; + +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.MOCK +) +@ContextConfiguration(classes = KodemyBackendApplication.class) +@ImportAutoConfiguration(value = TestChannelBinderConfiguration.class) +@Import({JwtConfiguration.class}) +public class SuperclassTest { +} \ No newline at end of file diff --git a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/WithUserPrincipal.java b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/WithUserPrincipal.java deleted file mode 100644 index 5ac58484..00000000 --- a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/WithUserPrincipal.java +++ /dev/null @@ -1,17 +0,0 @@ -package pl.sknikod.kodemysearch; - -import java.lang.annotation.*; - -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@Documented -public @interface WithUserPrincipal { - long id() default 1L; - - String username() default "username"; - - String[] authorities() default {}; - - boolean authenticated() default true; -} \ No newline at end of file diff --git a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/WithUserPrincipalTestExecutionListener.java b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/WithUserPrincipalTestExecutionListener.java deleted file mode 100644 index beec620f..00000000 --- a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/WithUserPrincipalTestExecutionListener.java +++ /dev/null @@ -1,52 +0,0 @@ -package pl.sknikod.kodemysearch; - -import org.springframework.lang.NonNull; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.test.context.TestContext; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; -import pl.sknikod.kodemycommons.security.UserPrincipal; - -import java.util.Arrays; -import java.util.Collection; - -public class WithUserPrincipalTestExecutionListener extends DependencyInjectionTestExecutionListener { - @Override - public void beforeTestMethod(@NonNull TestContext testContext) throws Exception { - super.beforeTestMethod(testContext); - var withUserPrincipal = testContext.getTestMethod().getAnnotation(WithUserPrincipal.class); - if (withUserPrincipal == null) - withUserPrincipal = testContext.getTestClass().getAnnotation(WithUserPrincipal.class); - - if (withUserPrincipal != null) { - final var userPrincipal = toUserPrincipal(withUserPrincipal); - final var authenticationToken = withUserPrincipal.authenticated() ? - new UsernamePasswordAuthenticationToken(userPrincipal, null, userPrincipal.getAuthorities()) : - new UsernamePasswordAuthenticationToken(userPrincipal, null); - SecurityContextHolder.getContext().setAuthentication(authenticationToken); - } - } - - private UserPrincipal toUserPrincipal(WithUserPrincipal withUserPrincipal) { - return new UserPrincipal( - withUserPrincipal.id(), - withUserPrincipal.username(), - toAuthorities(withUserPrincipal.authorities()) - ); - } - - private Collection toAuthorities(String[] authorities) { - return Arrays.stream(authorities).map(SimpleGrantedAuthority::new).toList(); - } - - @Override - public void afterTestMethod(@NonNull TestContext testContext) throws Exception { - super.afterTestMethod(testContext); - var isAnnotation = testContext.getTestMethod().isAnnotationPresent(WithUserPrincipal.class); - if (!isAnnotation) - isAnnotation = testContext.getTestClass().isAnnotationPresent(WithUserPrincipal.class); - if (isAnnotation) - SecurityContextHolder.clearContext(); - } -} \ No newline at end of file diff --git a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/configuration/TestOpenSearchConfig.java b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/configuration/TestOpenSearchConfig.java deleted file mode 100644 index b60f7f93..00000000 --- a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/configuration/TestOpenSearchConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package pl.sknikod.kodemysearch.configuration; - -import org.mockito.Mockito; -import org.opensearch.client.opensearch.OpenSearchClient; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; - -@TestConfiguration -public class TestOpenSearchConfig { - @Bean - public OpenSearchClient openSearchClient() { - return Mockito.mock(OpenSearchClient.class); - } -} diff --git a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/configuration/TestSecurityConfig.java b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/configuration/TestSecurityConfig.java deleted file mode 100644 index 5dad008f..00000000 --- a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/configuration/TestSecurityConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package pl.sknikod.kodemysearch.configuration; - -import org.mockito.Mockito; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import pl.sknikod.kodemycommons.exception.handler.ServletExceptionHandler; -import pl.sknikod.kodemycommons.security.JwtAuthorizationFilter; -import pl.sknikod.kodemycommons.security.JwtProvider; - -@TestConfiguration -public class TestSecurityConfig { - @Bean - public ServletExceptionHandler servletExceptionHandler() { - return Mockito.mock(ServletExceptionHandler.class); - } - - @Bean - public JwtAuthorizationFilter jwtAuthorizationFilter( - ) { - return Mockito.mock(JwtAuthorizationFilter.class); - } - - @Bean - public JwtProvider jwtProvider() { - return Mockito.mock(JwtProvider.class); - } -} diff --git a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/factory/TokenFactory.java b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/factory/TokenFactory.java deleted file mode 100644 index 77295c66..00000000 --- a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/factory/TokenFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -package pl.sknikod.kodemysearch.factory; - -import pl.sknikod.kodemycommons.security.JwtProvider; - -import java.util.Collections; -import java.util.Date; -import java.util.UUID; - -public class TokenFactory { - private TokenFactory() { - } - - public static JwtProvider.Token jwtServiceToken = jwtServiceToken(); - public static JwtProvider.Token.Deserialize jwtServiceTokenDeserialize = jwtServiceTokenDeserialize(); - - private static JwtProvider.Token jwtServiceToken() { - return new JwtProvider.Token( - UUID.randomUUID(), - "header.payload.signature", - new Date() - ); - } - - private static JwtProvider.Token.Deserialize jwtServiceTokenDeserialize() { - return new JwtProvider.Token.Deserialize( - 1L, - "username", - 1, - Collections.emptySet() - ); - } -} \ No newline at end of file diff --git a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/infrastructure/module/TestModuleConfig.java b/kodemy-search/src/test/java/pl/sknikod/kodemysearch/infrastructure/module/TestModuleConfig.java deleted file mode 100644 index ccf3f659..00000000 --- a/kodemy-search/src/test/java/pl/sknikod/kodemysearch/infrastructure/module/TestModuleConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package pl.sknikod.kodemysearch.infrastructure.module; - -import org.mockito.Mockito; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialAddUpdateService; -import pl.sknikod.kodemysearch.infrastructure.module.material.MaterialSearchService; - -@TestConfiguration -public class TestModuleConfig { - @Bean - public MaterialAddUpdateService materialAddUpdateService() { - return Mockito.mock(MaterialAddUpdateService.class); - } - - @Bean - public MaterialSearchService materialSearchService() { - return Mockito.mock(MaterialSearchService.class); - } -} diff --git a/kodemy-search/src/test/resources/application-test.yml b/kodemy-search/src/test/resources/application-test.yml new file mode 100644 index 00000000..d9fbedb7 --- /dev/null +++ b/kodemy-search/src/test/resources/application-test.yml @@ -0,0 +1,5 @@ +spring: + main: + allow-bean-definition-overriding: true + profiles: + active: test \ No newline at end of file diff --git a/kodemy-search/src/test/resources/application.yml b/kodemy-search/src/test/resources/application.yml deleted file mode 100644 index 3aefce01..00000000 --- a/kodemy-search/src/test/resources/application.yml +++ /dev/null @@ -1,3 +0,0 @@ -spring: - main: - allow-bean-definition-overriding: true \ No newline at end of file