Skip to content

Commit 30ef2f7

Browse files
authored
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.
1 parent d7c1c21 commit 30ef2f7

File tree

6 files changed

+280
-27
lines changed

6 files changed

+280
-27
lines changed

hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/AuthenticationFilter.java

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,38 @@
1717

1818
package org.apache.hugegraph.api.filter;
1919

20+
import static org.apache.hugegraph.config.ServerOptions.WHITE_IP_STATUS;
21+
2022
import java.io.IOException;
2123
import java.security.Principal;
2224
import java.util.HashMap;
2325
import java.util.List;
2426
import java.util.Map;
27+
import java.util.Objects;
28+
import java.util.Set;
29+
30+
import javax.xml.bind.DatatypeConverter;
31+
32+
import org.apache.hugegraph.auth.HugeAuthenticator;
33+
import org.apache.hugegraph.auth.HugeAuthenticator.RequiredPerm;
34+
import org.apache.hugegraph.auth.HugeAuthenticator.RolePerm;
35+
import org.apache.hugegraph.auth.HugeAuthenticator.User;
36+
import org.apache.hugegraph.auth.RolePermission;
37+
import org.apache.hugegraph.config.HugeConfig;
38+
import org.apache.hugegraph.core.GraphManager;
39+
import org.apache.hugegraph.util.E;
40+
import org.apache.hugegraph.util.Log;
41+
import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
42+
import org.glassfish.grizzly.http.server.Request;
43+
import org.glassfish.grizzly.utils.Charsets;
44+
import org.slf4j.Logger;
45+
46+
import com.alipay.remoting.util.StringUtils;
47+
import com.google.common.collect.ImmutableList;
2548

2649
import jakarta.annotation.Priority;
2750
import jakarta.ws.rs.BadRequestException;
51+
import jakarta.ws.rs.ForbiddenException;
2852
import jakarta.ws.rs.NotAuthorizedException;
2953
import jakarta.ws.rs.Priorities;
3054
import jakarta.ws.rs.container.ContainerRequestContext;
@@ -35,23 +59,6 @@
3559
import jakarta.ws.rs.core.SecurityContext;
3660
import jakarta.ws.rs.core.UriInfo;
3761
import jakarta.ws.rs.ext.Provider;
38-
import javax.xml.bind.DatatypeConverter;
39-
40-
import org.apache.commons.lang3.StringUtils;
41-
import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
42-
import org.glassfish.grizzly.http.server.Request;
43-
import org.glassfish.grizzly.utils.Charsets;
44-
import org.slf4j.Logger;
45-
46-
import org.apache.hugegraph.auth.HugeAuthenticator;
47-
import org.apache.hugegraph.auth.HugeAuthenticator.RequiredPerm;
48-
import org.apache.hugegraph.auth.HugeAuthenticator.RolePerm;
49-
import org.apache.hugegraph.auth.HugeAuthenticator.User;
50-
import org.apache.hugegraph.auth.RolePermission;
51-
import org.apache.hugegraph.core.GraphManager;
52-
import org.apache.hugegraph.util.E;
53-
import org.apache.hugegraph.util.Log;
54-
import com.google.common.collect.ImmutableList;
5562

5663
@Provider
5764
@PreMatching
@@ -68,12 +75,20 @@ public class AuthenticationFilter implements ContainerRequestFilter {
6875
"versions"
6976
);
7077

78+
private static String whiteIpStatus;
79+
80+
private static final String STRING_WHITE_IP_LIST = "whiteiplist";
81+
private static final String STRING_ENABLE = "enable";
82+
7183
@Context
7284
private jakarta.inject.Provider<GraphManager> managerProvider;
7385

7486
@Context
7587
private jakarta.inject.Provider<Request> requestProvider;
7688

89+
@Context
90+
private jakarta.inject.Provider<HugeConfig> configProvider;
91+
7792
@Override
7893
public void filter(ContainerRequestContext context) throws IOException {
7994
if (AuthenticationFilter.isWhiteAPI(context)) {
@@ -102,6 +117,26 @@ protected User authenticate(ContainerRequestContext context) {
102117
path = request.getRequestURI();
103118
}
104119

120+
// Check whiteIp
121+
if (whiteIpStatus == null) {
122+
whiteIpStatus = this.configProvider.get().get(WHITE_IP_STATUS);
123+
}
124+
125+
if (Objects.equals(whiteIpStatus, STRING_ENABLE) && request != null) {
126+
peer = request.getRemoteAddr() + ":" + request.getRemotePort();
127+
path = request.getRequestURI();
128+
129+
String remoteIp = request.getRemoteAddr();
130+
Set<String> whiteIpList = manager.authManager().listWhiteIPs();
131+
boolean whiteIpEnabled = manager.authManager().getWhiteIpStatus();
132+
if (!path.contains(STRING_WHITE_IP_LIST) && whiteIpEnabled &&
133+
!whiteIpList.contains(remoteIp)) {
134+
throw new ForbiddenException(
135+
String.format("Remote ip '%s' is not permitted",
136+
remoteIp));
137+
}
138+
}
139+
105140
Map<String, String> credentials = new HashMap<>();
106141
// Extract authentication credentials
107142
String auth = context.getHeaderString(HttpHeaders.AUTHORIZATION);
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with this
4+
* work for additional information regarding copyright ownership. The ASF
5+
* licenses this file to You under the Apache License, Version 2.0 (the
6+
* "License"); you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14+
* License for the specific language governing permissions and limitations
15+
* under the License.
16+
*/
17+
18+
package org.apache.hugegraph.api.profile;
19+
20+
import java.util.HashMap;
21+
import java.util.HashSet;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.Set;
25+
import java.util.regex.Matcher;
26+
import java.util.regex.Pattern;
27+
28+
import org.apache.commons.lang.StringUtils;
29+
import org.apache.hugegraph.api.API;
30+
import org.apache.hugegraph.api.filter.StatusFilter;
31+
import org.apache.hugegraph.auth.AuthManager;
32+
import org.apache.hugegraph.core.GraphManager;
33+
import org.apache.hugegraph.util.E;
34+
import org.apache.hugegraph.util.Log;
35+
import org.slf4j.Logger;
36+
37+
import com.codahale.metrics.annotation.Timed;
38+
import com.google.common.collect.ImmutableMap;
39+
40+
import jakarta.annotation.security.RolesAllowed;
41+
import jakarta.inject.Singleton;
42+
import jakarta.ws.rs.Consumes;
43+
import jakarta.ws.rs.GET;
44+
import jakarta.ws.rs.POST;
45+
import jakarta.ws.rs.PUT;
46+
import jakarta.ws.rs.Path;
47+
import jakarta.ws.rs.Produces;
48+
import jakarta.ws.rs.QueryParam;
49+
import jakarta.ws.rs.core.Context;
50+
51+
@Path("whiteiplist")
52+
@Singleton
53+
public class WhiteIpListAPI extends API {
54+
55+
private static final Logger LOG = Log.logger(WhiteIpListAPI.class);
56+
57+
@GET
58+
@Timed
59+
@Produces(APPLICATION_JSON_WITH_CHARSET)
60+
@RolesAllowed("admin")
61+
public Map<String, Object> list(@Context GraphManager manager) {
62+
LOG.debug("List white ips");
63+
AuthManager authManager = manager.authManager();
64+
Set<String> whiteIpList = authManager.listWhiteIPs();
65+
return ImmutableMap.of("whiteIpList", whiteIpList);
66+
}
67+
68+
@POST
69+
@Timed
70+
@StatusFilter.Status(StatusFilter.Status.ACCEPTED)
71+
@Consumes(APPLICATION_JSON)
72+
@Produces(APPLICATION_JSON_WITH_CHARSET)
73+
@RolesAllowed("admin")
74+
public Map<String, Object> updateWhiteIPs(@Context GraphManager manager, Map<String, Object> actionMap) {
75+
E.checkArgument(actionMap != null,
76+
"Missing argument: actionMap");
77+
Set<String> whiteIpList = manager.authManager().listWhiteIPs();
78+
Object ipListRaw = actionMap.get("ips");
79+
E.checkArgument(ipListRaw instanceof List,
80+
"Invalid ips type '%s', must be list", ipListRaw.getClass());
81+
List<String> ipList = (List<String>) ipListRaw;
82+
Object actionRaw = actionMap.get("action");
83+
E.checkArgument(actionRaw != null,
84+
"Missing argument: action");
85+
E.checkArgument(actionRaw instanceof String,
86+
"Invalid action type '%s', must be string",
87+
actionRaw.getClass());
88+
String action = (String) actionRaw;
89+
E.checkArgument(StringUtils.isNotEmpty(action),
90+
"Missing argument: action");
91+
Set<String> existedIPs = new HashSet<>();
92+
Set<String> loadedIPs = new HashSet<>();
93+
Set<String> illegalIPs = new HashSet<>();
94+
Map<String, Object> result = new HashMap<>();
95+
for (String ip : ipList) {
96+
if (whiteIpList.contains(ip)) {
97+
existedIPs.add(ip);
98+
continue;
99+
}
100+
if ("load".equals(action)) {
101+
boolean rightIp = checkIp(ip) ? loadedIPs.add(ip) : illegalIPs.add(ip);
102+
}
103+
}
104+
switch (action) {
105+
case "load":
106+
LOG.debug("Load to white ip list");
107+
result.put("existed_ips", existedIPs);
108+
result.put("added_ips", loadedIPs);
109+
if (!illegalIPs.isEmpty()) {
110+
result.put("illegal_ips", illegalIPs);
111+
}
112+
whiteIpList.addAll(loadedIPs);
113+
break;
114+
case "remove":
115+
LOG.debug("Remove from white ip list");
116+
result.put("removed_ips", existedIPs);
117+
result.put("non_existed_ips", loadedIPs);
118+
whiteIpList.removeAll(existedIPs);
119+
break;
120+
default:
121+
throw new AssertionError(String.format("Invalid action '%s', " +
122+
"supported action is " +
123+
"'load' or 'remove'",
124+
action));
125+
}
126+
manager.authManager().setWhiteIPs(whiteIpList);
127+
return result;
128+
}
129+
130+
@PUT
131+
@Timed
132+
@Produces(APPLICATION_JSON_WITH_CHARSET)
133+
@RolesAllowed("admin")
134+
public Map<String, Object> updateStatus(@Context GraphManager manager, @QueryParam("status") String status) {
135+
LOG.debug("Enable or disable white ip list");
136+
E.checkArgument("true".equals(status) ||
137+
"false".equals(status),
138+
"Invalid status, valid status is 'true' or 'false'");
139+
boolean open = Boolean.parseBoolean(status);
140+
manager.authManager().enabledWhiteIpList(open);
141+
Map<String, Object> map = new HashMap<>();
142+
map.put("WhiteIpListOpen", open);
143+
return map;
144+
}
145+
146+
private boolean checkIp(String ipStr) {
147+
String ip = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
148+
+ "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
149+
+ "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
150+
+ "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";
151+
Pattern pattern = Pattern.compile(ip);
152+
Matcher matcher = pattern.matcher(ipStr);
153+
return matcher.matches();
154+
}
155+
}

hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,26 @@ public UserWithRole validateUser(String token) {
15681568
}
15691569
}
15701570

1571+
@Override
1572+
public Set<String> listWhiteIPs() {
1573+
return this.authManager.listWhiteIPs();
1574+
}
1575+
1576+
@Override
1577+
public void setWhiteIPs(Set<String> whiteIpList) {
1578+
this.authManager.setWhiteIPs(whiteIpList);
1579+
}
1580+
1581+
@Override
1582+
public boolean getWhiteIpStatus() {
1583+
return this.authManager.getWhiteIpStatus();
1584+
}
1585+
1586+
@Override
1587+
public void enabledWhiteIpList(boolean status) {
1588+
this.authManager.enabledWhiteIpList(status);
1589+
}
1590+
15711591
@Override
15721592
public String loginUser(String username, String password) {
15731593
try {

hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,4 +264,12 @@ public static synchronized ServerOptions instance() {
264264
disallowEmpty(),
265265
true
266266
);
267-
}
267+
268+
public static final ConfigOption<String> WHITE_IP_STATUS =
269+
new ConfigOption<>(
270+
"white_ip.status",
271+
"The status of whether enable white ip.",
272+
disallowEmpty(),
273+
"disable"
274+
);
275+
}

hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,12 @@ public interface AuthManager {
126126
UserWithRole validateUser(String username, String password);
127127

128128
UserWithRole validateUser(String token);
129+
130+
Set<String> listWhiteIPs();
131+
132+
void setWhiteIPs(Set<String> whiteIpList);
133+
134+
boolean getWhiteIpStatus();
135+
136+
void enabledWhiteIpList(boolean status);
129137
}

0 commit comments

Comments
 (0)