forked from hugegraph/hugegraph-sync
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.
This commit is contained in:
parent
b116fc8a21
commit
4bb48814bb
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -1600,6 +1600,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 {
|
||||
|
|
|
|||
|
|
@ -264,4 +264,12 @@ public class ServerOptions extends OptionHolder {
|
|||
disallowEmpty(),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
public static final ConfigOption<String> WHITE_IP_STATUS =
|
||||
new ConfigOption<>(
|
||||
"white_ip.status",
|
||||
"The status of whether enable white ip.",
|
||||
disallowEmpty(),
|
||||
"disable"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue