You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by xi...@apache.org on 2023/01/16 06:37:18 UTC
[shenyu] branch master updated: Fixed compatibility of Sign-Plugin of 2.5.0 version (#4316)
This is an automated email from the ASF dual-hosted git repository.
xiaoyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new c1408e545 Fixed compatibility of Sign-Plugin of 2.5.0 version (#4316)
c1408e545 is described below
commit c1408e545f4333f38156ffcbe50acf63b4936ff8
Author: 愿凌飞 <ti...@foxmail.com>
AuthorDate: Mon Jan 16 14:37:12 2023 +0800
Fixed compatibility of Sign-Plugin of 2.5.0 version (#4316)
* [ISSUE #4208] Refactored Sign-plugin
* fix
* fix
* fix
* fix code style
* fix
* fix
* added versionOne and VersionTwo
* code style
* fix
* fix
* fix
* fix
* code style
* code style
Co-authored-by: xiaoyu <xi...@apache.org>
---
.../http/combination/SignPluginVersionOneTest.java | 289 +++++++++++++++++++++
...uginTest.java => SignPluginVersionTwoTest.java} | 35 ++-
.../shenyu/plugin/sign/api/SignParameters.java | 23 +-
.../plugin/sign/extractor/DefaultExtractor.java | 40 +--
...aultExtractor.java => VersionOneExtractor.java} | 34 +--
...aultExtractor.java => VersionTwoExtractor.java} | 5 +-
.../plugin/sign/provider/DefaultSignProvider.java | 36 ++-
.../sign/provider/VersionOneSignProvider.java | 85 ++++++
...gnProvider.java => VersionTwoSignProvider.java} | 8 +-
.../plugin/sign/service/ComposableSignService.java | 3 +-
.../sign/extractor/DefaultExtractorTest.java | 24 +-
.../sign/provider/DefaultSignProviderTest.java | 13 +-
...iceTest.java => SignServiceVersionOneTest.java} | 162 ++++++------
...iceTest.java => SignServiceVersionTwoTest.java} | 7 +-
14 files changed, 570 insertions(+), 194 deletions(-)
diff --git a/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionOneTest.java b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionOneTest.java
new file mode 100644
index 000000000..fca030a9e
--- /dev/null
+++ b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionOneTest.java
@@ -0,0 +1,289 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.integrated.test.http.combination;
+
+import com.google.common.collect.Maps;
+import com.google.gson.reflect.TypeToken;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.dto.AuthParamData;
+import org.apache.shenyu.common.dto.AuthPathData;
+import org.apache.shenyu.common.dto.ConditionData;
+import org.apache.shenyu.common.enums.OperatorEnum;
+import org.apache.shenyu.common.enums.ParamTypeEnum;
+import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.utils.DigestUtils;
+import org.apache.shenyu.integratedtest.common.AbstractPluginDataInit;
+import org.apache.shenyu.integratedtest.common.dto.AdminResponse;
+import org.apache.shenyu.integratedtest.common.dto.UserDTO;
+import org.apache.shenyu.integratedtest.common.helper.HttpHelper;
+import org.apache.shenyu.web.controller.LocalPluginController.RuleLocalData;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static org.apache.shenyu.common.constant.Constants.SIGN_PARAMS_ERROR;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public final class SignPluginVersionOneTest extends AbstractPluginDataInit {
+
+ private static final String APP_KEY = "108C27175A2C43C1BC29B1E483D57E3D";
+
+ private static final String APP_SECRET = "061521A73DD94A3FA873C25D050685BB";
+
+ @Test
+ public void testSign() throws Exception {
+ String authResult = initAuthData(APP_KEY, APP_SECRET, buildAuthParamDataList(), buildAuthPathDataList());
+ assertThat(authResult, is("success"));
+ String pluginResult = initPlugin(PluginEnum.SIGN.getName(), null);
+ assertThat(pluginResult, is("success"));
+ String selectorAndRulesResult = initSelectorAndRules(PluginEnum.SIGN.getName(), "", buildSelectorConditionList(), buildRuleLocalDataList());
+ assertThat(selectorAndRulesResult, is("success"));
+ final String path = "/http/test/path/456";
+ final String testUrlPath = "/http/test/path/456?name=Lee&data=3";
+ final String version = "1.0.0";
+ String now = String.valueOf(System.currentTimeMillis());
+ Map<String, Object> normalHeaders = buildHeadersMap(now, path, APP_KEY, APP_SECRET, version);
+ UserDTO normalRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath, normalHeaders,
+ UserDTO.class);
+ assertEquals("Lee", normalRespFuture.getUserName());
+
+ Map<String, Object> errorPathHeaders = buildHeadersMap(now, "errorPath", APP_KEY, APP_SECRET, version);
+ AdminResponse<Object> rejectedErrorPathRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorPathHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals("signature value is error!", rejectedErrorPathRespFuture.getMessage());
+
+ Map<String, Object> errorAppKeyHeaders = buildHeadersMap(now, path, "ERRORKEY", APP_SECRET, version);
+ AdminResponse<Object> rejectedErrorAKRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorAppKeyHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals("sign appKey does not exist.", rejectedErrorAKRespFuture.getMessage());
+
+ Map<String, Object> errorAppSecretHeaders = buildHeadersMap(now, path, APP_KEY, "ERRORSECRET", version);
+ AdminResponse<Object> rejectedErrorSKRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorAppSecretHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals("signature value is error!", rejectedErrorSKRespFuture.getMessage());
+
+ Map<String, Object> errorVersionHeaders = buildHeadersMap(now, path, APP_KEY, APP_SECRET, "1.0.2");
+ AdminResponse<Object> rejectedErrorVersionRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorVersionHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals(SIGN_PARAMS_ERROR, rejectedErrorVersionRespFuture.getMessage());
+
+ String errorTime = String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+0")).toEpochMilli() - 360000);
+ Map<String, Object> errorTimestampHeaders = buildHeadersMap(errorTime, path, APP_KEY, APP_SECRET, version);
+ AdminResponse<Object> rejectedErrorTimestampRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorTimestampHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals("The signature timestamp has exceeded 5 minutes!", rejectedErrorTimestampRespFuture.getMessage());
+ }
+
+ @Test
+ public void testSignRequestBody() throws Exception {
+
+ String authResult = initAuthData(APP_KEY, APP_SECRET, buildAuthParamDataList(), buildAuthPathDataList());
+ assertThat(authResult, is("success"));
+ String pluginResult = initPlugin(PluginEnum.SIGN.getName(), null);
+ assertThat(pluginResult, is("success"));
+ String selectorAndRulesResult = initSelectorAndRules(PluginEnum.SIGN.getName(), "",
+ buildSelectorConditionListOpenRequestBody(), buildRuleLocalDataListRequestBody());
+ assertThat(selectorAndRulesResult, is("success"));
+ final String path = "/http/test/path/789";
+ final String testUrlPath = "/http/test/path/789?name=Lee&data=3";
+ final String version = "1.0.0";
+ String now = String.valueOf(System.currentTimeMillis());
+ Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(2);
+ requestBody.put("name", "Lee");
+ requestBody.put("data", "3");
+ Map<String, Object> normalHeaders = buildHeadersMapRequestBody(now, path, APP_KEY, APP_SECRET, version, requestBody);
+ UserDTO normalRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath, normalHeaders,
+ UserDTO.class);
+ assertEquals("Lee", normalRespFuture.getUserName());
+
+ Map<String, Object> errorPathHeaders = buildHeadersMapRequestBody(now, "errorPath", APP_KEY, APP_SECRET, version, requestBody);
+ AdminResponse<Object> rejectedErrorPathRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorPathHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals("signature value is error!", rejectedErrorPathRespFuture.getMessage());
+
+ Map<String, Object> errorAppKeyHeaders = buildHeadersMapRequestBody(now, path, "ERRORKEY", APP_SECRET, version, requestBody);
+ AdminResponse<Object> rejectedErrorAKRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorAppKeyHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals("sign appKey does not exist.", rejectedErrorAKRespFuture.getMessage());
+
+ Map<String, Object> errorAppSecretHeaders = buildHeadersMapRequestBody(now, path, APP_KEY, "ERRORSECRET", version, requestBody);
+ AdminResponse<Object> rejectedErrorSKRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorAppSecretHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals("signature value is error!", rejectedErrorSKRespFuture.getMessage());
+
+ Map<String, Object> errorVersionHeaders = buildHeadersMapRequestBody(now, path, APP_KEY, APP_SECRET, "1.0.2", requestBody);
+ AdminResponse<Object> rejectedErrorVersionRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorVersionHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals(SIGN_PARAMS_ERROR, rejectedErrorVersionRespFuture.getMessage());
+
+ Map<String, Object> errorRequestBody = buildHeadersMapRequestBody(now, path, APP_KEY, APP_SECRET, "1.0.0", null);
+ AdminResponse<Object> rejectedErrorRequestBodyRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorRequestBody,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals("signature value is error!", rejectedErrorRequestBodyRespFuture.getMessage());
+
+ String errorTime = String.valueOf(System.currentTimeMillis() - 360000);
+ Map<String, Object> errorTimestampHeaders = buildHeadersMapRequestBody(errorTime, path, APP_KEY, APP_SECRET, version, requestBody);
+ AdminResponse<Object> rejectedErrorTimestampRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+ errorTimestampHeaders,
+ new TypeToken<AdminResponse<Object>>() {
+ }.getType());
+ assertEquals("The signature timestamp has exceeded 5 minutes!", rejectedErrorTimestampRespFuture.getMessage());
+ }
+
+ private Map<String, Object> buildHeadersMap(final String timestamp, final String path, final String appKey,
+ final String appSecret, final String version) {
+ Map<String, String> params = Maps.newHashMapWithExpectedSize(3);
+ params.put("timestamp", timestamp);
+ params.put("path", path);
+ params.put("version", version);
+ String sign = generateSign(appSecret, params);
+
+ Map<String, Object> headers = Maps.newHashMapWithExpectedSize(4);
+ headers.put("timestamp", timestamp);
+ headers.put("appKey", appKey);
+ headers.put("sign", sign);
+ headers.put("version", version);
+ return headers;
+ }
+
+ private Map<String, Object> buildHeadersMapRequestBody(final String timestamp, final String path, final String appKey,
+ final String appSecret, final String version, final Map<String, String> requestBody) {
+ Map<String, String> params = Maps.newHashMapWithExpectedSize(3);
+ params.put("timestamp", timestamp);
+ params.put("path", path);
+ params.put("version", version);
+ if (!ObjectUtils.isEmpty(requestBody)) {
+ params.putAll(requestBody);
+ }
+ String sign = generateSign(appSecret, params);
+
+ Map<String, Object> headers = Maps.newHashMapWithExpectedSize(4);
+ headers.put("timestamp", timestamp);
+ headers.put("appKey", appKey);
+ headers.put("sign", sign);
+ headers.put("version", version);
+ return headers;
+ }
+
+ private static List<AuthParamData> buildAuthParamDataList() {
+ AuthParamData authParamData = new AuthParamData();
+ authParamData.setAppName("http-sign");
+ authParamData.setAppParam("appParam");
+ return Collections.singletonList(authParamData);
+ }
+
+ private static List<AuthPathData> buildAuthPathDataList() {
+ AuthPathData authPathData = new AuthPathData();
+ authPathData.setAppName("http-sign");
+ authPathData.setPath("/http/test/path/456");
+ authPathData.setEnabled(true);
+ AuthPathData authPathData2 = new AuthPathData();
+ authPathData2.setAppName("http-sign");
+ authPathData2.setPath("/http/test/path/789");
+ authPathData2.setEnabled(true);
+ return Arrays.asList(authPathData, authPathData2);
+ }
+
+ private static List<ConditionData> buildSelectorConditionList() {
+ ConditionData conditionData = new ConditionData();
+ conditionData.setParamType(ParamTypeEnum.URI.getName());
+ conditionData.setOperator(OperatorEnum.EQ.getAlias());
+ conditionData.setParamValue("/http/test/path/456");
+ return Collections.singletonList(conditionData);
+ }
+
+ private static List<ConditionData> buildSelectorConditionListOpenRequestBody() {
+ ConditionData conditionData2 = new ConditionData();
+ conditionData2.setParamType(ParamTypeEnum.URI.getName());
+ conditionData2.setOperator(OperatorEnum.EQ.getAlias());
+ conditionData2.setParamValue("/http/test/path/789");
+ return Collections.singletonList(conditionData2);
+ }
+
+ private static List<RuleLocalData> buildRuleLocalDataList() {
+ final RuleLocalData ruleLocalData = new RuleLocalData();
+ ConditionData conditionData = new ConditionData();
+ conditionData.setParamType(ParamTypeEnum.URI.getName());
+ conditionData.setOperator(OperatorEnum.EQ.getAlias());
+ conditionData.setParamValue("/http/test/path/456");
+ ruleLocalData.setConditionDataList(Collections.singletonList(conditionData));
+ ruleLocalData.setRuleHandler("{\"signRequestBody\": false}");
+ return Collections.singletonList(ruleLocalData);
+ }
+
+ private static List<RuleLocalData> buildRuleLocalDataListRequestBody() {
+ final RuleLocalData ruleLocalData2 = new RuleLocalData();
+ ConditionData conditionData2 = new ConditionData();
+ conditionData2.setParamType(ParamTypeEnum.URI.getName());
+ conditionData2.setOperator(OperatorEnum.EQ.getAlias());
+ conditionData2.setParamValue("/http/test/path/789");
+ ruleLocalData2.setConditionDataList(Collections.singletonList(conditionData2));
+ ruleLocalData2.setRuleHandler("{\"signRequestBody\": true}");
+ return Collections.singletonList(ruleLocalData2);
+ }
+
+ @AfterAll
+ public static void clean() throws IOException {
+ cleanPluginData(PluginEnum.SIGN.getName());
+ cleanAuthData(APP_KEY);
+ }
+
+ private String generateSign(final String signKey, final Map<String, String> params) {
+ final String sign = params.keySet().stream()
+ .sorted(Comparator.naturalOrder())
+ .filter(key -> !Objects.equals(key, Constants.SIGN))
+ .map(key -> String.join("", key, params.get(key)))
+ .collect(Collectors.joining()).trim()
+ .concat(signKey);
+ // TODO this is a risk for error charset coding with getBytes
+ return DigestUtils.md5Hex(sign.getBytes()).toUpperCase();
+ }
+}
diff --git a/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginTest.java b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionTwoTest.java
similarity index 90%
rename from shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginTest.java
rename to shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionTwoTest.java
index 86890fdbe..00bcaa1c5 100644
--- a/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginTest.java
+++ b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionTwoTest.java
@@ -51,9 +51,10 @@ import java.util.Objects;
import java.util.Optional;
import static org.apache.shenyu.integratedtest.common.helper.HttpHelper.GATEWAY_END_POINT;
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
import static org.junit.jupiter.api.Assertions.assertEquals;
-public final class SignPluginTest extends AbstractPluginDataInit {
+public final class SignPluginVersionTwoTest extends AbstractPluginDataInit {
private static final String APP_KEY = "108C27175A2C43C1BC29B1E483D57E3D";
@@ -67,8 +68,6 @@ public final class SignPluginTest extends AbstractPluginDataInit {
private static final String POST_URL = "/http/test/payment?userName=Lee&userId=3";
- private static final String VERSION = "1.0.0";
-
@BeforeAll
public static void setUp() throws IOException {
initAuthData(APP_KEY, APP_SECRET, buildAuthParamDataList(), buildAuthPathDataList());
@@ -80,7 +79,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
@Test
public void testSign() throws Exception {
String now = String.valueOf(System.currentTimeMillis());
- Map<String, Object> normalHeaders = buildHeadersMap(GATEWAY_END_POINT + GET_URL, now, APP_KEY, APP_SECRET, VERSION, null);
+ Map<String, Object> normalHeaders = buildHeadersMap(GATEWAY_END_POINT + GET_URL, now, APP_KEY, APP_SECRET, null);
UserDTO result = HttpHelper.INSTANCE
.getFromGateway(GET_URL, normalHeaders, UserDTO.class);
assertEquals("Lee", result.getUserName());
@@ -89,7 +88,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
@Test
public void testSignWithWrongPath() throws Exception {
String now = String.valueOf(System.currentTimeMillis());
- Map<String, Object> errorPathHeaders = buildHeadersMap(GATEWAY_END_POINT + "/wrong_path", now, APP_KEY, APP_SECRET, VERSION, null);
+ Map<String, Object> errorPathHeaders = buildHeadersMap(GATEWAY_END_POINT + "/wrong_path", now, APP_KEY, APP_SECRET, null);
AdminResponse<Object> result = HttpHelper.INSTANCE
.getFromGateway(GET_URL, errorPathHeaders, AdminResponse.class);
assertEquals("signature value is error!", result.getMessage());
@@ -98,7 +97,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
@Test
public void testSignWithWrongKey() throws Exception {
String now = String.valueOf(System.currentTimeMillis());
- Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + GET_URL, now, "ERRORKEY", APP_SECRET, VERSION, null);
+ Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + GET_URL, now, "ERRORKEY", APP_SECRET, null);
AdminResponse<Object> result = HttpHelper.INSTANCE
.getFromGateway(GET_URL, headers, AdminResponse.class);
@@ -110,7 +109,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
public void testSignWithExpiredSignature() throws Exception {
String errorTime = String.valueOf(System.currentTimeMillis() - 360000);
- Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + GET_URL, errorTime, APP_KEY, APP_SECRET, VERSION, null);
+ Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + GET_URL, errorTime, APP_KEY, APP_SECRET, null);
AdminResponse<Object> result = HttpHelper.INSTANCE
.getFromGateway(GET_URL, headers, AdminResponse.class);
@@ -125,7 +124,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(2);
requestBody.put("userName", "Lee");
requestBody.put("userId", "3");
- Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL, now, APP_KEY, APP_SECRET, VERSION, JsonUtils.toJson(requestBody));
+ Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL, now, APP_KEY, APP_SECRET, JsonUtils.toJson(requestBody));
UserDTO result = HttpHelper.INSTANCE
.postGateway(POST_URL, headers, requestBody, UserDTO.class);
@@ -142,7 +141,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
requestBody.put("userName", "Lee");
requestBody.put("userId", "3");
- Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL, now, APP_KEY, APP_SECRET, VERSION, JsonUtils.toJson(ImmutableMap.of("userId", "1234")));
+ Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL, now, APP_KEY, APP_SECRET, JsonUtils.toJson(ImmutableMap.of("userId", "1234")));
AdminResponse<Object> result = HttpHelper.INSTANCE
.postGateway(POST_URL, headers, requestBody, AdminResponse.class);
@@ -152,8 +151,11 @@ public final class SignPluginTest extends AbstractPluginDataInit {
@Test
public void testSignWithIncompleteParam() throws Exception {
+ Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL,
+ null, APP_KEY, APP_SECRET, null);
+
AdminResponse<Object> result = HttpHelper.INSTANCE
- .getFromGateway(GET_URL, AdminResponse.class);
+ .getFromGateway(GET_URL, headers, AdminResponse.class);
assertEquals("sign parameters are incomplete!", result.getMessage());
}
@@ -167,7 +169,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
buildSelectorConditionList(notConfiguredPath),
buildRuleLocalDataList(false, notConfiguredPath));
String now = String.valueOf(System.currentTimeMillis());
- Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + notConfiguredPath, now, APP_KEY, APP_SECRET, "1.0.0", null);
+ Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + notConfiguredPath, now, APP_KEY, APP_SECRET, null);
AdminResponse<Object> result = HttpHelper.INSTANCE
.getFromGateway(notConfiguredPath, headers, AdminResponse.class);
@@ -178,11 +180,11 @@ public final class SignPluginTest extends AbstractPluginDataInit {
@Test
private Map<String, Object> buildHeadersMap(final String uri, final String timestamp, final String appKey,
- final String appSecret, final String version, final String requestBody) {
- String parameters = buildParameters(timestamp, appKey, version);
+ final String appSecret, final String requestBody) {
+ String parameters = buildParameters(timestamp, appKey);
String sign = buildSign(appSecret, parameters, URI.create(uri), requestBody);
String token = parameters + "." + sign;
- return ImmutableMap.of(HttpHeaders.AUTHORIZATION, token);
+ return ImmutableMap.of(HttpHeaders.AUTHORIZATION, token, Constants.VERSION, VERSION_2);
}
private static List<AuthParamData> buildAuthParamDataList() {
@@ -227,7 +229,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
cleanAuthData(APP_KEY);
}
- private String buildParameters(final String timestamp, final String appKey, final String version) {
+ private String buildParameters(final String timestamp, final String appKey) {
Map<String, String> map = new HashMap<>();
if (timestamp != null) {
map.put(Constants.TIMESTAMP, timestamp);
@@ -235,9 +237,6 @@ public final class SignPluginTest extends AbstractPluginDataInit {
if (appKey != null) {
map.put(Constants.APP_KEY, appKey);
}
- if (version != null) {
- map.put("version", version);
- }
map.put("alg", "MD5");
return Base64.getEncoder().encodeToString(JsonUtils.toJson(map).getBytes(StandardCharsets.UTF_8));
}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/SignParameters.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/SignParameters.java
index 3cb57cdfa..180cf8ab2 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/SignParameters.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/SignParameters.java
@@ -23,6 +23,8 @@ import java.net.URI;
public class SignParameters {
+ public static final SignParameters ERROR_PARAMETERS = new SignParameters();
+
private final String appKey;
private final String timestamp;
@@ -33,20 +35,25 @@ public class SignParameters {
private final String signAlg;
+ private final String version;
+
private String parameters;
- public SignParameters(final String appKey,
+ public SignParameters(final String version,
+ final String appKey,
final String timestamp,
final String signature,
final URI uri) {
- this(appKey, timestamp, signature, uri, SignUtils.SIGN_MD5);
+ this(version, appKey, timestamp, signature, uri, SignUtils.SIGN_MD5);
}
- public SignParameters(final String appKey,
+ public SignParameters(final String version,
+ final String appKey,
final String timestamp,
final String signature,
final URI uri,
final String signAlg) {
+ this.version = version;
this.appKey = appKey;
this.timestamp = timestamp;
this.signature = signature;
@@ -121,6 +128,15 @@ public class SignParameters {
this.parameters = parameters;
}
+ /**
+ * Gets version.
+ *
+ * @return version
+ */
+ public String getVersion() {
+ return version;
+ }
+
@Override
public String toString() {
return "SignParameters{"
@@ -129,6 +145,7 @@ public class SignParameters {
+ ", signature='" + signature + '\''
+ ", uri=" + uri
+ ", signAlg='" + signAlg + '\''
+ + ", version='" + version + '\''
+ ", parameters='" + parameters + '\''
+ '}';
}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
index 4d41917e4..4f380484c 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
@@ -17,40 +17,40 @@
package org.apache.shenyu.plugin.sign.extractor;
-import org.apache.commons.lang3.StringUtils;
+import com.google.common.collect.ImmutableMap;
import org.apache.shenyu.common.constant.Constants;
-import org.apache.shenyu.common.utils.JsonUtils;
import org.apache.shenyu.plugin.sign.api.SignParameters;
-import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
-import java.util.Base64;
import java.util.Map;
+import java.util.Objects;
public class DefaultExtractor implements SignParameterExtractor {
+ public static final String VERSION_1 = "1.0.0";
+
+ public static final String VERSION_2 = "2.0.0";
+
+ private static final Map<String, SignParameterExtractor> VERSION_EXTRACTOR =
+ ImmutableMap.of(
+ VERSION_1, new VersionOneExtractor(),
+ VERSION_2, new VersionTwoExtractor()
+ );
+
@Override
public SignParameters extract(final HttpRequest httpRequest) {
- String token = httpRequest.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
-
- if (StringUtils.isEmpty(token) || !token.contains(".")) {
- return new SignParameters();
+ String version = httpRequest.getHeaders().getFirst(Constants.VERSION);
+ if (Objects.isNull(version)) {
+ return SignParameters.ERROR_PARAMETERS;
}
- String[] tokenArray = StringUtils.split(token, '.');
- String parameters = tokenArray[0];
- String signature = tokenArray[1];
- Map<String, Object> headerMap = JsonUtils.jsonToMap(new String(Base64.getDecoder().decode(parameters)));
+ SignParameterExtractor extractor = VERSION_EXTRACTOR.get(version);
- SignParameters signParameters = new SignParameters(
- (String) headerMap.get(Constants.APP_KEY),
- (String) headerMap.get(Constants.TIMESTAMP),
- signature,
- httpRequest.getURI(),
- (String) headerMap.get("alg"));
- signParameters.setParameters(parameters);
+ if (Objects.isNull(extractor)) {
+ return SignParameters.ERROR_PARAMETERS;
+ }
- return signParameters;
+ return extractor.extract(httpRequest);
}
}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionOneExtractor.java
similarity index 50%
copy from shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
copy to shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionOneExtractor.java
index 4d41917e4..bac784987 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionOneExtractor.java
@@ -17,40 +17,22 @@
package org.apache.shenyu.plugin.sign.extractor;
-import org.apache.commons.lang3.StringUtils;
import org.apache.shenyu.common.constant.Constants;
-import org.apache.shenyu.common.utils.JsonUtils;
import org.apache.shenyu.plugin.sign.api.SignParameters;
-import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
-import java.util.Base64;
-import java.util.Map;
+import java.net.URI;
-public class DefaultExtractor implements SignParameterExtractor {
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
+public class VersionOneExtractor implements SignParameterExtractor {
@Override
public SignParameters extract(final HttpRequest httpRequest) {
+ String appKey = httpRequest.getHeaders().getFirst(Constants.APP_KEY);
+ String signature = httpRequest.getHeaders().getFirst(Constants.SIGN);
+ String timestamp = httpRequest.getHeaders().getFirst(Constants.TIMESTAMP);
+ URI uri = httpRequest.getURI();
- String token = httpRequest.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
-
- if (StringUtils.isEmpty(token) || !token.contains(".")) {
- return new SignParameters();
- }
- String[] tokenArray = StringUtils.split(token, '.');
- String parameters = tokenArray[0];
- String signature = tokenArray[1];
-
- Map<String, Object> headerMap = JsonUtils.jsonToMap(new String(Base64.getDecoder().decode(parameters)));
-
- SignParameters signParameters = new SignParameters(
- (String) headerMap.get(Constants.APP_KEY),
- (String) headerMap.get(Constants.TIMESTAMP),
- signature,
- httpRequest.getURI(),
- (String) headerMap.get("alg"));
- signParameters.setParameters(parameters);
-
- return signParameters;
+ return new SignParameters(VERSION_1, appKey, timestamp, signature, uri);
}
}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionTwoExtractor.java
similarity index 92%
copy from shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
copy to shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionTwoExtractor.java
index 4d41917e4..5e3f4b151 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionTwoExtractor.java
@@ -27,7 +27,9 @@ import org.springframework.http.HttpRequest;
import java.util.Base64;
import java.util.Map;
-public class DefaultExtractor implements SignParameterExtractor {
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
+
+public class VersionTwoExtractor implements SignParameterExtractor {
@Override
public SignParameters extract(final HttpRequest httpRequest) {
@@ -44,6 +46,7 @@ public class DefaultExtractor implements SignParameterExtractor {
Map<String, Object> headerMap = JsonUtils.jsonToMap(new String(Base64.getDecoder().decode(parameters)));
SignParameters signParameters = new SignParameters(
+ VERSION_2,
(String) headerMap.get(Constants.APP_KEY),
(String) headerMap.get(Constants.TIMESTAMP),
signature,
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
index 413c68119..d370349a1 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
@@ -17,37 +17,31 @@
package org.apache.shenyu.plugin.sign.provider;
-import org.apache.shenyu.common.utils.SignUtils;
+import com.google.common.collect.ImmutableMap;
import org.apache.shenyu.plugin.sign.api.SignParameters;
-import java.net.URI;
-import java.util.Objects;
-import java.util.Optional;
+import java.util.Map;
+
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
public class DefaultSignProvider implements SignProvider {
+ private static final Map<String, SignProvider> VERSION_SIGN =
+ ImmutableMap.of(
+ VERSION_1, new VersionOneSignProvider(),
+ VERSION_2, new VersionTwoSignProvider()
+ );
+
@Override
public String generateSign(final String signKey, final SignParameters signParameters, final String requestBody) {
-
- String data = signParameters.getParameters()
- + getRelativeURL(signParameters.getUri())
- + Optional.ofNullable(requestBody).orElse("");
- return SignUtils.sign(signParameters.getSignAlg(), signKey, data).toUpperCase();
+ return VERSION_SIGN.get(signParameters.getVersion())
+ .generateSign(signKey, signParameters, requestBody);
}
@Override
public String generateSign(final String signKey, final SignParameters signParameters) {
- return generateSign(signKey, signParameters, null);
- }
-
- /** Gets RelativeURL.
- * @param uri uri
- * @return relativeURL
- */
- public String getRelativeURL(final URI uri) {
- if (Objects.isNull(uri.getQuery())) {
- return uri.getPath();
- }
- return uri.getPath() + "?" + uri.getQuery();
+ return VERSION_SIGN.get(signParameters.getVersion())
+ .generateSign(signKey, signParameters);
}
}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionOneSignProvider.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionOneSignProvider.java
new file mode 100644
index 000000000..45878db75
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionOneSignProvider.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.plugin.sign.provider;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.utils.JsonUtils;
+import org.apache.shenyu.common.utils.SignUtils;
+import org.apache.shenyu.plugin.sign.api.SignParameters;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class VersionOneSignProvider implements SignProvider {
+
+ @Override
+ public String generateSign(final String signKey, final SignParameters signParameters, final String requestBody) {
+ return sign(signKey, signParameters, requestBody);
+ }
+
+ @Override
+ public String generateSign(final String signKey, final SignParameters signParameters) {
+
+ return sign(signKey, signParameters, null);
+ }
+
+ private String sign(final String signKey, final SignParameters signParameters, final String requestBody) {
+
+ Map<String, String> params = getParams(signParameters, requestBody);
+
+ final String data = params.keySet().stream()
+ .sorted(Comparator.naturalOrder())
+ .filter(key -> !Objects.equals(key, Constants.SIGN))
+ .map(key -> String.join("", key, params.get(key)))
+ .collect(Collectors.joining()).trim();
+
+ return SignUtils.sign(signParameters.getSignAlg(), signKey, data).toUpperCase();
+ }
+
+ private Map<String, String> getParams(final SignParameters signParameters, final String requestBody) {
+
+ Map<String, String> params = Maps.newHashMap();
+ params.put(Constants.TIMESTAMP, signParameters.getTimestamp());
+ params.put(Constants.PATH, signParameters.getUri().getPath());
+ params.put(Constants.VERSION, signParameters.getVersion());
+
+ if (Objects.isNull(requestBody)) {
+ return params;
+ }
+
+ //get requestBodyParameter
+ if (!StringUtils.isEmpty(requestBody)) {
+ JsonUtils.jsonToMap(requestBody)
+ .forEach((k, v) -> params.putIfAbsent(k, Objects.toString(v, null)));
+ }
+
+ // get url params
+ Map<String, String> queryParams = UriComponentsBuilder.fromUri(signParameters.getUri())
+ .build()
+ .getQueryParams()
+ .toSingleValueMap();
+ params.putAll(queryParams);
+
+ return params;
+ }
+}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionTwoSignProvider.java
similarity index 90%
copy from shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
copy to shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionTwoSignProvider.java
index 413c68119..6c5aded45 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionTwoSignProvider.java
@@ -24,7 +24,7 @@ import java.net.URI;
import java.util.Objects;
import java.util.Optional;
-public class DefaultSignProvider implements SignProvider {
+public class VersionTwoSignProvider implements SignProvider {
@Override
public String generateSign(final String signKey, final SignParameters signParameters, final String requestBody) {
@@ -40,11 +40,7 @@ public class DefaultSignProvider implements SignProvider {
return generateSign(signKey, signParameters, null);
}
- /** Gets RelativeURL.
- * @param uri uri
- * @return relativeURL
- */
- public String getRelativeURL(final URI uri) {
+ private String getRelativeURL(final URI uri) {
if (Objects.isNull(uri.getQuery())) {
return uri.getPath();
}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
index bed5e2616..fd9f6506a 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
@@ -49,7 +49,8 @@ import java.util.function.BiFunction;
* The ComposableSignService is composable SignService.
* <pre>
* 1. new ComposableSignService(new DefaultExtractor(), new DefaultSignProvider())
- * Implements from <a href="https://github.com/apache/shenyu/issues/4208">#4208</a>
+ * Version 1: 2.5.0 SignService
+ * Version 2:Implements from <a href="https://github.com/apache/shenyu/issues/4208">#4208</a>
* parameters:
* {
* "alg":"HMD5",
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractorTest.java b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractorTest.java
index d01ab38f0..bce19304f 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractorTest.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractorTest.java
@@ -29,6 +29,8 @@ import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@@ -37,12 +39,27 @@ public class DefaultExtractorTest {
private final SignParameterExtractor extractor = new DefaultExtractor();
@Test
- public void testExtract() {
+ public void testVersionOneExtract() {
+
+ HttpRequest httpRequest = MockServerHttpRequest
+ .get("http://localhost:9195/springcloud/class/annotation/get?id=1&id=1")
+ .header("timestamp", "1660659201000")
+ .header("appKey", "BD7980F5688A4DE6BCF1B5327FE07F5C")
+ .header("version", VERSION_1)
+ .header("sign", "BF485842D2C08A3378308BA9992A309F")
+ .build();
+
+ SignParameters signParameters = new SignParameters(VERSION_1, "BD7980F5688A4DE6BCF1B5327FE07F5C", "1660659201000",
+ "BF485842D2C08A3378308BA9992A309F", httpRequest.getURI(), "MD5");
+ assertThat(extractor.extract(httpRequest).toString(), is(signParameters.toString()));
+ }
+
+ @Test
+ public void testVersionTwoExtract() {
Map<String, String> map = ImmutableMap.of(
"timestamp", "1660659201000",
"appKey", "BD7980F5688A4DE6BCF1B5327FE07F5C",
- "version", "1.0.0",
"sign", "BF485842D2C08A3378308BA9992A309F",
"alg", "MD5");
@@ -52,8 +69,9 @@ public class DefaultExtractorTest {
HttpRequest httpRequest = MockServerHttpRequest
.get("http://localhost:9195/springcloud/class/annotation/get?id=1&id=1")
.header(HttpHeaders.AUTHORIZATION, token)
+ .header("version", VERSION_2)
.build();
- SignParameters signParameters = new SignParameters("BD7980F5688A4DE6BCF1B5327FE07F5C", "1660659201000",
+ SignParameters signParameters = new SignParameters(VERSION_2, "BD7980F5688A4DE6BCF1B5327FE07F5C", "1660659201000",
"BF485842D2C08A3378308BA9992A309F", httpRequest.getURI(), "MD5");
signParameters.setParameters(parameters);
assertThat(extractor.extract(httpRequest).toString(), is(signParameters.toString()));
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProviderTest.java b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProviderTest.java
index abe043d2f..5d4a84d02 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProviderTest.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProviderTest.java
@@ -35,33 +35,32 @@ public class DefaultSignProviderTest {
@Test
void testGenerateSign() {
- SignParameters signParameters = new SignParameters("108C27175A2C43C1BC29B1E483D57E3D",
+ SignParameters signParameters = new SignParameters("2.0.0", "108C27175A2C43C1BC29B1E483D57E3D",
"1673093719090", "C25A751BBCE25392DF61B352A2440FF9",
URI.create("http://localhost:9195/http/test/path/456?name=Lee&data=3"));
String token = JsonUtils.toJson(ImmutableMap.of("alg", "MD5",
- "version", "1.0.0",
"appKey", "108C27175A2C43C1BC29B1E483D57E3D",
"timestamp", "1673093719090"));
signParameters.setParameters(Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8)));
String actual = signProvider.generateSign("061521A73DD94A3FA873C25D050685BB", signParameters);
- assertThat(actual, is("AC53FD0F51F57DD18FE6861BB97E9F01"));
+ assertThat(actual, is("4892285C655127FE0B05BCAA4A47B093"));
}
@Test
void testGenerateSignWithBody() {
- SignParameters signParameters = new SignParameters("108C27175A2C43C1BC29B1E483D57E3D",
+ SignParameters signParameters = new SignParameters("2.0.0", "108C27175A2C43C1BC29B1E483D57E3D",
"1673093719090", "C25A751BBCE25392DF61B352A2440FF9",
URI.create("http://localhost:9195/http/test/payment?userName=Lee&userId=3"));
- String token = JsonUtils.toJson(ImmutableMap.of("alg", "MD5",
- "version", "1.0.0",
+ String token = JsonUtils.toJson(ImmutableMap.of(
+ "alg", "MD5",
"appKey", "108C27175A2C43C1BC29B1E483D57E3D",
"timestamp", "1673093719090"));
signParameters.setParameters(Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8)));
ImmutableMap<String, String> requestBody = ImmutableMap.of("userName", "Lee", "userId", "3");
String actual = signProvider.generateSign("061521A73DD94A3FA873C25D050685BB", signParameters, JsonUtils.toJson(requestBody));
- assertThat(actual, is("725D6157459EFCDD2428D7BADA779077"));
+ assertThat(actual, is("61A097079016A18B1246A375482BEDBC"));
}
}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/SignServiceVersionOneTest.java
similarity index 73%
copy from shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java
copy to shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/SignServiceVersionOneTest.java
index 56e8c2213..0b50c5818 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/SignServiceVersionOneTest.java
@@ -25,8 +25,8 @@ import org.apache.shenyu.common.dto.AuthParamData;
import org.apache.shenyu.common.dto.AuthPathData;
import org.apache.shenyu.common.dto.PluginData;
import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.utils.DigestUtils;
import org.apache.shenyu.common.utils.JsonUtils;
-import org.apache.shenyu.common.utils.SignUtils;
import org.apache.shenyu.plugin.api.context.ShenyuContext;
import org.apache.shenyu.plugin.api.result.ShenyuResultEnum;
import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
@@ -43,20 +43,19 @@ import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.http.HttpHeaders;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.web.server.ServerWebExchange;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.stream.Collectors;
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
@@ -65,7 +64,7 @@ import static org.mockito.Mockito.mock;
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
-public final class DefaultSignServiceTest {
+public final class SignServiceVersionOneTest {
private SignService signService;
@@ -120,10 +119,10 @@ public final class DefaultSignServiceTest {
@Test
public void normalTest() {
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+ timestamp,
+ appKey,
+ buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -132,11 +131,11 @@ public final class DefaultSignServiceTest {
@Test
public void nullTimestampTest() {
-
- String parameters = buildParameters(null, appKey);
+ String timestamp = String.valueOf(System.currentTimeMillis());
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+ null,
+ appKey,
+ buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -147,9 +146,9 @@ public final class DefaultSignServiceTest {
public void nullSignTest() {
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
+ timestamp,
+ appKey,
null);
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
@@ -163,12 +162,11 @@ public final class DefaultSignServiceTest {
@Test
public void nullAppKeyTest() {
-
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, null);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+ timestamp,
+ null,
+ buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -178,10 +176,10 @@ public final class DefaultSignServiceTest {
@Test
public void overdueTest() {
String errorTimestamp = String.valueOf(System.currentTimeMillis() - ((long) (delay + 1) * 1000 * 60));
- String parameters = buildParameters(errorTimestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+ errorTimestamp,
+ appKey,
+ buildSign(secretKey, errorTimestamp, "/test-api/demo/test", null, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -190,12 +188,11 @@ public final class DefaultSignServiceTest {
@Test
public void errorAppKeyTest() {
-
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, "errorKey");
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
- buildSign("errorKey", parameters, URI.create("http://localhost/test-api/demo/test"), null));
+ timestamp,
+ "errorKey",
+ buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -206,10 +203,10 @@ public final class DefaultSignServiceTest {
public void emptyAuthPath() {
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+ timestamp,
+ appKey,
+ buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
AppAuthData authData = SignAuthDataCache.getInstance().obtainAuthData(appKey);
@@ -223,10 +220,10 @@ public final class DefaultSignServiceTest {
@Test
public void fillParamPath() {
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+ timestamp,
+ appKey,
+ buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
AppAuthData authData = SignAuthDataCache.getInstance().obtainAuthData(appKey);
@@ -243,10 +240,10 @@ public final class DefaultSignServiceTest {
@Test
public void emptyParamPath() {
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+ timestamp,
+ appKey,
+ buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
AppAuthData authData = SignAuthDataCache.getInstance().obtainAuthData(appKey);
@@ -259,10 +256,10 @@ public final class DefaultSignServiceTest {
@Test
public void errorAuthPath() {
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/errorPath",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/errorPath"), null));
+ timestamp,
+ appKey,
+ buildSign(secretKey, timestamp, "/errorPath", null, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -272,9 +269,10 @@ public final class DefaultSignServiceTest {
@Test
public void errorSign() {
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters, "errorSign");
+ timestamp,
+ appKey,
+ "errorSign");
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -284,9 +282,9 @@ public final class DefaultSignServiceTest {
@Test
public void errorBodySign() {
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
+ timestamp,
+ appKey,
"errorSign");
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
@@ -298,14 +296,14 @@ public final class DefaultSignServiceTest {
@Test
public void bodySign() {
+
Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(1);
requestBody.put("data", "data");
-
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), JsonUtils.toJson(requestBody)));
+ timestamp,
+ appKey,
+ buildSign(secretKey, timestamp, "/test-api/demo/test", requestBody, null));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
VerifyResult ret = this.signService.signatureVerify(this.exchange, JsonUtils.toJson(requestBody));
@@ -316,43 +314,48 @@ public final class DefaultSignServiceTest {
public void bodyAndUrlQueryParamsSign() {
Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(1);
requestBody.put("data", "data");
+ Map<String, String> queryParams = Maps.newHashMapWithExpectedSize(1);
+ queryParams.put("data2", "data");
String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test?data2=data",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test?data2=data"), JsonUtils.toJson(requestBody)));
+ timestamp,
+ appKey,
+ buildSign(secretKey, timestamp, "/test-api/demo/test", requestBody, queryParams));
this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
-
VerifyResult ret = this.signService.signatureVerify(this.exchange, JsonUtils.toJson(requestBody));
assertEquals(ret, VerifyResult.success());
}
- @Test
- public void errorBodyAndUrlQueryParamsSign() {
- Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(1);
- requestBody.put("data", "data");
+ private String buildSign(final String signKey, final String timeStamp, final String path, final Map<String, String> jsonParams, final Map<String, String> queryParams) {
- String timestamp = String.valueOf(System.currentTimeMillis());
- String parameters = buildParameters(timestamp, appKey);
- this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test?data=data",
- parameters,
- buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test?data=data"), JsonUtils.toJson(requestBody)));
- this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
+ Map<String, String> params = Maps.newHashMap(Optional.ofNullable(jsonParams)
+ .orElse(Collections.EMPTY_MAP));
- // Tamper with request body parameters
- requestBody.put("data", "data2");
- VerifyResult ret = this.signService.signatureVerify(this.exchange, JsonUtils.toJson(requestBody));
- assertEquals(ret, VerifyResult.fail(Constants.SIGN_VALUE_IS_ERROR));
- }
+ params.putAll(Maps.newHashMap(Optional.ofNullable(queryParams)
+ .orElse(Collections.EMPTY_MAP)));
- private String buildSign(final String signKey, final String parameters, final URI url, final String body) {
+ params.put(Constants.TIMESTAMP, timeStamp);
+ params.put(Constants.PATH, path);
+ params.put(Constants.VERSION, "1.0.0");
+
+ final String sign = params.keySet().stream()
+ .sorted(Comparator.naturalOrder())
+ .filter(key -> !Objects.equals(key, Constants.SIGN))
+ .map(key -> String.join("", key, params.get(key)))
+ .collect(Collectors.joining()).trim()
+ .concat(signKey);
+
+ return DigestUtils.md5Hex(sign.getBytes()).toUpperCase();
+ }
- String data = parameters + getRelativeURL(url) + Optional.ofNullable(body).orElse("");
- return SignUtils.sign(SignUtils.SIGN_MD5, signKey, data).toUpperCase();
+ private MockServerHttpRequest buildMockServerHttpRequest(final String url, final Map<String, String> headers) {
+ MockServerHttpRequest.BaseBuilder<?> builder = MockServerHttpRequest.get(url);
+ headers.forEach(builder::header);
+ return builder.build();
}
- private String buildParameters(final String timestamp, final String appKey) {
+ private ServerWebExchange buildServerWebExchange(final String url, final String timestamp, final String appKey, final String sign) {
Map<String, String> map = new HashMap<>();
if (timestamp != null) {
map.put(Constants.TIMESTAMP, timestamp);
@@ -360,22 +363,11 @@ public final class DefaultSignServiceTest {
if (appKey != null) {
map.put(Constants.APP_KEY, appKey);
}
- map.put("alg", "MD5");
- map.put("version", "1.0.0");
- return Base64.getEncoder().encodeToString(JsonUtils.toJson(map).getBytes(StandardCharsets.UTF_8));
- }
-
- private ServerWebExchange buildServerWebExchange(final String url, final String parameters, final String sign) {
-
- return MockServerWebExchange
- .builder(MockServerHttpRequest.get(url)
- .header(HttpHeaders.AUTHORIZATION, Objects.isNull(sign) ? parameters : parameters + "." + sign)).build();
- }
-
- private String getRelativeURL(final URI uri) {
- if (Objects.isNull(uri.getQuery())) {
- return uri.getPath();
+ if (sign != null) {
+ map.put(Constants.SIGN, sign);
}
- return uri.getPath() + "?" + uri.getQuery();
+ map.put(Constants.VERSION, VERSION_1);
+ return MockServerWebExchange.builder(buildMockServerHttpRequest(url, map)).build();
}
+
}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/SignServiceVersionTwoTest.java
similarity index 98%
rename from shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java
rename to shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/SignServiceVersionTwoTest.java
index 56e8c2213..514fe88c5 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/SignServiceVersionTwoTest.java
@@ -57,6 +57,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
@@ -65,7 +66,7 @@ import static org.mockito.Mockito.mock;
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
-public final class DefaultSignServiceTest {
+public final class SignServiceVersionTwoTest {
private SignService signService;
@@ -361,7 +362,6 @@ public final class DefaultSignServiceTest {
map.put(Constants.APP_KEY, appKey);
}
map.put("alg", "MD5");
- map.put("version", "1.0.0");
return Base64.getEncoder().encodeToString(JsonUtils.toJson(map).getBytes(StandardCharsets.UTF_8));
}
@@ -369,7 +369,8 @@ public final class DefaultSignServiceTest {
return MockServerWebExchange
.builder(MockServerHttpRequest.get(url)
- .header(HttpHeaders.AUTHORIZATION, Objects.isNull(sign) ? parameters : parameters + "." + sign)).build();
+ .header(HttpHeaders.AUTHORIZATION, Objects.isNull(sign) ? parameters : parameters + "." + sign)
+ .header(Constants.VERSION, VERSION_2)).build();
}
private String getRelativeURL(final URI uri) {