From 3c52bbc3c8c318ce81966fbfa8b381ad0a20cf05 Mon Sep 17 00:00:00 2001 From: Carpenter Lee Date: Thu, 14 Mar 2019 10:03:03 +0800 Subject: [PATCH] dashboard: Add interface of authentication/authorization and provide a default stub implementation (#503) Signed-off-by: Carpenter Lee --- .../sentinel/dashboard/config/WebConfig.java | 46 ++++++++ .../controller/AuthorityRuleController.java | 28 ++++- .../controller/DegradeController.java | 33 +++++- .../controller/FlowControllerV1.java | 35 ++++-- .../controller/ParamFlowRuleController.java | 32 ++++- .../controller/SystemController.java | 26 +++- .../controller/v2/FlowControllerV2.java | 30 ++++- .../dashboard/service/AuthService.java | 111 ++++++++++++++++++ .../service/FakeAuthServiceImpl.java | 64 ++++++++++ 9 files changed, 375 insertions(+), 30 deletions(-) create mode 100644 sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/service/AuthService.java create mode 100644 sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/service/FakeAuthServiceImpl.java diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/config/WebConfig.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/config/WebConfig.java index d0e29659..14a90b09 100755 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/config/WebConfig.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/config/WebConfig.java @@ -15,12 +15,24 @@ */ package com.alibaba.csp.sentinel.dashboard.config; +import java.io.IOException; +import java.io.PrintWriter; + import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; +import com.alibaba.csp.sentinel.dashboard.service.AuthService; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -35,6 +47,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; public class WebConfig implements WebMvcConfigurer { private final Logger logger = LoggerFactory.getLogger(WebConfig.class); + @Autowired + private AuthService authService; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { @@ -62,4 +76,36 @@ public class WebConfig implements WebMvcConfigurer { return registration; } + + @Bean + public FilterRegistrationBean authenticationFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setFilter(new Filter() { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, + FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest)servletRequest; + AuthUser authUser = authService.getAuthUser(request); + // authentication fail + if (authUser == null) { + PrintWriter writer = servletResponse.getWriter(); + writer.append("login needed"); + writer.flush(); + } else { + filterChain.doFilter(servletRequest, servletResponse); + } + } + + @Override + public void destroy() { } + }); + registration.addUrlPatterns("/*"); + registration.setName("authenticationFilter"); + registration.setOrder(0); + return registration; + } } diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthorityRuleController.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthorityRuleController.java index f76ec34b..4f5d53b1 100644 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthorityRuleController.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthorityRuleController.java @@ -18,14 +18,20 @@ package com.alibaba.csp.sentinel.dashboard.controller; import java.util.Date; import java.util.List; +import javax.servlet.http.HttpServletRequest; + import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; +import com.alibaba.csp.sentinel.dashboard.service.AuthService; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity; import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -54,10 +60,16 @@ public class AuthorityRuleController { @Autowired private RuleRepository repository; + @Autowired + private AuthService authService; + @GetMapping("/rules") - public Result> apiQueryAllRulesForMachine(@RequestParam String app, + public Result> apiQueryAllRulesForMachine(HttpServletRequest request, + @RequestParam String app, @RequestParam String ip, @RequestParam Integer port) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(app, PrivilegeType.READ_RULE); if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app cannot be null or empty"); } @@ -107,7 +119,10 @@ public class AuthorityRuleController { } @PostMapping("/rule") - public Result apiAddAuthorityRule(@RequestBody AuthorityRuleEntity entity) { + public Result apiAddAuthorityRule(HttpServletRequest request, + @RequestBody AuthorityRuleEntity entity) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE); Result checkResult = checkEntityInternal(entity); if (checkResult != null) { return checkResult; @@ -129,8 +144,11 @@ public class AuthorityRuleController { } @PutMapping("/rule/{id}") - public Result apiUpdateParamFlowRule(@PathVariable("id") Long id, + public Result apiUpdateParamFlowRule(HttpServletRequest request, + @PathVariable("id") Long id, @RequestBody AuthorityRuleEntity entity) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE); if (id == null || id <= 0) { return Result.ofFail(-1, "Invalid id"); } @@ -158,7 +176,8 @@ public class AuthorityRuleController { } @DeleteMapping("/rule/{id}") - public Result apiDeleteRule(@PathVariable("id") Long id) { + public Result apiDeleteRule(HttpServletRequest request, @PathVariable("id") Long id) { + AuthUser authUser = authService.getAuthUser(request); if (id == null) { return Result.ofFail(-1, "id cannot be null"); } @@ -166,6 +185,7 @@ public class AuthorityRuleController { if (oldEntity == null) { return Result.ofSuccess(null); } + authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE); try { repository.delete(id); } catch (Exception e) { diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/DegradeController.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/DegradeController.java index 79818e77..9905d551 100755 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/DegradeController.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/DegradeController.java @@ -18,14 +18,20 @@ package com.alibaba.csp.sentinel.dashboard.controller; import java.util.Date; import java.util.List; +import javax.servlet.http.HttpServletRequest; + import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; +import com.alibaba.csp.sentinel.dashboard.service.AuthService; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity; import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemDegradeRuleStore; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -48,9 +54,15 @@ public class DegradeController { @Autowired private SentinelApiClient sentinelApiClient; + @Autowired + private AuthService authService; + @ResponseBody @RequestMapping("/rules.json") - public Result> queryMachineRules(String app, String ip, Integer port) { + public Result> queryMachineRules(HttpServletRequest request, String app, String ip, Integer port) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(app, PrivilegeType.READ_RULE); + if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } @@ -72,8 +84,12 @@ public class DegradeController { @ResponseBody @RequestMapping("/new.json") - public Result add(String app, String ip, Integer port, String limitApp, String resource, - Double count, Integer timeWindow, Integer grade) { + public Result add(HttpServletRequest request, + String app, String ip, Integer port, String limitApp, String resource, + Double count, Integer timeWindow, Integer grade) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(app, PrivilegeType.WRITE_RULE); + if (StringUtil.isBlank(app)) { return Result.ofFail(-1, "app can't be null or empty"); } @@ -127,8 +143,10 @@ public class DegradeController { @ResponseBody @RequestMapping("/save.json") - public Result updateIfNotNull(Long id, String app, String limitApp, String resource, - Double count, Integer timeWindow, Integer grade) { + public Result updateIfNotNull(HttpServletRequest request, + Long id, String app, String limitApp, String resource, + Double count, Integer timeWindow, Integer grade) { + AuthUser authUser = authService.getAuthUser(request); if (id == null) { return Result.ofFail(-1, "id can't be null"); } @@ -141,6 +159,7 @@ public class DegradeController { if (entity == null) { return Result.ofFail(-1, "id " + id + " dose not exist"); } + authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE); if (StringUtil.isNotBlank(app)) { entity.setApp(app.trim()); } @@ -176,7 +195,8 @@ public class DegradeController { @ResponseBody @RequestMapping("/delete.json") - public Result delete(Long id) { + public Result delete(HttpServletRequest request, Long id) { + AuthUser authUser = authService.getAuthUser(request); if (id == null) { return Result.ofFail(-1, "id can't be null"); } @@ -185,6 +205,7 @@ public class DegradeController { if (oldEntity == null) { return Result.ofSuccess(null); } + authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE); try { repository.delete(id); } catch (Throwable throwable) { diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/FlowControllerV1.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/FlowControllerV1.java index 23bdfee7..35315ea0 100755 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/FlowControllerV1.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/FlowControllerV1.java @@ -18,6 +18,11 @@ package com.alibaba.csp.sentinel.dashboard.controller; import java.util.Date; import java.util.List; +import javax.servlet.http.HttpServletRequest; + +import com.alibaba.csp.sentinel.dashboard.service.AuthService; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; @@ -25,6 +30,7 @@ import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -51,14 +57,20 @@ public class FlowControllerV1 { @Autowired private InMemoryRuleRepositoryAdapter repository; + @Autowired + private AuthService authService; @Autowired private SentinelApiClient sentinelApiClient; @GetMapping("/rules") - public Result> apiQueryMachineRules(@RequestParam String app, + public Result> apiQueryMachineRules(HttpServletRequest request, + @RequestParam String app, @RequestParam String ip, @RequestParam Integer port) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(app, PrivilegeType.READ_RULE); + if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } @@ -126,7 +138,10 @@ public class FlowControllerV1 { } @PostMapping("/rule") - public Result apiAddFlowRule(@RequestBody FlowRuleEntity entity) { + public Result apiAddFlowRule(HttpServletRequest request, @RequestBody FlowRuleEntity entity) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE); + Result checkResult = checkEntityInternal(entity); if (checkResult != null) { return checkResult; @@ -150,10 +165,14 @@ public class FlowControllerV1 { } @PutMapping("/save.json") - public Result updateIfNotNull(Long id, String app, - String limitApp, String resource, Integer grade, - Double count, Integer strategy, String refResource, - Integer controlBehavior, Integer warmUpPeriodSec, Integer maxQueueingTimeMs) { + public Result updateIfNotNull(HttpServletRequest request, Long id, String app, + String limitApp, String resource, Integer grade, + Double count, Integer strategy, String refResource, + Integer controlBehavior, Integer warmUpPeriodSec, + Integer maxQueueingTimeMs) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(app, PrivilegeType.WRITE_RULE); + if (id == null) { return Result.ofFail(-1, "id can't be null"); } @@ -227,7 +246,8 @@ public class FlowControllerV1 { } @DeleteMapping("/delete.json") - public Result delete(Long id) { + public Result delete(HttpServletRequest request, Long id) { + AuthUser authUser = authService.getAuthUser(request); if (id == null) { return Result.ofFail(-1, "id can't be null"); } @@ -235,6 +255,7 @@ public class FlowControllerV1 { if (oldEntity == null) { return Result.ofSuccess(null); } + authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE); try { repository.delete(id); } catch (Exception e) { diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/ParamFlowRuleController.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/ParamFlowRuleController.java index 9d962eae..c603613a 100644 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/ParamFlowRuleController.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/ParamFlowRuleController.java @@ -21,10 +21,15 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import javax.servlet.http.HttpServletRequest; + import com.alibaba.csp.sentinel.dashboard.client.CommandNotFoundException; 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.service.AuthService; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.util.StringUtil; @@ -33,6 +38,7 @@ import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEn import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository; import com.alibaba.csp.sentinel.dashboard.util.VersionUtils; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -63,6 +69,9 @@ public class ParamFlowRuleController { @Autowired private RuleRepository repository; + @Autowired + private AuthService authService; + private boolean checkIfSupported(String app, String ip, int port) { try { return Optional.ofNullable(appManagement.getDetailApp(app)) @@ -77,9 +86,12 @@ public class ParamFlowRuleController { } @GetMapping("/rules") - public Result> apiQueryAllRulesForMachine(@RequestParam String app, + public Result> apiQueryAllRulesForMachine(HttpServletRequest request, + @RequestParam String app, @RequestParam String ip, @RequestParam Integer port) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(app, PrivilegeType.READ_RULE); if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app cannot be null or empty"); } @@ -115,7 +127,10 @@ public class ParamFlowRuleController { } @PostMapping("/rule") - public Result apiAddParamFlowRule(@RequestBody ParamFlowRuleEntity entity) { + public Result apiAddParamFlowRule(HttpServletRequest request, + @RequestBody ParamFlowRuleEntity entity) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE); Result checkResult = checkEntityInternal(entity); if (checkResult != null) { return checkResult; @@ -177,7 +192,10 @@ public class ParamFlowRuleController { } @PutMapping("/rule/{id}") - public Result apiUpdateParamFlowRule(@PathVariable("id") Long id, @RequestBody ParamFlowRuleEntity entity) { + public Result apiUpdateParamFlowRule(HttpServletRequest request, + @PathVariable("id") Long id, + @RequestBody ParamFlowRuleEntity entity) { + AuthUser authUser = authService.getAuthUser(request); if (id == null || id <= 0) { return Result.ofFail(-1, "Invalid id"); } @@ -185,6 +203,7 @@ public class ParamFlowRuleController { if (oldEntity == null) { return Result.ofFail(-1, "id " + id + " does not exist"); } + authUser.authTarget(oldEntity.getApp(), PrivilegeType.WRITE_RULE); Result checkResult = checkEntityInternal(entity); if (checkResult != null) { return checkResult; @@ -214,7 +233,8 @@ public class ParamFlowRuleController { } @DeleteMapping("/rule/{id}") - public Result apiDeleteRule(@PathVariable("id") Long id) { + public Result apiDeleteRule(HttpServletRequest request, @PathVariable("id") Long id) { + AuthUser authUser = authService.getAuthUser(request); if (id == null) { return Result.ofFail(-1, "id cannot be null"); } @@ -222,6 +242,7 @@ public class ParamFlowRuleController { if (oldEntity == null) { return Result.ofSuccess(null); } + authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE); try { repository.delete(id); publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get(); @@ -245,7 +266,8 @@ public class ParamFlowRuleController { } private Result unsupportedVersion() { - return Result.ofFail(4041, "Sentinel client not supported for parameter flow control (unsupported version or dependency absent)"); + return Result.ofFail(4041, + "Sentinel client not supported for parameter flow control (unsupported version or dependency absent)"); } private final SentinelVersion version020 = new SentinelVersion().setMinorVersion(2); diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/SystemController.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/SystemController.java index f496a74b..ad2ac2f4 100755 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/SystemController.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/SystemController.java @@ -18,6 +18,11 @@ package com.alibaba.csp.sentinel.dashboard.controller; import java.util.Date; import java.util.List; +import javax.servlet.http.HttpServletRequest; + +import com.alibaba.csp.sentinel.dashboard.service.AuthService; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity; @@ -25,6 +30,7 @@ import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemSystemRuleStore; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -45,10 +51,14 @@ public class SystemController { private InMemSystemRuleStore repository; @Autowired private SentinelApiClient sentinelApiClient; + @Autowired + private AuthService authService; @ResponseBody @RequestMapping("/rules.json") - Result> queryMachineRules(String app, String ip, Integer port) { + Result> queryMachineRules(HttpServletRequest request, String app, String ip, Integer port) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(app, PrivilegeType.READ_RULE); if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } @@ -80,7 +90,10 @@ public class SystemController { @ResponseBody @RequestMapping("/new.json") - Result add(String app, String ip, Integer port, Double avgLoad, Long avgRt, Long maxThread, Double qps) { + Result add(HttpServletRequest request, + String app, String ip, Integer port, Double avgLoad, Long avgRt, Long maxThread, Double qps) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(app, PrivilegeType.WRITE_RULE); if (StringUtil.isBlank(app)) { return Result.ofFail(-1, "app can't be null or empty"); } @@ -137,7 +150,9 @@ public class SystemController { @ResponseBody @RequestMapping("/save.json") - Result updateIfNotNull(Long id, String app, Double avgLoad, Long avgRt, Long maxThread, Double qps) { + Result updateIfNotNull(HttpServletRequest request, + Long id, String app, Double avgLoad, Long avgRt, Long maxThread, Double qps) { + AuthUser authUser = authService.getAuthUser(request); if (id == null) { return Result.ofFail(-1, "id can't be null"); } @@ -145,6 +160,7 @@ public class SystemController { if (entity == null) { return Result.ofFail(-1, "id " + id + " dose not exist"); } + authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE); if (StringUtil.isNotBlank(app)) { entity.setApp(app.trim()); } @@ -188,7 +204,8 @@ public class SystemController { @ResponseBody @RequestMapping("/delete.json") - Result delete(Long id) { + Result delete(HttpServletRequest request, Long id) { + AuthUser authUser = authService.getAuthUser(request); if (id == null) { return Result.ofFail(-1, "id can't be null"); } @@ -196,6 +213,7 @@ public class SystemController { if (oldEntity == null) { return Result.ofSuccess(null); } + authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE); try { repository.delete(id); } catch (Throwable throwable) { diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/v2/FlowControllerV2.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/v2/FlowControllerV2.java index 30ae0ba9..1b110811 100755 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/v2/FlowControllerV2.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/v2/FlowControllerV2.java @@ -18,6 +18,11 @@ package com.alibaba.csp.sentinel.dashboard.controller.v2; import java.util.Date; import java.util.List; +import javax.servlet.http.HttpServletRequest; + +import com.alibaba.csp.sentinel.dashboard.service.AuthService; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser; +import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; @@ -25,6 +30,7 @@ import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepository import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import com.alibaba.csp.sentinel.dashboard.domain.Result; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -61,8 +67,14 @@ public class FlowControllerV2 { @Qualifier("flowRuleDefaultPublisher") private DynamicRulePublisher> rulePublisher; + @Autowired + private AuthService authService; + @GetMapping("/rules") - public Result> apiQueryMachineRules(@RequestParam String app) { + public Result> apiQueryMachineRules(HttpServletRequest request, @RequestParam String app) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(app, PrivilegeType.READ_RULE); + if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } @@ -129,7 +141,10 @@ public class FlowControllerV2 { } @PostMapping("/rule") - public Result apiAddFlowRule(@RequestBody FlowRuleEntity entity) { + public Result apiAddFlowRule(HttpServletRequest request, @RequestBody FlowRuleEntity entity) { + AuthUser authUser = authService.getAuthUser(request); + authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE); + Result checkResult = checkEntityInternal(entity); if (checkResult != null) { return checkResult; @@ -151,7 +166,10 @@ public class FlowControllerV2 { } @PutMapping("/rule/{id}") - public Result apiUpdateFlowRule(@PathVariable("id") Long id, @RequestBody FlowRuleEntity entity) { + public Result apiUpdateFlowRule(HttpServletRequest request, + @PathVariable("id") Long id, + @RequestBody FlowRuleEntity entity) { + AuthUser authUser = authService.getAuthUser(request); if (id == null || id <= 0) { return Result.ofFail(-1, "Invalid id"); } @@ -162,6 +180,8 @@ public class FlowControllerV2 { if (entity == null) { return Result.ofFail(-1, "invalid body"); } + authUser.authTarget(oldEntity.getApp(), PrivilegeType.WRITE_RULE); + entity.setApp(oldEntity.getApp()); entity.setIp(oldEntity.getIp()); entity.setPort(oldEntity.getPort()); @@ -188,7 +208,8 @@ public class FlowControllerV2 { } @DeleteMapping("/rule/{id}") - public Result apiDeleteRule(@PathVariable("id") Long id) { + public Result apiDeleteRule(HttpServletRequest request, @PathVariable("id") Long id) { + AuthUser authUser = authService.getAuthUser(request); if (id == null || id <= 0) { return Result.ofFail(-1, "Invalid id"); } @@ -196,6 +217,7 @@ public class FlowControllerV2 { if (oldEntity == null) { return Result.ofSuccess(null); } + authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE); try { repository.delete(id); publishRules(oldEntity.getApp()); diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/service/AuthService.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/service/AuthService.java new file mode 100644 index 00000000..3a6c1e02 --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/service/AuthService.java @@ -0,0 +1,111 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed 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 com.alibaba.csp.sentinel.dashboard.service; + +/** + * Interface about authentication and authorization + * + * @author Carpenter Lee + */ +public interface AuthService { + /** + * Get the authentication user. + * + * @param request the request contains the user information + * @return the auth user represent the current user, when the user is illegal, a null value will return. + */ + AuthUser getAuthUser(R request); + + /** + * privilege type. + */ + enum PrivilegeType { + /** + * read rule + */ + READ_RULE, + /** + * create or modify rule + */ + WRITE_RULE, + /** + * delete rule + */ + DELETE_RULE, + /** + * read metrics + */ + READ_METRIC, + /** + * add machine + */ + ADD_MACHINE, + /** + * equals all privileges above + */ + ALL + } + + /** + * entity represents the current user + */ + interface AuthUser { + /** + * query whether current user has the specific privilege to the target, the target + * may be an app name or an ip address, or other destination. + *

+ * This method will use return value to represent whether user has the specific + * privileges to the target, but to throw a RuntimeException to represent no auth + * is also a good way. + *

+ * + * @param target the target to check + * @param privilegeType the privilege type to check + * @return if current user has the specific privileges to the target, return true, + * otherwise return false. + */ + boolean authTarget(String target, PrivilegeType privilegeType); + + /** + * check whether current user is super user + * + * @return if current user is super user return true, else return false. + */ + boolean isSuperUser(); + + /** + * get current user's nick name. + * + * @return current user's nick name. + */ + String getNickName(); + + /** + * get current user's login name. + * + * @return current user's login name. + */ + String getLoginName(); + + /** + * get current user's employ id. + * + * @return current user's employ id. + */ + String getEmpId(); + + } +} diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/service/FakeAuthServiceImpl.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/service/FakeAuthServiceImpl.java new file mode 100644 index 00000000..6c1352f1 --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/service/FakeAuthServiceImpl.java @@ -0,0 +1,64 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed 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 com.alibaba.csp.sentinel.dashboard.service; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Component; + +/** + * A fake AuthService implementation, which will pass all user auth checking. + * + * @author Carpenter Lee + */ +@Component +public class FakeAuthServiceImpl implements AuthService { + @Override + public AuthUser getAuthUser(HttpServletRequest request) { + + return new AuthUserImpl(); + } + + static final class AuthUserImpl implements AuthUser { + + @Override + public boolean authTarget(String target, PrivilegeType privilegeType) { + // fake implementation, always return true + return true; + } + + @Override + public boolean isSuperUser() { + // fake implementation, always return true + return true; + } + + @Override + public String getNickName() { + return "FAKE_NICK_NAME"; + } + + @Override + public String getLoginName() { + return "FAKE_LOGIN_NAME"; + } + + @Override + public String getEmpId() { + return "FAKE_EMP_ID"; + } + } +}