dashboard: Improve IP validation in SentinelApiClient and rule controllers

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
Eric Zhao 2022-09-26 19:16:04 +08:00
parent 84df19b2c5
commit e13d20ce55
8 changed files with 60 additions and 1 deletions

View File

@ -71,6 +71,7 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.conn.util.InetAddressUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
@ -282,6 +283,14 @@ public class SentinelApiClient {
future.completeExceptionally(new IllegalArgumentException("Bad URL or command name"));
return future;
}
if (!InetAddressUtils.isIPv4Address(ip) && !InetAddressUtils.isIPv6Address(ip)) {
future.completeExceptionally(new IllegalArgumentException("Bad IP"));
return future;
}
if (!StringUtil.isEmpty(app) && !appManagement.isValidMachineOfApp(app, ip)) {
future.completeExceptionally(new IllegalArgumentException("Given ip does not belong to given app"));
return future;
}
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append("http://");
urlBuilder.append(ip).append(':').append(port).append('/').append(api);

View File

@ -20,6 +20,7 @@ import java.util.List;
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
@ -56,6 +57,8 @@ public class AuthorityRuleController {
private SentinelApiClient sentinelApiClient;
@Autowired
private RuleRepository<AuthorityRuleEntity, Long> repository;
@Autowired
private AppManagement appManagement;
@GetMapping("/rules")
@AuthAction(PrivilegeType.READ_RULE)
@ -71,6 +74,9 @@ public class AuthorityRuleController {
if (port == null || port <= 0) {
return Result.ofFail(-1, "Invalid parameter: port");
}
if (!appManagement.isValidMachineOfApp(app, ip)) {
return Result.ofFail(-1, "given ip does not belong to given app");
}
try {
List<AuthorityRuleEntity> rules = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port);
rules = repository.saveAll(rules);

View File

@ -20,6 +20,7 @@ import java.util.List;
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
@ -58,6 +59,8 @@ public class DegradeController {
private RuleRepository<DegradeRuleEntity, Long> repository;
@Autowired
private SentinelApiClient sentinelApiClient;
@Autowired
private AppManagement appManagement;
@GetMapping("/rules.json")
@AuthAction(PrivilegeType.READ_RULE)
@ -71,6 +74,9 @@ public class DegradeController {
if (port == null) {
return Result.ofFail(-1, "port can't be null");
}
if (!appManagement.isValidMachineOfApp(app, ip)) {
return Result.ofFail(-1, "given ip does not belong to given app");
}
try {
List<DegradeRuleEntity> rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port);
rules = repository.saveAll(rules);
@ -173,6 +179,9 @@ public class DegradeController {
if (StringUtil.isBlank(entity.getIp())) {
return Result.ofFail(-1, "ip can't be null or empty");
}
if (!appManagement.isValidMachineOfApp(entity.getApp(), entity.getIp())) {
return Result.ofFail(-1, "given ip does not belong to given app");
}
if (entity.getPort() == null || entity.getPort() <= 0) {
return Result.ofFail(-1, "invalid port: " + entity.getPort());
}

View File

@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
@ -57,6 +58,8 @@ public class FlowControllerV1 {
@Autowired
private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
@Autowired
private AppManagement appManagement;
@Autowired
private SentinelApiClient sentinelApiClient;
@ -66,7 +69,6 @@ public class FlowControllerV1 {
public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app,
@RequestParam String ip,
@RequestParam Integer port) {
if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty");
}
@ -76,6 +78,9 @@ public class FlowControllerV1 {
if (port == null) {
return Result.ofFail(-1, "port can't be null");
}
if (!appManagement.isValidMachineOfApp(app, ip)) {
return Result.ofFail(-1, "given ip does not belong to given app");
}
try {
List<FlowRuleEntity> rules = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port);
rules = repository.saveAll(rules);
@ -96,6 +101,9 @@ public class FlowControllerV1 {
if (entity.getPort() == null) {
return Result.ofFail(-1, "port can't be null");
}
if (!appManagement.isValidMachineOfApp(entity.getApp(), entity.getIp())) {
return Result.ofFail(-1, "given ip does not belong to given app");
}
if (StringUtil.isBlank(entity.getLimitApp())) {
return Result.ofFail(-1, "limitApp can't be null or empty");
}

View File

@ -93,6 +93,9 @@ public class ParamFlowRuleController {
if (port == null || port <= 0) {
return Result.ofFail(-1, "Invalid parameter: port");
}
if (!appManagement.isValidMachineOfApp(app, ip)) {
return Result.ofFail(-1, "given ip does not belong to given app");
}
if (!checkIfSupported(app, ip, port)) {
return unsupportedVersion();
}

View File

@ -20,6 +20,7 @@ import java.util.List;
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
import com.alibaba.csp.sentinel.util.StringUtil;
@ -48,6 +49,8 @@ public class SystemController {
private RuleRepository<SystemRuleEntity, Long> repository;
@Autowired
private SentinelApiClient sentinelApiClient;
@Autowired
private AppManagement appManagement;
private <R> Result<R> checkBasicParams(String app, String ip, Integer port) {
if (StringUtil.isEmpty(app)) {
@ -59,6 +62,9 @@ public class SystemController {
if (port == null) {
return Result.ofFail(-1, "port can't be null");
}
if (!appManagement.isValidMachineOfApp(app, ip)) {
return Result.ofFail(-1, "given ip does not belong to given app");
}
if (port <= 0 || port > 65535) {
return Result.ofFail(-1, "port should be in (0, 65535)");
}

View File

@ -96,6 +96,12 @@ public class AppInfo {
.findFirst();
}
public Optional<MachineInfo> getMachine(String ip) {
return machines.stream()
.filter(e -> e.getIp().equals(ip))
.findFirst();
}
private boolean heartbeatJudge(final int threshold) {
if (machines.size() == 0) {
return false;

View File

@ -16,10 +16,13 @@
package com.alibaba.csp.sentinel.dashboard.discovery;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.annotation.PostConstruct;
import com.alibaba.csp.sentinel.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@ -67,4 +70,13 @@ public class AppManagement implements MachineDiscovery {
machineDiscovery.removeApp(app);
}
public boolean isValidMachineOfApp(String app, String ip) {
if (StringUtil.isEmpty(app)) {
return false;
}
return Optional.ofNullable(getDetailApp(app))
.flatMap(a -> a.getMachine(ip))
.isPresent();
}
}