This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new 0c7f5e1bb [#4300] black/white microservice authentication add 
apiWhiteList (#4301)
0c7f5e1bb is described below

commit 0c7f5e1bb13e1f029f2fd861c5ff52b6fc8f5dfa
Author: Cheng YouLing <[email protected]>
AuthorDate: Mon May 6 10:15:26 2024 +0800

    [#4300] black/white microservice authentication add apiWhiteList (#4301)
---
 .../servicecomb/samples/ConsumerController.java    |  5 ++
 .../servicecomb/samples/ProviderService.java       |  2 +
 .../consumer/src/main/resources/application.yml    |  5 +-
 .../servicecomb/samples/ProviderController.java    |  5 ++
 .../provider/src/main/resources/application.yml    |  9 +++
 .../apache/servicecomb/samples/HelloWorldIT.java   | 11 +++
 .../authentication/provider/PathCheckUtils.java    | 92 ++++++++++++++++++++++
 .../provider/ProviderAuthFilter.java               |  9 ++-
 8 files changed, 136 insertions(+), 2 deletions(-)

diff --git 
a/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java
 
b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java
index 4ed0ecd85..437f88bfa 100644
--- 
a/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java
+++ 
b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ConsumerController.java
@@ -34,4 +34,9 @@ public class ConsumerController {
   public String sayHello(@RequestParam("name") String name) {
     return providerService.sayHello(name);
   }
+
+  @GetMapping("/authIncludePath")
+  public String authIncludePath() {
+    return providerService.authIncludePath();
+  }
 }
diff --git 
a/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java
 
b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java
index f327412b7..ee62a1106 100644
--- 
a/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java
+++ 
b/demo/demo-nacos/consumer/src/main/java/org/apache/servicecomb/samples/ProviderService.java
@@ -19,4 +19,6 @@ package org.apache.servicecomb.samples;
 
 public interface ProviderService {
   String sayHello(String name);
+
+  String authIncludePath();
 }
diff --git a/demo/demo-nacos/consumer/src/main/resources/application.yml 
b/demo/demo-nacos/consumer/src/main/resources/application.yml
index 0110e6e27..d2317215e 100644
--- a/demo/demo-nacos/consumer/src/main/resources/application.yml
+++ b/demo/demo-nacos/consumer/src/main/resources/application.yml
@@ -29,5 +29,8 @@ servicecomb:
   rest:
     address: 0.0.0.0:9092
 
-
+  publicKey:
+    accessControl:
+      enabled: true
+      excludePathPatterns: '/*'
 
diff --git 
a/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java
 
b/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java
index 6eea7776a..0076440d2 100644
--- 
a/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java
+++ 
b/demo/demo-nacos/provider/src/main/java/org/apache/servicecomb/samples/ProviderController.java
@@ -30,4 +30,9 @@ public class ProviderController {
   public String sayHello(@RequestParam("name") String name) {
     return "Hello " + name;
   }
+
+  @GetMapping("/authIncludePath")
+  public String authIncludePath() {
+    return "success.";
+  }
 }
diff --git a/demo/demo-nacos/provider/src/main/resources/application.yml 
b/demo/demo-nacos/provider/src/main/resources/application.yml
index b24d281cd..ae6e029b7 100644
--- a/demo/demo-nacos/provider/src/main/resources/application.yml
+++ b/demo/demo-nacos/provider/src/main/resources/application.yml
@@ -31,3 +31,12 @@ servicecomb:
   rest:
     address: 0.0.0.0:9094
 
+  publicKey:
+    accessControl:
+      enabled: true
+      includePathPatterns: '/authIncludePath'
+      black:
+        authPath:
+          category: property
+          propertyName: serviceName
+          rule: consumer*
diff --git 
a/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java
 
b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java
index 59d06bb1e..ad9460753 100644
--- 
a/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java
+++ 
b/demo/demo-nacos/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java
@@ -30,6 +30,7 @@ public class HelloWorldIT implements CategorizedTestCase {
   @Override
   public void testRestTransport() throws Exception {
     testHelloWorld();
+    testAuthIncludePath();
   }
 
   private void testHelloWorld() {
@@ -37,4 +38,14 @@ public class HelloWorldIT implements CategorizedTestCase {
         .getForObject(Config.GATEWAY_URL + "/sayHello?name=World", 
String.class);
     TestMgr.check("Hello World", result);
   }
+
+  private void testAuthIncludePath() {
+    String result = "";
+    try {
+      result = template.getForObject(Config.GATEWAY_URL + "/authIncludePath", 
String.class);
+    } catch (Exception e) {
+      result = "failed";
+    }
+    TestMgr.check("failed", result);
+  }
 }
diff --git 
a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/PathCheckUtils.java
 
b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/PathCheckUtils.java
new file mode 100644
index 000000000..c587195d2
--- /dev/null
+++ 
b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/PathCheckUtils.java
@@ -0,0 +1,92 @@
+/*
+ * 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.servicecomb.authentication.provider;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.env.Environment;
+
+public class PathCheckUtils {
+  private static final String KEY_INCLUDE_PATH = 
"servicecomb.publicKey.accessControl.includePathPatterns";
+
+  private static final String KEY_EXCLUDE_PATH = 
"servicecomb.publicKey.accessControl.excludePathPatterns";
+
+  /**
+   * first determine configured non-authentication path is matched 
requestPath, if match not needed auth.
+   * second determine whether of configured authentication path, if not 
configured, default all path need auth;
+   * if configured, then check whether of matched requestPath, if match needed 
auth, otherwise not needed auth.
+   *
+   * @param requestPath path
+   * @param env environment
+   * @return notRequiredAuth
+   */
+  public static boolean isNotRequiredAuth(String requestPath, Environment env) 
{
+    if (excludePathMatchPath(requestPath, env)) {
+      return true;
+    }
+    return includePathMatchPath(requestPath, env);
+  }
+
+  private static boolean excludePathMatchPath(String requestPath, Environment 
env) {
+    String excludePathPattern = env.getProperty(KEY_EXCLUDE_PATH, "");
+    if (StringUtils.isEmpty(excludePathPattern)) {
+      return false;
+    }
+    return isPathMather(requestPath, excludePathPattern);
+  }
+
+  private static boolean includePathMatchPath(String requestPath, Environment 
env) {
+    String includePathPattern = env.getProperty(KEY_INCLUDE_PATH, "");
+    if (StringUtils.isEmpty(includePathPattern)) {
+      return false;
+    }
+    return !isPathMather(requestPath, includePathPattern);
+  }
+
+  private static boolean isPathMather(String requestPath, String pathPattern) {
+    for (String pattern : pathPattern.split(",")) {
+      if (!pattern.isEmpty() && isPatternMatch(requestPath, pattern)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public static boolean isPatternMatch(String value, String pattern) {
+    if (pattern.startsWith("*") || pattern.startsWith("/*")) {
+      int index = 0;
+      for (int i = 0; i < pattern.length(); i++) {
+        if (pattern.charAt(i) != '*' && pattern.charAt(i) != '/') {
+          break;
+        }
+        index++;
+      }
+      return value.endsWith(pattern.substring(index));
+    }
+    if (pattern.endsWith("*")) {
+      int index = pattern.length() - 1;
+      for (int i = pattern.length() - 1; i >= 0; i--) {
+        if (pattern.charAt(i) != '*' && pattern.charAt(i) != '/') {
+          break;
+        }
+        index--;
+      }
+      return value.startsWith(pattern.substring(0, index + 1));
+    }
+    return value.equals(pattern);
+  }
+}
diff --git 
a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthFilter.java
 
b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthFilter.java
index 93563f403..02b1108a5 100644
--- 
a/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthFilter.java
+++ 
b/handlers/handler-publickey-auth/src/main/java/org/apache/servicecomb/authentication/provider/ProviderAuthFilter.java
@@ -27,15 +27,19 @@ import org.apache.servicecomb.core.filter.ProviderFilter;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
 
 import jakarta.ws.rs.core.Response.Status;
 
 public class ProviderAuthFilter extends AbstractFilter implements 
ProviderFilter {
   private ProviderTokenManager authenticationTokenManager;
 
+  private Environment env;
+
   @Autowired
-  public void setProviderTokenManager(ProviderTokenManager 
providerTokenManager) {
+  public void setProviderTokenManager(ProviderTokenManager 
providerTokenManager, Environment env) {
     this.authenticationTokenManager = providerTokenManager;
+    this.env = env;
   }
 
   @Override
@@ -50,6 +54,9 @@ public class ProviderAuthFilter extends AbstractFilter 
implements ProviderFilter
 
   @Override
   public CompletableFuture<Response> onFilter(Invocation invocation, 
FilterNode nextNode) {
+    if 
(PathCheckUtils.isNotRequiredAuth(invocation.getOperationMeta().getOperationPath(),
 env)) {
+      return nextNode.onFilter(invocation);
+    }
     String token = invocation.getContext(CoreConst.AUTH_TOKEN);
     if (null != token && authenticationTokenManager.valid(token)) {
       return nextNode.onFilter(invocation);

Reply via email to