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();
+    }
+}

Reply via email to