This is an automated email from the ASF dual-hosted git repository.
jermy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git
The following commit(s) were added to refs/heads/master by this push:
new 30ef2f7c6 feat: support White IP List (#2299)
30ef2f7c6 is described below
commit 30ef2f7c6b7d55de65200f8222b52f12cbe82853
Author: SunnyBoy-WYH <[email protected]>
AuthorDate: Mon Oct 2 13:25:45 2023 +0800
feat: support White IP List (#2299)
tips:
- this feat works when auth mode was set.
- this feat works when white ip status was enabled.
because now PD is unavailable,just use java list; when pd ready , we can
checkout pd.
---
.../hugegraph/api/filter/AuthenticationFilter.java | 69 ++++++---
.../hugegraph/api/profile/WhiteIpListAPI.java | 155 +++++++++++++++++++++
.../apache/hugegraph/auth/HugeGraphAuthProxy.java | 20 +++
.../org/apache/hugegraph/config/ServerOptions.java | 10 +-
.../org/apache/hugegraph/auth/AuthManager.java | 8 ++
.../apache/hugegraph/auth/StandardAuthManager.java | 45 ++++--
6 files changed, 280 insertions(+), 27 deletions(-)
diff --git
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/AuthenticationFilter.java
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/AuthenticationFilter.java
index f534a0ac9..464e695fe 100644
---
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/AuthenticationFilter.java
+++
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/AuthenticationFilter.java
@@ -17,14 +17,38 @@
package org.apache.hugegraph.api.filter;
+import static org.apache.hugegraph.config.ServerOptions.WHITE_IP_STATUS;
+
import java.io.IOException;
import java.security.Principal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.hugegraph.auth.HugeAuthenticator;
+import org.apache.hugegraph.auth.HugeAuthenticator.RequiredPerm;
+import org.apache.hugegraph.auth.HugeAuthenticator.RolePerm;
+import org.apache.hugegraph.auth.HugeAuthenticator.User;
+import org.apache.hugegraph.auth.RolePermission;
+import org.apache.hugegraph.config.HugeConfig;
+import org.apache.hugegraph.core.GraphManager;
+import org.apache.hugegraph.util.E;
+import org.apache.hugegraph.util.Log;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.utils.Charsets;
+import org.slf4j.Logger;
+
+import com.alipay.remoting.util.StringUtils;
+import com.google.common.collect.ImmutableList;
import jakarta.annotation.Priority;
import jakarta.ws.rs.BadRequestException;
+import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.NotAuthorizedException;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.container.ContainerRequestContext;
@@ -35,23 +59,6 @@ import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.Provider;
-import javax.xml.bind.DatatypeConverter;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
-import org.glassfish.grizzly.http.server.Request;
-import org.glassfish.grizzly.utils.Charsets;
-import org.slf4j.Logger;
-
-import org.apache.hugegraph.auth.HugeAuthenticator;
-import org.apache.hugegraph.auth.HugeAuthenticator.RequiredPerm;
-import org.apache.hugegraph.auth.HugeAuthenticator.RolePerm;
-import org.apache.hugegraph.auth.HugeAuthenticator.User;
-import org.apache.hugegraph.auth.RolePermission;
-import org.apache.hugegraph.core.GraphManager;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.Log;
-import com.google.common.collect.ImmutableList;
@Provider
@PreMatching
@@ -68,12 +75,20 @@ public class AuthenticationFilter implements
ContainerRequestFilter {
"versions"
);
+ private static String whiteIpStatus;
+
+ private static final String STRING_WHITE_IP_LIST = "whiteiplist";
+ private static final String STRING_ENABLE = "enable";
+
@Context
private jakarta.inject.Provider<GraphManager> managerProvider;
@Context
private jakarta.inject.Provider<Request> requestProvider;
+ @Context
+ private jakarta.inject.Provider<HugeConfig> configProvider;
+
@Override
public void filter(ContainerRequestContext context) throws IOException {
if (AuthenticationFilter.isWhiteAPI(context)) {
@@ -102,6 +117,26 @@ public class AuthenticationFilter implements
ContainerRequestFilter {
path = request.getRequestURI();
}
+ // Check whiteIp
+ if (whiteIpStatus == null) {
+ whiteIpStatus = this.configProvider.get().get(WHITE_IP_STATUS);
+ }
+
+ if (Objects.equals(whiteIpStatus, STRING_ENABLE) && request != null) {
+ peer = request.getRemoteAddr() + ":" + request.getRemotePort();
+ path = request.getRequestURI();
+
+ String remoteIp = request.getRemoteAddr();
+ Set<String> whiteIpList = manager.authManager().listWhiteIPs();
+ boolean whiteIpEnabled = manager.authManager().getWhiteIpStatus();
+ if (!path.contains(STRING_WHITE_IP_LIST) && whiteIpEnabled &&
+ !whiteIpList.contains(remoteIp)) {
+ throw new ForbiddenException(
+ String.format("Remote ip '%s' is not permitted",
+ remoteIp));
+ }
+ }
+
Map<String, String> credentials = new HashMap<>();
// Extract authentication credentials
String auth = context.getHeaderString(HttpHeaders.AUTHORIZATION);
diff --git
a/hugegraph-api/src/main/java/org/apache/hugegraph/api/profile/WhiteIpListAPI.java
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/profile/WhiteIpListAPI.java
new file mode 100644
index 000000000..7503e1382
--- /dev/null
+++
b/hugegraph-api/src/main/java/org/apache/hugegraph/api/profile/WhiteIpListAPI.java
@@ -0,0 +1,155 @@
+/*
+ * 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.hugegraph.api.profile;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hugegraph.api.API;
+import org.apache.hugegraph.api.filter.StatusFilter;
+import org.apache.hugegraph.auth.AuthManager;
+import org.apache.hugegraph.core.GraphManager;
+import org.apache.hugegraph.util.E;
+import org.apache.hugegraph.util.Log;
+import org.slf4j.Logger;
+
+import com.codahale.metrics.annotation.Timed;
+import com.google.common.collect.ImmutableMap;
+
+import jakarta.annotation.security.RolesAllowed;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.Context;
+
+@Path("whiteiplist")
+@Singleton
+public class WhiteIpListAPI extends API {
+
+ private static final Logger LOG = Log.logger(WhiteIpListAPI.class);
+
+ @GET
+ @Timed
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ @RolesAllowed("admin")
+ public Map<String, Object> list(@Context GraphManager manager) {
+ LOG.debug("List white ips");
+ AuthManager authManager = manager.authManager();
+ Set<String> whiteIpList = authManager.listWhiteIPs();
+ return ImmutableMap.of("whiteIpList", whiteIpList);
+ }
+
+ @POST
+ @Timed
+ @StatusFilter.Status(StatusFilter.Status.ACCEPTED)
+ @Consumes(APPLICATION_JSON)
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ @RolesAllowed("admin")
+ public Map<String, Object> updateWhiteIPs(@Context GraphManager manager,
Map<String, Object> actionMap) {
+ E.checkArgument(actionMap != null,
+ "Missing argument: actionMap");
+ Set<String> whiteIpList = manager.authManager().listWhiteIPs();
+ Object ipListRaw = actionMap.get("ips");
+ E.checkArgument(ipListRaw instanceof List,
+ "Invalid ips type '%s', must be list",
ipListRaw.getClass());
+ List<String> ipList = (List<String>) ipListRaw;
+ Object actionRaw = actionMap.get("action");
+ E.checkArgument(actionRaw != null,
+ "Missing argument: action");
+ E.checkArgument(actionRaw instanceof String,
+ "Invalid action type '%s', must be string",
+ actionRaw.getClass());
+ String action = (String) actionRaw;
+ E.checkArgument(StringUtils.isNotEmpty(action),
+ "Missing argument: action");
+ Set<String> existedIPs = new HashSet<>();
+ Set<String> loadedIPs = new HashSet<>();
+ Set<String> illegalIPs = new HashSet<>();
+ Map<String, Object> result = new HashMap<>();
+ for (String ip : ipList) {
+ if (whiteIpList.contains(ip)) {
+ existedIPs.add(ip);
+ continue;
+ }
+ if ("load".equals(action)) {
+ boolean rightIp = checkIp(ip) ? loadedIPs.add(ip) :
illegalIPs.add(ip);
+ }
+ }
+ switch (action) {
+ case "load":
+ LOG.debug("Load to white ip list");
+ result.put("existed_ips", existedIPs);
+ result.put("added_ips", loadedIPs);
+ if (!illegalIPs.isEmpty()) {
+ result.put("illegal_ips", illegalIPs);
+ }
+ whiteIpList.addAll(loadedIPs);
+ break;
+ case "remove":
+ LOG.debug("Remove from white ip list");
+ result.put("removed_ips", existedIPs);
+ result.put("non_existed_ips", loadedIPs);
+ whiteIpList.removeAll(existedIPs);
+ break;
+ default:
+ throw new AssertionError(String.format("Invalid action '%s', "
+
+ "supported action is " +
+ "'load' or 'remove'",
+ action));
+ }
+ manager.authManager().setWhiteIPs(whiteIpList);
+ return result;
+ }
+
+ @PUT
+ @Timed
+ @Produces(APPLICATION_JSON_WITH_CHARSET)
+ @RolesAllowed("admin")
+ public Map<String, Object> updateStatus(@Context GraphManager manager,
@QueryParam("status") String status) {
+ LOG.debug("Enable or disable white ip list");
+ E.checkArgument("true".equals(status) ||
+ "false".equals(status),
+ "Invalid status, valid status is 'true' or 'false'");
+ boolean open = Boolean.parseBoolean(status);
+ manager.authManager().enabledWhiteIpList(open);
+ Map<String, Object> map = new HashMap<>();
+ map.put("WhiteIpListOpen", open);
+ return map;
+ }
+
+ private boolean checkIp(String ipStr) {
+ String ip = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
+ + "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
+ + "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
+ + "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";
+ Pattern pattern = Pattern.compile(ip);
+ Matcher matcher = pattern.matcher(ipStr);
+ return matcher.matches();
+ }
+}
diff --git
a/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
b/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
index 04cfac30d..2435e2667 100644
---
a/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
+++
b/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
@@ -1568,6 +1568,26 @@ public final class HugeGraphAuthProxy implements
HugeGraph {
}
}
+ @Override
+ public Set<String> listWhiteIPs() {
+ return this.authManager.listWhiteIPs();
+ }
+
+ @Override
+ public void setWhiteIPs(Set<String> whiteIpList) {
+ this.authManager.setWhiteIPs(whiteIpList);
+ }
+
+ @Override
+ public boolean getWhiteIpStatus() {
+ return this.authManager.getWhiteIpStatus();
+ }
+
+ @Override
+ public void enabledWhiteIpList(boolean status) {
+ this.authManager.enabledWhiteIpList(status);
+ }
+
@Override
public String loginUser(String username, String password) {
try {
diff --git
a/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java
b/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java
index e66b59356..6e41ae87c 100644
--- a/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java
+++ b/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java
@@ -264,4 +264,12 @@ public class ServerOptions extends OptionHolder {
disallowEmpty(),
true
);
-}
\ No newline at end of file
+
+ public static final ConfigOption<String> WHITE_IP_STATUS =
+ new ConfigOption<>(
+ "white_ip.status",
+ "The status of whether enable white ip.",
+ disallowEmpty(),
+ "disable"
+ );
+}
diff --git
a/hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java
b/hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java
index 2dba7c7a1..908eed01f 100644
--- a/hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java
+++ b/hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java
@@ -126,4 +126,12 @@ public interface AuthManager {
UserWithRole validateUser(String username, String password);
UserWithRole validateUser(String token);
+
+ Set<String> listWhiteIPs();
+
+ void setWhiteIPs(Set<String> whiteIpList);
+
+ boolean getWhiteIpStatus();
+
+ void enabledWhiteIpList(boolean status);
}
diff --git
a/hugegraph-core/src/main/java/org/apache/hugegraph/auth/StandardAuthManager.java
b/hugegraph-core/src/main/java/org/apache/hugegraph/auth/StandardAuthManager.java
index 910f19cdc..123c8e9ff 100644
---
a/hugegraph-core/src/main/java/org/apache/hugegraph/auth/StandardAuthManager.java
+++
b/hugegraph-core/src/main/java/org/apache/hugegraph/auth/StandardAuthManager.java
@@ -27,31 +27,30 @@ import java.util.concurrent.Callable;
import javax.security.sasl.AuthenticationException;
-import jakarta.ws.rs.ForbiddenException;
-
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
+import org.apache.hugegraph.HugeException;
+import org.apache.hugegraph.HugeGraphParams;
+import org.apache.hugegraph.auth.HugeUser.P;
+import org.apache.hugegraph.auth.SchemaDefine.AuthElement;
import org.apache.hugegraph.backend.cache.Cache;
import org.apache.hugegraph.backend.cache.CacheManager;
import org.apache.hugegraph.backend.id.Id;
import org.apache.hugegraph.backend.id.IdGenerator;
import org.apache.hugegraph.config.AuthOptions;
+import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.type.define.Directions;
+import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.LockUtil;
+import org.apache.hugegraph.util.Log;
import org.apache.hugegraph.util.StringEncoding;
import org.slf4j.Logger;
-import org.apache.hugegraph.HugeException;
-import org.apache.hugegraph.HugeGraphParams;
-import org.apache.hugegraph.auth.HugeUser.P;
-import org.apache.hugegraph.auth.SchemaDefine.AuthElement;
-import org.apache.hugegraph.config.HugeConfig;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.Log;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.jsonwebtoken.Claims;
+import jakarta.ws.rs.ForbiddenException;
public class StandardAuthManager implements AuthManager {
@@ -77,6 +76,10 @@ public class StandardAuthManager implements AuthManager {
private final TokenGenerator tokenGenerator;
private final long tokenExpire;
+ private Set<String> ipWhiteList;
+
+ private Boolean ipWhiteListEnabled;
+
public StandardAuthManager(HugeGraphParams graph) {
E.checkNotNull(graph, "graph");
HugeConfig config = graph.configuration();
@@ -104,6 +107,10 @@ public class StandardAuthManager implements AuthManager {
HugeAccess::fromEdge);
this.tokenGenerator = new TokenGenerator(config);
+
+ this.ipWhiteList = new HashSet<>();
+
+ this.ipWhiteListEnabled = false;
}
private <V> Cache<Id, V> cache(String prefix, long capacity,
@@ -689,6 +696,26 @@ public class StandardAuthManager implements AuthManager {
return new UserWithRole(user.id(), username,
this.rolePermission(user));
}
+ @Override
+ public Set<String> listWhiteIPs() {
+ return ipWhiteList;
+ }
+
+ @Override
+ public void setWhiteIPs(Set<String> ipWhiteList) {
+ this.ipWhiteList = ipWhiteList;
+ }
+
+ @Override
+ public boolean getWhiteIpStatus() {
+ return this.ipWhiteListEnabled;
+ }
+
+ @Override
+ public void enabledWhiteIpList(boolean status) {
+ this.ipWhiteListEnabled = status;
+ }
+
/**
* Maybe can define an proxy class to choose forward or call local
*/