From 0a89c2d15522c6f63bae6ff2091cff0d1a4ea72f Mon Sep 17 00:00:00 2001 From: zywang Date: Fri, 15 Nov 2024 14:29:00 +0800 Subject: [PATCH] fixed buyer with wrong env --- .../operator/auth/model/AuthDataProperty.java | 6 ++ .../controller/service/BuyerService.java | 3 +- .../operator/core/toolkit/Constants.java | 1 + .../gateway/service/BuyerCheckerService.java | 98 ++++++++++++------- .../service/BuyerCheckServiceTest.java | 27 ++++- 5 files changed, 94 insertions(+), 41 deletions(-) diff --git a/kraken-java-sdk/kraken-java-sdk-auth/src/main/java/com/consoleconnect/kraken/operator/auth/model/AuthDataProperty.java b/kraken-java-sdk/kraken-java-sdk-auth/src/main/java/com/consoleconnect/kraken/operator/auth/model/AuthDataProperty.java index 532cc75d..773874ff 100644 --- a/kraken-java-sdk/kraken-java-sdk-auth/src/main/java/com/consoleconnect/kraken/operator/auth/model/AuthDataProperty.java +++ b/kraken-java-sdk/kraken-java-sdk-auth/src/main/java/com/consoleconnect/kraken/operator/auth/model/AuthDataProperty.java @@ -70,6 +70,7 @@ public static class ResourceServer { private String bearerTokenHeaderName = "Authorization"; private String userId = "x-kraken-userId"; private SecurityFilter securityFilter = new SecurityFilter(); + private Verifier verifier = new Verifier(); } @Data @@ -130,4 +131,9 @@ public static class FilterConfig { private List paths = List.of(); private String filterName; } + + @Data + public static class Verifier { + private String env; + } } diff --git a/kraken-java-sdk/kraken-java-sdk-controller/src/main/java/com/consoleconnect/kraken/operator/controller/service/BuyerService.java b/kraken-java-sdk/kraken-java-sdk-controller/src/main/java/com/consoleconnect/kraken/operator/controller/service/BuyerService.java index d04916da..e5cbb449 100644 --- a/kraken-java-sdk/kraken-java-sdk-controller/src/main/java/com/consoleconnect/kraken/operator/controller/service/BuyerService.java +++ b/kraken-java-sdk/kraken-java-sdk-controller/src/main/java/com/consoleconnect/kraken/operator/controller/service/BuyerService.java @@ -47,6 +47,7 @@ public class BuyerService extends AssetStatusManager { private static final String BUYER_KEY_PREFIX = "mef.sonata.buyer"; private static final String BUYER_NAME = "Buyer"; private static final String BUYER_DESC = "Onboard buyer information"; + public static final String ENV = "env"; @Getter private final UnifiedAssetService unifiedAssetService; private final UnifiedAssetRepository unifiedAssetRepository; @@ -166,7 +167,7 @@ private BuyerAssetDto.BuyerToken generateBuyerToken( if (StringUtils.isNotBlank(envId)) { Environment environment = environmentService.findOne(envId); log.info("generateBuyerToken, envId:{}, envName:{}", envId, environment.getName()); - claims.put("env", environment.getName()); + claims.put(ENV, environment.getName()); } if (authServer.isEnabled()) { String token = diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/toolkit/Constants.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/toolkit/Constants.java index 14a8229e..3f678dcb 100644 --- a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/toolkit/Constants.java +++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/toolkit/Constants.java @@ -8,6 +8,7 @@ private Constants() {} public static final String COMMA = ","; public static final String MAPPER_SIGN = "-mapper"; public static final String INIT_VERSION = "1.0"; + public static final String ENV = "env"; public static String formatVersion(String version) { return version.replaceFirst("[V|v]", ""); diff --git a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/BuyerCheckerService.java b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/BuyerCheckerService.java index 299d6a67..316bf04a 100644 --- a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/BuyerCheckerService.java +++ b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/BuyerCheckerService.java @@ -1,5 +1,6 @@ package com.consoleconnect.kraken.operator.gateway.service; +import com.consoleconnect.kraken.operator.auth.model.AuthDataProperty; import com.consoleconnect.kraken.operator.auth.security.SecurityChecker; import com.consoleconnect.kraken.operator.core.dto.Tuple2; import com.consoleconnect.kraken.operator.core.dto.UnifiedAssetDto; @@ -8,21 +9,27 @@ import com.consoleconnect.kraken.operator.core.exception.KrakenException; import com.consoleconnect.kraken.operator.core.service.UnifiedAssetService; import com.consoleconnect.kraken.operator.core.toolkit.AssetsConstants; +import com.consoleconnect.kraken.operator.core.toolkit.Constants; import com.consoleconnect.kraken.operator.core.toolkit.LabelConstants; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.function.BiConsumer; import lombok.AllArgsConstructor; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.PageRequest; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.security.core.context.SecurityContext; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import reactor.core.publisher.SynchronousSink; @Component(value = "securityBuyerChecker") @AllArgsConstructor @@ -30,48 +37,63 @@ public class BuyerCheckerService implements SecurityChecker { public static final int INTERVAL = 60; private UnifiedAssetService unifiedAssetService; + private AuthDataProperty.ResourceServer resourceServer; @Override public Mono internalRun(ServerWebExchange exchange) { return ReactiveSecurityContextHolder.getContext() - .handle( - (securityContext, sink) -> { - Authentication authentication = securityContext.getAuthentication(); - List list = - unifiedAssetService - .findBySpecification( - Tuple2.ofList( - AssetsConstants.FIELD_KIND, AssetKindEnum.PRODUCT_BUYER.getKind()), - Tuple2.ofList(LabelConstants.LABEL_BUYER_ID, authentication.getName()), - null, - PageRequest.ofSize(1), - null) - .getData(); - if (CollectionUtils.isEmpty(list)) { - sink.error(KrakenException.badRequest("buyer not found")); - return; - } - UnifiedAssetDto unifiedAssetDto = list.get(0); - if (AssetStatusEnum.DEACTIVATED - .getKind() - .equalsIgnoreCase(unifiedAssetDto.getMetadata().getStatus())) { - sink.error(KrakenException.badRequest("buyer deactivated")); - return; - } - Map labels = unifiedAssetDto.getMetadata().getLabels(); - Instant dbGeneratedAt = - Optional.ofNullable(labels.get(LabelConstants.LABEL_ISSUE_AT)) - .map(DateTimeFormatter.ISO_INSTANT::parse) - .map(Instant::from) - .orElse(Instant.MIN); - Jwt principal = (Jwt) authentication.getPrincipal(); - Instant issuedAt = principal.getIssuedAt(); - if (issuedAt.isBefore(dbGeneratedAt.minusSeconds(INTERVAL))) { - sink.error(KrakenException.badRequest("Token expired ")); - return; - } - sink.next(new Object()); - }); + .handle(getSecurityContextSynchronousSinkBiConsumer()); + } + + public BiConsumer> + getSecurityContextSynchronousSinkBiConsumer() { + return (securityContext, sink) -> { + Authentication authentication = securityContext.getAuthentication(); + List list = + unifiedAssetService + .findBySpecification( + Tuple2.ofList(AssetsConstants.FIELD_KIND, AssetKindEnum.PRODUCT_BUYER.getKind()), + Tuple2.ofList(LabelConstants.LABEL_BUYER_ID, authentication.getName()), + null, + PageRequest.ofSize(1), + null) + .getData(); + if (CollectionUtils.isEmpty(list)) { + sink.error(KrakenException.badRequest("buyer not found")); + return; + } + UnifiedAssetDto unifiedAssetDto = list.get(0); + if (AssetStatusEnum.DEACTIVATED + .getKind() + .equalsIgnoreCase(unifiedAssetDto.getMetadata().getStatus())) { + sink.error(KrakenException.badRequest("buyer deactivated")); + return; + } + Map labels = unifiedAssetDto.getMetadata().getLabels(); + Instant dbGeneratedAt = + Optional.ofNullable(labels.get(LabelConstants.LABEL_ISSUE_AT)) + .map(DateTimeFormatter.ISO_INSTANT::parse) + .map(Instant::from) + .orElse(Instant.MIN); + Jwt principal = (Jwt) authentication.getPrincipal(); + String signEnv = + Optional.ofNullable(principal.getClaims()) + .map(map -> map.get(Constants.ENV)) + .map(Object::toString) + .orElse(""); + if (!StringUtils.equalsIgnoreCase(resourceServer.getVerifier().getEnv(), signEnv)) { + sink.error( + KrakenException.badRequest( + "Invalid buyer: invalid environment identity env:" + signEnv)); + return; + } + Instant issuedAt = principal.getIssuedAt(); + if (Objects.requireNonNull(issuedAt).isBefore(dbGeneratedAt.minusSeconds(INTERVAL))) { + sink.error(KrakenException.badRequest("Token expired ")); + return; + } + sink.next(new Object()); + }; } @Override diff --git a/kraken-java-sdk/kraken-java-sdk-gateway/src/test/java/com/consoleconnect/kraken/operator/gateway/service/BuyerCheckServiceTest.java b/kraken-java-sdk/kraken-java-sdk-gateway/src/test/java/com/consoleconnect/kraken/operator/gateway/service/BuyerCheckServiceTest.java index 9d05fb21..0952a7ae 100644 --- a/kraken-java-sdk/kraken-java-sdk-gateway/src/test/java/com/consoleconnect/kraken/operator/gateway/service/BuyerCheckServiceTest.java +++ b/kraken-java-sdk/kraken-java-sdk-gateway/src/test/java/com/consoleconnect/kraken/operator/gateway/service/BuyerCheckServiceTest.java @@ -1,5 +1,7 @@ package com.consoleconnect.kraken.operator.gateway.service; +import static org.mockito.Mockito.when; + import com.consoleconnect.kraken.operator.auth.model.AuthDataProperty; import com.consoleconnect.kraken.operator.core.enums.AssetKindEnum; import com.consoleconnect.kraken.operator.core.enums.AssetStatusEnum; @@ -12,15 +14,19 @@ import com.consoleconnect.kraken.operator.gateway.CustomConfig; import com.consoleconnect.kraken.operator.test.AbstractIntegrationTest; import com.consoleconnect.kraken.operator.test.MockIntegrationTest; -import com.nimbusds.jwt.JWTParser; import java.time.Instant; import java.time.format.DateTimeFormatter; import lombok.SneakyThrows; import org.junit.jupiter.api.*; +import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.reactive.server.WebTestClient; +import reactor.core.publisher.SynchronousSink; @MockIntegrationTest @ContextConfiguration(classes = CustomConfig.class) @@ -32,6 +38,8 @@ public class BuyerCheckServiceTest extends AbstractIntegrationTest { @Autowired BuyerCheckerService buyerCheckerService; @Autowired WebTestClient webTestClient; @Autowired AuthDataProperty.ResourceServer resourceServer; + @Mock private Authentication principal; + @Mock SynchronousSink sink; private final String xKrakenKeyToken = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtyYWtlbiIsInR5cCI6IkpXVCJ9.eyJleHAiOjQ0Mzg1Mzc5NDIsImlhdCI6MTcyNzMyODM0MiwiaXNzIjoiaHR0cHM6Ly9rcmFrZW4uY29uc29sZWNvbm5lY3QuY29tL2lzc3VlciIsInN1YiI6ImJ1eWVyMDIifQ.9FL7_ph6-NtJg5hNSOqt8HaxwMg66gnEjpb_XCMsXrY"; @@ -42,8 +50,19 @@ void givenBuyer_whenInit_thenReturnData() { UnifiedAsset unifiedAsset = UnifiedAsset.of(AssetKindEnum.PRODUCT_BUYER.getKind(), "buyer02", "buyer02"); unifiedAsset.getMetadata().setStatus(AssetStatusEnum.ACTIVATED.getKind()); + Jwt jwt = + Jwt.withTokenValue(xKrakenKeyToken) + .headers( + map -> { + map.put("alg", "HS256"); + map.put("typ", "JWT"); + }) + .issuedAt(Instant.now().minusSeconds(60)) + .claim("env", "stage") + .build(); + ; - Instant instant = JWTParser.parse(xKrakenKeyToken).getJWTClaimsSet().getIssueTime().toInstant(); + Instant instant = jwt.getIssuedAt(); unifiedAsset .getMetadata() .getLabels() @@ -57,6 +76,10 @@ void givenBuyer_whenInit_thenReturnData() { unifiedAsset, new SyncMetadata("", "", DateTime.nowInUTCString(), ""), true); + when(principal.getName()).thenReturn("buyer02"); + when(principal.getPrincipal()).thenReturn(jwt); + SecurityContextImpl context = new SecurityContextImpl(this.principal); + buyerCheckerService.getSecurityContextSynchronousSinkBiConsumer().accept(context, sink); Assertions.assertEquals(200, ingestionDataResult.getCode()); } }