From 788ac6cb9e4d5df1dcfd346ff783ae37b776dcd4 Mon Sep 17 00:00:00 2001 From: Egor Cherniak Date: Fri, 27 Jun 2025 14:52:30 +0300 Subject: [PATCH 1/7] Revert "Auth via tokenkeeper (#73)" This reverts commit 520a524690bbc53d967793b40fdcab0faccc09a9. --- pom.xml | 69 +++++++++++++++---- .../anapi/v2/config/ApplicationConfig.java | 19 ++--- .../anapi/v2/config/KeycloakConfig.java | 60 ++++++++++++++++ .../anapi/v2/config/SecurityConfig.java | 67 ++++++++++++++++++ .../dev/vality/anapi/v2/config/WebConfig.java | 54 +++++++++------ .../config/properties/KeycloakProperties.java | 34 +++++++++ .../v2/controller/ErrorControllerAdvice.java | 12 ++-- .../v2/exception/TokenKeeperException.java | 12 ---- .../anapi/v2/security/AccessService.java | 9 ++- .../v2/security/AnapiBouncerContext.java | 3 +- .../v2/security/BouncerContextFactory.java | 28 ++++---- .../anapi/v2/service/KeycloakService.java | 17 +++++ .../anapi/v2/service/TokenKeeperService.java | 48 ------------- .../dev/vality/anapi/v2/util/JwtUtil.java | 33 --------- src/main/resources/application.yml | 13 +++- .../dev/vality/anapi/v2/AnalyticsTest.java | 21 ++---- .../java/dev/vality/anapi/v2/ReportsTest.java | 27 ++------ .../anapi/v2/SearchChargebacksTest.java | 20 ++---- .../anapi/v2/SearchInvoiceTemplatesTest.java | 20 ++---- .../vality/anapi/v2/SearchInvoicesTest.java | 20 ++---- .../vality/anapi/v2/SearchPaymentsTest.java | 20 ++---- .../vality/anapi/v2/SearchPayoutsTest.java | 20 ++---- .../vality/anapi/v2/SearchRefundsTest.java | 20 ++---- .../auth/KeycloakOpenIdTestConfiguration.java | 6 +- .../v2/auth/utils/KeycloakOpenIdStub.java | 43 +++++++++++- ...stractKeycloakOpenIdAsWiremockConfig.java} | 12 +++- .../v2/controller/ErrorControllerTest.java | 33 +++------ .../vality/anapi/v2/testutil/BouncerUtil.java | 26 ------- .../vality/anapi/v2/testutil/MagistaUtil.java | 19 +++++ .../anapi/v2/testutil/TokenKeeperUtil.java | 24 ------- 30 files changed, 435 insertions(+), 374 deletions(-) create mode 100644 src/main/java/dev/vality/anapi/v2/config/KeycloakConfig.java create mode 100644 src/main/java/dev/vality/anapi/v2/config/SecurityConfig.java create mode 100644 src/main/java/dev/vality/anapi/v2/config/properties/KeycloakProperties.java delete mode 100644 src/main/java/dev/vality/anapi/v2/exception/TokenKeeperException.java create mode 100644 src/main/java/dev/vality/anapi/v2/service/KeycloakService.java delete mode 100644 src/main/java/dev/vality/anapi/v2/service/TokenKeeperService.java delete mode 100644 src/main/java/dev/vality/anapi/v2/util/JwtUtil.java rename src/test/java/dev/vality/anapi/v2/config/{AbstractConfig.java => AbstractKeycloakOpenIdAsWiremockConfig.java} (67%) delete mode 100644 src/test/java/dev/vality/anapi/v2/testutil/BouncerUtil.java delete mode 100644 src/test/java/dev/vality/anapi/v2/testutil/TokenKeeperUtil.java diff --git a/pom.xml b/pom.xml index 46cfb4ae..6dd774fc 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ anapi-v2 - 1.0.4 + 1.0.3 jar anapi-v2 @@ -44,7 +44,7 @@ dev.vality bouncer-proto - 1.51-23d1761 + 1.46-d5e5639 dev.vality @@ -69,7 +69,7 @@ dev.vality analytics-proto - 1.43-2d1fdc2 + 1.41-f691834 dev.vality @@ -83,19 +83,60 @@ dev.vality damsel - 1.614-3df747f - - - dev.vality - token-keeper-proto - 1.32-8b8bb43 + 1.597-bfedcb9 + + org.springframework.boot + spring-boot-starter-security + org.springframework.boot spring-boot-starter-aop + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-web + + + org.keycloak + keycloak-admin-client + 15.1.1 + + + org.jboss.resteasy + resteasy-client + + + org.jboss.resteasy + resteasy-multipart-provider + + + org.jboss.resteasy + resteasy-jackson2-provider + + + org.jboss.resteasy + resteasy-jaxb-provider + + + + + org.keycloak + keycloak-spring-security-adapter + 15.1.1 + + + org.bouncycastle + bcprov-jdk15on + + + org.springframework.boot spring-boot-starter @@ -132,7 +173,7 @@ io.swagger swagger-annotations - 1.6.12 + 1.6.8 provided @@ -181,7 +222,7 @@ org.openapitools jackson-databind-nullable - 0.2.6 + 0.2.3 provided @@ -213,7 +254,7 @@ com.github.tomakehurst wiremock-jre8-standalone - 2.35.1 + 2.34.0 test @@ -256,12 +297,12 @@ org.apache.maven.plugins maven-remote-resources-plugin - 3.1.0 + 3.0.0 org.apache.maven.shared maven-filtering - 3.3.1 + 3.3.0 diff --git a/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java b/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java index 4f9c8b77..f83b6b56 100644 --- a/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java +++ b/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java @@ -1,17 +1,16 @@ package dev.vality.anapi.v2.config; import dev.vality.bouncer.decisions.ArbiterSrv; -import dev.vality.damsel.analytics.AnalyticsServiceSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; -import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.reporter.ReportingSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityEmailExtensionKit; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityIdExtensionKit; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityRealmExtensionKit; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityUsernameExtensionKit; import dev.vality.woody.thrift.impl.http.THSpawnClientBuilder; +import dev.vality.damsel.analytics.AnalyticsServiceSrv; +import dev.vality.damsel.vortigon.VortigonServiceSrv; +import dev.vality.orgmanagement.AuthContextProviderSrv; +import dev.vality.reporter.ReportingSrv; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -87,14 +86,4 @@ public ReportingSrv.Iface reporterClient( .withAddress(resource.getURI()) .build(ReportingSrv.Iface.class); } - - @Bean - public TokenAuthenticatorSrv.Iface tokenKeeperClient( - @Value("${service.tokenKeeper.url}") Resource resource, - @Value("${service.tokenKeeper.networkTimeout}") int networkTimeout) throws IOException { - return new THSpawnClientBuilder() - .withNetworkTimeout(networkTimeout) - .withAddress(resource.getURI()) - .build(TokenAuthenticatorSrv.Iface.class); - } } diff --git a/src/main/java/dev/vality/anapi/v2/config/KeycloakConfig.java b/src/main/java/dev/vality/anapi/v2/config/KeycloakConfig.java new file mode 100644 index 00000000..d5b1c66c --- /dev/null +++ b/src/main/java/dev/vality/anapi/v2/config/KeycloakConfig.java @@ -0,0 +1,60 @@ +package dev.vality.anapi.v2.config; + +import dev.vality.anapi.v2.config.properties.KeycloakProperties; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.keycloak.adapters.KeycloakConfigResolver; +import org.keycloak.adapters.KeycloakDeployment; +import org.keycloak.adapters.KeycloakDeploymentBuilder; +import org.keycloak.representations.adapters.config.AdapterConfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Configuration +@ConditionalOnProperty(value = "auth.enabled", havingValue = "true") +public class KeycloakConfig { + + private final KeycloakProperties keycloakProperties; + + @Bean + public KeycloakConfigResolver keycloakConfigResolver() { + return facade -> { + KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(adapterConfig()); + deployment.setNotBefore(keycloakProperties.getNotBefore()); + return deployment; + }; + } + + private AdapterConfig adapterConfig() { + if (StringUtils.hasLength(keycloakProperties.getRealmPublicKeyPath())) { + keycloakProperties.setRealmPublicKey(readKeyFromFile(keycloakProperties.getRealmPublicKeyPath())); + } + + AdapterConfig adapterConfig = new AdapterConfig(); + adapterConfig.setRealm(keycloakProperties.getRealm()); + adapterConfig.setRealmKey(keycloakProperties.getRealmPublicKey()); + adapterConfig.setResource(keycloakProperties.getResource()); + adapterConfig.setAuthServerUrl(keycloakProperties.getAuthServerUrl()); + adapterConfig.setUseResourceRoleMappings(true); + adapterConfig.setBearerOnly(true); + adapterConfig.setSslRequired(keycloakProperties.getSslRequired()); + return adapterConfig; + } + + @SneakyThrows + private String readKeyFromFile(String filePath) { + List strings = Files.readAllLines(Paths.get(filePath)); + strings.remove(strings.size() - 1); + strings.remove(0); + return strings.stream().map(String::trim).collect(Collectors.joining()); + } + +} diff --git a/src/main/java/dev/vality/anapi/v2/config/SecurityConfig.java b/src/main/java/dev/vality/anapi/v2/config/SecurityConfig.java new file mode 100644 index 00000000..f04157b1 --- /dev/null +++ b/src/main/java/dev/vality/anapi/v2/config/SecurityConfig.java @@ -0,0 +1,67 @@ +package dev.vality.anapi.v2.config; + +import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents; +import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy; +import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +@Configuration +@EnableWebSecurity +@ComponentScan( + basePackageClasses = KeycloakSecurityComponents.class, + excludeFilters = @ComponentScan.Filter( + type = FilterType.REGEX, + pattern = "org.keycloak.adapters.springsecurity.management.HttpSessionManager")) +@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) +@ConditionalOnProperty(value = "auth.enabled", havingValue = "true") +public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { + + @Bean + @Override + protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { + return new NullAuthenticatedSessionStrategy(); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + super.configure(http); + http + .cors().and() + .csrf().disable() + .authorizeRequests() + .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .antMatchers(HttpMethod.GET, "/**/health").permitAll() + .antMatchers(HttpMethod.GET, "/**/prometheus").permitAll() + .anyRequest().authenticated(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) { + auth.authenticationProvider(keycloakAuthenticationProvider()); + } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.applyPermitDefaultValues(); + configuration.addAllowedMethod(HttpMethod.PUT); + configuration.addAllowedMethod(HttpMethod.DELETE); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } +} diff --git a/src/main/java/dev/vality/anapi/v2/config/WebConfig.java b/src/main/java/dev/vality/anapi/v2/config/WebConfig.java index bee665e4..37bf35aa 100644 --- a/src/main/java/dev/vality/anapi/v2/config/WebConfig.java +++ b/src/main/java/dev/vality/anapi/v2/config/WebConfig.java @@ -1,12 +1,17 @@ package dev.vality.anapi.v2.config; import dev.vality.woody.api.flow.WFlow; +import dev.vality.woody.api.trace.context.metadata.user.UserIdentityEmailExtensionKit; +import dev.vality.woody.api.trace.context.metadata.user.UserIdentityIdExtensionKit; +import dev.vality.woody.api.trace.context.metadata.user.UserIdentityRealmExtensionKit; +import dev.vality.woody.api.trace.context.metadata.user.UserIdentityUsernameExtensionKit; +import org.keycloak.KeycloakSecurityContext; +import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; +import org.keycloak.representations.AccessToken; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.OncePerRequestFilter; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -14,27 +19,18 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.security.Principal; import java.time.Instant; import java.time.temporal.ChronoUnit; import static dev.vality.anapi.v2.util.DeadlineUtil.*; +import static dev.vality.woody.api.trace.ContextUtils.setCustomMetadataValue; import static dev.vality.woody.api.trace.ContextUtils.setDeadline; @Configuration @SuppressWarnings({"ParameterName", "LocalVariableName"}) public class WebConfig { - @Bean - public WebMvcConfigurer corsConfigurer() { - return new WebMvcConfigurer() { - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowedOriginPatterns("*"); - } - }; - } - @Bean public FilterRegistrationBean woodyFilter() { WFlow woodyFlow = new WFlow(); @@ -45,15 +41,20 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { woodyFlow.createServiceFork( - () -> { - try { - setWoodyDeadline(request); - filterChain.doFilter(request, response); - } catch (IOException | ServletException e) { - sneakyThrow(e); - } + () -> { + try { + if (request.getUserPrincipal() != null) { + addWoodyContext(request.getUserPrincipal()); } - ) + + setWoodyDeadline(request); + + filterChain.doFilter(request, response); + } catch (IOException | ServletException e) { + sneakyThrow(e); + } + } + ) .run(); } @@ -70,6 +71,17 @@ private T sneakyThrow(Throwable t) throws E { return filterRegistrationBean; } + private void addWoodyContext(Principal principal) { + KeycloakSecurityContext keycloakSecurityContext = + ((KeycloakAuthenticationToken) principal).getAccount().getKeycloakSecurityContext(); + AccessToken accessToken = keycloakSecurityContext.getToken(); + + setCustomMetadataValue(UserIdentityIdExtensionKit.KEY, accessToken.getSubject()); + setCustomMetadataValue(UserIdentityUsernameExtensionKit.KEY, accessToken.getPreferredUsername()); + setCustomMetadataValue(UserIdentityEmailExtensionKit.KEY, accessToken.getEmail()); + setCustomMetadataValue(UserIdentityRealmExtensionKit.KEY, keycloakSecurityContext.getRealm()); + } + private void setWoodyDeadline(HttpServletRequest request) { String xRequestDeadline = request.getHeader("X-Request-Deadline"); String xRequestId = request.getHeader("X-Request-ID"); diff --git a/src/main/java/dev/vality/anapi/v2/config/properties/KeycloakProperties.java b/src/main/java/dev/vality/anapi/v2/config/properties/KeycloakProperties.java new file mode 100644 index 00000000..57b9a4f0 --- /dev/null +++ b/src/main/java/dev/vality/anapi/v2/config/properties/KeycloakProperties.java @@ -0,0 +1,34 @@ +package dev.vality.anapi.v2.config.properties; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotEmpty; + +@Getter +@Setter +@Component +@Validated +@ConfigurationProperties(prefix = "keycloak") +public class KeycloakProperties { + + @NotEmpty + private String realm; + @NotEmpty + private String authServerUrl; + @NotEmpty + private String resource; + + private Integer notBefore; + + @NotEmpty + private String sslRequired; + + private String realmPublicKey; + + private String realmPublicKeyPath; + +} diff --git a/src/main/java/dev/vality/anapi/v2/controller/ErrorControllerAdvice.java b/src/main/java/dev/vality/anapi/v2/controller/ErrorControllerAdvice.java index 2d290786..35fac6f8 100644 --- a/src/main/java/dev/vality/anapi/v2/controller/ErrorControllerAdvice.java +++ b/src/main/java/dev/vality/anapi/v2/controller/ErrorControllerAdvice.java @@ -1,6 +1,9 @@ package dev.vality.anapi.v2.controller; -import dev.vality.anapi.v2.exception.*; +import dev.vality.anapi.v2.exception.AuthorizationException; +import dev.vality.anapi.v2.exception.BadRequestException; +import dev.vality.anapi.v2.exception.DeadlineException; +import dev.vality.anapi.v2.exception.NotFoundException; import dev.vality.anapi.v2.model.DefaultLogicError; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -8,6 +11,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; import org.springframework.util.CollectionUtils; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotSupportedException; @@ -80,15 +84,15 @@ public Object handleMissingServletRequestParameterException(MissingServletReques } - @ExceptionHandler({TokenKeeperException.class}) + @ExceptionHandler({AccessDeniedException.class}) @ResponseStatus(HttpStatus.FORBIDDEN) - public void handleTokenKeeperException(TokenKeeperException e) { + public void handleAccessDeniedException(AccessDeniedException e) { log.warn("<- Res [403]: Request denied access", e); } @ExceptionHandler({AuthorizationException.class}) @ResponseStatus(HttpStatus.FORBIDDEN) - public void handleAuthorizationException(AuthorizationException e) { + public void handleAccessDeniedException(AuthorizationException e) { log.warn("<- Res [403]: Request denied access", e); } diff --git a/src/main/java/dev/vality/anapi/v2/exception/TokenKeeperException.java b/src/main/java/dev/vality/anapi/v2/exception/TokenKeeperException.java deleted file mode 100644 index 930c036f..00000000 --- a/src/main/java/dev/vality/anapi/v2/exception/TokenKeeperException.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.vality.anapi.v2.exception; - -public class TokenKeeperException extends RuntimeException { - - public TokenKeeperException(String s) { - super(s); - } - - public TokenKeeperException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/dev/vality/anapi/v2/security/AccessService.java b/src/main/java/dev/vality/anapi/v2/security/AccessService.java index 0aefd7e7..5a9c0b90 100644 --- a/src/main/java/dev/vality/anapi/v2/security/AccessService.java +++ b/src/main/java/dev/vality/anapi/v2/security/AccessService.java @@ -3,7 +3,7 @@ import dev.vality.anapi.v2.exception.AuthorizationException; import dev.vality.anapi.v2.exception.BouncerException; import dev.vality.anapi.v2.service.BouncerService; -import dev.vality.anapi.v2.service.TokenKeeperService; +import dev.vality.anapi.v2.service.KeycloakService; import dev.vality.anapi.v2.service.VortigonService; import dev.vality.bouncer.base.Entity; import lombok.RequiredArgsConstructor; @@ -24,7 +24,7 @@ public class AccessService { private final VortigonService vortigonService; private final BouncerService bouncerService; - private final TokenKeeperService tokenKeeperService; + private final KeycloakService keycloakService; @Value("${service.bouncer.auth.enabled}") private boolean authEnabled; @@ -86,13 +86,16 @@ private List getRestrictedShops(AccessData accessData, @Nullable List shopIds) { + var token = keycloakService.getAccessToken(); return AnapiBouncerContext.builder() .operationId(accessData.getOperationId()) .partyId(accessData.getPartyId()) .shopIds(shopIds) .fileId(accessData.getFileId()) .reportId(accessData.getReportId()) - .authData(tokenKeeperService.getAuthData()) + .tokenExpiration(token.getExp()) + .tokenId(token.getId()) + .userId(token.getSubject()) .build(); } } diff --git a/src/main/java/dev/vality/anapi/v2/security/AnapiBouncerContext.java b/src/main/java/dev/vality/anapi/v2/security/AnapiBouncerContext.java index b00f4eed..cfe6d68e 100644 --- a/src/main/java/dev/vality/anapi/v2/security/AnapiBouncerContext.java +++ b/src/main/java/dev/vality/anapi/v2/security/AnapiBouncerContext.java @@ -1,6 +1,5 @@ package dev.vality.anapi.v2.security; -import dev.vality.token.keeper.AuthData; import lombok.Builder; import lombok.Data; @@ -18,6 +17,6 @@ public class AnapiBouncerContext { private final List shopIds; private final String reportId; private final String fileId; - private final AuthData authData; + } diff --git a/src/main/java/dev/vality/anapi/v2/security/BouncerContextFactory.java b/src/main/java/dev/vality/anapi/v2/security/BouncerContextFactory.java index 9a496bd4..b68fc2ab 100644 --- a/src/main/java/dev/vality/anapi/v2/security/BouncerContextFactory.java +++ b/src/main/java/dev/vality/anapi/v2/security/BouncerContextFactory.java @@ -1,8 +1,8 @@ package dev.vality.anapi.v2.security; import dev.vality.anapi.v2.config.properties.BouncerProperties; +import dev.vality.anapi.v2.service.KeycloakService; import dev.vality.anapi.v2.service.OrgManagerService; -import dev.vality.anapi.v2.util.JwtUtil; import dev.vality.bouncer.base.Entity; import dev.vality.bouncer.context.v1.*; import dev.vality.bouncer.ctx.ContextFragmentType; @@ -14,7 +14,6 @@ import org.springframework.stereotype.Component; import java.time.Instant; -import java.util.Optional; import java.util.Set; @RequiredArgsConstructor @@ -24,6 +23,7 @@ public class BouncerContextFactory { private final BouncerProperties bouncerProperties; private final OrgManagerService orgManagerService; + private final KeycloakService keycloakService; @SneakyThrows public Context buildContext(AnapiBouncerContext bouncerContext) { @@ -32,17 +32,11 @@ public Context buildContext(AnapiBouncerContext bouncerContext) { var fragment = new dev.vality.bouncer.ctx.ContextFragment() .setType(ContextFragmentType.v1_thrift_binary) .setContent(serializer.serialize(contextFragment)); - + var userFragment = orgManagerService.getUserAuthContext( + keycloakService.getAccessToken().getSubject()); var context = new Context(); - context.putToFragments("anapi", fragment); - context.putToFragments("token-keeper", bouncerContext.getAuthData().getContext()); - - Optional subject = JwtUtil.getSubject(bouncerContext.getAuthData().getToken()); - if (subject.isPresent()) { - log.debug("User context fragment will be added"); - var userFragment = orgManagerService.getUserAuthContext(subject.get()); - context.putToFragments("user", userFragment); - } + context.putToFragments(bouncerProperties.getContextFragmentId(), fragment); + context.putToFragments("user", userFragment); return context; } @@ -52,11 +46,21 @@ private ContextFragment buildContextFragment(AnapiBouncerContext bouncerContext) var contextReports = buildReportContext(bouncerContext); ContextFragment fragment = new ContextFragment(); return fragment + .setAuth(buildAuth()) .setEnv(env) .setAnapi(contextAnalyticsApi) .setReports(contextReports); } + private Auth buildAuth() { + var auth = new Auth(); + var accessToken = keycloakService.getAccessToken(); + return auth + .setToken(new Token().setId(accessToken.getId())) + .setMethod(bouncerProperties.getAuthMethod()) + .setExpiration(Instant.ofEpochSecond(accessToken.getExp()).toString()); + } + private Environment buildEnvironment() { var deployment = new Deployment() .setId(bouncerProperties.getDeploymentId()); diff --git a/src/main/java/dev/vality/anapi/v2/service/KeycloakService.java b/src/main/java/dev/vality/anapi/v2/service/KeycloakService.java new file mode 100644 index 00000000..a898d18e --- /dev/null +++ b/src/main/java/dev/vality/anapi/v2/service/KeycloakService.java @@ -0,0 +1,17 @@ +package dev.vality.anapi.v2.service; + +import org.keycloak.KeycloakPrincipal; +import org.keycloak.representations.AccessToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +@Service +public class KeycloakService { + + public AccessToken getAccessToken() { + var keycloakPrincipal = (KeycloakPrincipal) SecurityContextHolder.getContext() + .getAuthentication() + .getPrincipal(); + return keycloakPrincipal.getKeycloakSecurityContext().getToken(); + } +} diff --git a/src/main/java/dev/vality/anapi/v2/service/TokenKeeperService.java b/src/main/java/dev/vality/anapi/v2/service/TokenKeeperService.java deleted file mode 100644 index 1acc7a8e..00000000 --- a/src/main/java/dev/vality/anapi/v2/service/TokenKeeperService.java +++ /dev/null @@ -1,48 +0,0 @@ -package dev.vality.anapi.v2.service; - -import dev.vality.anapi.v2.exception.TokenKeeperException; -import dev.vality.token.keeper.AuthData; -import dev.vality.token.keeper.TokenAuthenticatorSrv; -import dev.vality.token.keeper.TokenSourceContext; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.http.HttpHeaders; -import org.apache.thrift.TException; -import org.springframework.stereotype.Service; -import org.springframework.util.ObjectUtils; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import java.util.Optional; - - -@Slf4j -@Service -@RequiredArgsConstructor -public class TokenKeeperService { - - private static final String bearerPrefix = "Bearer "; - private final TokenAuthenticatorSrv.Iface tokenKeeperClient; - - public AuthData getAuthData() { - log.debug("Retrieving auth info"); - try { - var token = getBearerToken(); - return tokenKeeperClient.authenticate( - token.orElseThrow(() -> new TokenKeeperException("Token not found!")), new TokenSourceContext()); - } catch (TException e) { - throw new TokenKeeperException("Error while call token keeper: ", e); - } - } - - private Optional getBearerToken() { - var attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - if (ObjectUtils.isEmpty(attributes) - || ObjectUtils.isEmpty(attributes.getRequest().getHeader(HttpHeaders.AUTHORIZATION))) { - return Optional.empty(); - } - String token = attributes.getRequest().getHeader(HttpHeaders.AUTHORIZATION).substring(bearerPrefix.length()); - return Optional.of(token); - } - -} diff --git a/src/main/java/dev/vality/anapi/v2/util/JwtUtil.java b/src/main/java/dev/vality/anapi/v2/util/JwtUtil.java deleted file mode 100644 index c61b2f2c..00000000 --- a/src/main/java/dev/vality/anapi/v2/util/JwtUtil.java +++ /dev/null @@ -1,33 +0,0 @@ -package dev.vality.anapi.v2.util; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; - -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -@Slf4j -@UtilityClass -public class JwtUtil { - - private static final ObjectMapper objectMapper = new ObjectMapper(); - private static final String subjectFieldName = "sub"; - - public static Optional getSubject(String token) { - try { - String[] chunks = token.split("\\."); - Base64.Decoder decoder = Base64.getUrlDecoder(); - String payload = new String(decoder.decode(chunks[1])); - Map parsedPayload = objectMapper.readValue(payload, HashMap.class); - if (parsedPayload.containsKey(subjectFieldName)) { - return Optional.of(String.valueOf(parsedPayload.get(subjectFieldName))); - } - } catch (Exception e) { - log.warn("Unable to parse jwt token while looking for subject: ", e); - } - return Optional.empty(); - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 302f7c73..8c8e4b11 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -33,9 +33,6 @@ service: orgManager: url: http://localhost:8022/change_it networkTimeout: 5000 - tokenKeeper: - url: http://localhost:8022/change_it - networkTimeout: 5000 bouncer: url: http://localhost:8022/change_it networkTimeout: 10000 @@ -60,3 +57,13 @@ spring: info: version: '@project.version@' stage: dev + +keycloak: + realm: internal + auth-server-url: http://keycloak:8080/auth/ + resource: common-api + not-before: 0 + ssl-required: none + realm-public-key: + +auth.enabled: true diff --git a/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java b/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java index 8df6814a..ce9efb77 100644 --- a/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java +++ b/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java @@ -1,6 +1,6 @@ package dev.vality.anapi.v2; -import dev.vality.anapi.v2.config.AbstractConfig; +import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.AnalyticsUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; @@ -8,7 +8,6 @@ import dev.vality.damsel.analytics.AnalyticsServiceSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; import org.junit.jupiter.api.AfterEach; @@ -25,9 +24,8 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createJudgementAllowed; -import static dev.vality.anapi.v2.testutil.TokenKeeperUtil.createAuthData; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -36,7 +34,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -class AnalyticsTest extends AbstractConfig { +class AnalyticsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockBean public VortigonServiceSrv.Iface vortigonClient; @@ -46,8 +44,6 @@ class AnalyticsTest extends AbstractConfig { public ArbiterSrv.Iface bouncerClient; @MockBean private AnalyticsServiceSrv.Iface analyticsClient; - @MockBean - public TokenAuthenticatorSrv.Iface tokenKeeperClient; @Autowired private MockMvc mvc; @@ -59,8 +55,7 @@ class AnalyticsTest extends AbstractConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{analyticsClient, vortigonClient, - orgManagerClient, bouncerClient, tokenKeeperClient}; + preparedMocks = new Object[]{analyticsClient, vortigonClient, orgManagerClient, bouncerClient}; } @AfterEach @@ -73,7 +68,6 @@ public void clean() throws Exception { @SneakyThrows void getAveragePaymentRequiredParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(analyticsClient.getAveragePayment(any())).thenReturn(AnalyticsUtil.createAveragePaymentRequiredResponse()); @@ -88,7 +82,6 @@ void getAveragePaymentRequiredParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(analyticsClient, times(1)).getAveragePayment(any()); @@ -98,7 +91,6 @@ void getAveragePaymentRequiredParamsRequestSuccess() { @SneakyThrows void getAveragePaymentAllParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(analyticsClient.getAveragePayment(any())).thenReturn(AnalyticsUtil.createAveragePaymentAllResponse()); @@ -113,7 +105,6 @@ void getAveragePaymentAllParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(analyticsClient, times(1)).getAveragePayment(any()); @@ -141,7 +132,6 @@ void getAveragePaymentRequestInvalid() { @SneakyThrows void getAveragePaymentRequestServerUnavailable() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(analyticsClient.getAveragePayment(any())).thenThrow(TException.class); @@ -155,7 +145,6 @@ void getAveragePaymentRequestServerUnavailable() { .andDo(print()) .andExpect(status().is5xxServerError()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(analyticsClient, times(1)).getAveragePayment(any()); diff --git a/src/test/java/dev/vality/anapi/v2/ReportsTest.java b/src/test/java/dev/vality/anapi/v2/ReportsTest.java index 25084afb..fbcf5821 100644 --- a/src/test/java/dev/vality/anapi/v2/ReportsTest.java +++ b/src/test/java/dev/vality/anapi/v2/ReportsTest.java @@ -1,12 +1,11 @@ package dev.vality.anapi.v2; -import dev.vality.anapi.v2.config.AbstractConfig; +import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import dev.vality.reporter.ReportingSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; import org.junit.jupiter.api.AfterEach; @@ -22,14 +21,13 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createJudgementAllowed; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; import static dev.vality.anapi.v2.testutil.OpenApiUtil.getReportsRequiredParams; import static dev.vality.anapi.v2.testutil.RandomUtil.randomInt; import static dev.vality.anapi.v2.testutil.RandomUtil.randomIntegerAsString; import static dev.vality.anapi.v2.testutil.ReporterUtil.createReport; import static dev.vality.anapi.v2.testutil.ReporterUtil.createSearchReportsResponse; -import static dev.vality.anapi.v2.testutil.TokenKeeperUtil.createAuthData; import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -39,7 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -class ReportsTest extends AbstractConfig { +class ReportsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockBean public VortigonServiceSrv.Iface vortigonClient; @@ -49,8 +47,6 @@ class ReportsTest extends AbstractConfig { public ArbiterSrv.Iface bouncerClient; @MockBean private ReportingSrv.Iface reporterClient; - @MockBean - public TokenAuthenticatorSrv.Iface tokenKeeperClient; @Autowired private MockMvc mvc; @@ -62,8 +58,7 @@ class ReportsTest extends AbstractConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[] {reporterClient, vortigonClient, orgManagerClient, - bouncerClient, tokenKeeperClient}; + preparedMocks = new Object[] {reporterClient, vortigonClient, orgManagerClient, bouncerClient}; } @AfterEach @@ -77,7 +72,6 @@ public void clean() throws Exception { void cancelReportRequestSuccess() { when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); int reportId = randomInt(1, 1000); mvc.perform(post("/lk/v2/reports/{reportId}/cancel", reportId) .header("Authorization", "Bearer " + generateSimpleJwt()) @@ -90,7 +84,6 @@ void cancelReportRequestSuccess() { .andExpect(status().isAccepted()) .andExpect(jsonPath("$").doesNotExist()); verify(orgManagerClient, times(1)).getUserContext(any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(reporterClient, times(1)).cancelReport(reportId); } @@ -100,7 +93,6 @@ void cancelReportRequestSuccess() { void cancelReportRequestServerUnavailable() { when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); int reportId = randomInt(1, 1000); doThrow(new TException()).when(reporterClient).cancelReport(reportId); mvc.perform(post("/lk/v2/reports/{reportId}/cancel", reportId) @@ -114,7 +106,6 @@ void cancelReportRequestServerUnavailable() { .andExpect(status().isInternalServerError()) .andExpect(jsonPath("$").doesNotExist()); verify(orgManagerClient, times(1)).getUserContext(any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(reporterClient, times(1)).cancelReport(reportId); } @@ -124,7 +115,6 @@ void cancelReportRequestServerUnavailable() { void createReportRequestSuccess() { when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); long reportId = randomInt(1, 1000); when(reporterClient.createReport(any(), any())).thenReturn(reportId); when(reporterClient.getReport(reportId)).thenReturn(createReport(reportId)); @@ -139,7 +129,6 @@ void createReportRequestSuccess() { .andExpect(status().isCreated()) .andExpect(jsonPath("$").exists()); verify(orgManagerClient, times(1)).getUserContext(any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(reporterClient, times(1)).createReport(any(), any()); verify(reporterClient, times(1)).getReport(reportId); @@ -150,7 +139,6 @@ void createReportRequestSuccess() { void downloadUrlRequestSuccess() { when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); String reportId = randomIntegerAsString(1, 1000); String fileId = randomIntegerAsString(1, 1000); when(reporterClient.generatePresignedUrl(eq(fileId), any())).thenReturn("www.google.ru"); @@ -165,7 +153,6 @@ void downloadUrlRequestSuccess() { .andExpect(status().isOk()) .andExpect(jsonPath("$").exists()); verify(orgManagerClient, times(1)).getUserContext(any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(reporterClient, times(1)).generatePresignedUrl(eq(fileId), notNull()); } @@ -175,7 +162,6 @@ void downloadUrlRequestSuccess() { void getReportRequestSuccess() { when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); long reportId = randomInt(1, 1000); when(reporterClient.getReport(reportId)).thenReturn(createReport(reportId)); mvc.perform(get("/lk/v2/reports/{reportID}", reportId) @@ -189,7 +175,6 @@ void getReportRequestSuccess() { .andExpect(status().isOk()) .andExpect(jsonPath("$").exists()); verify(orgManagerClient, times(1)).getUserContext(any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(reporterClient, times(1)).getReport(reportId); } @@ -198,7 +183,6 @@ void getReportRequestSuccess() { @SneakyThrows void getSearchReportsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(reporterClient.getReports(any())).thenReturn(createSearchReportsResponse()); @@ -213,7 +197,6 @@ void getSearchReportsRequestSuccess() { .andExpect(status().isOk()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(reporterClient, times(1)).getReports(notNull()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java b/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java index 8252aeb1..c0cea864 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java @@ -1,6 +1,6 @@ package dev.vality.anapi.v2; -import dev.vality.anapi.v2.config.AbstractConfig; +import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; @@ -8,7 +8,6 @@ import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; import org.junit.jupiter.api.AfterEach; @@ -25,9 +24,8 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createJudgementAllowed; -import static dev.vality.anapi.v2.testutil.TokenKeeperUtil.createAuthData; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -37,7 +35,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -class SearchChargebacksTest extends AbstractConfig { +class SearchChargebacksTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockBean public MerchantStatisticsServiceSrv.Iface magistaClient; @@ -47,8 +45,6 @@ class SearchChargebacksTest extends AbstractConfig { public AuthContextProviderSrv.Iface orgManagerClient; @MockBean public ArbiterSrv.Iface bouncerClient; - @MockBean - public TokenAuthenticatorSrv.Iface tokenKeeperClient; @Autowired private MockMvc mvc; @@ -60,7 +56,7 @@ class SearchChargebacksTest extends AbstractConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient, tokenKeeperClient}; + preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; } @AfterEach @@ -73,7 +69,6 @@ public void clean() throws Exception { @SneakyThrows void searchChargebacksRequiredParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchChargebacks(any())).thenReturn(MagistaUtil.createSearchChargebackRequiredResponse()); @@ -88,7 +83,6 @@ void searchChargebacksRequiredParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchChargebacks(any()); @@ -98,7 +92,6 @@ void searchChargebacksRequiredParamsRequestSuccess() { @SneakyThrows void searchChargebacksAllParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchChargebacks(any())).thenReturn(MagistaUtil.createSearchChargebackAllResponse()); @@ -113,7 +106,6 @@ void searchChargebacksAllParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchChargebacks(any()); @@ -141,7 +133,6 @@ void searchChargebacksRequestInvalid() { @SneakyThrows void searchChargebacksRequestMagistaUnavailable() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayments(any())).thenThrow(TException.class); @@ -155,7 +146,6 @@ void searchChargebacksRequestMagistaUnavailable() { .andDo(print()) .andExpect(status().is5xxServerError()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchChargebacks(any()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java b/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java index 7e76009d..908a5354 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java @@ -1,6 +1,6 @@ package dev.vality.anapi.v2; -import dev.vality.anapi.v2.config.AbstractConfig; +import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; @@ -8,7 +8,6 @@ import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; import org.junit.jupiter.api.AfterEach; @@ -25,9 +24,8 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createJudgementAllowed; -import static dev.vality.anapi.v2.testutil.TokenKeeperUtil.createAuthData; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -36,7 +34,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -class SearchInvoiceTemplatesTest extends AbstractConfig { +class SearchInvoiceTemplatesTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockBean public MerchantStatisticsServiceSrv.Iface magistaClient; @@ -46,8 +44,6 @@ class SearchInvoiceTemplatesTest extends AbstractConfig { public AuthContextProviderSrv.Iface orgManagerClient; @MockBean public ArbiterSrv.Iface bouncerClient; - @MockBean - public TokenAuthenticatorSrv.Iface tokenKeeperClient; @Autowired private MockMvc mvc; @@ -59,7 +55,7 @@ class SearchInvoiceTemplatesTest extends AbstractConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient, tokenKeeperClient}; + preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; } @AfterEach @@ -72,7 +68,6 @@ public void clean() throws Exception { @SneakyThrows void searchInvoiceTemplatesRequiredParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoiceTemplates(any())).thenReturn( @@ -88,7 +83,6 @@ void searchInvoiceTemplatesRequiredParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoiceTemplates(any()); @@ -98,7 +92,6 @@ void searchInvoiceTemplatesRequiredParamsRequestSuccess() { @SneakyThrows void searchInvoiceTemplatesAllParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoiceTemplates(any())).thenReturn( @@ -114,7 +107,6 @@ void searchInvoiceTemplatesAllParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoiceTemplates(any()); @@ -142,7 +134,6 @@ void searchInvoiceTemplatesRequestInvalid() { @SneakyThrows void searchInvoiceTemplatesRequestMagistaUnavailable() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoiceTemplates(any())).thenThrow(TException.class); @@ -156,7 +147,6 @@ void searchInvoiceTemplatesRequestMagistaUnavailable() { .andDo(print()) .andExpect(status().is5xxServerError()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoiceTemplates(any()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java b/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java index 3cc9822b..1d220e1d 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java @@ -1,6 +1,6 @@ package dev.vality.anapi.v2; -import dev.vality.anapi.v2.config.AbstractConfig; +import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; @@ -8,7 +8,6 @@ import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; import org.junit.jupiter.api.AfterEach; @@ -25,9 +24,8 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createJudgementAllowed; -import static dev.vality.anapi.v2.testutil.TokenKeeperUtil.createAuthData; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -36,7 +34,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -class SearchInvoicesTest extends AbstractConfig { +class SearchInvoicesTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockBean public MerchantStatisticsServiceSrv.Iface magistaClient; @@ -45,8 +43,6 @@ class SearchInvoicesTest extends AbstractConfig { @MockBean public AuthContextProviderSrv.Iface orgManagerClient; @MockBean - public TokenAuthenticatorSrv.Iface tokenKeeperClient; - @MockBean public ArbiterSrv.Iface bouncerClient; @Autowired @@ -59,7 +55,7 @@ class SearchInvoicesTest extends AbstractConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient, tokenKeeperClient}; + preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; } @AfterEach @@ -72,7 +68,6 @@ public void clean() throws Exception { @SneakyThrows void searchInvoicesRequiredParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoices(any())).thenReturn(MagistaUtil.createSearchInvoiceRequiredResponse()); @@ -87,7 +82,6 @@ void searchInvoicesRequiredParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoices(any()); @@ -97,7 +91,6 @@ void searchInvoicesRequiredParamsRequestSuccess() { @SneakyThrows void searchInvoicesAllParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoices(any())).thenReturn(MagistaUtil.createSearchInvoiceAllResponse()); @@ -112,7 +105,6 @@ void searchInvoicesAllParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoices(any()); @@ -140,7 +132,6 @@ void searchInvoicesRequestInvalid() { @SneakyThrows void searchInvoicesRequestMagistaUnavailable() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoices(any())).thenThrow(TException.class); @@ -154,7 +145,6 @@ void searchInvoicesRequestMagistaUnavailable() { .andDo(print()) .andExpect(status().is5xxServerError()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoices(any()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java b/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java index d9285c49..641d397e 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java @@ -1,6 +1,6 @@ package dev.vality.anapi.v2; -import dev.vality.anapi.v2.config.AbstractConfig; +import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; @@ -8,7 +8,6 @@ import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; import org.junit.jupiter.api.AfterEach; @@ -25,9 +24,8 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createJudgementAllowed; -import static dev.vality.anapi.v2.testutil.TokenKeeperUtil.createAuthData; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -36,7 +34,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -class SearchPaymentsTest extends AbstractConfig { +class SearchPaymentsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockBean public MerchantStatisticsServiceSrv.Iface magistaClient; @@ -46,8 +44,6 @@ class SearchPaymentsTest extends AbstractConfig { public AuthContextProviderSrv.Iface orgManagerClient; @MockBean public ArbiterSrv.Iface bouncerClient; - @MockBean - public TokenAuthenticatorSrv.Iface tokenKeeperClient; @Autowired private MockMvc mvc; @@ -59,7 +55,7 @@ class SearchPaymentsTest extends AbstractConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient, tokenKeeperClient}; + preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; } @AfterEach @@ -72,7 +68,6 @@ public void clean() throws Exception { @SneakyThrows void searchPaymentsRequiredParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayments(any())).thenReturn(MagistaUtil.createSearchPaymentRequiredResponse()); @@ -87,7 +82,6 @@ void searchPaymentsRequiredParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchPayments(any()); @@ -97,7 +91,6 @@ void searchPaymentsRequiredParamsRequestSuccess() { @SneakyThrows void searchPaymentsAllParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayments(any())).thenReturn(MagistaUtil.createSearchPaymentAllResponse()); @@ -112,7 +105,6 @@ void searchPaymentsAllParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchPayments(any()); @@ -140,7 +132,6 @@ void searchPaymentsRequestInvalid() { @SneakyThrows void searchPaymentsRequestMagistaUnavailable() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayments(any())).thenThrow(TException.class); @@ -154,7 +145,6 @@ void searchPaymentsRequestMagistaUnavailable() { .andDo(print()) .andExpect(status().is5xxServerError()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchPayments(any()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchPayoutsTest.java b/src/test/java/dev/vality/anapi/v2/SearchPayoutsTest.java index 0d05e881..3f016a37 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchPayoutsTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchPayoutsTest.java @@ -1,6 +1,6 @@ package dev.vality.anapi.v2; -import dev.vality.anapi.v2.config.AbstractConfig; +import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; @@ -8,7 +8,6 @@ import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; import org.junit.jupiter.api.AfterEach; @@ -25,9 +24,8 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createJudgementAllowed; -import static dev.vality.anapi.v2.testutil.TokenKeeperUtil.createAuthData; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -36,7 +34,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -class SearchPayoutsTest extends AbstractConfig { +class SearchPayoutsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockBean public MerchantStatisticsServiceSrv.Iface magistaClient; @@ -46,8 +44,6 @@ class SearchPayoutsTest extends AbstractConfig { public AuthContextProviderSrv.Iface orgManagerClient; @MockBean public ArbiterSrv.Iface bouncerClient; - @MockBean - public TokenAuthenticatorSrv.Iface tokenKeeperClient; @Autowired private MockMvc mvc; @@ -59,7 +55,7 @@ class SearchPayoutsTest extends AbstractConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient, tokenKeeperClient}; + preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; } @AfterEach @@ -72,7 +68,6 @@ public void clean() throws Exception { @SneakyThrows void searchPayoutsRequiredParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayouts(any())).thenReturn(MagistaUtil.createSearchPayoutRequiredResponse()); @@ -87,7 +82,6 @@ void searchPayoutsRequiredParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchPayouts(any()); @@ -97,7 +91,6 @@ void searchPayoutsRequiredParamsRequestSuccess() { @SneakyThrows void searchPayoutsAllParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayouts(any())).thenReturn(MagistaUtil.createSearchPayoutAllResponse()); @@ -112,7 +105,6 @@ void searchPayoutsAllParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchPayouts(any()); @@ -140,7 +132,6 @@ void searchPayoutsRequestInvalid() { @SneakyThrows void searchPayoutsRequestMagistaUnavailable() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayouts(any())).thenThrow(TException.class); @@ -154,7 +145,6 @@ void searchPayoutsRequestMagistaUnavailable() { .andDo(print()) .andExpect(status().is5xxServerError()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchPayouts(any()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java b/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java index d52996de..86342e21 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java @@ -1,6 +1,6 @@ package dev.vality.anapi.v2; -import dev.vality.anapi.v2.config.AbstractConfig; +import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; @@ -8,7 +8,6 @@ import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; import org.junit.jupiter.api.AfterEach; @@ -25,9 +24,8 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createJudgementAllowed; -import static dev.vality.anapi.v2.testutil.TokenKeeperUtil.createAuthData; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; +import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -36,7 +34,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -class SearchRefundsTest extends AbstractConfig { +class SearchRefundsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockBean public MerchantStatisticsServiceSrv.Iface magistaClient; @@ -46,8 +44,6 @@ class SearchRefundsTest extends AbstractConfig { public AuthContextProviderSrv.Iface orgManagerClient; @MockBean public ArbiterSrv.Iface bouncerClient; - @MockBean - public TokenAuthenticatorSrv.Iface tokenKeeperClient; @Autowired private MockMvc mvc; @@ -59,7 +55,7 @@ class SearchRefundsTest extends AbstractConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient, tokenKeeperClient}; + preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; } @AfterEach @@ -72,7 +68,6 @@ public void clean() throws Exception { @SneakyThrows void searchRefundsRequiredParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchRefunds(any())).thenReturn(MagistaUtil.createSearchRefundRequiredResponse()); @@ -87,7 +82,6 @@ void searchRefundsRequiredParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchRefunds(any()); @@ -97,7 +91,6 @@ void searchRefundsRequiredParamsRequestSuccess() { @SneakyThrows void searchRefundsAllParamsRequestSuccess() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchRefunds(any())).thenReturn(MagistaUtil.createSearchRefundAllResponse()); @@ -112,7 +105,6 @@ void searchRefundsAllParamsRequestSuccess() { .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchRefunds(any()); @@ -140,7 +132,6 @@ void searchRefundsRequestInvalid() { @SneakyThrows void searchRefundsRequestMagistaUnavailable() { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchRefunds(any())).thenThrow(TException.class); @@ -154,7 +145,6 @@ void searchRefundsRequestMagistaUnavailable() { .andDo(print()) .andExpect(status().is5xxServerError()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchRefunds(any()); diff --git a/src/test/java/dev/vality/anapi/v2/auth/KeycloakOpenIdTestConfiguration.java b/src/test/java/dev/vality/anapi/v2/auth/KeycloakOpenIdTestConfiguration.java index 534454ea..872b1bd1 100644 --- a/src/test/java/dev/vality/anapi/v2/auth/KeycloakOpenIdTestConfiguration.java +++ b/src/test/java/dev/vality/anapi/v2/auth/KeycloakOpenIdTestConfiguration.java @@ -10,7 +10,9 @@ public class KeycloakOpenIdTestConfiguration { @Bean - public KeycloakOpenIdStub keycloakOpenIdStub(JwtTokenBuilder jwtTokenBuilder) { - return new KeycloakOpenIdStub(jwtTokenBuilder); + public KeycloakOpenIdStub keycloakOpenIdStub(@Value("${keycloak.auth-server-url}") String keycloakAuthServerUrl, + @Value("${keycloak.realm}") String keycloakRealm, + JwtTokenBuilder jwtTokenBuilder) { + return new KeycloakOpenIdStub(keycloakAuthServerUrl, keycloakRealm, jwtTokenBuilder); } } diff --git a/src/test/java/dev/vality/anapi/v2/auth/utils/KeycloakOpenIdStub.java b/src/test/java/dev/vality/anapi/v2/auth/utils/KeycloakOpenIdStub.java index 0eeece9e..0ff3b0a9 100644 --- a/src/test/java/dev/vality/anapi/v2/auth/utils/KeycloakOpenIdStub.java +++ b/src/test/java/dev/vality/anapi/v2/auth/utils/KeycloakOpenIdStub.java @@ -1,16 +1,55 @@ package dev.vality.anapi.v2.auth.utils; +import static com.github.tomakehurst.wiremock.client.WireMock.*; + public class KeycloakOpenIdStub { + private final String keycloakRealm; private final String issuer; + private final String openidConfig; private final JwtTokenBuilder jwtTokenBuilder; - public KeycloakOpenIdStub(JwtTokenBuilder jwtTokenBuilder) { + public KeycloakOpenIdStub(String keycloakAuthServerUrl, String keycloakRealm, JwtTokenBuilder jwtTokenBuilder) { + this.keycloakRealm = keycloakRealm; this.jwtTokenBuilder = jwtTokenBuilder; - this.issuer = "test/realms/test"; + this.issuer = keycloakAuthServerUrl + "/realms/" + keycloakRealm; + this.openidConfig = "{\n" + + " \"issuer\": \"" + issuer + "\",\n" + + " \"authorization_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + + "/protocol/openid-connect/auth\",\n" + + " \"token_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + + "/protocol/openid-connect/token\",\n" + + " \"token_introspection_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + + "/protocol/openid-connect/token/introspect\",\n" + + " \"userinfo_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + + "/protocol/openid-connect/userinfo\",\n" + + " \"end_session_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + + "/protocol/openid-connect/logout\",\n" + + " \"jwks_uri\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + + "/protocol/openid-connect/certs\",\n" + + " \"check_session_iframe\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + + "/protocol/openid-connect/login-status-iframe.html\",\n" + + " \"registration_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + + "/clients-registrations/openid-connect\",\n" + + " \"introspection_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + + "/protocol/openid-connect/token/introspect\"\n" + + "}"; + } + + public void givenStub() { + stubFor(get(urlEqualTo(String.format("/auth/realms/%s/.well-known/openid-configuration", keycloakRealm))) + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withBody(openidConfig) + ) + ); } public String generateJwt(String... roles) { return jwtTokenBuilder.generateJwtWithRoles(issuer, roles); } + + public String generateJwt(long iat, long exp, String... roles) { + return jwtTokenBuilder.generateJwtWithRoles(iat, exp, issuer, roles); + } } diff --git a/src/test/java/dev/vality/anapi/v2/config/AbstractConfig.java b/src/test/java/dev/vality/anapi/v2/config/AbstractKeycloakOpenIdAsWiremockConfig.java similarity index 67% rename from src/test/java/dev/vality/anapi/v2/config/AbstractConfig.java rename to src/test/java/dev/vality/anapi/v2/config/AbstractKeycloakOpenIdAsWiremockConfig.java index ba4cef9e..3c5282a8 100644 --- a/src/test/java/dev/vality/anapi/v2/config/AbstractConfig.java +++ b/src/test/java/dev/vality/anapi/v2/config/AbstractKeycloakOpenIdAsWiremockConfig.java @@ -2,6 +2,7 @@ import dev.vality.anapi.v2.AnapiV2Application; import dev.vality.anapi.v2.auth.utils.KeycloakOpenIdStub; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -12,15 +13,22 @@ @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {AnapiV2Application.class}, - properties = {"wiremock.server.baseUrl=http://localhost:${wiremock.server.port}"}) + properties = { + "wiremock.server.baseUrl=http://localhost:${wiremock.server.port}", + "keycloak.auth-server-url=${wiremock.server.baseUrl}/auth"}) @AutoConfigureMockMvc @AutoConfigureWireMock(port = 0) @ExtendWith(SpringExtension.class) -public abstract class AbstractConfig { +public abstract class AbstractKeycloakOpenIdAsWiremockConfig { @Autowired private KeycloakOpenIdStub keycloakOpenIdStub; + @BeforeAll + public static void setUp(@Autowired KeycloakOpenIdStub keycloakOpenIdStub) throws Exception { + keycloakOpenIdStub.givenStub(); + } + protected String generateSimpleJwt() { return keycloakOpenIdStub.generateJwt(); } diff --git a/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java b/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java index 8167e534..e89796a0 100644 --- a/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java +++ b/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java @@ -1,14 +1,14 @@ package dev.vality.anapi.v2.controller; -import dev.vality.anapi.v2.config.AbstractConfig; +import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.converter.magista.request.ParamsToRefundSearchQueryConverter; import dev.vality.anapi.v2.exception.BadRequestException; import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.OpenApiUtil; +import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.token.keeper.TokenAuthenticatorSrv; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -24,9 +24,6 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.BouncerUtil.createJudgementAllowed; -import static dev.vality.anapi.v2.testutil.TokenKeeperUtil.createAuthData; import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -35,7 +32,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -class ErrorControllerTest extends AbstractConfig { +class ErrorControllerTest extends AbstractKeycloakOpenIdAsWiremockConfig { @Autowired private MockMvc mockMvc; @@ -47,8 +44,6 @@ class ErrorControllerTest extends AbstractConfig { public AuthContextProviderSrv.Iface orgManagerClient; @MockBean public ArbiterSrv.Iface bouncerClient; - @MockBean - public TokenAuthenticatorSrv.Iface tokenKeeperClient; private AutoCloseable mocks; @@ -57,8 +52,7 @@ class ErrorControllerTest extends AbstractConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{refundSearchConverter, vortigonClient, orgManagerClient, - bouncerClient, tokenKeeperClient}; + preparedMocks = new Object[]{refundSearchConverter, vortigonClient, orgManagerClient, bouncerClient}; } @AfterEach @@ -89,9 +83,8 @@ void testConstraintViolationException() throws Exception { @Test void testBadRequestException() throws Exception { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); - when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); - when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); + when(orgManagerClient.getUserContext(any())).thenReturn(MagistaUtil.createContextFragment()); + when(bouncerClient.judge(any(), any())).thenReturn(MagistaUtil.createJudgementAllowed()); String message = "Error!"; Mockito.doThrow(new BadRequestException(message)).when(refundSearchConverter) .convert(any(), any(), any(), any(), @@ -113,7 +106,6 @@ void testBadRequestException() throws Exception { .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) .andExpect(jsonPath("$.message").value(message)); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(refundSearchConverter, times(1)) @@ -161,9 +153,8 @@ void testDeadlineException() throws Exception { @Test void testInternalException() throws Exception { when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(tokenKeeperClient.authenticate(any(), any())).thenReturn(createAuthData(generateSimpleJwt())); - when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); - when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); + when(orgManagerClient.getUserContext(any())).thenReturn(MagistaUtil.createContextFragment()); + when(bouncerClient.judge(any(), any())).thenReturn(MagistaUtil.createJudgementAllowed()); doThrow(new RuntimeException()).when(refundSearchConverter) .convert(any(), any(), any(), any(), any(), any(), any(), any(), @@ -183,7 +174,6 @@ void testInternalException() throws Exception { .andExpect(status().isInternalServerError()) .andExpect(jsonPath("$").doesNotExist()); verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(tokenKeeperClient, times(1)).authenticate(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(refundSearchConverter, times(1)) @@ -194,19 +184,16 @@ void testInternalException() throws Exception { @Test void testUnauthorizedException() throws Exception { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); mockMvc.perform( get("/lk/v2/refunds") .header("X-Request-ID", randomUUID()) - .header("X-Request-Deadline", - Instant.now().plus(1, ChronoUnit.DAYS).toString()) + .header("X-Request-Deadline", "fail") .params(OpenApiUtil.getSearchRequiredParams()) .contentType(MediaType.APPLICATION_JSON_UTF8) .content("")) .andDo(print()) - .andExpect(status().isForbidden()) + .andExpect(status().isUnauthorized()) .andExpect(jsonPath("$").doesNotExist()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); } } diff --git a/src/test/java/dev/vality/anapi/v2/testutil/BouncerUtil.java b/src/test/java/dev/vality/anapi/v2/testutil/BouncerUtil.java deleted file mode 100644 index 327dea62..00000000 --- a/src/test/java/dev/vality/anapi/v2/testutil/BouncerUtil.java +++ /dev/null @@ -1,26 +0,0 @@ -package dev.vality.anapi.v2.testutil; - -import dev.vality.bouncer.ctx.ContextFragment; -import dev.vality.bouncer.decisions.Judgement; -import dev.vality.bouncer.decisions.Resolution; -import dev.vality.bouncer.decisions.ResolutionAllowed; -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; -import org.apache.thrift.TSerializer; - -@UtilityClass -public class BouncerUtil { - - @SneakyThrows - public static ContextFragment createContextFragment() { - ContextFragment fragment = DamselUtil.fillRequiredTBaseObject(new ContextFragment(), ContextFragment.class); - fragment.setContent(new TSerializer().serialize(new dev.vality.bouncer.context.v1.ContextFragment())); - return fragment; - } - - public static Judgement createJudgementAllowed() { - Resolution resolution = new Resolution(); - resolution.setAllowed(new ResolutionAllowed()); - return new Judgement().setResolution(resolution); - } -} diff --git a/src/test/java/dev/vality/anapi/v2/testutil/MagistaUtil.java b/src/test/java/dev/vality/anapi/v2/testutil/MagistaUtil.java index 9117454d..4f2df0af 100644 --- a/src/test/java/dev/vality/anapi/v2/testutil/MagistaUtil.java +++ b/src/test/java/dev/vality/anapi/v2/testutil/MagistaUtil.java @@ -1,5 +1,9 @@ package dev.vality.anapi.v2.testutil; +import dev.vality.bouncer.ctx.ContextFragment; +import dev.vality.bouncer.decisions.Judgement; +import dev.vality.bouncer.decisions.Resolution; +import dev.vality.bouncer.decisions.ResolutionAllowed; import dev.vality.damsel.base.Content; import dev.vality.damsel.domain.InvoicePaymentRefundStatus; import dev.vality.damsel.domain.InvoicePaymentStatus; @@ -11,7 +15,9 @@ import dev.vality.magista.InvoicePaymentFlowInstant; import dev.vality.magista.Payer; import dev.vality.magista.*; +import lombok.SneakyThrows; import lombok.experimental.UtilityClass; +import org.apache.thrift.TSerializer; import java.time.Instant; import java.util.HashMap; @@ -163,6 +169,19 @@ public static StatInvoiceTemplateResponse createSearchInvoiceTemplateRequiredRes return DamselUtil.fillRequiredTBaseObject(new StatInvoiceTemplateResponse(), StatInvoiceTemplateResponse.class); } + @SneakyThrows + public static ContextFragment createContextFragment() { + ContextFragment fragment = DamselUtil.fillRequiredTBaseObject(new ContextFragment(), ContextFragment.class); + fragment.setContent(new TSerializer().serialize(new dev.vality.bouncer.context.v1.ContextFragment())); + return fragment; + } + + public static Judgement createJudgementAllowed() { + Resolution resolution = new Resolution(); + resolution.setAllowed(new ResolutionAllowed()); + return new Judgement().setResolution(resolution); + } + public static InvoicePaymentFlow createInvoicePaymentFlowHold() { return InvoicePaymentFlow.hold( DamselUtil.fillRequiredTBaseObject(new InvoicePaymentFlowHold(), InvoicePaymentFlowHold.class)); diff --git a/src/test/java/dev/vality/anapi/v2/testutil/TokenKeeperUtil.java b/src/test/java/dev/vality/anapi/v2/testutil/TokenKeeperUtil.java deleted file mode 100644 index 1891d94c..00000000 --- a/src/test/java/dev/vality/anapi/v2/testutil/TokenKeeperUtil.java +++ /dev/null @@ -1,24 +0,0 @@ -package dev.vality.anapi.v2.testutil; - -import dev.vality.token.keeper.AuthData; -import dev.vality.token.keeper.AuthDataStatus; -import lombok.experimental.UtilityClass; - -import java.util.UUID; - -import static dev.vality.anapi.v2.testutil.BouncerUtil.createContextFragment; - -@UtilityClass -public class TokenKeeperUtil { - - public static AuthData createAuthData(String token) { - return new AuthData() - .setId(UUID.randomUUID().toString()) - .setAuthority(UUID.randomUUID().toString()) - .setToken(token) - .setStatus(AuthDataStatus.active) - .setContext(createContextFragment()); - } - - -} From ab18f995648510fec28eca28b675c9cf5f72a15f Mon Sep 17 00:00:00 2001 From: Egor Cherniak Date: Mon, 30 Jun 2025 17:49:37 +0300 Subject: [PATCH 2/7] Bump deps + remove payout --- package-lock.json | 6 + pom.xml | 107 +++------- .../v2/api/AnalyticsApiDelegateService.java | 77 ++++--- .../v2/api/ReportsApiDelegateService.java | 19 +- .../anapi/v2/api/SearchApiDelegate.java | 1 - .../v2/api/SearchApiDelegateService.java | 60 ++---- .../anapi/v2/config/ApplicationConfig.java | 8 +- .../anapi/v2/config/KeycloakConfig.java | 60 ------ .../anapi/v2/config/SecurityConfig.java | 63 +++--- .../dev/vality/anapi/v2/config/WebConfig.java | 52 +++-- .../config/properties/BouncerProperties.java | 3 +- .../config/properties/KeycloakProperties.java | 34 ---- .../v2/controller/ErrorControllerAdvice.java | 10 +- ...ToInvoiceTemplateSearchQueryConverter.java | 2 +- .../ParamsToPayoutSearchQueryConverter.java | 39 ---- ...PaymentToPaymentSearchResultConverter.java | 6 +- .../response/StatPayoutToPayoutConverter.java | 125 ------------ .../ParamsToStatReportRequestConverter.java | 6 +- .../ReporterResponseToReportConverter.java | 5 +- .../v2/exception/BadRequestException.java | 2 +- .../vality/anapi/v2/security/AccessData.java | 2 +- .../anapi/v2/security/AccessService.java | 11 +- .../v2/security/AnapiBouncerContext.java | 1 - .../v2/security/BouncerContextFactory.java | 16 +- .../security/converter/JwtAuthConverter.java | 53 +++++ .../anapi/v2/service/AnalyticsService.java | 50 ++--- .../anapi/v2/service/KeycloakService.java | 17 -- .../anapi/v2/service/MagistaService.java | 62 ++---- .../anapi/v2/service/ReporterService.java | 8 +- src/main/resources/application.yml | 21 +- .../dev/vality/anapi/v2/AnalyticsTest.java | 30 +-- .../java/dev/vality/anapi/v2/ReportsTest.java | 40 ++-- .../anapi/v2/SearchChargebacksTest.java | 30 +-- .../anapi/v2/SearchInvoiceTemplatesTest.java | 30 +-- .../vality/anapi/v2/SearchInvoicesTest.java | 30 +-- .../vality/anapi/v2/SearchPaymentsTest.java | 30 +-- .../vality/anapi/v2/SearchPayoutsTest.java | 152 -------------- .../vality/anapi/v2/SearchRefundsTest.java | 30 +-- .../v2/auth/JwtTokenTestConfiguration.java | 28 +-- .../auth/KeycloakOpenIdTestConfiguration.java | 11 +- .../anapi/v2/auth/utils/JwtTokenBuilder.java | 36 +++- .../v2/auth/utils/KeycloakOpenIdStub.java | 38 ++++ ...bstractKeycloakOpenIdAsWiremockConfig.java | 5 +- .../v2/controller/ErrorControllerTest.java | 46 ++--- ...aramsToPayoutSearchQueryConverterTest.java | 38 ---- ...entToPaymentSearchResultConverterTest.java | 16 +- .../StatPayoutToPayoutConverterTest.java | 190 ------------------ ...ReporterResponseToReportConverterTest.java | 2 +- .../anapi/v2/testutil/GenerateSelfSigned.java | 37 ++++ .../vality/anapi/v2/testutil/MagistaUtil.java | 22 +- .../vality/anapi/v2/testutil/OpenApiUtil.java | 15 -- .../anapi/v2/testutil/PublicKeyUtil.java | 25 +++ .../vality/anapi/v2/testutil/RandomUtil.java | 6 + .../anapi/v2/util/DeadlineUtilTest.java | 3 +- 54 files changed, 587 insertions(+), 1229 deletions(-) create mode 100644 package-lock.json delete mode 100644 src/main/java/dev/vality/anapi/v2/config/KeycloakConfig.java delete mode 100644 src/main/java/dev/vality/anapi/v2/config/properties/KeycloakProperties.java delete mode 100644 src/main/java/dev/vality/anapi/v2/converter/magista/request/ParamsToPayoutSearchQueryConverter.java delete mode 100644 src/main/java/dev/vality/anapi/v2/converter/magista/response/StatPayoutToPayoutConverter.java create mode 100644 src/main/java/dev/vality/anapi/v2/security/converter/JwtAuthConverter.java delete mode 100644 src/main/java/dev/vality/anapi/v2/service/KeycloakService.java delete mode 100644 src/test/java/dev/vality/anapi/v2/SearchPayoutsTest.java delete mode 100644 src/test/java/dev/vality/anapi/v2/converter/magista/request/ParamsToPayoutSearchQueryConverterTest.java delete mode 100644 src/test/java/dev/vality/anapi/v2/converter/magista/response/StatPayoutToPayoutConverterTest.java create mode 100644 src/test/java/dev/vality/anapi/v2/testutil/GenerateSelfSigned.java create mode 100644 src/test/java/dev/vality/anapi/v2/testutil/PublicKeyUtil.java diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..ffd50ab9 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "anapi-v2", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/pom.xml b/pom.xml index 6dd774fc..2be09877 100644 --- a/pom.xml +++ b/pom.xml @@ -6,11 +6,11 @@ dev.vality service-parent-pom - 1.0.19 + 3.1.1 anapi-v2 - 1.0.3 + 2.0.0 jar anapi-v2 @@ -19,7 +19,7 @@ UTF-8 UTF-8 - 15 + 21 8022 8023 ${server.port} ${management.port} @@ -30,7 +30,7 @@ 2.5.3 1.3.2 2.3.1 - 1.0.4 + 0.12.6 @@ -39,7 +39,7 @@ dev.vality swag-anapi-v2 - 1.81-8f1ba21-server + 1.95-4741f96-server dev.vality @@ -51,11 +51,6 @@ org-management-proto 1.12-1a0110a - - dev.vality - payout-manager-proto - 1.38-635dc24 - dev.vality magista-proto @@ -103,40 +98,6 @@ org.springframework.security spring-security-web - - org.keycloak - keycloak-admin-client - 15.1.1 - - - org.jboss.resteasy - resteasy-client - - - org.jboss.resteasy - resteasy-multipart-provider - - - org.jboss.resteasy - resteasy-jackson2-provider - - - org.jboss.resteasy - resteasy-jaxb-provider - - - - - org.keycloak - keycloak-spring-security-adapter - 15.1.1 - - - org.bouncycastle - bcprov-jdk15on - - - org.springframework.boot spring-boot-starter @@ -164,11 +125,15 @@ spring-boot-configuration-processor true + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + - javax.servlet - javax.servlet-api + jakarta.servlet + jakarta.servlet-api io.swagger @@ -192,27 +157,10 @@ provided - javax.servlet - servlet-api - ${servlet-api-version} + jakarta.validation + jakarta.validation-api provided - - javax.annotation - javax.annotation-api - ${javax-annotation-api-version} - - - javax.validation - validation-api - 2.0.1.Final - provided - - - javax.xml.bind - jaxb-api - ${jaxb-version} - com.google.code.findbugs jsr305 @@ -225,11 +173,6 @@ 0.2.3 provided - - org.bouncycastle - bcprov-jdk15on - 1.70 - io.micrometer micrometer-core @@ -247,20 +190,32 @@ io.jsonwebtoken - jjwt - 0.9.1 + jjwt-api + ${jjwt-version} + test + + + io.jsonwebtoken + jjwt-impl + ${jjwt-version} test - com.github.tomakehurst - wiremock-jre8-standalone - 2.34.0 + io.jsonwebtoken + jjwt-jackson + ${jjwt-version} test org.springframework.cloud spring-cloud-contract-wiremock - 3.1.4 + 4.3.0 + test + + + org.bouncycastle + bcpkix-jdk18on + 1.79 test diff --git a/src/main/java/dev/vality/anapi/v2/api/AnalyticsApiDelegateService.java b/src/main/java/dev/vality/anapi/v2/api/AnalyticsApiDelegateService.java index d9bf539f..17c76788 100644 --- a/src/main/java/dev/vality/anapi/v2/api/AnalyticsApiDelegateService.java +++ b/src/main/java/dev/vality/anapi/v2/api/AnalyticsApiDelegateService.java @@ -5,11 +5,8 @@ import dev.vality.anapi.v2.security.AccessService; import dev.vality.anapi.v2.service.AnalyticsService; import dev.vality.anapi.v2.util.DeadlineUtil; -import dev.vality.damsel.analytics.FilterRequest; -import dev.vality.damsel.analytics.MerchantFilter; -import dev.vality.damsel.analytics.SplitFilterRequest; +import dev.vality.damsel.analytics.*; import dev.vality.damsel.analytics.SplitUnit; -import dev.vality.damsel.analytics.TimeFilter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; @@ -29,7 +26,7 @@ public class AnalyticsApiDelegateService implements AnalyticsApiDelegate { private final AnalyticsService analyticsService; @Override - public ResponseEntity getAveragePayment(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getAveragePayment(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -38,9 +35,9 @@ public ResponseEntity getAveragePayment(String xRequestID, St .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse200 response; + GetPaymentsAmount200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse200(); + response = new GetPaymentsAmount200Response(); } else { var filterRequest = getFilterRequest(partyID, shopIDs, excludeShopIDs, fromTime, toTime); response = analyticsService.getAveragePayment(filterRequest); @@ -50,7 +47,7 @@ public ResponseEntity getAveragePayment(String xRequestID, St } @Override - public ResponseEntity getCreditingsAmount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getCreditingsAmount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -59,9 +56,9 @@ public ResponseEntity getCreditingsAmount(String xRequestID, .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse200 response; + GetPaymentsAmount200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse200(); + response = new GetPaymentsAmount200Response(); } else { var filterRequest = getFilterRequest(partyID, shopIDs, excludeShopIDs, fromTime, toTime); response = analyticsService.getCreditingsAmount(filterRequest); @@ -71,7 +68,7 @@ public ResponseEntity getCreditingsAmount(String xRequestID, } @Override - public ResponseEntity getCurrentBalances(String xRequestID, String partyID, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getCurrentBalances(String xRequestID, String partyID, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -80,9 +77,9 @@ public ResponseEntity getCurrentBalances(String xRequestID, S .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse200 response; + GetPaymentsAmount200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse200(); + response = new GetPaymentsAmount200Response(); } else { var merchantFilter = getMerchantFilter(partyID, shopIDs, excludeShopIDs); response = analyticsService.getCurrentBalances(merchantFilter); @@ -92,7 +89,7 @@ public ResponseEntity getCurrentBalances(String xRequestID, S } @Override - public ResponseEntity getCurrentShopBalances(String xRequestID, String partyID, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getCurrentShopBalances(String xRequestID, String partyID, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -101,9 +98,9 @@ public ResponseEntity getCurrentShopBalances(String xRequest .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse2007 response; + GetCurrentShopBalances200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse2007(); + response = new GetCurrentShopBalances200Response(); } else { var merchantFilter = getMerchantFilter(partyID, shopIDs, excludeShopIDs); response = analyticsService.getCurrentShopBalances(merchantFilter); @@ -113,7 +110,7 @@ public ResponseEntity getCurrentShopBalances(String xRequest } @Override - public ResponseEntity getPaymentsAmount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getPaymentsAmount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -122,9 +119,9 @@ public ResponseEntity getPaymentsAmount(String xRequestID, St .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse200 response; + GetPaymentsAmount200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse200(); + response = new GetPaymentsAmount200Response(); } else { var filterRequest = getFilterRequest(partyID, shopIDs, excludeShopIDs, fromTime, toTime); response = analyticsService.getPaymentsAmount(filterRequest); @@ -134,7 +131,7 @@ public ResponseEntity getPaymentsAmount(String xRequestID, St } @Override - public ResponseEntity getPaymentsCount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getPaymentsCount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -143,9 +140,9 @@ public ResponseEntity getPaymentsCount(String xRequestID, St .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse2001 response; + GetPaymentsCount200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse2001(); + response = new GetPaymentsCount200Response(); } else { var filterRequest = getFilterRequest(partyID, shopIDs, excludeShopIDs, fromTime, toTime); response = analyticsService.getPaymentsCount(filterRequest); @@ -155,7 +152,7 @@ public ResponseEntity getPaymentsCount(String xRequestID, St } @Override - public ResponseEntity getPaymentsErrorDistribution(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getPaymentsErrorDistribution(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -164,9 +161,9 @@ public ResponseEntity getPaymentsErrorDistribution(String xR .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse2002 response; + GetPaymentsErrorDistribution200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse2002(); + response = new GetPaymentsErrorDistribution200Response(); } else { var filterRequest = getFilterRequest(partyID, shopIDs, excludeShopIDs, fromTime, toTime); response = analyticsService.getPaymentsErrorDistribution(filterRequest); @@ -176,7 +173,7 @@ public ResponseEntity getPaymentsErrorDistribution(String xR } @Override - public ResponseEntity getPaymentsSplitAmount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String splitUnit, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getPaymentsSplitAmount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String splitUnit, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -185,9 +182,9 @@ public ResponseEntity getPaymentsSplitAmount(String xRequest .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse2003 response; + GetPaymentsSplitAmount200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse2003(); + response = new GetPaymentsSplitAmount200Response(); } else { var splitFilterRequest = getSplitFilterRequest( partyID, @@ -202,7 +199,7 @@ public ResponseEntity getPaymentsSplitAmount(String xRequest } @Override - public ResponseEntity getPaymentsSplitCount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String splitUnit, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getPaymentsSplitCount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String splitUnit, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -211,9 +208,9 @@ public ResponseEntity getPaymentsSplitCount(String xRequestI .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse2004 response; + GetPaymentsSplitCount200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse2004(); + response = new GetPaymentsSplitCount200Response(); } else { var splitFilterRequest = getSplitFilterRequest( partyID, @@ -228,7 +225,7 @@ public ResponseEntity getPaymentsSplitCount(String xRequestI } @Override - public ResponseEntity getPaymentsSubErrorDistribution(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getPaymentsSubErrorDistribution(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -237,9 +234,9 @@ public ResponseEntity getPaymentsSubErrorDistribution(String .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse2005 response; + GetPaymentsSubErrorDistribution200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse2005(); + response = new GetPaymentsSubErrorDistribution200Response(); } else { var filterRequest = getFilterRequest(partyID, shopIDs, excludeShopIDs, fromTime, toTime); response = analyticsService.getPaymentsSubErrorDistribution(filterRequest); @@ -249,7 +246,7 @@ public ResponseEntity getPaymentsSubErrorDistribution(String } @Override - public ResponseEntity getPaymentsToolDistribution(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getPaymentsToolDistribution(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -258,9 +255,9 @@ public ResponseEntity getPaymentsToolDistribution(String xRe .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse2006 response; + GetPaymentsToolDistribution200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse2006(); + response = new GetPaymentsToolDistribution200Response(); } else { var filterRequest = getFilterRequest(partyID, shopIDs, excludeShopIDs, fromTime, toTime); response = analyticsService.getPaymentsToolDistribution(filterRequest); @@ -270,7 +267,7 @@ public ResponseEntity getPaymentsToolDistribution(String xRe } @Override - public ResponseEntity getRefundsAmount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { + public ResponseEntity getRefundsAmount(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, String xRequestDeadline, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -279,9 +276,9 @@ public ResponseEntity getRefundsAmount(String xRequestID, Str .shopIds(shopIDs) .realm(paymentInstitutionRealm) .build()); - InlineResponse200 response; + GetPaymentsAmount200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse200(); + response = new GetPaymentsAmount200Response(); } else { var filterRequest = getFilterRequest(partyID, shopIDs, excludeShopIDs, fromTime, toTime); response = analyticsService.getRefundsAmount(filterRequest); diff --git a/src/main/java/dev/vality/anapi/v2/api/ReportsApiDelegateService.java b/src/main/java/dev/vality/anapi/v2/api/ReportsApiDelegateService.java index 86553606..e889c4b6 100644 --- a/src/main/java/dev/vality/anapi/v2/api/ReportsApiDelegateService.java +++ b/src/main/java/dev/vality/anapi/v2/api/ReportsApiDelegateService.java @@ -1,14 +1,14 @@ package dev.vality.anapi.v2.api; import dev.vality.anapi.v2.converter.reporter.request.ParamsToStatReportRequestConverter; -import dev.vality.anapi.v2.model.InlineResponse20014; import dev.vality.anapi.v2.model.Report; import dev.vality.anapi.v2.model.ReportLink; +import dev.vality.anapi.v2.model.SearchReports200Response; import dev.vality.anapi.v2.security.AccessData; import dev.vality.anapi.v2.security.AccessService; import dev.vality.anapi.v2.service.ReporterService; -import dev.vality.geck.common.util.TypeUtil; import dev.vality.anapi.v2.util.DeadlineUtil; +import dev.vality.geck.common.util.TypeUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -102,11 +102,12 @@ public ResponseEntity getReport(String xRequestID, String partyID, Long } @Override - public ResponseEntity searchReports(String xRequestID, String partyID, OffsetDateTime fromTime, - OffsetDateTime toTime, Integer limit, - List reportTypes, String xRequestDeadline, - String shopID, String paymentInstitutionRealm, - String continuationToken) { + public ResponseEntity searchReports(String xRequestID, String partyID, + OffsetDateTime fromTime, + OffsetDateTime toTime, Integer limit, + List reportTypes, String xRequestDeadline, + String shopID, String paymentInstitutionRealm, + String continuationToken) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); List shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -115,14 +116,14 @@ public ResponseEntity searchReports(String xRequestID, Stri .shopIds(shopID == null ? null : List.of(shopID)) .realm(paymentInstitutionRealm) .build()); - InlineResponse20014 response; + SearchReports200Response response; if (shopID == null || shopIDs.contains(shopID)) { var request = statReportRequestConverter.convert(partyID, shopID, fromTime, toTime, limit, reportTypes, continuationToken); response = reporterService.getReports(request); } else { - response = new InlineResponse20014(); + response = new SearchReports200Response(); } log.info("<- Res [200]: xRequestID={}", xRequestID); return ResponseEntity.ok(response); diff --git a/src/main/java/dev/vality/anapi/v2/api/SearchApiDelegate.java b/src/main/java/dev/vality/anapi/v2/api/SearchApiDelegate.java index dfaba874..dde0c756 100644 --- a/src/main/java/dev/vality/anapi/v2/api/SearchApiDelegate.java +++ b/src/main/java/dev/vality/anapi/v2/api/SearchApiDelegate.java @@ -9,7 +9,6 @@ public interface SearchApiDelegate PaymentsApiDelegate, ChargebacksApiDelegate, InvoicesApiDelegate, - PayoutsApiDelegate, RefundsApiDelegate, InvoiceTemplatesApiDelegate { diff --git a/src/main/java/dev/vality/anapi/v2/api/SearchApiDelegateService.java b/src/main/java/dev/vality/anapi/v2/api/SearchApiDelegateService.java index be30c954..94cf339b 100644 --- a/src/main/java/dev/vality/anapi/v2/api/SearchApiDelegateService.java +++ b/src/main/java/dev/vality/anapi/v2/api/SearchApiDelegateService.java @@ -27,11 +27,10 @@ public class SearchApiDelegateService implements SearchApiDelegate { private final ParamsToPaymentSearchQueryConverter paymentSearchConverter; private final ParamsToRefundSearchQueryConverter refundSearchConverter; private final ParamsToChargebackSearchQueryConverter chargebackSearchConverter; - private final ParamsToPayoutSearchQueryConverter payoutSearchConverter; private final ParamsToInvoiceTemplateSearchQueryConverter invoiceTemplateSearchConverter; @Override - public ResponseEntity searchInvoices(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, String shopID, List shopIDs, String paymentInstitutionRealm, String invoiceID, List invoiceIDs, String invoiceStatus, Long invoiceAmountFrom, Long invoiceAmountTo, String externalID, String continuationToken) { + public ResponseEntity searchInvoices(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, String shopID, List shopIDs, String paymentInstitutionRealm, String invoiceID, List invoiceIDs, String invoiceStatus, Long invoiceAmountFrom, Long invoiceAmountTo, String externalID, String continuationToken) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -40,9 +39,9 @@ public ResponseEntity searchInvoices(String xRequestID, Stri .shopIds(ConverterUtil.merge(shopID, shopIDs)) .realm(paymentInstitutionRealm) .build()); - InlineResponse2008 response; + SearchInvoices200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse2008(); + response = new SearchInvoices200Response(); } else { var query = invoiceSearchConverter.convert( partyID, @@ -64,7 +63,7 @@ public ResponseEntity searchInvoices(String xRequestID, Stri } @Override - public ResponseEntity searchPayments(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, String shopID, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm, String invoiceID, List invoiceIDs, String paymentID, String paymentStatus, String paymentFlow, String paymentMethod, String paymentTerminalProvider, String payerEmail, String payerIP, String payerFingerprint, String customerID, String first6, String last4, String rrn, String approvalCode, String bankCardTokenProvider, String bankCardPaymentSystem, Long paymentAmountFrom, Long paymentAmountTo, String externalID, String continuationToken) { + public ResponseEntity searchPayments(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, String shopID, List shopIDs, List excludeShopIDs, String paymentInstitutionRealm, String invoiceID, List invoiceIDs, String paymentID, String paymentStatus, String paymentFlow, String paymentMethod, String paymentTerminalProvider, String payerEmail, String payerIP, String payerFingerprint, String customerID, String first6, String last4, String rrn, String approvalCode, String bankCardTokenProvider, String bankCardPaymentSystem, Long paymentAmountFrom, Long paymentAmountTo, String externalID, String continuationToken) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -73,9 +72,9 @@ public ResponseEntity searchPayments(String xRequestID, Stri .shopIds(ConverterUtil.merge(shopID, shopIDs)) .realm(paymentInstitutionRealm) .build()); - InlineResponse2009 response; + SearchPayments200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse2009(); + response = new SearchPayments200Response(); } else { var query = paymentSearchConverter.convert( partyID, @@ -111,7 +110,7 @@ public ResponseEntity searchPayments(String xRequestID, Stri } @Override - public ResponseEntity searchRefunds(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, String shopID, List shopIDs, String paymentInstitutionRealm, String invoiceID, List invoiceIDs, String paymentID, String refundID, String refundStatus, String externalID, String continuationToken) { + public ResponseEntity searchRefunds(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, String shopID, List shopIDs, String paymentInstitutionRealm, String invoiceID, List invoiceIDs, String paymentID, String refundID, String refundStatus, String externalID, String continuationToken) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -120,9 +119,9 @@ public ResponseEntity searchRefunds(String xRequestID, Stri .shopIds(ConverterUtil.merge(shopID, shopIDs)) .realm(paymentInstitutionRealm) .build()); - InlineResponse20010 response; + SearchRefunds200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse20010(); + response = new SearchRefunds200Response(); } else { var query = refundSearchConverter.convert( partyID, @@ -144,7 +143,7 @@ public ResponseEntity searchRefunds(String xRequestID, Stri } @Override - public ResponseEntity searchChargebacks(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, String shopID, List shopIDs, String paymentInstitutionRealm, String invoiceID, String paymentID, String chargebackID, List chargebackStatuses, List chargebackStages, List chargebackCategories, String continuationToken) { + public ResponseEntity searchChargebacks(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, String shopID, List shopIDs, String paymentInstitutionRealm, String invoiceID, String paymentID, String chargebackID, List chargebackStatuses, List chargebackStages, List chargebackCategories, String continuationToken) { DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); shopIDs = accessService.getRestrictedShops( AccessData.builder() @@ -153,9 +152,9 @@ public ResponseEntity searchChargebacks(String xRequestID, .shopIds(ConverterUtil.merge(shopID, shopIDs)) .realm(paymentInstitutionRealm) .build()); - InlineResponse20011 response; + SearchChargebacks200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse20011(); + response = new SearchChargebacks200Response(); } else { var query = chargebackSearchConverter.convert( partyID, @@ -177,36 +176,7 @@ public ResponseEntity searchChargebacks(String xRequestID, } @Override - public ResponseEntity searchPayouts(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, String shopID, List shopIDs, String paymentInstitutionRealm, String payoutID, String payoutToolType, String continuationToken) { - DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); - shopIDs = accessService.getRestrictedShops( - AccessData.builder() - .operationId("SearchPayouts") - .partyId(partyID) - .shopIds(ConverterUtil.merge(shopID, shopIDs)) - .realm(paymentInstitutionRealm) - .build()); - InlineResponse20012 response; - if (shopIDs.isEmpty()) { - response = new InlineResponse20012(); - } else { - var query = payoutSearchConverter.convert( - partyID, - fromTime, - toTime, - limit, - shopIDs, - payoutID, - payoutToolType, - continuationToken); - response = magistaService.searchPayouts(query); - } - log.info("<- Res [200]: xRequestID={}", xRequestID); - return ResponseEntity.ok(response); - } - - @Override - public ResponseEntity searchInvoiceTemplates(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, List shopIDs, String paymentInstitutionRealm, String invoiceTemplateID, String invoiceTemplateStatus, String name, String product, OffsetDateTime invoiceValidUntil, String continuationToken) { + public ResponseEntity searchInvoiceTemplates(String xRequestID, String partyID, OffsetDateTime fromTime, OffsetDateTime toTime, Integer limit, String xRequestDeadline, List shopIDs, String paymentInstitutionRealm, String invoiceTemplateID, String invoiceTemplateStatus, String name, String product, OffsetDateTime invoiceValidUntil, String continuationToken) { shopIDs = accessService.getRestrictedShops( AccessData.builder() .operationId("SearchInvoiceTemplates") @@ -215,9 +185,9 @@ public ResponseEntity searchInvoiceTemplates(String xReques .realm(paymentInstitutionRealm) .build()); DeadlineUtil.checkDeadline(xRequestDeadline, xRequestID); - InlineResponse20013 response; + SearchInvoiceTemplates200Response response; if (shopIDs.isEmpty()) { - response = new InlineResponse20013(); + response = new SearchInvoiceTemplates200Response(); } else { var query = invoiceTemplateSearchConverter.convert( partyID, diff --git a/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java b/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java index f83b6b56..07be9b6b 100644 --- a/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java +++ b/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java @@ -1,16 +1,16 @@ package dev.vality.anapi.v2.config; import dev.vality.bouncer.decisions.ArbiterSrv; +import dev.vality.damsel.analytics.AnalyticsServiceSrv; +import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; +import dev.vality.orgmanagement.AuthContextProviderSrv; +import dev.vality.reporter.ReportingSrv; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityEmailExtensionKit; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityIdExtensionKit; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityRealmExtensionKit; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityUsernameExtensionKit; import dev.vality.woody.thrift.impl.http.THSpawnClientBuilder; -import dev.vality.damsel.analytics.AnalyticsServiceSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; -import dev.vality.orgmanagement.AuthContextProviderSrv; -import dev.vality.reporter.ReportingSrv; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/dev/vality/anapi/v2/config/KeycloakConfig.java b/src/main/java/dev/vality/anapi/v2/config/KeycloakConfig.java deleted file mode 100644 index d5b1c66c..00000000 --- a/src/main/java/dev/vality/anapi/v2/config/KeycloakConfig.java +++ /dev/null @@ -1,60 +0,0 @@ -package dev.vality.anapi.v2.config; - -import dev.vality.anapi.v2.config.properties.KeycloakProperties; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import org.keycloak.adapters.KeycloakConfigResolver; -import org.keycloak.adapters.KeycloakDeployment; -import org.keycloak.adapters.KeycloakDeploymentBuilder; -import org.keycloak.representations.adapters.config.AdapterConfig; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.StringUtils; - -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; -import java.util.stream.Collectors; - -@RequiredArgsConstructor -@Configuration -@ConditionalOnProperty(value = "auth.enabled", havingValue = "true") -public class KeycloakConfig { - - private final KeycloakProperties keycloakProperties; - - @Bean - public KeycloakConfigResolver keycloakConfigResolver() { - return facade -> { - KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(adapterConfig()); - deployment.setNotBefore(keycloakProperties.getNotBefore()); - return deployment; - }; - } - - private AdapterConfig adapterConfig() { - if (StringUtils.hasLength(keycloakProperties.getRealmPublicKeyPath())) { - keycloakProperties.setRealmPublicKey(readKeyFromFile(keycloakProperties.getRealmPublicKeyPath())); - } - - AdapterConfig adapterConfig = new AdapterConfig(); - adapterConfig.setRealm(keycloakProperties.getRealm()); - adapterConfig.setRealmKey(keycloakProperties.getRealmPublicKey()); - adapterConfig.setResource(keycloakProperties.getResource()); - adapterConfig.setAuthServerUrl(keycloakProperties.getAuthServerUrl()); - adapterConfig.setUseResourceRoleMappings(true); - adapterConfig.setBearerOnly(true); - adapterConfig.setSslRequired(keycloakProperties.getSslRequired()); - return adapterConfig; - } - - @SneakyThrows - private String readKeyFromFile(String filePath) { - List strings = Files.readAllLines(Paths.get(filePath)); - strings.remove(strings.size() - 1); - strings.remove(0); - return strings.stream().map(String::trim).collect(Collectors.joining()); - } - -} diff --git a/src/main/java/dev/vality/anapi/v2/config/SecurityConfig.java b/src/main/java/dev/vality/anapi/v2/config/SecurityConfig.java index f04157b1..72d49de5 100644 --- a/src/main/java/dev/vality/anapi/v2/config/SecurityConfig.java +++ b/src/main/java/dev/vality/anapi/v2/config/SecurityConfig.java @@ -1,67 +1,52 @@ package dev.vality.anapi.v2.config; -import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents; -import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; -import org.springframework.beans.factory.annotation.Autowired; +import dev.vality.anapi.v2.security.converter.JwtAuthConverter; +import lombok.RequiredArgsConstructor; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.FilterType; import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy; -import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @Configuration @EnableWebSecurity -@ComponentScan( - basePackageClasses = KeycloakSecurityComponents.class, - excludeFilters = @ComponentScan.Filter( - type = FilterType.REGEX, - pattern = "org.keycloak.adapters.springsecurity.management.HttpSessionManager")) -@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true) +@RequiredArgsConstructor @ConditionalOnProperty(value = "auth.enabled", havingValue = "true") -public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { +public class SecurityConfig { - @Bean - @Override - protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { - return new NullAuthenticatedSessionStrategy(); - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - super.configure(http); - http - .cors().and() - .csrf().disable() - .authorizeRequests() - .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() - .antMatchers(HttpMethod.GET, "/**/health").permitAll() - .antMatchers(HttpMethod.GET, "/**/prometheus").permitAll() - .anyRequest().authenticated(); - } + private final JwtAuthConverter jwtAuthConverter; - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) { - auth.authenticationProvider(keycloakAuthenticationProvider()); + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http.csrf(AbstractHttpConfigurer::disable); + http.authorizeHttpRequests( + (authorize) -> authorize + .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .requestMatchers(HttpMethod.GET, "/*/health/liveness").permitAll() + .requestMatchers(HttpMethod.GET, "/*/health/readiness").permitAll() + .requestMatchers(HttpMethod.GET, "/*/actuator/prometheus").permitAll() + .anyRequest().authenticated()); + http.oauth2ResourceServer(server -> server.jwt(token -> token.jwtAuthenticationConverter(jwtAuthConverter))); + http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + http.cors(c -> c.configurationSource(corsConfigurationSource())); + return http.build(); } - @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.applyPermitDefaultValues(); configuration.addAllowedMethod(HttpMethod.PUT); configuration.addAllowedMethod(HttpMethod.DELETE); + configuration.addAllowedMethod(HttpMethod.OPTIONS); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", configuration); + source.registerCorsConfiguration("/*", configuration); return source; } } diff --git a/src/main/java/dev/vality/anapi/v2/config/WebConfig.java b/src/main/java/dev/vality/anapi/v2/config/WebConfig.java index 37bf35aa..414a5d70 100644 --- a/src/main/java/dev/vality/anapi/v2/config/WebConfig.java +++ b/src/main/java/dev/vality/anapi/v2/config/WebConfig.java @@ -5,21 +5,22 @@ import dev.vality.woody.api.trace.context.metadata.user.UserIdentityIdExtensionKit; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityRealmExtensionKit; import dev.vality.woody.api.trace.context.metadata.user.UserIdentityUsernameExtensionKit; -import org.keycloak.KeycloakSecurityContext; -import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; -import org.keycloak.representations.AccessToken; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.jwt.JwtClaimNames; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.web.filter.OncePerRequestFilter; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.security.Principal; import java.time.Instant; import java.time.temporal.ChronoUnit; @@ -27,6 +28,7 @@ import static dev.vality.woody.api.trace.ContextUtils.setCustomMetadataValue; import static dev.vality.woody.api.trace.ContextUtils.setDeadline; +@Slf4j @Configuration @SuppressWarnings({"ParameterName", "LocalVariableName"}) public class WebConfig { @@ -39,14 +41,14 @@ public FilterRegistrationBean woodyFilter() { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { + FilterChain filterChain) { woodyFlow.createServiceFork( () -> { try { - if (request.getUserPrincipal() != null) { - addWoodyContext(request.getUserPrincipal()); + var auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth instanceof JwtAuthenticationToken) { + addWoodyContext((JwtAuthenticationToken) auth); } - setWoodyDeadline(request); filterChain.doFilter(request, response); @@ -71,22 +73,28 @@ private T sneakyThrow(Throwable t) throws E { return filterRegistrationBean; } - private void addWoodyContext(Principal principal) { - KeycloakSecurityContext keycloakSecurityContext = - ((KeycloakAuthenticationToken) principal).getAccount().getKeycloakSecurityContext(); - AccessToken accessToken = keycloakSecurityContext.getToken(); + private void addWoodyContext(JwtAuthenticationToken token) { + setCustomMetadataValue(UserIdentityIdExtensionKit.KEY, token.getToken().getClaimAsString(JwtClaimNames.SUB)); + setCustomMetadataValue(UserIdentityUsernameExtensionKit.KEY, + ((Jwt)token.getPrincipal()).getClaimAsString("preferred_username")); + setCustomMetadataValue(UserIdentityEmailExtensionKit.KEY, token.getToken().getClaimAsString("email")); + setCustomMetadataValue(UserIdentityRealmExtensionKit.KEY, extractRealm(token.getToken())); + } - setCustomMetadataValue(UserIdentityIdExtensionKit.KEY, accessToken.getSubject()); - setCustomMetadataValue(UserIdentityUsernameExtensionKit.KEY, accessToken.getPreferredUsername()); - setCustomMetadataValue(UserIdentityEmailExtensionKit.KEY, accessToken.getEmail()); - setCustomMetadataValue(UserIdentityRealmExtensionKit.KEY, keycloakSecurityContext.getRealm()); + private String extractRealm(Jwt token) { + var iss = token.getClaimAsString("iss"); + return iss.substring(iss.lastIndexOf("/")); } private void setWoodyDeadline(HttpServletRequest request) { String xRequestDeadline = request.getHeader("X-Request-Deadline"); String xRequestId = request.getHeader("X-Request-ID"); if (xRequestDeadline != null) { - setDeadline(getInstant(xRequestDeadline, xRequestId)); + try { + setDeadline(getInstant(xRequestDeadline, xRequestId)); + } catch (Exception e) { + log.warn("Unable to parse 'X-Request-Deadline' header value '{}'", xRequestDeadline); + } } } diff --git a/src/main/java/dev/vality/anapi/v2/config/properties/BouncerProperties.java b/src/main/java/dev/vality/anapi/v2/config/properties/BouncerProperties.java index e2415a07..6fac8d31 100644 --- a/src/main/java/dev/vality/anapi/v2/config/properties/BouncerProperties.java +++ b/src/main/java/dev/vality/anapi/v2/config/properties/BouncerProperties.java @@ -1,13 +1,12 @@ package dev.vality.anapi.v2.config.properties; +import jakarta.validation.constraints.NotEmpty; import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotEmpty; - @Getter @Setter @Component diff --git a/src/main/java/dev/vality/anapi/v2/config/properties/KeycloakProperties.java b/src/main/java/dev/vality/anapi/v2/config/properties/KeycloakProperties.java deleted file mode 100644 index 57b9a4f0..00000000 --- a/src/main/java/dev/vality/anapi/v2/config/properties/KeycloakProperties.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.vality.anapi.v2.config.properties; - -import lombok.Getter; -import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.NotEmpty; - -@Getter -@Setter -@Component -@Validated -@ConfigurationProperties(prefix = "keycloak") -public class KeycloakProperties { - - @NotEmpty - private String realm; - @NotEmpty - private String authServerUrl; - @NotEmpty - private String resource; - - private Integer notBefore; - - @NotEmpty - private String sslRequired; - - private String realmPublicKey; - - private String realmPublicKeyPath; - -} diff --git a/src/main/java/dev/vality/anapi/v2/controller/ErrorControllerAdvice.java b/src/main/java/dev/vality/anapi/v2/controller/ErrorControllerAdvice.java index 35fac6f8..2a27f769 100644 --- a/src/main/java/dev/vality/anapi/v2/controller/ErrorControllerAdvice.java +++ b/src/main/java/dev/vality/anapi/v2/controller/ErrorControllerAdvice.java @@ -5,6 +5,7 @@ import dev.vality.anapi.v2.exception.DeadlineException; import dev.vality.anapi.v2.exception.NotFoundException; import dev.vality.anapi.v2.model.DefaultLogicError; +import jakarta.validation.ConstraintViolationException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; @@ -23,7 +24,6 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.context.request.WebRequest; -import javax.validation.ConstraintViolationException; import java.net.http.HttpTimeoutException; import java.util.List; import java.util.stream.Collectors; @@ -49,7 +49,7 @@ public Object handleBadRequestException(BadRequestException e) { public Object handleDeadlineException(DeadlineException e) { log.warn("<- Res [400]: Not valid", e); return new DefaultLogicError() - .code(DefaultLogicError.CodeEnum.INVALIDDEADLINE) + .code(DefaultLogicError.CodeEnum.INVALID_DEADLINE) .message(e.getMessage()); } @@ -61,7 +61,7 @@ public Object handleConstraintViolationException(ConstraintViolationException e) .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage()) .collect(Collectors.joining(", ")); return new DefaultLogicError() - .code(DefaultLogicError.CodeEnum.INVALIDREQUEST) + .code(DefaultLogicError.CodeEnum.INVALID_REQUEST) .message(errorMessage); } @@ -70,7 +70,7 @@ public Object handleConstraintViolationException(ConstraintViolationException e) public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { log.warn("<- Res [400]: MethodArgument not valid", e); return new DefaultLogicError() - .code(DefaultLogicError.CodeEnum.INVALIDREQUEST) + .code(DefaultLogicError.CodeEnum.INVALID_REQUEST) .message(e.getMessage()); } @@ -79,7 +79,7 @@ public Object handleMethodArgumentNotValidException(MethodArgumentNotValidExcept public Object handleMissingServletRequestParameterException(MissingServletRequestParameterException e) { log.warn("<- Res [400]: Missing ServletRequestParameter", e); return new DefaultLogicError() - .code(DefaultLogicError.CodeEnum.INVALIDREQUEST) + .code(DefaultLogicError.CodeEnum.INVALID_REQUEST) .message(e.getMessage()); } diff --git a/src/main/java/dev/vality/anapi/v2/converter/magista/request/ParamsToInvoiceTemplateSearchQueryConverter.java b/src/main/java/dev/vality/anapi/v2/converter/magista/request/ParamsToInvoiceTemplateSearchQueryConverter.java index 91983b8e..1871b4e5 100644 --- a/src/main/java/dev/vality/anapi/v2/converter/magista/request/ParamsToInvoiceTemplateSearchQueryConverter.java +++ b/src/main/java/dev/vality/anapi/v2/converter/magista/request/ParamsToInvoiceTemplateSearchQueryConverter.java @@ -1,8 +1,8 @@ package dev.vality.anapi.v2.converter.magista.request; import dev.vality.anapi.v2.exception.BadRequestException; -import dev.vality.geck.common.util.TypeUtil; import dev.vality.anapi.v2.util.ConverterUtil; +import dev.vality.geck.common.util.TypeUtil; import dev.vality.magista.InvoiceTemplateSearchQuery; import dev.vality.magista.InvoiceTemplateStatus; import org.springframework.stereotype.Component; diff --git a/src/main/java/dev/vality/anapi/v2/converter/magista/request/ParamsToPayoutSearchQueryConverter.java b/src/main/java/dev/vality/anapi/v2/converter/magista/request/ParamsToPayoutSearchQueryConverter.java deleted file mode 100644 index 94bd796b..00000000 --- a/src/main/java/dev/vality/anapi/v2/converter/magista/request/ParamsToPayoutSearchQueryConverter.java +++ /dev/null @@ -1,39 +0,0 @@ -package dev.vality.anapi.v2.converter.magista.request; - -import dev.vality.anapi.v2.exception.BadRequestException; -import dev.vality.anapi.v2.util.ConverterUtil; -import dev.vality.magista.PayoutSearchQuery; -import dev.vality.magista.PayoutToolType; -import org.springframework.stereotype.Component; - -import java.time.OffsetDateTime; -import java.util.List; - -@Component -public class ParamsToPayoutSearchQueryConverter { - - public PayoutSearchQuery convert(String partyID, - OffsetDateTime fromTime, - OffsetDateTime toTime, - Integer limit, - List shopIDs, - String payoutID, - String payoutToolType, - String continuationToken) { - return new PayoutSearchQuery() - .setCommonSearchQueryParams( - ConverterUtil.fillCommonParams(fromTime, toTime, limit, partyID, shopIDs, continuationToken)) - .setPayoutId(payoutID) - .setPayoutType(payoutToolType != null ? mapPayoutToolType(payoutToolType) : null); - } - - protected PayoutToolType mapPayoutToolType(String payoutToolType) { - return switch (payoutToolType) { - case "PayoutAccount" -> PayoutToolType.payout_account; - case "Wallet" -> PayoutToolType.wallet; - case "PaymentInstitutionAccount" -> PayoutToolType.payment_institution_account; - default -> throw new BadRequestException( - String.format("PayoutToolType %s cannot be processed", payoutToolType)); - }; - } -} diff --git a/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatPaymentToPaymentSearchResultConverter.java b/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatPaymentToPaymentSearchResultConverter.java index 92d2ca85..6a4d6056 100644 --- a/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatPaymentToPaymentSearchResultConverter.java +++ b/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatPaymentToPaymentSearchResultConverter.java @@ -1,5 +1,6 @@ package dev.vality.anapi.v2.converter.magista.response; +import dev.vality.anapi.v2.model.*; import dev.vality.anapi.v2.model.ClientInfo; import dev.vality.anapi.v2.model.ContactInfo; import dev.vality.anapi.v2.model.CustomerPayer; @@ -7,7 +8,6 @@ import dev.vality.anapi.v2.model.PaymentResourcePayer; import dev.vality.anapi.v2.model.RecurrentPayer; import dev.vality.anapi.v2.model.TransactionInfo; -import dev.vality.anapi.v2.model.*; import dev.vality.anapi.v2.util.MaskUtil; import dev.vality.damsel.domain.*; import dev.vality.geck.common.util.TypeUtil; @@ -56,10 +56,10 @@ protected PaymentFlow mapFlow(InvoicePaymentFlow flow) { .heldUntil(TypeUtil.stringToInstant(hold.getHeldUntil()).atOffset(ZoneOffset.UTC)) .onHoldExpiration( PaymentFlowHold.OnHoldExpirationEnum.fromValue(hold.getOnHoldExpiration().name())) - .type(PaymentFlow.TypeEnum.PAYMENTFLOWHOLD); + .type(PaymentFlow.TypeEnum.PAYMENT_FLOW_HOLD); } else { return new PaymentFlowInstant() - .type(PaymentFlow.TypeEnum.PAYMENTFLOWINSTANT); + .type(PaymentFlow.TypeEnum.PAYMENT_FLOW_INSTANT); } } diff --git a/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatPayoutToPayoutConverter.java b/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatPayoutToPayoutConverter.java deleted file mode 100644 index c217548e..00000000 --- a/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatPayoutToPayoutConverter.java +++ /dev/null @@ -1,125 +0,0 @@ -package dev.vality.anapi.v2.converter.magista.response; - -import dev.vality.damsel.domain.CountryCode; -import dev.vality.damsel.domain.PayoutToolInfo; -import dev.vality.geck.common.util.TypeUtil; -import dev.vality.magista.PayoutStatus; -import dev.vality.magista.StatPayout; -import dev.vality.anapi.v2.model.*; -import org.springframework.stereotype.Component; - -import javax.annotation.Nullable; -import java.time.ZoneOffset; - -@Component -public class StatPayoutToPayoutConverter { - - public Payout convert(StatPayout payout) { - return new Payout() - .amount(payout.getAmount()) - .createdAt(TypeUtil.stringToInstant(payout.getCreatedAt()).atOffset(ZoneOffset.UTC)) - .currency(payout.getCurrencySymbolicCode()) - .fee(payout.getFee()) - .id(payout.getId()) - .payoutToolDetails(mapPayoutToolDetails(payout.getPayoutToolInfo())) - .shopID(payout.getShopId()) - .status(mapStatus(payout.getStatus())) - .cancellationDetails( - payout.getStatus().isSetCancelled() - ? payout.getStatus().getCancelled().getDetails() - : null); - } - - protected String mapStatus(PayoutStatus status) { - try { - var field = PayoutStatus._Fields.findByName(status.getSetField().getFieldName()); - return switch (field) { - case UNPAID -> "Unpaid"; - case PAID -> "Paid"; - case CANCELLED -> "Cancelled"; - case CONFIRMED -> "Confirmed"; - default -> throw new IllegalArgumentException(); - }; - } catch (Exception e) { - throw new IllegalArgumentException( - String.format("Payout status %s cannot be processed", status)); - } - } - - protected PayoutToolDetails mapPayoutToolDetails(PayoutToolInfo payoutToolInfo) { - try { - var field = PayoutToolInfo._Fields.findByName(payoutToolInfo.getSetField().getFieldName()); - switch (field) { - case RUSSIAN_BANK_ACCOUNT -> { - var account = payoutToolInfo.getRussianBankAccount(); - return new PayoutToolDetailsBankAccount() - .account(account.getAccount()) - .bankBik(account.getBankBik()) - .bankName(account.getBankName()) - .bankPostAccount(account.getBankPostAccount()) - .detailsType("PayoutToolDetailsBankAccount"); - } - case INTERNATIONAL_BANK_ACCOUNT -> { - var account = payoutToolInfo.getInternationalBankAccount(); - return new PayoutToolDetailsInternationalBankAccount() - .iban(account.getIban()) - .number(account.getNumber()) - .bankDetails(account.isSetBank() - ? new InternationalBankDetails() - .name(account.getBank().getName()) - .bic(account.getBank().getBic()) - .countryCode(mapCountryCode(account.getBank().getCountry())) - .address(account.getBank().getAddress()) - .abartn(account.getBank().getAbaRtn()) - : null) - .correspondentBankAccount( - mapInternationalCorrespondentBankAccount(account.getCorrespondentAccount())) - .detailsType("PayoutToolDetailsInternationalBankAccount"); - } - case WALLET_INFO -> { - return new PayoutToolDetailsWalletInfo() - .walletID(payoutToolInfo.getWalletInfo().getWalletId()) - .detailsType("PayoutToolDetailsWalletInfo"); - } - case PAYMENT_INSTITUTION_ACCOUNT -> { - return new PayoutToolDetailsPaymentInstitutionAccount() - .detailsType("PayoutToolDetailsPaymentInstitutionAccount"); - } - default -> throw new IllegalArgumentException(); - } - } catch (Exception e) { - throw new IllegalArgumentException( - String.format("PayoutToolInfo %s cannot be processed", payoutToolInfo)); - } - - } - - protected String mapCountryCode(@Nullable CountryCode countryCode) { - if (countryCode == null) { - return null; - } - return countryCode.name(); - } - - protected InternationalCorrespondentBankAccount mapInternationalCorrespondentBankAccount( - dev.vality.damsel.domain.InternationalBankAccount account) { - if (account == null) { - return null; - } - var details = account.getBank(); - return new InternationalCorrespondentBankAccount() - .bankDetails(details != null - ? new InternationalBankDetails() - .name(details.getName()) - .bic(details.getBic()) - .countryCode(details.getCountry().name()) - .address(details.getAddress()) - .abartn(details.getAbaRtn()) - : null) - .iban(account.getIban()) - .number(account.getNumber()) - .correspondentBankAccount(account.isSetCorrespondentAccount() - ? mapInternationalCorrespondentBankAccount(account.getCorrespondentAccount()) - : null); - } -} diff --git a/src/main/java/dev/vality/anapi/v2/converter/reporter/request/ParamsToStatReportRequestConverter.java b/src/main/java/dev/vality/anapi/v2/converter/reporter/request/ParamsToStatReportRequestConverter.java index 99429f00..d2f72629 100644 --- a/src/main/java/dev/vality/anapi/v2/converter/reporter/request/ParamsToStatReportRequestConverter.java +++ b/src/main/java/dev/vality/anapi/v2/converter/reporter/request/ParamsToStatReportRequestConverter.java @@ -37,10 +37,8 @@ public ReportRequest mapToReportRequest(String partyId, String shopId, OffsetDat public String mapReportType(String requestReportType) { Report.ReportTypeEnum inputType = Report.ReportTypeEnum.fromValue(requestReportType); return switch (inputType) { - case PAYMENTREGISTRY -> "payment_registry"; - case PROVISIONOFSERVICE -> "provision_of_service"; - case PAYMENTREGISTRYBYPAYOUT -> "payment_registry_by_payout"; - default -> throw new IllegalArgumentException("Unknown report type: " + inputType.getValue()); + case PAYMENT_REGISTRY -> "payment_registry"; + case PROVISION_OF_SERVICE -> "provision_of_service"; }; } diff --git a/src/main/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverter.java b/src/main/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverter.java index 9b3e910e..e2bf1c65 100644 --- a/src/main/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverter.java +++ b/src/main/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverter.java @@ -36,9 +36,8 @@ public Report convert(dev.vality.reporter.Report response) { private Report.ReportTypeEnum mapReportType(String type) { return switch (type) { - case "provision_of_service" -> Report.ReportTypeEnum.PROVISIONOFSERVICE; - case "payment_registry" -> Report.ReportTypeEnum.PAYMENTREGISTRY; - case "payment_registry_by_payout" -> Report.ReportTypeEnum.PAYMENTREGISTRYBYPAYOUT; + case "provision_of_service" -> Report.ReportTypeEnum.PROVISION_OF_SERVICE; + case "payment_registry" -> Report.ReportTypeEnum.PAYMENT_REGISTRY; default -> throw new IllegalArgumentException("Unknown report type: " + type); }; } diff --git a/src/main/java/dev/vality/anapi/v2/exception/BadRequestException.java b/src/main/java/dev/vality/anapi/v2/exception/BadRequestException.java index 30462726..914a23c8 100644 --- a/src/main/java/dev/vality/anapi/v2/exception/BadRequestException.java +++ b/src/main/java/dev/vality/anapi/v2/exception/BadRequestException.java @@ -21,7 +21,7 @@ public BadRequestException(String message, Object response) { public BadRequestException(String message) { super(message); this.response = new DefaultLogicError() - .code(DefaultLogicError.CodeEnum.INVALIDREQUEST) + .code(DefaultLogicError.CodeEnum.INVALID_REQUEST) .message(message); } } \ No newline at end of file diff --git a/src/main/java/dev/vality/anapi/v2/security/AccessData.java b/src/main/java/dev/vality/anapi/v2/security/AccessData.java index 945ef324..6010ff57 100644 --- a/src/main/java/dev/vality/anapi/v2/security/AccessData.java +++ b/src/main/java/dev/vality/anapi/v2/security/AccessData.java @@ -1,9 +1,9 @@ package dev.vality.anapi.v2.security; +import jakarta.annotation.Nullable; import lombok.Builder; import lombok.Data; -import javax.annotation.Nullable; import java.util.List; @Builder diff --git a/src/main/java/dev/vality/anapi/v2/security/AccessService.java b/src/main/java/dev/vality/anapi/v2/security/AccessService.java index 5a9c0b90..82e0a693 100644 --- a/src/main/java/dev/vality/anapi/v2/security/AccessService.java +++ b/src/main/java/dev/vality/anapi/v2/security/AccessService.java @@ -3,12 +3,13 @@ import dev.vality.anapi.v2.exception.AuthorizationException; import dev.vality.anapi.v2.exception.BouncerException; import dev.vality.anapi.v2.service.BouncerService; -import dev.vality.anapi.v2.service.KeycloakService; import dev.vality.anapi.v2.service.VortigonService; import dev.vality.bouncer.base.Entity; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Service; import javax.annotation.Nullable; @@ -24,7 +25,6 @@ public class AccessService { private final VortigonService vortigonService; private final BouncerService bouncerService; - private final KeycloakService keycloakService; @Value("${service.bouncer.auth.enabled}") private boolean authEnabled; @@ -86,16 +86,15 @@ private List getRestrictedShops(AccessData accessData, @Nullable List shopIds) { - var token = keycloakService.getAccessToken(); + var token = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); return AnapiBouncerContext.builder() .operationId(accessData.getOperationId()) .partyId(accessData.getPartyId()) .shopIds(shopIds) .fileId(accessData.getFileId()) .reportId(accessData.getReportId()) - .tokenExpiration(token.getExp()) - .tokenId(token.getId()) - .userId(token.getSubject()) + .tokenId(token.getToken().getId()) + .userId(token.getToken().getSubject()) .build(); } } diff --git a/src/main/java/dev/vality/anapi/v2/security/AnapiBouncerContext.java b/src/main/java/dev/vality/anapi/v2/security/AnapiBouncerContext.java index cfe6d68e..5e577af3 100644 --- a/src/main/java/dev/vality/anapi/v2/security/AnapiBouncerContext.java +++ b/src/main/java/dev/vality/anapi/v2/security/AnapiBouncerContext.java @@ -9,7 +9,6 @@ @Data public class AnapiBouncerContext { - private final long tokenExpiration; private final String tokenId; private final String userId; private final String operationId; diff --git a/src/main/java/dev/vality/anapi/v2/security/BouncerContextFactory.java b/src/main/java/dev/vality/anapi/v2/security/BouncerContextFactory.java index b68fc2ab..83dec0ea 100644 --- a/src/main/java/dev/vality/anapi/v2/security/BouncerContextFactory.java +++ b/src/main/java/dev/vality/anapi/v2/security/BouncerContextFactory.java @@ -1,7 +1,6 @@ package dev.vality.anapi.v2.security; import dev.vality.anapi.v2.config.properties.BouncerProperties; -import dev.vality.anapi.v2.service.KeycloakService; import dev.vality.anapi.v2.service.OrgManagerService; import dev.vality.bouncer.base.Entity; import dev.vality.bouncer.context.v1.*; @@ -11,6 +10,8 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.thrift.TSerializer; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Component; import java.time.Instant; @@ -23,7 +24,6 @@ public class BouncerContextFactory { private final BouncerProperties bouncerProperties; private final OrgManagerService orgManagerService; - private final KeycloakService keycloakService; @SneakyThrows public Context buildContext(AnapiBouncerContext bouncerContext) { @@ -33,7 +33,7 @@ public Context buildContext(AnapiBouncerContext bouncerContext) { .setType(ContextFragmentType.v1_thrift_binary) .setContent(serializer.serialize(contextFragment)); var userFragment = orgManagerService.getUserAuthContext( - keycloakService.getAccessToken().getSubject()); + bouncerContext.getUserId()); var context = new Context(); context.putToFragments(bouncerProperties.getContextFragmentId(), fragment); context.putToFragments("user", userFragment); @@ -54,11 +54,11 @@ private ContextFragment buildContextFragment(AnapiBouncerContext bouncerContext) private Auth buildAuth() { var auth = new Auth(); - var accessToken = keycloakService.getAccessToken(); + var token = (JwtAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); return auth - .setToken(new Token().setId(accessToken.getId())) + .setToken(new Token().setId(token.getToken().getId())) .setMethod(bouncerProperties.getAuthMethod()) - .setExpiration(Instant.ofEpochSecond(accessToken.getExp()).toString()); + .setExpiration(Instant.ofEpochSecond(token.getToken().getExpiresAt().getEpochSecond()).toString()); } private Environment buildEnvironment() { @@ -76,7 +76,7 @@ private ContextAnalyticsAPI buildAnapiContext(AnapiBouncerContext ctx) { .setParty(ctx.getPartyId() != null ? new Entity().setId(ctx.getPartyId()) : null) .setShop(ctx.getShopIds() != null && ctx.getShopIds().size() == 1 - ? new Entity().setId(ctx.getShopIds().get(0)) : null) + ? new Entity().setId(ctx.getShopIds().getFirst()) : null) .setFile(ctx.getFileId() != null ? new Entity().setId(ctx.getFileId()) : null) .setReport(ctx.getReportId() != null @@ -91,7 +91,7 @@ private ContextReports buildReportContext(AnapiBouncerContext ctx) { .setParty(ctx.getPartyId() != null ? new Entity().setId(ctx.getPartyId()) : null) .setShop(ctx.getShopIds() != null && ctx.getShopIds().size() == 1 - ? new Entity().setId(ctx.getShopIds().get(0)) : null) + ? new Entity().setId(ctx.getShopIds().getFirst()) : null) .setFiles(ctx.getFileId() != null ? Set.of(new Entity().setId(ctx.getFileId())) : null)); } diff --git a/src/main/java/dev/vality/anapi/v2/security/converter/JwtAuthConverter.java b/src/main/java/dev/vality/anapi/v2/security/converter/JwtAuthConverter.java new file mode 100644 index 00000000..568aae6b --- /dev/null +++ b/src/main/java/dev/vality/anapi/v2/security/converter/JwtAuthConverter.java @@ -0,0 +1,53 @@ +package dev.vality.anapi.v2.security.converter; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.convert.converter.Converter; +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class JwtAuthConverter implements Converter { + + private static final String principleAttribute = "preferred_username"; + private static final String resourceAttribute = "resource_access"; + + @Override + public AbstractAuthenticationToken convert(Jwt jwt) { + return new JwtAuthenticationToken( + jwt, + new HashSet<>(extractResourceRoles(jwt)), + getPrincipleClaimName(jwt) + ); + } + + private Collection extractResourceRoles(Jwt token) { + if (token.getClaim(resourceAttribute) == null) { + return Set.of(); + } + Map resourceAccess = token.getClaim(resourceAttribute); + if (resourceAccess.isEmpty()) { + return Set.of(); + } + + return resourceAccess.values().stream() + .map(resourceAccessInfo -> (Map) resourceAccessInfo) + .flatMap(resourceAccessInfo -> ((Collection) resourceAccessInfo.get("roles")).stream()) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toSet()); + } + + private String getPrincipleClaimName(Jwt jwt) { + return jwt.getClaim(principleAttribute); + } +} diff --git a/src/main/java/dev/vality/anapi/v2/service/AnalyticsService.java b/src/main/java/dev/vality/anapi/v2/service/AnalyticsService.java index 1193b9b8..8ab60329 100644 --- a/src/main/java/dev/vality/anapi/v2/service/AnalyticsService.java +++ b/src/main/java/dev/vality/anapi/v2/service/AnalyticsService.java @@ -1,11 +1,11 @@ package dev.vality.anapi.v2.service; import dev.vality.anapi.v2.exception.AnalytycsException; +import dev.vality.anapi.v2.model.*; import dev.vality.anapi.v2.model.OffsetAmount; import dev.vality.anapi.v2.model.OffsetCount; import dev.vality.anapi.v2.model.SplitUnit; import dev.vality.anapi.v2.model.SubError; -import dev.vality.anapi.v2.model.*; import dev.vality.damsel.analytics.*; import lombok.RequiredArgsConstructor; import org.apache.thrift.TException; @@ -19,10 +19,10 @@ public class AnalyticsService { private final AnalyticsServiceSrv.Iface analyticsClient; - public InlineResponse2006 getPaymentsToolDistribution(FilterRequest filterRequest) { + public GetPaymentsToolDistribution200Response getPaymentsToolDistribution(FilterRequest filterRequest) { try { var distribution = analyticsClient.getPaymentsToolDistribution(filterRequest); - return new InlineResponse2006() + return new GetPaymentsToolDistribution200Response() .result(distribution.getPaymentToolsDistributions().stream() .map(o -> new PaymentsToolDistributionResult() .name(o.getName()) @@ -33,10 +33,10 @@ public InlineResponse2006 getPaymentsToolDistribution(FilterRequest filterReques } } - public InlineResponse200 getPaymentsAmount(FilterRequest filterRequest) { + public GetPaymentsAmount200Response getPaymentsAmount(FilterRequest filterRequest) { try { var paymentsAmount = analyticsClient.getPaymentsAmount(filterRequest); - return new InlineResponse200() + return new GetPaymentsAmount200Response() .result(paymentsAmount.getGroupsAmount().stream() .map(o -> new AmountResult() .amount(o.getAmount()) @@ -47,10 +47,10 @@ public InlineResponse200 getPaymentsAmount(FilterRequest filterRequest) { } } - public InlineResponse200 getCreditingsAmount(FilterRequest filterRequest) { + public GetPaymentsAmount200Response getCreditingsAmount(FilterRequest filterRequest) { try { var creditingsAmount = analyticsClient.getCreditingsAmount(filterRequest); - return new InlineResponse200() + return new GetPaymentsAmount200Response() .result(creditingsAmount.getGroupsAmount().stream() .map(o -> new AmountResult() .amount(o.getAmount()) @@ -61,10 +61,10 @@ public InlineResponse200 getCreditingsAmount(FilterRequest filterRequest) { } } - public InlineResponse200 getAveragePayment(FilterRequest filterRequest) { + public GetPaymentsAmount200Response getAveragePayment(FilterRequest filterRequest) { try { var averagePayment = analyticsClient.getAveragePayment(filterRequest); - return new InlineResponse200() + return new GetPaymentsAmount200Response() .result(averagePayment.getGroupsAmount().stream() .map(o -> new AmountResult() .amount(o.getAmount()) @@ -75,10 +75,10 @@ public InlineResponse200 getAveragePayment(FilterRequest filterRequest) { } } - public InlineResponse2001 getPaymentsCount(FilterRequest filterRequest) { + public GetPaymentsCount200Response getPaymentsCount(FilterRequest filterRequest) { try { var paymentsCount = analyticsClient.getPaymentsCount(filterRequest); - return new InlineResponse2001() + return new GetPaymentsCount200Response() .result(paymentsCount.getGroupsCount().stream() .map(o -> new CountResult() .count(o.getCount()) @@ -89,10 +89,10 @@ public InlineResponse2001 getPaymentsCount(FilterRequest filterRequest) { } } - public InlineResponse2002 getPaymentsErrorDistribution(FilterRequest filterRequest) { + public GetPaymentsErrorDistribution200Response getPaymentsErrorDistribution(FilterRequest filterRequest) { try { var distribution = analyticsClient.getPaymentsErrorDistribution(filterRequest); - return new InlineResponse2002() + return new GetPaymentsErrorDistribution200Response() .result(distribution.getErrorDistributions().stream() .map(o -> new PaymentsErrorsDistributionResult() .error(o.getName()) @@ -103,10 +103,10 @@ public InlineResponse2002 getPaymentsErrorDistribution(FilterRequest filterReque } } - public InlineResponse2005 getPaymentsSubErrorDistribution(FilterRequest filterRequest) { + public GetPaymentsSubErrorDistribution200Response getPaymentsSubErrorDistribution(FilterRequest filterRequest) { try { var distribution = analyticsClient.getPaymentsSubErrorDistribution(filterRequest); - return new InlineResponse2005() + return new GetPaymentsSubErrorDistribution200Response() .result(distribution.getErrorDistributions().stream() .map(o -> new PaymentsSubErrorsDistributionResult() .error(getSubError(o.getError())) @@ -117,10 +117,10 @@ public InlineResponse2005 getPaymentsSubErrorDistribution(FilterRequest filterRe } } - public InlineResponse2003 getPaymentsSplitAmount(SplitFilterRequest splitFilterRequest) { + public GetPaymentsSplitAmount200Response getPaymentsSplitAmount(SplitFilterRequest splitFilterRequest) { try { var paymentsSplitAmount = analyticsClient.getPaymentsSplitAmount(splitFilterRequest); - return new InlineResponse2003() + return new GetPaymentsSplitAmount200Response() .result(paymentsSplitAmount.getGroupedCurrencyAmounts().stream() .map(o -> createSplitAmountResult(o, paymentsSplitAmount.getResultSplitUnit())) .collect(Collectors.toList())); @@ -129,10 +129,10 @@ public InlineResponse2003 getPaymentsSplitAmount(SplitFilterRequest splitFilterR } } - public InlineResponse2004 getPaymentsSplitCount(SplitFilterRequest splitFilterRequest) { + public GetPaymentsSplitCount200Response getPaymentsSplitCount(SplitFilterRequest splitFilterRequest) { try { var paymentsSplitCount = analyticsClient.getPaymentsSplitCount(splitFilterRequest); - return new InlineResponse2004() + return new GetPaymentsSplitCount200Response() .result(paymentsSplitCount.getPaymentToolsDestrobutions().stream() .map(o -> createSplitCountResult(o, paymentsSplitCount.getResultSplitUnit())) .collect(Collectors.toList())); @@ -141,10 +141,10 @@ public InlineResponse2004 getPaymentsSplitCount(SplitFilterRequest splitFilterRe } } - public InlineResponse200 getRefundsAmount(FilterRequest filterRequest) { + public GetPaymentsAmount200Response getRefundsAmount(FilterRequest filterRequest) { try { var refundsAmount = analyticsClient.getRefundsAmount(filterRequest); - return new InlineResponse200() + return new GetPaymentsAmount200Response() .result(refundsAmount.getGroupsAmount().stream() .map(o -> new AmountResult() .amount(o.getAmount()) @@ -155,10 +155,10 @@ public InlineResponse200 getRefundsAmount(FilterRequest filterRequest) { } } - public InlineResponse200 getCurrentBalances(MerchantFilter merchantFilter) { + public GetPaymentsAmount200Response getCurrentBalances(MerchantFilter merchantFilter) { try { var refundsAmount = analyticsClient.getCurrentBalances(merchantFilter); - return new InlineResponse200() + return new GetPaymentsAmount200Response() .result(refundsAmount.getGroupsAmount().stream() .map(o -> new AmountResult() .amount(o.getAmount()) @@ -169,7 +169,7 @@ public InlineResponse200 getCurrentBalances(MerchantFilter merchantFilter) { } } - public InlineResponse2007 getCurrentShopBalances(MerchantFilter merchantFilter) { + public GetCurrentShopBalances200Response getCurrentShopBalances(MerchantFilter merchantFilter) { try { var currentShopBalances = analyticsClient.getCurrentShopBalances(merchantFilter); var shopAmountResults = currentShopBalances.getGroupsAmount().stream() @@ -185,7 +185,7 @@ public InlineResponse2007 getCurrentShopBalances(MerchantFilter merchantFilter) .id(entry.getKey()) .amountResults(entry.getValue())) .collect(Collectors.toList()); - return new InlineResponse2007() + return new GetCurrentShopBalances200Response() .result(shopAmountResults); } catch (TException e) { throw new AnalytycsException("Error while call analyticsClient.getCurrentShopBalances", e); diff --git a/src/main/java/dev/vality/anapi/v2/service/KeycloakService.java b/src/main/java/dev/vality/anapi/v2/service/KeycloakService.java deleted file mode 100644 index a898d18e..00000000 --- a/src/main/java/dev/vality/anapi/v2/service/KeycloakService.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.vality.anapi.v2.service; - -import org.keycloak.KeycloakPrincipal; -import org.keycloak.representations.AccessToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Service; - -@Service -public class KeycloakService { - - public AccessToken getAccessToken() { - var keycloakPrincipal = (KeycloakPrincipal) SecurityContextHolder.getContext() - .getAuthentication() - .getPrincipal(); - return keycloakPrincipal.getKeycloakSecurityContext().getToken(); - } -} diff --git a/src/main/java/dev/vality/anapi/v2/service/MagistaService.java b/src/main/java/dev/vality/anapi/v2/service/MagistaService.java index f0c2d8c6..69d30fdb 100644 --- a/src/main/java/dev/vality/anapi/v2/service/MagistaService.java +++ b/src/main/java/dev/vality/anapi/v2/service/MagistaService.java @@ -20,14 +20,13 @@ public class MagistaService { private final StatPaymentToPaymentSearchResultConverter paymentResponseConverter; private final StatChargebackToChargebackConverter chargebackResponseConverter; private final StatInvoiceToInvoiceConverter invoiceResponseConverter; - private final StatPayoutToPayoutConverter payoutResponseConverter; private final StatRefundToRefundSearchResultConverter refundResponseConverter; private final StatInvoiceTemplateToInvoiceTemplateConverter invoiceTemplateResponseConverter; - public InlineResponse2008 searchInvoices(InvoiceSearchQuery query) { + public SearchInvoices200Response searchInvoices(InvoiceSearchQuery query) { try { StatInvoiceResponse magistaResponse = magistaClient.searchInvoices(query); - return new InlineResponse2008() + return new SearchInvoices200Response() .result(magistaResponse.getInvoices().stream() .map(invoiceResponseConverter::convert) .collect(Collectors.toList())) @@ -59,10 +58,10 @@ public InlineResponse2008 searchInvoices(InvoiceSearchQuery query) { } } - public InlineResponse2009 searchPayments(PaymentSearchQuery query) { + public SearchPayments200Response searchPayments(PaymentSearchQuery query) { try { StatPaymentResponse magistaResponse = magistaClient.searchPayments(query); - return new InlineResponse2009() + return new SearchPayments200Response() .result(magistaResponse.getPayments().stream() .map(paymentResponseConverter::convert) .collect(Collectors.toList())) @@ -94,10 +93,10 @@ public InlineResponse2009 searchPayments(PaymentSearchQuery query) { } } - public InlineResponse20010 searchRefunds(RefundSearchQuery query) { + public SearchRefunds200Response searchRefunds(RefundSearchQuery query) { try { StatRefundResponse magistaResponse = magistaClient.searchRefunds(query); - return new InlineResponse20010() + return new SearchRefunds200Response() .result(magistaResponse.getRefunds().stream() .map(refundResponseConverter::convert) .collect(Collectors.toList())) @@ -129,10 +128,10 @@ public InlineResponse20010 searchRefunds(RefundSearchQuery query) { } } - public InlineResponse20011 searchChargebacks(ChargebackSearchQuery query) { + public SearchChargebacks200Response searchChargebacks(ChargebackSearchQuery query) { try { StatChargebackResponse magistaResponse = magistaClient.searchChargebacks(query); - return new InlineResponse20011() + return new SearchChargebacks200Response() .result(magistaResponse.getChargebacks().stream() .map(chargebackResponseConverter::convert) .collect(Collectors.toList())) @@ -164,45 +163,10 @@ public InlineResponse20011 searchChargebacks(ChargebackSearchQuery query) { } } - public InlineResponse20012 searchPayouts(PayoutSearchQuery query) { - try { - StatPayoutResponse magistaResponse = magistaClient.searchPayouts(query); - return new InlineResponse20012() - .result(magistaResponse.getPayouts().stream() - .map(payoutResponseConverter::convert) - .collect(Collectors.toList())) - .continuationToken(magistaResponse.getContinuationToken()); - } catch (BadContinuationToken e) { - var message = String.format( - "Bad token exceeded, partyId=%s, payoutId=%s", - query.getCommonSearchQueryParams().getPartyId(), - query.getPayoutId()); - throw badContinuationTokenException(e, message); - } catch (LimitExceeded e) { - var message = String.format( - "Limit exceeded, partyId=%s, payoutId=%s", - query.getCommonSearchQueryParams().getPartyId(), - query.getPayoutId()); - throw limitExceededException(e, message); - } catch (InvalidRequest e) { - var message = String.format( - "Invalid request, partyId=%s, payoutId=%s, errors=%s", - query.getCommonSearchQueryParams().getPartyId(), - query.getPayoutId(), - String.join(", ", e.getErrors())); - throw invalidRequestException(e, message); - } catch (TException e) { - throw new MagistaException( - String.format("Error while call magistaClient.searchPayouts, partyId=%s, payoutId=%s", - query.getCommonSearchQueryParams().getPartyId(), query.getPayoutId()), - e); - } - } - - public InlineResponse20013 searchInvoiceTemplates(InvoiceTemplateSearchQuery query) { + public SearchInvoiceTemplates200Response searchInvoiceTemplates(InvoiceTemplateSearchQuery query) { try { StatInvoiceTemplateResponse magistaResponse = magistaClient.searchInvoiceTemplates(query); - return new InlineResponse20013() + return new SearchInvoiceTemplates200Response() .result(magistaResponse.getInvoiceTemplates().stream() .map(invoiceTemplateResponseConverter::convert) .collect(Collectors.toList())) @@ -237,21 +201,21 @@ public InlineResponse20013 searchInvoiceTemplates(InvoiceTemplateSearchQuery que private BadRequestException badContinuationTokenException(BadContinuationToken e, String message) { var error = new SearchRequestError() - .code(SearchRequestError.CodeEnum.BADCONTINUATIONTOKEN) + .code(SearchRequestError.CodeEnum.BAD_CONTINUATION_TOKEN) .message(message); return new BadRequestException(message, e, error); } private BadRequestException limitExceededException(LimitExceeded e, String message) { var error = new SearchRequestError() - .code(SearchRequestError.CodeEnum.LIMITEXCEEDED) + .code(SearchRequestError.CodeEnum.LIMIT_EXCEEDED) .message(message); return new BadRequestException(message, e, error); } private BadRequestException invalidRequestException(InvalidRequest e, String message) { var error = new SearchRequestError() - .code(SearchRequestError.CodeEnum.INVALIDREQUEST) + .code(SearchRequestError.CodeEnum.INVALID_REQUEST) .message(message); return new BadRequestException(message, e, error); } diff --git a/src/main/java/dev/vality/anapi/v2/service/ReporterService.java b/src/main/java/dev/vality/anapi/v2/service/ReporterService.java index 68587250..58f56569 100644 --- a/src/main/java/dev/vality/anapi/v2/service/ReporterService.java +++ b/src/main/java/dev/vality/anapi/v2/service/ReporterService.java @@ -2,7 +2,9 @@ import dev.vality.anapi.v2.converter.reporter.response.ReporterResponseToReportConverter; import dev.vality.anapi.v2.exception.ReporterException; -import dev.vality.anapi.v2.model.*; +import dev.vality.anapi.v2.model.Report; +import dev.vality.anapi.v2.model.ReportLink; +import dev.vality.anapi.v2.model.SearchReports200Response; import dev.vality.reporter.ReportRequest; import dev.vality.reporter.ReportingSrv; import dev.vality.reporter.StatReportRequest; @@ -59,10 +61,10 @@ public Report getReport(long reportId) { } } - public InlineResponse20014 getReports(StatReportRequest request) { + public SearchReports200Response getReports(StatReportRequest request) { try { var response = reporterClient.getReports(request); - return new InlineResponse20014() + return new SearchReports200Response() .result(response.getReports().stream() .map(reporterResponseToReportConverter::convert) .collect(Collectors.toList())) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8c8e4b11..40753d19 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,9 +1,9 @@ server: - port: '@server.port@' + port: ${server.port} management: server: - port: '@management.port@' + port: ${management.port} metrics: export: prometheus: @@ -54,16 +54,17 @@ spring: output: ansi: enabled: always + security: + oauth2: + resourceserver: + url: https://auth.domain + jwt: + realm: internal + issuer-uri: > + ${spring.security.oauth2.resourceserver.url}/auth/realms/ + ${spring.security.oauth2.resourceserver.jwt.realm} info: version: '@project.version@' stage: dev -keycloak: - realm: internal - auth-server-url: http://keycloak:8080/auth/ - resource: common-api - not-before: 0 - ssl-required: none - realm-public-key: - auth.enabled: true diff --git a/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java b/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java index ce9efb77..b8f2e165 100644 --- a/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java +++ b/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java @@ -4,6 +4,7 @@ import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.AnalyticsUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; +import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.analytics.AnalyticsServiceSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; @@ -15,8 +16,8 @@ import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.MultiValueMap; @@ -26,7 +27,6 @@ import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; -import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -36,13 +36,13 @@ class AnalyticsTest extends AbstractKeycloakOpenIdAsWiremockConfig { - @MockBean + @MockitoBean public VortigonServiceSrv.Iface vortigonClient; - @MockBean + @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; - @MockBean + @MockitoBean public ArbiterSrv.Iface bouncerClient; - @MockBean + @MockitoBean private AnalyticsServiceSrv.Iface analyticsClient; @Autowired @@ -73,10 +73,10 @@ void getAveragePaymentRequiredParamsRequestSuccess() { when(analyticsClient.getAveragePayment(any())).thenReturn(AnalyticsUtil.createAveragePaymentRequiredResponse()); mvc.perform(get("/lk/v2/analytics/payments/average") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getAnalyticsRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -96,10 +96,10 @@ void getAveragePaymentAllParamsRequestSuccess() { when(analyticsClient.getAveragePayment(any())).thenReturn(AnalyticsUtil.createAveragePaymentAllResponse()); mvc.perform(get("/lk/v2/analytics/payments/average") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getAnalyticsAllParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -117,14 +117,14 @@ void getAveragePaymentRequestInvalid() { params.remove("partyID"); mvc.perform(get("/lk/v2/analytics/payments/average") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").isNotEmpty()); } @@ -137,10 +137,10 @@ void getAveragePaymentRequestServerUnavailable() { when(analyticsClient.getAveragePayment(any())).thenThrow(TException.class); mvc.perform(get("/lk/v2/analytics/payments/average") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getAnalyticsRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); diff --git a/src/test/java/dev/vality/anapi/v2/ReportsTest.java b/src/test/java/dev/vality/anapi/v2/ReportsTest.java index fbcf5821..997a4b44 100644 --- a/src/test/java/dev/vality/anapi/v2/ReportsTest.java +++ b/src/test/java/dev/vality/anapi/v2/ReportsTest.java @@ -2,6 +2,7 @@ import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.testutil.OpenApiUtil; +import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; @@ -13,8 +14,8 @@ import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import java.time.Instant; @@ -28,7 +29,6 @@ import static dev.vality.anapi.v2.testutil.RandomUtil.randomIntegerAsString; import static dev.vality.anapi.v2.testutil.ReporterUtil.createReport; import static dev.vality.anapi.v2.testutil.ReporterUtil.createSearchReportsResponse; -import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -39,13 +39,13 @@ class ReportsTest extends AbstractKeycloakOpenIdAsWiremockConfig { - @MockBean + @MockitoBean public VortigonServiceSrv.Iface vortigonClient; - @MockBean + @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; - @MockBean + @MockitoBean public ArbiterSrv.Iface bouncerClient; - @MockBean + @MockitoBean private ReportingSrv.Iface reporterClient; @Autowired @@ -75,10 +75,10 @@ void cancelReportRequestSuccess() { int reportId = randomInt(1, 1000); mvc.perform(post("/lk/v2/reports/{reportId}/cancel", reportId) .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(getReportsRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isAccepted()) @@ -97,10 +97,10 @@ void cancelReportRequestServerUnavailable() { doThrow(new TException()).when(reporterClient).cancelReport(reportId); mvc.perform(post("/lk/v2/reports/{reportId}/cancel", reportId) .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(getReportsRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isInternalServerError()) @@ -120,10 +120,10 @@ void createReportRequestSuccess() { when(reporterClient.getReport(reportId)).thenReturn(createReport(reportId)); mvc.perform(post("/lk/v2/reports") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getCreateReportRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isCreated()) @@ -144,10 +144,10 @@ void downloadUrlRequestSuccess() { when(reporterClient.generatePresignedUrl(eq(fileId), any())).thenReturn("www.google.ru"); mvc.perform(get("/lk/v2/reports/{reportID}/files/{fileID}/download", reportId, fileId) .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getReportsRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isOk()) @@ -166,10 +166,10 @@ void getReportRequestSuccess() { when(reporterClient.getReport(reportId)).thenReturn(createReport(reportId)); mvc.perform(get("/lk/v2/reports/{reportID}", reportId) .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getCreateReportRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isOk()) @@ -188,10 +188,10 @@ void getSearchReportsRequestSuccess() { when(reporterClient.getReports(any())).thenReturn(createSearchReportsResponse()); mvc.perform(get("/lk/v2/reports") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchReportsRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isOk()) @@ -209,10 +209,10 @@ void getSearchReportsRequestInvalid() { params.remove("partyID"); mvc.perform(get("/lk/v2/reports") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isBadRequest()) diff --git a/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java b/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java index c0cea864..452ddffe 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java @@ -4,6 +4,7 @@ import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; +import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; @@ -15,8 +16,8 @@ import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.MultiValueMap; @@ -26,7 +27,6 @@ import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; -import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -37,13 +37,13 @@ class SearchChargebacksTest extends AbstractKeycloakOpenIdAsWiremockConfig { - @MockBean + @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; - @MockBean + @MockitoBean public VortigonServiceSrv.Iface vortigonClient; - @MockBean + @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; - @MockBean + @MockitoBean public ArbiterSrv.Iface bouncerClient; @Autowired @@ -74,10 +74,10 @@ void searchChargebacksRequiredParamsRequestSuccess() { when(magistaClient.searchChargebacks(any())).thenReturn(MagistaUtil.createSearchChargebackRequiredResponse()); mvc.perform(get("/lk/v2/chargebacks") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -97,10 +97,10 @@ void searchChargebacksAllParamsRequestSuccess() { when(magistaClient.searchChargebacks(any())).thenReturn(MagistaUtil.createSearchChargebackAllResponse()); mvc.perform(get("/lk/v2/chargebacks") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchChargebackAllParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -118,14 +118,14 @@ void searchChargebacksRequestInvalid() { params.remove("partyID"); mvc.perform(get("/lk/v2/chargebacks") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").isNotEmpty()); } @@ -138,10 +138,10 @@ void searchChargebacksRequestMagistaUnavailable() { when(magistaClient.searchPayments(any())).thenThrow(TException.class); mvc.perform(get("/lk/v2/chargebacks") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java b/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java index 908a5354..03bb20d2 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java @@ -4,6 +4,7 @@ import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; +import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; @@ -15,8 +16,8 @@ import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.MultiValueMap; @@ -26,7 +27,6 @@ import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; -import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -36,13 +36,13 @@ class SearchInvoiceTemplatesTest extends AbstractKeycloakOpenIdAsWiremockConfig { - @MockBean + @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; - @MockBean + @MockitoBean public VortigonServiceSrv.Iface vortigonClient; - @MockBean + @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; - @MockBean + @MockitoBean public ArbiterSrv.Iface bouncerClient; @Autowired @@ -74,10 +74,10 @@ void searchInvoiceTemplatesRequiredParamsRequestSuccess() { MagistaUtil.createSearchInvoiceTemplateRequiredResponse()); mvc.perform(get("/lk/v2/invoice-templates") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -98,10 +98,10 @@ void searchInvoiceTemplatesAllParamsRequestSuccess() { MagistaUtil.createSearchInvoiceTemplateAllResponse()); mvc.perform(get("/lk/v2/invoice-templates") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchInvoiceAllParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -119,14 +119,14 @@ void searchInvoiceTemplatesRequestInvalid() { params.remove("partyID"); mvc.perform(get("/lk/v2/invoice-templates") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").isNotEmpty()); } @@ -139,10 +139,10 @@ void searchInvoiceTemplatesRequestMagistaUnavailable() { when(magistaClient.searchInvoiceTemplates(any())).thenThrow(TException.class); mvc.perform(get("/lk/v2/invoice-templates") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java b/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java index 1d220e1d..47dc1606 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java @@ -4,6 +4,7 @@ import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; +import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; @@ -15,8 +16,8 @@ import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.MultiValueMap; @@ -26,7 +27,6 @@ import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; -import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -36,13 +36,13 @@ class SearchInvoicesTest extends AbstractKeycloakOpenIdAsWiremockConfig { - @MockBean + @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; - @MockBean + @MockitoBean public VortigonServiceSrv.Iface vortigonClient; - @MockBean + @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; - @MockBean + @MockitoBean public ArbiterSrv.Iface bouncerClient; @Autowired @@ -73,10 +73,10 @@ void searchInvoicesRequiredParamsRequestSuccess() { when(magistaClient.searchInvoices(any())).thenReturn(MagistaUtil.createSearchInvoiceRequiredResponse()); mvc.perform(get("/lk/v2/invoices") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -96,10 +96,10 @@ void searchInvoicesAllParamsRequestSuccess() { when(magistaClient.searchInvoices(any())).thenReturn(MagistaUtil.createSearchInvoiceAllResponse()); mvc.perform(get("/lk/v2/invoices") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchInvoiceAllParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -117,14 +117,14 @@ void searchInvoicesRequestInvalid() { params.remove("partyID"); mvc.perform(get("/lk/v2/invoices") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").isNotEmpty()); } @@ -137,10 +137,10 @@ void searchInvoicesRequestMagistaUnavailable() { when(magistaClient.searchInvoices(any())).thenThrow(TException.class); mvc.perform(get("/lk/v2/invoices") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java b/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java index 641d397e..49f5e5db 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java @@ -4,6 +4,7 @@ import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; +import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; @@ -15,8 +16,8 @@ import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.MultiValueMap; @@ -26,7 +27,6 @@ import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; -import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -36,13 +36,13 @@ class SearchPaymentsTest extends AbstractKeycloakOpenIdAsWiremockConfig { - @MockBean + @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; - @MockBean + @MockitoBean public VortigonServiceSrv.Iface vortigonClient; - @MockBean + @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; - @MockBean + @MockitoBean public ArbiterSrv.Iface bouncerClient; @Autowired @@ -73,10 +73,10 @@ void searchPaymentsRequiredParamsRequestSuccess() { when(magistaClient.searchPayments(any())).thenReturn(MagistaUtil.createSearchPaymentRequiredResponse()); mvc.perform(get("/lk/v2/payments") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -96,10 +96,10 @@ void searchPaymentsAllParamsRequestSuccess() { when(magistaClient.searchPayments(any())).thenReturn(MagistaUtil.createSearchPaymentAllResponse()); mvc.perform(get("/lk/v2/payments") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchPaymentAllParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -117,14 +117,14 @@ void searchPaymentsRequestInvalid() { params.remove("partyID"); mvc.perform(get("/lk/v2/payments") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").isNotEmpty()); } @@ -137,10 +137,10 @@ void searchPaymentsRequestMagistaUnavailable() { when(magistaClient.searchPayments(any())).thenThrow(TException.class); mvc.perform(get("/lk/v2/payments") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchPayoutsTest.java b/src/test/java/dev/vality/anapi/v2/SearchPayoutsTest.java deleted file mode 100644 index 3f016a37..00000000 --- a/src/test/java/dev/vality/anapi/v2/SearchPayoutsTest.java +++ /dev/null @@ -1,152 +0,0 @@ -package dev.vality.anapi.v2; - -import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; -import dev.vality.anapi.v2.model.DefaultLogicError; -import dev.vality.anapi.v2.testutil.MagistaUtil; -import dev.vality.anapi.v2.testutil.OpenApiUtil; -import dev.vality.bouncer.decisions.ArbiterSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; -import dev.vality.magista.MerchantStatisticsServiceSrv; -import dev.vality.orgmanagement.AuthContextProviderSrv; -import lombok.SneakyThrows; -import org.apache.thrift.TException; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.MockitoAnnotations; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.util.MultiValueMap; - -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.List; - -import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; -import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; -import static java.util.UUID.randomUUID; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -class SearchPayoutsTest extends AbstractKeycloakOpenIdAsWiremockConfig { - - @MockBean - public MerchantStatisticsServiceSrv.Iface magistaClient; - @MockBean - public VortigonServiceSrv.Iface vortigonClient; - @MockBean - public AuthContextProviderSrv.Iface orgManagerClient; - @MockBean - public ArbiterSrv.Iface bouncerClient; - - @Autowired - private MockMvc mvc; - - private AutoCloseable mocks; - - private Object[] preparedMocks; - - @BeforeEach - public void init() { - mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; - } - - @AfterEach - public void clean() throws Exception { - verifyNoMoreInteractions(preparedMocks); - mocks.close(); - } - - @Test - @SneakyThrows - void searchPayoutsRequiredParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); - when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); - when(magistaClient.searchPayouts(any())).thenReturn(MagistaUtil.createSearchPayoutRequiredResponse()); - mvc.perform(get("/lk/v2/payouts") - .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) - .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) - .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content("")) - .andDo(print()) - .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(orgManagerClient, times(1)).getUserContext(any()); - verify(bouncerClient, times(1)).judge(any(), any()); - verify(magistaClient, times(1)).searchPayouts(any()); - } - - @Test - @SneakyThrows - void searchPayoutsAllParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); - when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); - when(magistaClient.searchPayouts(any())).thenReturn(MagistaUtil.createSearchPayoutAllResponse()); - mvc.perform(get("/lk/v2/payouts") - .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) - .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) - .params(OpenApiUtil.getSearchPayoutAllParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content("")) - .andDo(print()) - .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(orgManagerClient, times(1)).getUserContext(any()); - verify(bouncerClient, times(1)).judge(any(), any()); - verify(magistaClient, times(1)).searchPayouts(any()); - } - - @Test - @SneakyThrows - void searchPayoutsRequestInvalid() { - MultiValueMap params = OpenApiUtil.getSearchRequiredParams(); - params.remove("partyID"); - mvc.perform(get("/lk/v2/payouts") - .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) - .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) - .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content("")) - .andDo(print()) - .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) - .andExpect(jsonPath("$.message").isNotEmpty()); - } - - @Test - @SneakyThrows - void searchPayoutsRequestMagistaUnavailable() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); - when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); - when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); - when(magistaClient.searchPayouts(any())).thenThrow(TException.class); - mvc.perform(get("/lk/v2/payouts") - .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) - .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) - .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content("")) - .andDo(print()) - .andExpect(status().is5xxServerError()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); - verify(orgManagerClient, times(1)).getUserContext(any()); - verify(bouncerClient, times(1)).judge(any(), any()); - verify(magistaClient, times(1)).searchPayouts(any()); - } -} diff --git a/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java b/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java index 86342e21..ad547ea3 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java @@ -4,6 +4,7 @@ import dev.vality.anapi.v2.model.DefaultLogicError; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; +import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; @@ -15,8 +16,8 @@ import org.junit.jupiter.api.Test; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.MultiValueMap; @@ -26,7 +27,6 @@ import static dev.vality.anapi.v2.testutil.MagistaUtil.createContextFragment; import static dev.vality.anapi.v2.testutil.MagistaUtil.createJudgementAllowed; -import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -36,13 +36,13 @@ class SearchRefundsTest extends AbstractKeycloakOpenIdAsWiremockConfig { - @MockBean + @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; - @MockBean + @MockitoBean public VortigonServiceSrv.Iface vortigonClient; - @MockBean + @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; - @MockBean + @MockitoBean public ArbiterSrv.Iface bouncerClient; @Autowired @@ -73,10 +73,10 @@ void searchRefundsRequiredParamsRequestSuccess() { when(magistaClient.searchRefunds(any())).thenReturn(MagistaUtil.createSearchRefundRequiredResponse()); mvc.perform(get("/lk/v2/refunds") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -96,10 +96,10 @@ void searchRefundsAllParamsRequestSuccess() { when(magistaClient.searchRefunds(any())).thenReturn(MagistaUtil.createSearchRefundAllResponse()); mvc.perform(get("/lk/v2/refunds") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRefundAllParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is2xxSuccessful()) @@ -117,14 +117,14 @@ void searchRefundsRequestInvalid() { params.remove("partyID"); mvc.perform(get("/lk/v2/refunds") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").isNotEmpty()); } @@ -137,10 +137,10 @@ void searchRefundsRequestMagistaUnavailable() { when(magistaClient.searchRefunds(any())).thenThrow(TException.class); mvc.perform(get("/lk/v2/refunds") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); diff --git a/src/test/java/dev/vality/anapi/v2/auth/JwtTokenTestConfiguration.java b/src/test/java/dev/vality/anapi/v2/auth/JwtTokenTestConfiguration.java index d9166329..f56da090 100644 --- a/src/test/java/dev/vality/anapi/v2/auth/JwtTokenTestConfiguration.java +++ b/src/test/java/dev/vality/anapi/v2/auth/JwtTokenTestConfiguration.java @@ -3,37 +3,17 @@ import dev.vality.anapi.v2.auth.utils.JwtTokenBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; -import org.springframework.core.io.ClassPathResource; -import java.io.IOException; -import java.security.*; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.util.Base64; -import java.util.Properties; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; @Configuration public class JwtTokenTestConfiguration { - @Bean - public static PropertySourcesPlaceholderConfigurer properties(KeyPair keyPair) - throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { - KeyFactory fact = KeyFactory.getInstance("RSA"); - X509EncodedKeySpec spec = fact.getKeySpec(keyPair.getPublic(), X509EncodedKeySpec.class); - String publicKey = Base64.getEncoder().encodeToString(spec.getEncoded()); - PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer(); - Properties properties = new Properties(); - properties.load(new ClassPathResource("application.yml").getInputStream()); - properties.setProperty("keycloak.realm-public-key", publicKey); - pspc.setProperties(properties); - pspc.setLocalOverride(true); - return pspc; - } - @Bean public JwtTokenBuilder jwtTokenBuilder(KeyPair keyPair) { - return new JwtTokenBuilder(keyPair.getPrivate()); + return new JwtTokenBuilder(keyPair); } @Bean diff --git a/src/test/java/dev/vality/anapi/v2/auth/KeycloakOpenIdTestConfiguration.java b/src/test/java/dev/vality/anapi/v2/auth/KeycloakOpenIdTestConfiguration.java index 872b1bd1..190b51ba 100644 --- a/src/test/java/dev/vality/anapi/v2/auth/KeycloakOpenIdTestConfiguration.java +++ b/src/test/java/dev/vality/anapi/v2/auth/KeycloakOpenIdTestConfiguration.java @@ -2,6 +2,7 @@ import dev.vality.anapi.v2.auth.utils.JwtTokenBuilder; import dev.vality.anapi.v2.auth.utils.KeycloakOpenIdStub; +import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -10,9 +11,11 @@ public class KeycloakOpenIdTestConfiguration { @Bean - public KeycloakOpenIdStub keycloakOpenIdStub(@Value("${keycloak.auth-server-url}") String keycloakAuthServerUrl, - @Value("${keycloak.realm}") String keycloakRealm, - JwtTokenBuilder jwtTokenBuilder) { - return new KeycloakOpenIdStub(keycloakAuthServerUrl, keycloakRealm, jwtTokenBuilder); + @SneakyThrows + public KeycloakOpenIdStub keycloakOpenIdStub( + @Value("${spring.security.oauth2.resourceserver.url}") String keycloakAuthServerUrl, + @Value("${spring.security.oauth2.resourceserver.jwt.realm}") String keycloakRealm, + JwtTokenBuilder jwtTokenBuilder) { + return new KeycloakOpenIdStub(keycloakAuthServerUrl + "/auth", keycloakRealm, jwtTokenBuilder); } } diff --git a/src/test/java/dev/vality/anapi/v2/auth/utils/JwtTokenBuilder.java b/src/test/java/dev/vality/anapi/v2/auth/utils/JwtTokenBuilder.java index f0be4b61..efd8fbc0 100644 --- a/src/test/java/dev/vality/anapi/v2/auth/utils/JwtTokenBuilder.java +++ b/src/test/java/dev/vality/anapi/v2/auth/utils/JwtTokenBuilder.java @@ -1,12 +1,14 @@ package dev.vality.anapi.v2.auth.utils; import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; +import lombok.SneakyThrows; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.security.KeyPair; import java.security.PrivateKey; +import java.security.PublicKey; import java.time.Instant; import java.util.UUID; @@ -24,15 +26,18 @@ public class JwtTokenBuilder { private final PrivateKey privateKey; - public JwtTokenBuilder(PrivateKey privateKey) { - this(UUID.randomUUID().toString(), DEFAULT_USERNAME, DEFAULT_EMAIL, privateKey); + private final PublicKey publicKey; + + public JwtTokenBuilder(KeyPair keyPair) { + this(UUID.randomUUID().toString(), DEFAULT_USERNAME, DEFAULT_EMAIL, keyPair.getPrivate(), keyPair.getPublic()); } - public JwtTokenBuilder(String userId, String username, String email, PrivateKey privateKey) { + public JwtTokenBuilder(String userId, String username, String email, PrivateKey privateKey, PublicKey publicKey) { this.userId = userId; this.username = username; this.email = email; this.privateKey = privateKey; + this.publicKey = publicKey; } public String generateJwtWithRoles(String issuer, String... roles) { @@ -42,12 +47,16 @@ public String generateJwtWithRoles(String issuer, String... roles) { } public String generateJwtWithRoles(long iat, long exp, String issuer, String... roles) { + return generateJwtWithRoles(privateKey, iat, exp, issuer, roles); + } + + public String generateJwtWithRoles(PrivateKey privateKey, long iat, long exp, String issuer, String... roles) { String payload; try { payload = new JSONObject() .put("jti", UUID.randomUUID().toString()) .put("exp", exp) - .put("nbf", "0") + .put("nbf", 0L) .put("iat", iat) .put("iss", issuer) .put("aud", "private-api") @@ -63,11 +72,20 @@ public String generateJwtWithRoles(long iat, long exp, String issuer, String... throw new RuntimeException(e); } - String jwt = Jwts.builder() - .setPayload(payload) - .signWith(SignatureAlgorithm.RS256, privateKey) + return Jwts.builder() + .content(payload) + .signWith(privateKey, Jwts.SIG.RS256) .compact(); - return jwt; + } + + @SneakyThrows + public PublicKey getPublicKey() { + return this.publicKey; + } + + @SneakyThrows + public PrivateKey getPrivateKey() { + return this.privateKey; } } diff --git a/src/test/java/dev/vality/anapi/v2/auth/utils/KeycloakOpenIdStub.java b/src/test/java/dev/vality/anapi/v2/auth/utils/KeycloakOpenIdStub.java index 0ff3b0a9..2cc136b8 100644 --- a/src/test/java/dev/vality/anapi/v2/auth/utils/KeycloakOpenIdStub.java +++ b/src/test/java/dev/vality/anapi/v2/auth/utils/KeycloakOpenIdStub.java @@ -1,5 +1,12 @@ package dev.vality.anapi.v2.auth.utils; +import dev.vality.anapi.v2.testutil.GenerateSelfSigned; +import dev.vality.anapi.v2.testutil.PublicKeyUtil; +import lombok.SneakyThrows; + +import java.security.KeyPair; +import java.util.Base64; + import static com.github.tomakehurst.wiremock.client.WireMock.*; public class KeycloakOpenIdStub { @@ -7,8 +14,10 @@ public class KeycloakOpenIdStub { private final String keycloakRealm; private final String issuer; private final String openidConfig; + private final String jwkConfig; private final JwtTokenBuilder jwtTokenBuilder; + @SneakyThrows public KeycloakOpenIdStub(String keycloakAuthServerUrl, String keycloakRealm, JwtTokenBuilder jwtTokenBuilder) { this.keycloakRealm = keycloakRealm; this.jwtTokenBuilder = jwtTokenBuilder; @@ -34,6 +43,30 @@ public KeycloakOpenIdStub(String keycloakAuthServerUrl, String keycloakRealm, Jw " \"introspection_endpoint\": \"" + keycloakAuthServerUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/token/introspect\"\n" + "}"; + this.jwkConfig = """ + { + "keys": [ + { + "alg": "RS256", + "e": "%s", + "kid": "BZdHlAdlt3F1XatlYtZg3f1Cfpk5IpEINuIgviUW59s", + "kty": "RSA", + "n": "%s", + "use": "sig", + "x5c": [ + "%s" + ], + "x5t": "9APiqOME1mVmyv8hak6HB_PTezA", + "x5t#S256": "kweH93DnMHKD_NrAZF-mgpAM3Njv_8-oxaDAzki4t48" + } + ] + } + """.formatted( + PublicKeyUtil.getExponent(jwtTokenBuilder.getPublicKey()), + PublicKeyUtil.getModulus(jwtTokenBuilder.getPublicKey()), + Base64.getEncoder().encodeToString( + GenerateSelfSigned.generateCertificate(new KeyPair(jwtTokenBuilder.getPublicKey(), + jwtTokenBuilder.getPrivateKey())).getEncoded())); } public void givenStub() { @@ -43,6 +76,11 @@ public void givenStub() { .withBody(openidConfig) ) ); + stubFor(get(urlEqualTo(String.format("/auth/realms/%s/protocol/openid-connect/certs", keycloakRealm))) + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withBody(jwkConfig) + )); } public String generateJwt(String... roles) { diff --git a/src/test/java/dev/vality/anapi/v2/config/AbstractKeycloakOpenIdAsWiremockConfig.java b/src/test/java/dev/vality/anapi/v2/config/AbstractKeycloakOpenIdAsWiremockConfig.java index 3c5282a8..d5228228 100644 --- a/src/test/java/dev/vality/anapi/v2/config/AbstractKeycloakOpenIdAsWiremockConfig.java +++ b/src/test/java/dev/vality/anapi/v2/config/AbstractKeycloakOpenIdAsWiremockConfig.java @@ -10,12 +10,15 @@ import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; import org.springframework.test.context.junit.jupiter.SpringExtension; +@SuppressWarnings("LineLength") @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {AnapiV2Application.class}, properties = { "wiremock.server.baseUrl=http://localhost:${wiremock.server.port}", - "keycloak.auth-server-url=${wiremock.server.baseUrl}/auth"}) + "spring.security.oauth2.resourceserver.url=http://localhost:${wiremock.server.port}", + "spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:${wiremock.server.port}/auth/realms/" + + "${spring.security.oauth2.resourceserver.jwt.realm}"}) @AutoConfigureMockMvc @AutoConfigureWireMock(port = 0) @ExtendWith(SpringExtension.class) diff --git a/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java b/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java index e89796a0..3e2c42ee 100644 --- a/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java +++ b/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java @@ -4,8 +4,9 @@ import dev.vality.anapi.v2.converter.magista.request.ParamsToRefundSearchQueryConverter; import dev.vality.anapi.v2.exception.BadRequestException; import dev.vality.anapi.v2.model.DefaultLogicError; -import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.anapi.v2.testutil.MagistaUtil; +import dev.vality.anapi.v2.testutil.OpenApiUtil; +import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; @@ -15,8 +16,8 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.util.MultiValueMap; @@ -24,7 +25,6 @@ import java.time.temporal.ChronoUnit; import java.util.List; -import static java.util.UUID.randomUUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -36,13 +36,13 @@ class ErrorControllerTest extends AbstractKeycloakOpenIdAsWiremockConfig { @Autowired private MockMvc mockMvc; - @MockBean + @MockitoBean private ParamsToRefundSearchQueryConverter refundSearchConverter; - @MockBean + @MockitoBean public VortigonServiceSrv.Iface vortigonClient; - @MockBean + @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; - @MockBean + @MockitoBean public ArbiterSrv.Iface bouncerClient; private AutoCloseable mocks; @@ -69,14 +69,14 @@ void testConstraintViolationException() throws Exception { mockMvc.perform( get("/lk/v2/payments") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").isNotEmpty()); } @@ -96,14 +96,14 @@ void testBadRequestException() throws Exception { mockMvc.perform( get("/lk/v2/refunds") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").value(message)); verify(vortigonClient, times(1)).getShopsIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); @@ -123,14 +123,14 @@ void testMissingServletRequestParameterException() throws Exception { mockMvc.perform( get("/lk/v2/refunds") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDREQUEST.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").isNotEmpty()); } @@ -139,14 +139,14 @@ void testDeadlineException() throws Exception { mockMvc.perform( get("/lk/v2/refunds") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", "fail") .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALIDDEADLINE.getValue())) + .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_DEADLINE.getValue())) .andExpect(jsonPath("$.message").isNotEmpty()); } @@ -165,10 +165,10 @@ void testInternalException() throws Exception { mockMvc.perform( get("/lk/v2/refunds") .header("Authorization", "Bearer " + generateSimpleJwt()) - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString()) .params(params) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isInternalServerError()) @@ -186,10 +186,10 @@ void testInternalException() throws Exception { void testUnauthorizedException() throws Exception { mockMvc.perform( get("/lk/v2/refunds") - .header("X-Request-ID", randomUUID()) + .header("X-Request-ID", RandomUtil.randomRequestId()) .header("X-Request-Deadline", "fail") .params(OpenApiUtil.getSearchRequiredParams()) - .contentType(MediaType.APPLICATION_JSON_UTF8) + .contentType(MediaType.APPLICATION_JSON) .content("")) .andDo(print()) .andExpect(status().isUnauthorized()) diff --git a/src/test/java/dev/vality/anapi/v2/converter/magista/request/ParamsToPayoutSearchQueryConverterTest.java b/src/test/java/dev/vality/anapi/v2/converter/magista/request/ParamsToPayoutSearchQueryConverterTest.java deleted file mode 100644 index c18b69b1..00000000 --- a/src/test/java/dev/vality/anapi/v2/converter/magista/request/ParamsToPayoutSearchQueryConverterTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package dev.vality.anapi.v2.converter.magista.request; - -import dev.vality.anapi.v2.exception.BadRequestException; -import dev.vality.magista.PayoutSearchQuery; -import dev.vality.magista.PayoutToolType; -import org.junit.jupiter.api.Test; - -import java.time.OffsetDateTime; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -class ParamsToPayoutSearchQueryConverterTest { - - private static final ParamsToPayoutSearchQueryConverter converter = new ParamsToPayoutSearchQueryConverter(); - - @Test - void convert() { - PayoutSearchQuery query = converter.convert("1", - OffsetDateTime.MIN, - OffsetDateTime.MAX, - 10, - List.of("1", "2", "3"), - "1", - "Wallet", - "test"); - assertNotNull(query); - } - - @Test - void mapPayoutToolType() { - assertEquals(PayoutToolType.payout_account, converter.mapPayoutToolType("PayoutAccount")); - assertEquals(PayoutToolType.wallet, converter.mapPayoutToolType("Wallet")); - assertEquals(PayoutToolType.payment_institution_account, - converter.mapPayoutToolType("PaymentInstitutionAccount")); - assertThrows(BadRequestException.class, () -> converter.mapPayoutToolType("unexpected")); - } -} \ No newline at end of file diff --git a/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatPaymentToPaymentSearchResultConverterTest.java b/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatPaymentToPaymentSearchResultConverterTest.java index 9603baba..b89e111e 100644 --- a/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatPaymentToPaymentSearchResultConverterTest.java +++ b/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatPaymentToPaymentSearchResultConverterTest.java @@ -4,18 +4,18 @@ import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.anapi.v2.util.MaskUtil; +import dev.vality.damsel.domain.*; import dev.vality.damsel.domain.ClientInfo; import dev.vality.damsel.domain.ContactInfo; import dev.vality.damsel.domain.InvoicePaymentStatus; import dev.vality.damsel.domain.PaymentResourcePayer; import dev.vality.damsel.domain.RecurrentPayer; -import dev.vality.damsel.domain.*; import dev.vality.geck.common.util.TypeUtil; +import dev.vality.magista.*; import dev.vality.magista.CustomerPayer; import dev.vality.magista.InvoicePaymentFlow; import dev.vality.magista.InvoicePaymentFlowInstant; import dev.vality.magista.Payer; -import dev.vality.magista.*; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -44,7 +44,7 @@ void convert() { () -> assertEquals(magistaPayment.getCurrencySymbolicCode(), result.getCurrency()), () -> assertEquals(magistaPayment.getExternalId(), result.getExternalID()), () -> assertEquals(magistaPayment.getFee(), result.getFee()), - () -> assertEquals(PaymentFlow.TypeEnum.PAYMENTFLOWINSTANT, result.getFlow().getType()), + () -> assertEquals(PaymentFlow.TypeEnum.PAYMENT_FLOW_INSTANT, result.getFlow().getType()), () -> assertEquals(magistaPayment.getStatusChangedAt(), result.getStatusChangedAt().toString()), () -> assertEquals(magistaPayment.getId(), result.getId()), () -> assertEquals(magistaPayment.getInvoiceId(), result.getInvoiceID()), @@ -104,9 +104,9 @@ void mapPayer() { assertAll( () -> assertEquals("1111", paymentResourcePayer.getPaymentToolToken()), () -> assertEquals("1111", paymentResourcePayer.getPaymentSession()), - () -> assertEquals("print", paymentResourcePayer.getClientInfo().get().getFingerprint()), - () -> assertTrue(paymentResourcePayer.getClientInfo().isPresent()), - () -> assertEquals("127.0.0.1", paymentResourcePayer.getClientInfo().get().getIp()), + () -> assertEquals("print", paymentResourcePayer.getClientInfo().getFingerprint()), + () -> assertNotNull(paymentResourcePayer.getClientInfo()), + () -> assertEquals("127.0.0.1", paymentResourcePayer.getClientInfo().getIp()), () -> assertEquals("mail@mail.com", paymentResourcePayer.getContactInfo().getEmail()), () -> assertEquals("88005553535", paymentResourcePayer.getContactInfo().getPhoneNumber()), () -> assertEquals("1234", resourcePayerPaymentToolDetails.getBin()), @@ -170,12 +170,12 @@ void mapStatus() { void mapFlow() { InvoicePaymentFlow flow = InvoicePaymentFlow.instant(new InvoicePaymentFlowInstant()); PaymentFlow instantFlow = converter.mapFlow(flow); - assertEquals(PaymentFlow.TypeEnum.PAYMENTFLOWINSTANT, instantFlow.getType()); + assertEquals(PaymentFlow.TypeEnum.PAYMENT_FLOW_INSTANT, instantFlow.getType()); InvoicePaymentFlow magistaFlow = MagistaUtil.createInvoicePaymentFlowHold(); var holdFlow = (PaymentFlowHold) converter.mapFlow(magistaFlow); assertAll( - () -> assertEquals(PaymentFlow.TypeEnum.PAYMENTFLOWHOLD, holdFlow.getType()), + () -> assertEquals(PaymentFlow.TypeEnum.PAYMENT_FLOW_HOLD, holdFlow.getType()), () -> assertEquals(magistaFlow.getHold().getHeldUntil(), holdFlow.getHeldUntil().toString()), () -> assertEquals(magistaFlow.getHold().getOnHoldExpiration().name(), holdFlow.getOnHoldExpiration().getValue()) diff --git a/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatPayoutToPayoutConverterTest.java b/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatPayoutToPayoutConverterTest.java deleted file mode 100644 index 24266ed6..00000000 --- a/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatPayoutToPayoutConverterTest.java +++ /dev/null @@ -1,190 +0,0 @@ -package dev.vality.anapi.v2.converter.magista.response; - -import dev.vality.anapi.v2.model.*; -import dev.vality.anapi.v2.testutil.MagistaUtil; -import dev.vality.anapi.v2.testutil.RandomUtil; -import dev.vality.damsel.domain.InternationalBankAccount; -import dev.vality.damsel.domain.InternationalBankDetails; -import dev.vality.damsel.domain.*; -import dev.vality.magista.*; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class StatPayoutToPayoutConverterTest { - - private static final StatPayoutToPayoutConverter converter = new StatPayoutToPayoutConverter(); - - @Test - void convert() { - StatPayoutResponse magistaResponse = MagistaUtil.createSearchPayoutAllResponse(); - StatPayout magistaPayout = magistaResponse.getPayouts().get(0); - Payout result = converter.convert(magistaPayout); - assertAll( - () -> assertEquals(magistaPayout.getAmount(), result.getAmount()), - () -> assertEquals(magistaPayout.getCreatedAt(), result.getCreatedAt().toString()), - () -> assertEquals(magistaPayout.getCurrencySymbolicCode(), result.getCurrency()), - () -> assertEquals(magistaPayout.getFee(), result.getFee()), - () -> assertEquals(magistaPayout.getId(), result.getId()), - () -> assertEquals(magistaPayout.getShopId(), result.getShopID()) - ); - - } - - @Test - void mapPayoutStatus() { - assertAll( - () -> assertEquals("Cancelled", converter.mapStatus(PayoutStatus.cancelled(new PayoutCancelled()))), - () -> assertEquals("Paid", converter.mapStatus(PayoutStatus.paid(new PayoutPaid()))), - () -> assertEquals("Confirmed", converter.mapStatus(PayoutStatus.confirmed(new PayoutConfirmed()))), - () -> assertEquals("Unpaid", converter.mapStatus(PayoutStatus.unpaid(new PayoutUnpaid()))), - () -> assertThrows(IllegalArgumentException.class, () -> converter.mapStatus(new PayoutStatus())) - ); - } - - @Test - void mapPayoutToolDetails() { - //RussianBankAccount - PayoutToolInfo toolInfo = new PayoutToolInfo(); - toolInfo.setRussianBankAccount(new RussianBankAccount() - .setAccount(RandomUtil.randomString(10)) - .setBankBik(RandomUtil.randomString(10)) - .setBankName(RandomUtil.randomString(10)) - .setBankPostAccount(RandomUtil.randomString(10))); - - PayoutToolDetailsBankAccount actualRussianBankAccount = - (PayoutToolDetailsBankAccount) converter.mapPayoutToolDetails(toolInfo); - RussianBankAccount expectedRussianBankAccount = toolInfo.getRussianBankAccount(); - assertAll( - () -> assertEquals(expectedRussianBankAccount.getAccount(), actualRussianBankAccount.getAccount()), - () -> assertEquals(expectedRussianBankAccount.getBankBik(), actualRussianBankAccount.getBankBik()), - () -> assertEquals(expectedRussianBankAccount.getBankName(), actualRussianBankAccount.getBankName()), - () -> assertEquals(expectedRussianBankAccount.getBankPostAccount(), - actualRussianBankAccount.getBankPostAccount()) - ); - - //WalletInfo - toolInfo = new PayoutToolInfo(); - toolInfo.setWalletInfo(new WalletInfo() - .setWalletId(RandomUtil.randomString(10))); - - PayoutToolDetailsWalletInfo walletActual = - (PayoutToolDetailsWalletInfo) converter.mapPayoutToolDetails(toolInfo); - WalletInfo walletExpected = toolInfo.getWalletInfo(); - assertEquals(walletExpected.getWalletId(), walletActual.getWalletID()); - - //PaymentInstitutionAccount - toolInfo = new PayoutToolInfo(); - toolInfo.setPaymentInstitutionAccount(new PaymentInstitutionAccount()); - - PayoutToolDetailsPaymentInstitutionAccount actualPaymentInstitutionAccount = - (PayoutToolDetailsPaymentInstitutionAccount) converter.mapPayoutToolDetails(toolInfo); - PaymentInstitutionAccount expectedPaymentInstitutionAccount = toolInfo.getPaymentInstitutionAccount(); - assertNotNull(expectedPaymentInstitutionAccount); - - //InternationalBankAccount - toolInfo = new PayoutToolInfo(); - toolInfo.setInternationalBankAccount(new InternationalBankAccount() - .setAccountHolder(RandomUtil.randomString(10)) - .setIban(RandomUtil.randomString(10)) - .setNumber(RandomUtil.randomString(10)) - .setBank(new InternationalBankDetails() - .setName(RandomUtil.randomString(10)) - .setAbaRtn(RandomUtil.randomString(10)) - .setAddress(RandomUtil.randomString(10)) - .setBic(RandomUtil.randomString(10)) - .setCountry(CountryCode.ABW))); - - PayoutToolDetailsInternationalBankAccount actualInternationalBankAccount = - (PayoutToolDetailsInternationalBankAccount) converter.mapPayoutToolDetails(toolInfo); - InternationalBankAccount expectedInternationalBankAccount = toolInfo.getInternationalBankAccount(); - - assertAll( - () -> assertEquals(expectedInternationalBankAccount.getIban(), - actualInternationalBankAccount.getIban()), - () -> assertEquals(expectedInternationalBankAccount.getNumber(), - actualInternationalBankAccount.getNumber()), - () -> assertEquals(expectedInternationalBankAccount.getBank().getAbaRtn(), - actualInternationalBankAccount.getBankDetails().getAbartn()), - () -> assertEquals(expectedInternationalBankAccount.getBank().getAddress(), - actualInternationalBankAccount.getBankDetails().getAddress()), - () -> assertEquals(expectedInternationalBankAccount.getBank().getBic(), - actualInternationalBankAccount.getBankDetails().getBic()), - () -> assertEquals(expectedInternationalBankAccount.getBank().getName(), - actualInternationalBankAccount.getBankDetails().getName()), - () -> assertEquals(expectedInternationalBankAccount.getBank().getCountry().name(), - actualInternationalBankAccount.getBankDetails().getCountryCode()), - //tested via mapInternationalCorrespondentBankAccount test - () -> assertNull(actualInternationalBankAccount.getCorrespondentBankAccount()) - ); - - //Some missing type - assertThrows(IllegalArgumentException.class, () -> converter.mapPayoutToolDetails(new PayoutToolInfo())); - - } - - @Test - void mapCountryCode() { - CountryCode countryCode = CountryCode.ABH; - assertEquals("ABH", converter.mapCountryCode(countryCode)); - assertNull(converter.mapCountryCode(null)); - } - - @Test - void mapInternationalCorrespondentBankAccount() { - InternationalBankAccount expected = new InternationalBankAccount() - .setAccountHolder(RandomUtil.randomString(10)) - .setIban(RandomUtil.randomString(10)) - .setNumber(RandomUtil.randomString(10)) - .setBank(new InternationalBankDetails() - .setName(RandomUtil.randomString(10)) - .setAbaRtn(RandomUtil.randomString(10)) - .setAddress(RandomUtil.randomString(10)) - .setBic(RandomUtil.randomString(10)) - .setCountry(CountryCode.ABW)) - .setCorrespondentAccount(new InternationalBankAccount() - .setAccountHolder(RandomUtil.randomString(5)) - .setIban(RandomUtil.randomString(5)) - .setNumber(RandomUtil.randomString(5)) - .setBank(new InternationalBankDetails() - .setName(RandomUtil.randomString(5)) - .setAbaRtn(RandomUtil.randomString(5)) - .setAddress(RandomUtil.randomString(5)) - .setBic(RandomUtil.randomString(5)) - .setCountry(CountryCode.RUS))); - - InternationalCorrespondentBankAccount actual = converter.mapInternationalCorrespondentBankAccount(expected); - - assertAll( - () -> assertEquals(expected.getIban(), - actual.getIban()), - () -> assertEquals(expected.getNumber(), - actual.getNumber()), - () -> assertEquals(expected.getBank().getAbaRtn(), - actual.getBankDetails().getAbartn()), - () -> assertEquals(expected.getBank().getAddress(), - actual.getBankDetails().getAddress()), - () -> assertEquals(expected.getBank().getBic(), - actual.getBankDetails().getBic()), - () -> assertEquals(expected.getBank().getName(), - actual.getBankDetails().getName()), - () -> assertEquals(expected.getBank().getCountry().name(), - actual.getBankDetails().getCountryCode()), - () -> assertEquals(expected.getCorrespondentAccount().getIban(), - actual.getCorrespondentBankAccount().getIban()), - () -> assertEquals(expected.getCorrespondentAccount().getNumber(), - actual.getCorrespondentBankAccount().getNumber()), - () -> assertEquals(expected.getCorrespondentAccount().getBank().getAbaRtn(), - actual.getCorrespondentBankAccount().getBankDetails().getAbartn()), - () -> assertEquals(expected.getCorrespondentAccount().getBank().getAddress(), - actual.getCorrespondentBankAccount().getBankDetails().getAddress()), - () -> assertEquals(expected.getCorrespondentAccount().getBank().getBic(), - actual.getCorrespondentBankAccount().getBankDetails().getBic()), - () -> assertEquals(expected.getCorrespondentAccount().getBank().getName(), - actual.getCorrespondentBankAccount().getBankDetails().getName()), - () -> assertEquals(expected.getCorrespondentAccount().getBank().getCountry().name(), - actual.getCorrespondentBankAccount().getBankDetails().getCountryCode()), - () -> assertNull(actual.getCorrespondentBankAccount().getCorrespondentBankAccount()) - ); - } -} \ No newline at end of file diff --git a/src/test/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverterTest.java b/src/test/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverterTest.java index 82eb1f4c..33ec2830 100644 --- a/src/test/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverterTest.java +++ b/src/test/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverterTest.java @@ -5,7 +5,7 @@ import dev.vality.reporter.StatReportResponse; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNotNull; class ReporterResponseToReportConverterTest { diff --git a/src/test/java/dev/vality/anapi/v2/testutil/GenerateSelfSigned.java b/src/test/java/dev/vality/anapi/v2/testutil/GenerateSelfSigned.java new file mode 100644 index 00000000..f40a81c6 --- /dev/null +++ b/src/test/java/dev/vality/anapi/v2/testutil/GenerateSelfSigned.java @@ -0,0 +1,37 @@ +package dev.vality.anapi.v2.testutil; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.util.Date; + +public class GenerateSelfSigned { + + public static X509Certificate generateCertificate(KeyPair keyPair) throws CertificateException, + OperatorCreationException { + X500Name x500Name = new X500Name("CN=***.com, OU=Security&Defense, O=*** Crypto., L=Ottawa, ST=Ontario, C=CA"); + SubjectPublicKeyInfo pubKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()); + final Date start = new Date(); + final Date until = Date.from(LocalDate.now().plusDays(365).atStartOfDay().toInstant(ZoneOffset.UTC)); + final X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(x500Name, + new BigInteger(10, new SecureRandom()), start, until, x500Name, pubKeyInfo + ); + ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSA").build(keyPair.getPrivate()); + return new JcaX509CertificateConverter() + .setProvider(new BouncyCastleProvider()) + .getCertificate(certificateBuilder.build(contentSigner)); + } +} \ No newline at end of file diff --git a/src/test/java/dev/vality/anapi/v2/testutil/MagistaUtil.java b/src/test/java/dev/vality/anapi/v2/testutil/MagistaUtil.java index 4f2df0af..88327936 100644 --- a/src/test/java/dev/vality/anapi/v2/testutil/MagistaUtil.java +++ b/src/test/java/dev/vality/anapi/v2/testutil/MagistaUtil.java @@ -5,16 +5,16 @@ import dev.vality.bouncer.decisions.Resolution; import dev.vality.bouncer.decisions.ResolutionAllowed; import dev.vality.damsel.base.Content; +import dev.vality.damsel.domain.*; import dev.vality.damsel.domain.InvoicePaymentRefundStatus; import dev.vality.damsel.domain.InvoicePaymentStatus; import dev.vality.damsel.domain.InvoiceStatus; -import dev.vality.damsel.domain.*; +import dev.vality.magista.*; import dev.vality.magista.CustomerPayer; import dev.vality.magista.InvoicePaymentFlow; import dev.vality.magista.InvoicePaymentFlowHold; import dev.vality.magista.InvoicePaymentFlowInstant; import dev.vality.magista.Payer; -import dev.vality.magista.*; import lombok.SneakyThrows; import lombok.experimental.UtilityClass; import org.apache.thrift.TSerializer; @@ -119,24 +119,6 @@ public static StatInvoiceResponse createSearchInvoiceAllResponse() { ); } - public static StatPayoutResponse createSearchPayoutRequiredResponse() { - return DamselUtil.fillRequiredTBaseObject(new StatPayoutResponse(), StatPayoutResponse.class); - } - - public static StatPayoutResponse createSearchPayoutAllResponse() { - var payout = DamselUtil.fillRequiredTBaseObject(new StatPayout(), StatPayout.class); - var toolInfo = DamselUtil.fillRequiredTBaseObject(new PayoutToolInfo(), PayoutToolInfo.class); - var bank = DamselUtil.fillRequiredTBaseObject(new RussianBankAccount(), RussianBankAccount.class); - var status = DamselUtil.fillRequiredTBaseObject(new PayoutStatus(), PayoutStatus.class); - var response = DamselUtil.fillRequiredTBaseObject(new StatPayoutResponse(), StatPayoutResponse.class); - toolInfo.setRussianBankAccount(bank); - return response.setPayouts( - List.of(payout - .setPayoutToolInfo(toolInfo) - .setStatus(status)) - ); - } - public static StatInvoiceTemplateResponse createSearchInvoiceTemplateAllResponse() { var invoiceTemplate = DamselUtil.fillRequiredTBaseObject(new StatInvoiceTemplate(), StatInvoiceTemplate.class); var cash = DamselUtil.fillRequiredTBaseObject(new Cash(), Cash.class); diff --git a/src/test/java/dev/vality/anapi/v2/testutil/OpenApiUtil.java b/src/test/java/dev/vality/anapi/v2/testutil/OpenApiUtil.java index 9ceb2d32..ff87ccf1 100644 --- a/src/test/java/dev/vality/anapi/v2/testutil/OpenApiUtil.java +++ b/src/test/java/dev/vality/anapi/v2/testutil/OpenApiUtil.java @@ -111,21 +111,6 @@ public static MultiValueMap getSearchInvoiceAllParams() { return params; } - public static MultiValueMap getSearchPayoutAllParams() { - MultiValueMap params = getSearchRequiredParams(); - params.add("shopID", randomIntegerAsString(1, 3)); - params.add("shopIDs", randomIntegerAsString(11, 20)); - params.add("shopIDs", randomIntegerAsString(21, 30)); - params.add("paymentInstitutionRealm", PaymentInstitutionRealm.live.name()); - params.add("offset", randomIntegerAsString(1, 10)); - params.add("payoutID", randomIntegerAsString(1, 1000)); - params.add("payoutToolType", "PayoutAccount"); - params.add("excludedShops", randomIntegerAsString(1, 10)); - params.add("excludedShops", randomIntegerAsString(11, 20)); - params.add("continuationToken", "test"); - return params; - } - public static MultiValueMap getAnalyticsRequiredParams() { MultiValueMap params = new LinkedMultiValueMap<>(); params.add("partyID", randomIntegerAsString(1, 1000)); diff --git a/src/test/java/dev/vality/anapi/v2/testutil/PublicKeyUtil.java b/src/test/java/dev/vality/anapi/v2/testutil/PublicKeyUtil.java new file mode 100644 index 00000000..62517415 --- /dev/null +++ b/src/test/java/dev/vality/anapi/v2/testutil/PublicKeyUtil.java @@ -0,0 +1,25 @@ +package dev.vality.anapi.v2.testutil; + +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Base64; + +@UtilityClass +public class PublicKeyUtil { + + @SneakyThrows + public String getModulus(PublicKey publicKey) { + BigInteger publicKeyModulus = ((RSAPublicKey) (publicKey)).getModulus(); + return Base64.getUrlEncoder().encodeToString(publicKeyModulus.toByteArray()); + } + + @SneakyThrows + public String getExponent(PublicKey publicKey) { + BigInteger publicKeyExponent = ((RSAPublicKey) (publicKey)).getPublicExponent(); + return Base64.getUrlEncoder().encodeToString(publicKeyExponent.toByteArray()); + } +} diff --git a/src/test/java/dev/vality/anapi/v2/testutil/RandomUtil.java b/src/test/java/dev/vality/anapi/v2/testutil/RandomUtil.java index 40aae493..ca6d1359 100644 --- a/src/test/java/dev/vality/anapi/v2/testutil/RandomUtil.java +++ b/src/test/java/dev/vality/anapi/v2/testutil/RandomUtil.java @@ -5,6 +5,8 @@ import java.nio.charset.StandardCharsets; import java.util.Random; +import static java.util.UUID.randomUUID; + @UtilityClass public class RandomUtil { @@ -28,4 +30,8 @@ public static byte[] randomBytes(int length) { return array; } + public static String randomRequestId() { + return randomUUID().toString().substring(0, 32); + } + } diff --git a/src/test/java/dev/vality/anapi/v2/util/DeadlineUtilTest.java b/src/test/java/dev/vality/anapi/v2/util/DeadlineUtilTest.java index 9f43b246..e0f61ec7 100644 --- a/src/test/java/dev/vality/anapi/v2/util/DeadlineUtilTest.java +++ b/src/test/java/dev/vality/anapi/v2/util/DeadlineUtilTest.java @@ -7,7 +7,8 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; class DeadlineUtilTest { From 1026f91d018837680636d2116355a8c530f9eae4 Mon Sep 17 00:00:00 2001 From: Egor Cherniak Date: Mon, 30 Jun 2025 20:33:10 +0300 Subject: [PATCH 3/7] Replace vortigon with dominant --- pom.xml | 6 --- .../anapi/v2/config/ApplicationConfig.java | 10 ++-- .../anapi/v2/exception/DominantException.java | 12 +++++ .../anapi/v2/exception/VortigonException.java | 12 ----- .../anapi/v2/security/AccessService.java | 6 +-- .../anapi/v2/service/DominantService.java | 54 +++++++++++++++++++ .../anapi/v2/service/VortigonService.java | 38 ------------- src/main/resources/application.yml | 2 +- .../dev/vality/anapi/v2/AnalyticsTest.java | 19 +++---- .../java/dev/vality/anapi/v2/ReportsTest.java | 10 ++-- .../anapi/v2/SearchChargebacksTest.java | 18 +++---- .../anapi/v2/SearchInvoiceTemplatesTest.java | 18 +++---- .../vality/anapi/v2/SearchInvoicesTest.java | 18 +++---- .../vality/anapi/v2/SearchPaymentsTest.java | 18 +++---- .../vality/anapi/v2/SearchRefundsTest.java | 18 +++---- .../v2/controller/ErrorControllerTest.java | 14 ++--- 16 files changed, 142 insertions(+), 131 deletions(-) create mode 100644 src/main/java/dev/vality/anapi/v2/exception/DominantException.java delete mode 100644 src/main/java/dev/vality/anapi/v2/exception/VortigonException.java create mode 100644 src/main/java/dev/vality/anapi/v2/service/DominantService.java delete mode 100644 src/main/java/dev/vality/anapi/v2/service/VortigonService.java diff --git a/pom.xml b/pom.xml index 2be09877..53d2b8c6 100644 --- a/pom.xml +++ b/pom.xml @@ -56,11 +56,6 @@ magista-proto 1.44-5352f74 - - dev.vality - party-shop-proto - 1.19-72faaf6 - dev.vality analytics-proto @@ -78,7 +73,6 @@ dev.vality damsel - 1.597-bfedcb9 diff --git a/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java b/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java index 07be9b6b..4b2772a9 100644 --- a/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java +++ b/src/main/java/dev/vality/anapi/v2/config/ApplicationConfig.java @@ -2,7 +2,7 @@ import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.analytics.AnalyticsServiceSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; +import dev.vality.damsel.domain_config_v2.RepositoryClientSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import dev.vality.reporter.ReportingSrv; @@ -43,13 +43,13 @@ public AnalyticsServiceSrv.Iface analyticsClient( } @Bean - public VortigonServiceSrv.Iface vortigonClient( - @Value("${service.vortigon.url}") Resource resource, - @Value("${service.vortigon.networkTimeout}") int networkTimeout) throws IOException { + public RepositoryClientSrv.Iface dominantClient( + @Value("${service.dominant.url}") Resource resource, + @Value("${service.dominant.networkTimeout}") int networkTimeout) throws IOException { return new THSpawnClientBuilder() .withNetworkTimeout(networkTimeout) .withAddress(resource.getURI()) - .build(VortigonServiceSrv.Iface.class); + .build(RepositoryClientSrv.Iface.class); } @Bean diff --git a/src/main/java/dev/vality/anapi/v2/exception/DominantException.java b/src/main/java/dev/vality/anapi/v2/exception/DominantException.java new file mode 100644 index 00000000..bedb8ff9 --- /dev/null +++ b/src/main/java/dev/vality/anapi/v2/exception/DominantException.java @@ -0,0 +1,12 @@ +package dev.vality.anapi.v2.exception; + +public class DominantException extends AnapiV25xxException { + + public DominantException(String s) { + super(s); + } + + public DominantException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/dev/vality/anapi/v2/exception/VortigonException.java b/src/main/java/dev/vality/anapi/v2/exception/VortigonException.java deleted file mode 100644 index cf78ee06..00000000 --- a/src/main/java/dev/vality/anapi/v2/exception/VortigonException.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.vality.anapi.v2.exception; - -public class VortigonException extends AnapiV25xxException { - - public VortigonException(String s) { - super(s); - } - - public VortigonException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/dev/vality/anapi/v2/security/AccessService.java b/src/main/java/dev/vality/anapi/v2/security/AccessService.java index 82e0a693..20b1a189 100644 --- a/src/main/java/dev/vality/anapi/v2/security/AccessService.java +++ b/src/main/java/dev/vality/anapi/v2/security/AccessService.java @@ -3,7 +3,7 @@ import dev.vality.anapi.v2.exception.AuthorizationException; import dev.vality.anapi.v2.exception.BouncerException; import dev.vality.anapi.v2.service.BouncerService; -import dev.vality.anapi.v2.service.VortigonService; +import dev.vality.anapi.v2.service.DominantService; import dev.vality.bouncer.base.Entity; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -23,7 +23,7 @@ @Service public class AccessService { - private final VortigonService vortigonService; + private final DominantService dominantService; private final BouncerService bouncerService; @Value("${service.bouncer.auth.enabled}") @@ -34,7 +34,7 @@ public void checkUserAccess(AccessData accessData) { } public List getRestrictedShops(AccessData accessData) { - var requestedShopIds = vortigonService.getShopIds(accessData.getPartyId(), + var requestedShopIds = dominantService.getShopIds(accessData.getPartyId(), Objects.requireNonNullElse(accessData.getRealm(), "live")); if (accessData.getShopIds() != null && !accessData.getShopIds().isEmpty()) { requestedShopIds = accessData.getShopIds().stream() diff --git a/src/main/java/dev/vality/anapi/v2/service/DominantService.java b/src/main/java/dev/vality/anapi/v2/service/DominantService.java new file mode 100644 index 00000000..10a9b2c7 --- /dev/null +++ b/src/main/java/dev/vality/anapi/v2/service/DominantService.java @@ -0,0 +1,54 @@ +package dev.vality.anapi.v2.service; + +import dev.vality.anapi.v2.exception.DominantException; +import dev.vality.damsel.domain.*; +import dev.vality.damsel.domain_config_v2.RepositoryClientSrv; +import dev.vality.damsel.domain_config_v2.VersionReference; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.thrift.TException; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class DominantService { + + private final RepositoryClientSrv.Iface dominantClient; + + public List getShopIds(String partyId, String realm) { + try { + log.info("Looking for shops, partyId={}, realm={}", partyId, realm); + List shopsRefs = getShopConfigRefs(partyId); + List shopsObjects = getShopConfigObjects(shopsRefs); + var shopIds = shopsObjects.stream() + .filter(shopConfigObject -> realmMatches(realm, shopConfigObject)) + .map(shopConfigObject -> shopConfigObject.getData().getId()).toList(); + log.info("Found {} shops, partyId={}, realm={}", shopIds.size(), partyId, realm); + return shopIds; + } catch (TException e) { + throw new DominantException(String.format("Error while call dominant, partyId=%s", partyId), e); + } + } + + private List getShopConfigRefs(String partyId) throws TException { + var partyReference = Reference.party_config(new PartyConfigRef(partyId)); + var party = dominantClient.checkoutObject(new VersionReference(), partyReference); + return party.getObject().getPartyConfig().getData().getShops(); + } + + private List getShopConfigObjects(List shopConfigRefs) throws TException { + var shopConfigs = dominantClient.checkoutObjects(new VersionReference(), + shopConfigRefs.stream().map(Reference::shop_config).toList()); + return shopConfigs.stream().map(domainObject -> domainObject.getObject().getShopConfig()).toList(); + } + + private boolean realmMatches(String expectedRealm, ShopConfigObject shopConfigObject) { + int realmId = shopConfigObject.getData().getPaymentInstitution().getId(); + var paymentInstitutionRealm = + PaymentInstitutionRealm.findByValue(realmId); + return expectedRealm.equals(paymentInstitutionRealm.name()); + } +} diff --git a/src/main/java/dev/vality/anapi/v2/service/VortigonService.java b/src/main/java/dev/vality/anapi/v2/service/VortigonService.java deleted file mode 100644 index 50de7e03..00000000 --- a/src/main/java/dev/vality/anapi/v2/service/VortigonService.java +++ /dev/null @@ -1,38 +0,0 @@ -package dev.vality.anapi.v2.service; - -import dev.vality.anapi.v2.exception.BadRequestException; -import dev.vality.anapi.v2.exception.VortigonException; -import dev.vality.damsel.vortigon.PaymentInstitutionRealm; -import dev.vality.damsel.vortigon.VortigonServiceSrv; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.thrift.TException; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Slf4j -@Service -@RequiredArgsConstructor -public class VortigonService { - - private final VortigonServiceSrv.Iface vortigonClient; - - public List getShopIds(String partyId, String realm) { - try { - List shops = vortigonClient.getShopsIds(partyId, mapRealm(realm)); - log.info("Received shops from vortigon: {}", shops); - return shops; - } catch (TException e) { - throw new VortigonException(String.format("Error while call vortigon, partyId=%s", partyId), e); - } - } - - private PaymentInstitutionRealm mapRealm(String realm) { - try { - return PaymentInstitutionRealm.valueOf(realm); - } catch (IllegalArgumentException e) { - throw new BadRequestException(String.format("Realm %s cannot be processed", realm)); - } - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 40753d19..abda6983 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -27,7 +27,7 @@ service: analytics: url: http://localhost:8022/change_it networkTimeout: 5000 - vortigon: + dominant: url: http://localhost:8022/change_it networkTimeout: 5000 orgManager: diff --git a/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java b/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java index b8f2e165..3b5df960 100644 --- a/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java +++ b/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java @@ -2,12 +2,13 @@ import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; +import dev.vality.anapi.v2.service.DominantService; import dev.vality.anapi.v2.testutil.AnalyticsUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.analytics.AnalyticsServiceSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; +import dev.vality.damsel.domain_config_v2.RepositoryClientSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; @@ -37,7 +38,7 @@ class AnalyticsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockitoBean - public VortigonServiceSrv.Iface vortigonClient; + public DominantService dominantService; @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; @MockitoBean @@ -55,7 +56,7 @@ class AnalyticsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{analyticsClient, vortigonClient, orgManagerClient, bouncerClient}; + preparedMocks = new Object[]{analyticsClient, dominantService, orgManagerClient, bouncerClient}; } @AfterEach @@ -67,7 +68,7 @@ public void clean() throws Exception { @Test @SneakyThrows void getAveragePaymentRequiredParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(analyticsClient.getAveragePayment(any())).thenReturn(AnalyticsUtil.createAveragePaymentRequiredResponse()); @@ -81,7 +82,7 @@ void getAveragePaymentRequiredParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(analyticsClient, times(1)).getAveragePayment(any()); @@ -90,7 +91,7 @@ void getAveragePaymentRequiredParamsRequestSuccess() { @Test @SneakyThrows void getAveragePaymentAllParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(analyticsClient.getAveragePayment(any())).thenReturn(AnalyticsUtil.createAveragePaymentAllResponse()); @@ -104,7 +105,7 @@ void getAveragePaymentAllParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(analyticsClient, times(1)).getAveragePayment(any()); @@ -131,7 +132,7 @@ void getAveragePaymentRequestInvalid() { @Test @SneakyThrows void getAveragePaymentRequestServerUnavailable() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(analyticsClient.getAveragePayment(any())).thenThrow(TException.class); @@ -144,7 +145,7 @@ void getAveragePaymentRequestServerUnavailable() { .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(analyticsClient, times(1)).getAveragePayment(any()); diff --git a/src/test/java/dev/vality/anapi/v2/ReportsTest.java b/src/test/java/dev/vality/anapi/v2/ReportsTest.java index 997a4b44..25da8a5d 100644 --- a/src/test/java/dev/vality/anapi/v2/ReportsTest.java +++ b/src/test/java/dev/vality/anapi/v2/ReportsTest.java @@ -1,10 +1,10 @@ package dev.vality.anapi.v2; import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; +import dev.vality.anapi.v2.service.DominantService; import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import dev.vality.reporter.ReportingSrv; import lombok.SneakyThrows; @@ -40,7 +40,7 @@ class ReportsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockitoBean - public VortigonServiceSrv.Iface vortigonClient; + public DominantService dominantService; @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; @MockitoBean @@ -58,7 +58,7 @@ class ReportsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[] {reporterClient, vortigonClient, orgManagerClient, bouncerClient}; + preparedMocks = new Object[] {reporterClient, dominantService, orgManagerClient, bouncerClient}; } @AfterEach @@ -182,7 +182,7 @@ void getReportRequestSuccess() { @Test @SneakyThrows void getSearchReportsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(reporterClient.getReports(any())).thenReturn(createSearchReportsResponse()); @@ -196,7 +196,7 @@ void getSearchReportsRequestSuccess() { .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(reporterClient, times(1)).getReports(notNull()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java b/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java index 452ddffe..cf5e457b 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchChargebacksTest.java @@ -2,11 +2,11 @@ import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; +import dev.vality.anapi.v2.service.DominantService; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import lombok.SneakyThrows; @@ -40,7 +40,7 @@ class SearchChargebacksTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; @MockitoBean - public VortigonServiceSrv.Iface vortigonClient; + public DominantService dominantService; @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; @MockitoBean @@ -56,7 +56,7 @@ class SearchChargebacksTest extends AbstractKeycloakOpenIdAsWiremockConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; + preparedMocks = new Object[]{magistaClient, dominantService, orgManagerClient, bouncerClient}; } @AfterEach @@ -68,7 +68,7 @@ public void clean() throws Exception { @Test @SneakyThrows void searchChargebacksRequiredParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchChargebacks(any())).thenReturn(MagistaUtil.createSearchChargebackRequiredResponse()); @@ -82,7 +82,7 @@ void searchChargebacksRequiredParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchChargebacks(any()); @@ -91,7 +91,7 @@ void searchChargebacksRequiredParamsRequestSuccess() { @Test @SneakyThrows void searchChargebacksAllParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchChargebacks(any())).thenReturn(MagistaUtil.createSearchChargebackAllResponse()); @@ -105,7 +105,7 @@ void searchChargebacksAllParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchChargebacks(any()); @@ -132,7 +132,7 @@ void searchChargebacksRequestInvalid() { @Test @SneakyThrows void searchChargebacksRequestMagistaUnavailable() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayments(any())).thenThrow(TException.class); @@ -145,7 +145,7 @@ void searchChargebacksRequestMagistaUnavailable() { .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchChargebacks(any()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java b/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java index 03bb20d2..a63eb41d 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchInvoiceTemplatesTest.java @@ -2,11 +2,11 @@ import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; +import dev.vality.anapi.v2.service.DominantService; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import lombok.SneakyThrows; @@ -39,7 +39,7 @@ class SearchInvoiceTemplatesTest extends AbstractKeycloakOpenIdAsWiremockConfig @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; @MockitoBean - public VortigonServiceSrv.Iface vortigonClient; + public DominantService dominantService; @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; @MockitoBean @@ -55,7 +55,7 @@ class SearchInvoiceTemplatesTest extends AbstractKeycloakOpenIdAsWiremockConfig @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; + preparedMocks = new Object[]{magistaClient, dominantService, orgManagerClient, bouncerClient}; } @AfterEach @@ -67,7 +67,7 @@ public void clean() throws Exception { @Test @SneakyThrows void searchInvoiceTemplatesRequiredParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoiceTemplates(any())).thenReturn( @@ -82,7 +82,7 @@ void searchInvoiceTemplatesRequiredParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoiceTemplates(any()); @@ -91,7 +91,7 @@ void searchInvoiceTemplatesRequiredParamsRequestSuccess() { @Test @SneakyThrows void searchInvoiceTemplatesAllParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoiceTemplates(any())).thenReturn( @@ -106,7 +106,7 @@ void searchInvoiceTemplatesAllParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoiceTemplates(any()); @@ -133,7 +133,7 @@ void searchInvoiceTemplatesRequestInvalid() { @Test @SneakyThrows void searchInvoiceTemplatesRequestMagistaUnavailable() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoiceTemplates(any())).thenThrow(TException.class); @@ -146,7 +146,7 @@ void searchInvoiceTemplatesRequestMagistaUnavailable() { .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoiceTemplates(any()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java b/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java index 47dc1606..662cb67a 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchInvoicesTest.java @@ -2,11 +2,11 @@ import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; +import dev.vality.anapi.v2.service.DominantService; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import lombok.SneakyThrows; @@ -39,7 +39,7 @@ class SearchInvoicesTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; @MockitoBean - public VortigonServiceSrv.Iface vortigonClient; + public DominantService dominantService; @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; @MockitoBean @@ -55,7 +55,7 @@ class SearchInvoicesTest extends AbstractKeycloakOpenIdAsWiremockConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; + preparedMocks = new Object[]{magistaClient, dominantService, orgManagerClient, bouncerClient}; } @AfterEach @@ -67,7 +67,7 @@ public void clean() throws Exception { @Test @SneakyThrows void searchInvoicesRequiredParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoices(any())).thenReturn(MagistaUtil.createSearchInvoiceRequiredResponse()); @@ -81,7 +81,7 @@ void searchInvoicesRequiredParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoices(any()); @@ -90,7 +90,7 @@ void searchInvoicesRequiredParamsRequestSuccess() { @Test @SneakyThrows void searchInvoicesAllParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoices(any())).thenReturn(MagistaUtil.createSearchInvoiceAllResponse()); @@ -104,7 +104,7 @@ void searchInvoicesAllParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoices(any()); @@ -131,7 +131,7 @@ void searchInvoicesRequestInvalid() { @Test @SneakyThrows void searchInvoicesRequestMagistaUnavailable() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchInvoices(any())).thenThrow(TException.class); @@ -144,7 +144,7 @@ void searchInvoicesRequestMagistaUnavailable() { .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchInvoices(any()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java b/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java index 49f5e5db..99ca469b 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchPaymentsTest.java @@ -2,11 +2,11 @@ import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; +import dev.vality.anapi.v2.service.DominantService; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import lombok.SneakyThrows; @@ -39,7 +39,7 @@ class SearchPaymentsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; @MockitoBean - public VortigonServiceSrv.Iface vortigonClient; + public DominantService dominantService; @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; @MockitoBean @@ -55,7 +55,7 @@ class SearchPaymentsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; + preparedMocks = new Object[]{magistaClient, dominantService, orgManagerClient, bouncerClient}; } @AfterEach @@ -67,7 +67,7 @@ public void clean() throws Exception { @Test @SneakyThrows void searchPaymentsRequiredParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayments(any())).thenReturn(MagistaUtil.createSearchPaymentRequiredResponse()); @@ -81,7 +81,7 @@ void searchPaymentsRequiredParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchPayments(any()); @@ -90,7 +90,7 @@ void searchPaymentsRequiredParamsRequestSuccess() { @Test @SneakyThrows void searchPaymentsAllParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayments(any())).thenReturn(MagistaUtil.createSearchPaymentAllResponse()); @@ -104,7 +104,7 @@ void searchPaymentsAllParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchPayments(any()); @@ -131,7 +131,7 @@ void searchPaymentsRequestInvalid() { @Test @SneakyThrows void searchPaymentsRequestMagistaUnavailable() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchPayments(any())).thenThrow(TException.class); @@ -144,7 +144,7 @@ void searchPaymentsRequestMagistaUnavailable() { .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchPayments(any()); diff --git a/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java b/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java index ad547ea3..eec3525e 100644 --- a/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java +++ b/src/test/java/dev/vality/anapi/v2/SearchRefundsTest.java @@ -2,11 +2,11 @@ import dev.vality.anapi.v2.config.AbstractKeycloakOpenIdAsWiremockConfig; import dev.vality.anapi.v2.model.DefaultLogicError; +import dev.vality.anapi.v2.service.DominantService; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.magista.MerchantStatisticsServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import lombok.SneakyThrows; @@ -39,7 +39,7 @@ class SearchRefundsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockitoBean public MerchantStatisticsServiceSrv.Iface magistaClient; @MockitoBean - public VortigonServiceSrv.Iface vortigonClient; + public DominantService dominantService; @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; @MockitoBean @@ -55,7 +55,7 @@ class SearchRefundsTest extends AbstractKeycloakOpenIdAsWiremockConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{magistaClient, vortigonClient, orgManagerClient, bouncerClient}; + preparedMocks = new Object[]{magistaClient, dominantService, orgManagerClient, bouncerClient}; } @AfterEach @@ -67,7 +67,7 @@ public void clean() throws Exception { @Test @SneakyThrows void searchRefundsRequiredParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchRefunds(any())).thenReturn(MagistaUtil.createSearchRefundRequiredResponse()); @@ -81,7 +81,7 @@ void searchRefundsRequiredParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchRefunds(any()); @@ -90,7 +90,7 @@ void searchRefundsRequiredParamsRequestSuccess() { @Test @SneakyThrows void searchRefundsAllParamsRequestSuccess() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchRefunds(any())).thenReturn(MagistaUtil.createSearchRefundAllResponse()); @@ -104,7 +104,7 @@ void searchRefundsAllParamsRequestSuccess() { .andDo(print()) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$").exists()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchRefunds(any()); @@ -131,7 +131,7 @@ void searchRefundsRequestInvalid() { @Test @SneakyThrows void searchRefundsRequestMagistaUnavailable() { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(createJudgementAllowed()); when(magistaClient.searchRefunds(any())).thenThrow(TException.class); @@ -144,7 +144,7 @@ void searchRefundsRequestMagistaUnavailable() { .content("")) .andDo(print()) .andExpect(status().is5xxServerError()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(magistaClient, times(1)).searchRefunds(any()); diff --git a/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java b/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java index 3e2c42ee..c572af58 100644 --- a/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java +++ b/src/test/java/dev/vality/anapi/v2/controller/ErrorControllerTest.java @@ -4,11 +4,11 @@ import dev.vality.anapi.v2.converter.magista.request.ParamsToRefundSearchQueryConverter; import dev.vality.anapi.v2.exception.BadRequestException; import dev.vality.anapi.v2.model.DefaultLogicError; +import dev.vality.anapi.v2.service.DominantService; import dev.vality.anapi.v2.testutil.MagistaUtil; import dev.vality.anapi.v2.testutil.OpenApiUtil; import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; -import dev.vality.damsel.vortigon.VortigonServiceSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -39,7 +39,7 @@ class ErrorControllerTest extends AbstractKeycloakOpenIdAsWiremockConfig { @MockitoBean private ParamsToRefundSearchQueryConverter refundSearchConverter; @MockitoBean - public VortigonServiceSrv.Iface vortigonClient; + public DominantService dominantService; @MockitoBean public AuthContextProviderSrv.Iface orgManagerClient; @MockitoBean @@ -52,7 +52,7 @@ class ErrorControllerTest extends AbstractKeycloakOpenIdAsWiremockConfig { @BeforeEach public void init() { mocks = MockitoAnnotations.openMocks(this); - preparedMocks = new Object[]{refundSearchConverter, vortigonClient, orgManagerClient, bouncerClient}; + preparedMocks = new Object[]{refundSearchConverter, dominantService, orgManagerClient, bouncerClient}; } @AfterEach @@ -82,7 +82,7 @@ void testConstraintViolationException() throws Exception { @Test void testBadRequestException() throws Exception { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(MagistaUtil.createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(MagistaUtil.createJudgementAllowed()); String message = "Error!"; @@ -105,7 +105,7 @@ void testBadRequestException() throws Exception { .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.code").value(DefaultLogicError.CodeEnum.INVALID_REQUEST.getValue())) .andExpect(jsonPath("$.message").value(message)); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(refundSearchConverter, times(1)) @@ -152,7 +152,7 @@ void testDeadlineException() throws Exception { @Test void testInternalException() throws Exception { - when(vortigonClient.getShopsIds(any(), any())).thenReturn(List.of("1", "2", "3")); + when(dominantService.getShopIds(any(), any())).thenReturn(List.of("1", "2", "3")); when(orgManagerClient.getUserContext(any())).thenReturn(MagistaUtil.createContextFragment()); when(bouncerClient.judge(any(), any())).thenReturn(MagistaUtil.createJudgementAllowed()); doThrow(new RuntimeException()).when(refundSearchConverter) @@ -173,7 +173,7 @@ void testInternalException() throws Exception { .andDo(print()) .andExpect(status().isInternalServerError()) .andExpect(jsonPath("$").doesNotExist()); - verify(vortigonClient, times(1)).getShopsIds(any(), any()); + verify(dominantService, times(1)).getShopIds(any(), any()); verify(orgManagerClient, times(1)).getUserContext(any()); verify(bouncerClient, times(1)).judge(any(), any()); verify(refundSearchConverter, times(1)) From f3ef8cece342d5e593089efaca3d1f6ca0990328 Mon Sep 17 00:00:00 2001 From: Egor Cherniak Date: Mon, 30 Jun 2025 20:37:25 +0300 Subject: [PATCH 4/7] Bump gh actions --- .github/workflows/build.yml | 2 +- .github/workflows/deploy.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2cb3849a..c0915544 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,4 +7,4 @@ on: jobs: build: - uses: valitydev/java-workflow/.github/workflows/maven-service-build.yml@v1 + uses: valitydev/java-workflow/.github/workflows/maven-service-build.yml@v3 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d5fa3bc8..ce19205a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -12,7 +12,7 @@ env: jobs: deploy: - uses: valitydev/java-workflow/.github/workflows/maven-service-deploy.yml@v1 + uses: valitydev/java-workflow/.github/workflows/maven-service-deploy.yml@v3 secrets: github-token: ${{ secrets.GITHUB_TOKEN }} mm-webhook-url: ${{ secrets.MATTERMOST_WEBHOOK_URL }} From 7e75c7343f5d229cb8e9e224303a092e3ad408ba Mon Sep 17 00:00:00 2001 From: Egor Cherniak Date: Tue, 1 Jul 2025 11:09:09 +0300 Subject: [PATCH 5/7] Bump deps + cleanup --- .gitignore | 1 + pom.xml | 44 ++++--------------- .../StatChargebackToChargebackConverter.java | 2 +- .../anapi/v2/security/AccessService.java | 2 +- .../vality/anapi/v2/util/ConverterUtil.java | 2 +- .../vality/anapi/v2/util/DeadlineUtil.java | 2 +- .../dev/vality/anapi/v2/AnalyticsTest.java | 1 - ...fundToRefundSearchResultConverterTest.java | 2 +- ...ReporterResponseToReportConverterTest.java | 2 +- 9 files changed, 15 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index fb08ff78..2fe58507 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ buildNumber.properties .idea/dictionaries .idea/vcs.xml .idea/jsLibraryMappings.xml +.vscode/ # Sensitive or high-churn files: .idea/dataSources.ids diff --git a/pom.xml b/pom.xml index 53d2b8c6..22ced32e 100644 --- a/pom.xml +++ b/pom.xml @@ -24,12 +24,6 @@ 8023 ${server.port} ${management.port} ${env.REGISTRY} - 2.10.5 - 2.5 - 2.12.5 - 2.5.3 - 1.3.2 - 2.3.1 0.12.6 @@ -39,27 +33,27 @@ dev.vality swag-anapi-v2 - 1.95-4741f96-server + SNAPSHOT dev.vality bouncer-proto - 1.46-d5e5639 + 1.57-31866c3 dev.vality org-management-proto - 1.12-1a0110a + 1.17-04de2f4 dev.vality magista-proto - 1.44-5352f74 + 1.55-bbdee33 dev.vality analytics-proto - 1.41-f691834 + 1.43-2d1fdc2 dev.vality @@ -129,22 +123,6 @@ jakarta.servlet jakarta.servlet-api - - io.swagger - swagger-annotations - 1.6.8 - provided - - - io.springfox - springfox-swagger2 - ${springfox-version} - - - io.springfox - springfox-swagger-ui - ${springfox-version} - org.projectlombok lombok @@ -155,16 +133,10 @@ jakarta.validation-api provided - - com.google.code.findbugs - jsr305 - 3.0.2 - provided - org.openapitools jackson-databind-nullable - 0.2.3 + 0.2.6 provided @@ -246,12 +218,12 @@ org.apache.maven.plugins maven-remote-resources-plugin - 3.0.0 + 3.3.0 org.apache.maven.shared maven-filtering - 3.3.0 + 3.4.0 diff --git a/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatChargebackToChargebackConverter.java b/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatChargebackToChargebackConverter.java index 7d8be0cf..ebfa0794 100644 --- a/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatChargebackToChargebackConverter.java +++ b/src/main/java/dev/vality/anapi/v2/converter/magista/response/StatChargebackToChargebackConverter.java @@ -39,7 +39,7 @@ protected ChargebackCategory mapCategory(InvoicePaymentChargebackCategory charge case DISPUTE -> ChargebackCategory.DISPUTE; case AUTHORISATION -> ChargebackCategory.AUTHORISATION; case PROCESSING_ERROR -> ChargebackCategory.PROCESSING_ERROR; - default -> throw new IllegalArgumentException(); + case SYSTEM_SET -> ChargebackCategory.SYSTEM_SET; }; } catch (Exception e) { throw new IllegalArgumentException( diff --git a/src/main/java/dev/vality/anapi/v2/security/AccessService.java b/src/main/java/dev/vality/anapi/v2/security/AccessService.java index 20b1a189..eccf4dde 100644 --- a/src/main/java/dev/vality/anapi/v2/security/AccessService.java +++ b/src/main/java/dev/vality/anapi/v2/security/AccessService.java @@ -5,6 +5,7 @@ import dev.vality.anapi.v2.service.BouncerService; import dev.vality.anapi.v2.service.DominantService; import dev.vality.bouncer.base.Entity; +import jakarta.annotation.Nullable; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -12,7 +13,6 @@ import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Service; -import javax.annotation.Nullable; import java.util.Collections; import java.util.List; import java.util.Objects; diff --git a/src/main/java/dev/vality/anapi/v2/util/ConverterUtil.java b/src/main/java/dev/vality/anapi/v2/util/ConverterUtil.java index 91a75190..30e3ee8a 100644 --- a/src/main/java/dev/vality/anapi/v2/util/ConverterUtil.java +++ b/src/main/java/dev/vality/anapi/v2/util/ConverterUtil.java @@ -2,9 +2,9 @@ import dev.vality.geck.common.util.TypeUtil; import dev.vality.magista.CommonSearchQueryParams; +import jakarta.annotation.Nullable; import lombok.experimental.UtilityClass; -import javax.annotation.Nullable; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/dev/vality/anapi/v2/util/DeadlineUtil.java b/src/main/java/dev/vality/anapi/v2/util/DeadlineUtil.java index e3fa4c0b..f3a002c7 100644 --- a/src/main/java/dev/vality/anapi/v2/util/DeadlineUtil.java +++ b/src/main/java/dev/vality/anapi/v2/util/DeadlineUtil.java @@ -1,9 +1,9 @@ package dev.vality.anapi.v2.util; import dev.vality.anapi.v2.exception.DeadlineException; +import jakarta.annotation.Nullable; import lombok.experimental.UtilityClass; -import javax.annotation.Nullable; import java.time.Instant; import java.util.ArrayList; import java.util.List; diff --git a/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java b/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java index 3b5df960..b653a248 100644 --- a/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java +++ b/src/test/java/dev/vality/anapi/v2/AnalyticsTest.java @@ -8,7 +8,6 @@ import dev.vality.anapi.v2.testutil.RandomUtil; import dev.vality.bouncer.decisions.ArbiterSrv; import dev.vality.damsel.analytics.AnalyticsServiceSrv; -import dev.vality.damsel.domain_config_v2.RepositoryClientSrv; import dev.vality.orgmanagement.AuthContextProviderSrv; import lombok.SneakyThrows; import org.apache.thrift.TException; diff --git a/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatRefundToRefundSearchResultConverterTest.java b/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatRefundToRefundSearchResultConverterTest.java index 2705039d..2d8976ca 100644 --- a/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatRefundToRefundSearchResultConverterTest.java +++ b/src/test/java/dev/vality/anapi/v2/converter/magista/response/StatRefundToRefundSearchResultConverterTest.java @@ -20,7 +20,7 @@ class StatRefundToRefundSearchResultConverterTest { @Test void convert() { StatRefundResponse magistaResponse = MagistaUtil.createSearchRefundAllResponse(); - StatRefund magistaRefund = magistaResponse.getRefunds().get(0); + StatRefund magistaRefund = magistaResponse.getRefunds().getFirst(); RefundSearchResult result = converter.convert(magistaRefund); assertAll( () -> assertEquals(magistaRefund.getAmount(), result.getAmount()), diff --git a/src/test/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverterTest.java b/src/test/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverterTest.java index 33ec2830..bd96e1e7 100644 --- a/src/test/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverterTest.java +++ b/src/test/java/dev/vality/anapi/v2/converter/reporter/response/ReporterResponseToReportConverterTest.java @@ -14,7 +14,7 @@ class ReporterResponseToReportConverterTest { @Test void convert() { StatReportResponse response = ReporterUtil.createSearchReportsResponse(); - Report report = converter.convert(response.getReports().get(0)); + Report report = converter.convert(response.getReports().getFirst()); assertNotNull(report); } } \ No newline at end of file From 116bf5230792c86911b171d7b643a3ebeb029ee3 Mon Sep 17 00:00:00 2001 From: Egor Cherniak Date: Tue, 1 Jul 2025 11:16:11 +0300 Subject: [PATCH 6/7] Update deprecated properties --- src/main/resources/application.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index abda6983..94745cf0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,21 +4,21 @@ server: management: server: port: ${management.port} - metrics: - export: - prometheus: - enabled: false endpoint: health: show-details: always metrics: - enabled: true + access: unrestricted prometheus: - enabled: true + access: unrestricted endpoints: web: exposure: include: health,info,prometheus + prometheus: + metrics: + export: + enabled: false service: magista: From 6c9554354effcb30098f4cb2e8a99db96b36db89 Mon Sep 17 00:00:00 2001 From: Egor Cherniak Date: Sun, 6 Jul 2025 14:29:50 +0300 Subject: [PATCH 7/7] upd swag --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 22ced32e..46f4e220 100644 --- a/pom.xml +++ b/pom.xml @@ -32,8 +32,8 @@ dev.vality - swag-anapi-v2 - SNAPSHOT + swag-anapi-v2-server + 1.101-adc5097 dev.vality