This is an automated email from the ASF dual-hosted git repository.
dengliming 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 47b7d3a9c2 feat: add unit tests for sign extractors and providers for
version one and two (#6931)
47b7d3a9c2 is described below
commit 47b7d3a9c292992e1e6fd099e7aca7a0e50c1436
Author: Limbo <[email protected]>
AuthorDate: Fri Sep 18 10:56:49 2026 +0800
feat: add unit tests for sign extractors and providers for version one and
two (#6931)
Co-authored-by: Liming Deng <[email protected]>
---
.../sign/extractor/VersionOneExtractorTest.java | 68 ++++++++++++
.../sign/extractor/VersionTwoExtractorTest.java | 117 +++++++++++++++++++++
.../sign/provider/VersionOneSignProviderTest.java | 89 ++++++++++++++++
.../sign/provider/VersionTwoSignProviderTest.java | 69 ++++++++++++
4 files changed, 343 insertions(+)
diff --git
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/VersionOneExtractorTest.java
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/VersionOneExtractorTest.java
new file mode 100644
index 0000000000..b9b32e2df1
--- /dev/null
+++
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/VersionOneExtractorTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.extractor;
+
+import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.utils.SignUtils;
+import org.apache.shenyu.plugin.sign.api.SignParameters;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpRequest;
+import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
+
+import static
org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * Test cases for {@link VersionOneExtractor}.
+ */
+final class VersionOneExtractorTest {
+
+ private final SignParameterExtractor extractor = new VersionOneExtractor();
+
+ @Test
+ void testExtractSignParameters() {
+ HttpRequest request =
MockServerHttpRequest.get("https://example.com/api/orders?id=1")
+ .header(Constants.APP_KEY, "app-key")
+ .header(Constants.TIMESTAMP, "1700000000000")
+ .header(Constants.SIGN, "signature")
+ .build();
+
+ SignParameters actual = extractor.extract(request);
+
+ assertEquals(VERSION_1, actual.getVersion());
+ assertEquals("app-key", actual.getAppKey());
+ assertEquals("1700000000000", actual.getTimestamp());
+ assertEquals("signature", actual.getSignature());
+ assertEquals(request.getURI(), actual.getUri());
+ assertEquals(SignUtils.SIGN_MD5, actual.getSignAlg());
+ }
+
+ @Test
+ void testExtractWithMissingHeaders() {
+ HttpRequest request =
MockServerHttpRequest.get("https://example.com/api/orders").build();
+
+ SignParameters actual = extractor.extract(request);
+
+ assertEquals(VERSION_1, actual.getVersion());
+ assertNull(actual.getAppKey());
+ assertNull(actual.getTimestamp());
+ assertNull(actual.getSignature());
+ assertEquals(request.getURI(), actual.getUri());
+ }
+}
diff --git
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/VersionTwoExtractorTest.java
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/VersionTwoExtractorTest.java
new file mode 100644
index 0000000000..9d1d9d8e25
--- /dev/null
+++
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/VersionTwoExtractorTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.extractor;
+
+import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.utils.JsonUtils;
+import org.apache.shenyu.plugin.sign.api.SignParameters;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpRequest;
+import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+import static
org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * Test cases for {@link VersionTwoExtractor}.
+ */
+final class VersionTwoExtractorTest {
+
+ private final SignParameterExtractor extractor = new VersionTwoExtractor();
+
+ @Test
+ void testExtractFromShenyuAuthorizationHeader() {
+ String parameters = parameters("preferred-app-key", "1700000000000",
"SHA-256");
+ String fallbackParameters = parameters("fallback-app-key",
"1600000000000", "MD5");
+ HttpRequest request =
MockServerHttpRequest.get("https://example.com/api/orders")
+ .header(Constants.SHENYU_AUTHORIZATION, parameters +
".preferred-signature")
+ .header(HttpHeaders.AUTHORIZATION, fallbackParameters +
".fallback-signature")
+ .build();
+
+ SignParameters actual = extractor.extract(request);
+
+ assertSignParameters(actual, request, parameters, "preferred-app-key",
"1700000000000",
+ "preferred-signature", "SHA-256");
+ }
+
+ @Test
+ void testExtractFromAuthorizationHeader() {
+ String parameters = parameters("app-key", "1700000000000", "MD5");
+ HttpRequest request =
MockServerHttpRequest.get("https://example.com/api/orders")
+ .header(HttpHeaders.AUTHORIZATION, parameters + ".signature")
+ .build();
+
+ SignParameters actual = extractor.extract(request);
+
+ assertSignParameters(actual, request, parameters, "app-key",
"1700000000000", "signature", "MD5");
+ }
+
+ @Test
+ void testExtractWithMissingAuthorizationHeader() {
+ SignParameters actual =
extractor.extract(MockServerHttpRequest.get("https://example.com/api/orders").build());
+
+ assertEmpty(actual);
+ }
+
+ @Test
+ void testExtractWithTokenWithoutSignatureSeparator() {
+ HttpRequest request =
MockServerHttpRequest.get("https://example.com/api/orders")
+ .header(Constants.SHENYU_AUTHORIZATION, "parameters-only")
+ .build();
+
+ SignParameters actual = extractor.extract(request);
+
+ assertEmpty(actual);
+ }
+
+ private String parameters(final String appKey, final String timestamp,
final String algorithm) {
+ Map<String, String> values = new HashMap<>();
+ values.put(Constants.APP_KEY, appKey);
+ values.put(Constants.TIMESTAMP, timestamp);
+ values.put("alg", algorithm);
+ return
Base64.getEncoder().encodeToString(JsonUtils.toJson(values).getBytes(StandardCharsets.UTF_8));
+ }
+
+ private void assertSignParameters(final SignParameters actual, final
HttpRequest request, final String parameters,
+ final String appKey, final String
timestamp, final String signature,
+ final String algorithm) {
+ assertEquals(VERSION_2, actual.getVersion());
+ assertEquals(appKey, actual.getAppKey());
+ assertEquals(timestamp, actual.getTimestamp());
+ assertEquals(signature, actual.getSignature());
+ assertEquals(request.getURI(), actual.getUri());
+ assertEquals(algorithm, actual.getSignAlg());
+ assertEquals(parameters, actual.getParameters());
+ }
+
+ private void assertEmpty(final SignParameters actual) {
+ assertNull(actual.getVersion());
+ assertNull(actual.getAppKey());
+ assertNull(actual.getTimestamp());
+ assertNull(actual.getSignature());
+ assertNull(actual.getUri());
+ assertNull(actual.getParameters());
+ }
+}
diff --git
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/VersionOneSignProviderTest.java
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/VersionOneSignProviderTest.java
new file mode 100644
index 0000000000..592cb26b38
--- /dev/null
+++
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/VersionOneSignProviderTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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 org.apache.shenyu.common.utils.SignUtils;
+import org.apache.shenyu.plugin.sign.api.SignParameters;
+import org.junit.jupiter.api.Test;
+
+import java.net.URI;
+
+import static
org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Test cases for {@link VersionOneSignProvider}.
+ */
+final class VersionOneSignProviderTest {
+
+ private static final String SIGN_KEY = "sign-key";
+
+ private static final String TIMESTAMP = "1700000000000";
+
+ private final SignProvider signProvider = new VersionOneSignProvider();
+
+ @Test
+ void testGenerateSignWithoutRequestBody() {
+ SignParameters signParameters =
createSignParameters(URI.create("https://example.com/api/orders"));
+ String data = "path/api/orderstimestamp" + TIMESTAMP + "version" +
VERSION_1;
+
+ String actual = signProvider.generateSign(SIGN_KEY, signParameters);
+
+ assertEquals(sign(data), actual);
+ }
+
+ @Test
+ void testGenerateSignWithRequestBodyAndQuery() {
+ SignParameters signParameters =
createSignParameters(URI.create("https://example.com/api/orders?channel=web"));
+ String requestBody = "{\"name\":\"ShenYu\",\"count\":2}";
+ String data = "channelwebcount2nameShenYupath/api/orderstimestamp" +
TIMESTAMP + "version" + VERSION_1;
+
+ String actual = signProvider.generateSign(SIGN_KEY, signParameters,
requestBody);
+
+ assertEquals(sign(data), actual);
+ }
+
+ @Test
+ void testGenerateSignWithEmptyRequestBody() {
+ SignParameters signParameters =
createSignParameters(URI.create("https://example.com/api/orders?channel=web"));
+ String data = "channelwebpath/api/orderstimestamp" + TIMESTAMP +
"version" + VERSION_1;
+
+ String actual = signProvider.generateSign(SIGN_KEY, signParameters,
"");
+
+ assertEquals(sign(data), actual);
+ }
+
+ @Test
+ void testGenerateSignIgnoresSignatureParameter() {
+ SignParameters signParameters =
createSignParameters(URI.create("https://example.com/api/orders"));
+ String requestBody =
"{\"name\":\"ShenYu\",\"sign\":\"untrusted-signature\"}";
+ String data = "nameShenYupath/api/orderstimestamp" + TIMESTAMP +
"version" + VERSION_1;
+
+ String actual = signProvider.generateSign(SIGN_KEY, signParameters,
requestBody);
+
+ assertEquals(sign(data), actual);
+ }
+
+ private SignParameters createSignParameters(final URI uri) {
+ return new SignParameters(VERSION_1, "app-key", TIMESTAMP,
"signature", uri, SignUtils.SIGN_MD5);
+ }
+
+ private String sign(final String data) {
+ return SignUtils.sign(SignUtils.SIGN_MD5, SIGN_KEY,
data).toUpperCase();
+ }
+}
diff --git
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/VersionTwoSignProviderTest.java
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/VersionTwoSignProviderTest.java
new file mode 100644
index 0000000000..2da3d7c459
--- /dev/null
+++
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/VersionTwoSignProviderTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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 org.apache.shenyu.common.utils.SignUtils;
+import org.apache.shenyu.plugin.sign.api.SignParameters;
+import org.junit.jupiter.api.Test;
+
+import java.net.URI;
+
+import static
org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Test cases for {@link VersionTwoSignProvider}.
+ */
+final class VersionTwoSignProviderTest {
+
+ private static final String SIGN_KEY = "sign-key";
+
+ private static final String PARAMETERS = "encoded-parameters";
+
+ private final SignProvider signProvider = new VersionTwoSignProvider();
+
+ @Test
+ void testGenerateSignWithoutRequestBody() {
+ SignParameters signParameters =
createSignParameters(URI.create("https://example.com/api/orders?channel=web"));
+
+ String actual = signProvider.generateSign(SIGN_KEY, signParameters);
+
+ assertEquals(sign(PARAMETERS + "/api/orders?channel=web"), actual);
+ }
+
+ @Test
+ void testGenerateSignWithRequestBody() {
+ SignParameters signParameters =
createSignParameters(URI.create("https://example.com/api/orders"));
+ String requestBody = "{\"name\":\"ShenYu\"}";
+
+ String actual = signProvider.generateSign(SIGN_KEY, signParameters,
requestBody);
+
+ assertEquals(sign(PARAMETERS + "/api/orders" + requestBody), actual);
+ }
+
+ private SignParameters createSignParameters(final URI uri) {
+ SignParameters signParameters = new SignParameters(VERSION_2,
"app-key", "1700000000000",
+ "signature", uri, SignUtils.SIGN_MD5);
+ signParameters.setParameters(PARAMETERS);
+ return signParameters;
+ }
+
+ private String sign(final String data) {
+ return SignUtils.sign(SignUtils.SIGN_MD5, SIGN_KEY,
data).toUpperCase();
+ }
+}