From 44dacf653ce1c7265121cd94604cf5ffa771863b Mon Sep 17 00:00:00 2001 From: shangeyao Date: Sat, 27 Jun 2026 16:36:33 +0800 Subject: [PATCH] [Console] Add team-level permission checks for Spark applications Extend PermissionAspect to validate Spark app ownership and add @Permission annotations on SparkApplicationController endpoints. Generated-by: Cursor Co-authored-by: Cursor --- .../console/core/aspect/PermissionAspect.java | 25 +++++++++++++++---- .../SparkApplicationController.java | 25 +++++++++++++++++-- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/PermissionAspect.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/PermissionAspect.java index 698e023d1f..9db605eb06 100644 --- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/PermissionAspect.java +++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/PermissionAspect.java @@ -21,8 +21,10 @@ import org.apache.streampark.console.base.exception.ApiAlertException; import org.apache.streampark.console.core.annotation.Permission; import org.apache.streampark.console.core.entity.FlinkApplication; +import org.apache.streampark.console.core.entity.SparkApplication; import org.apache.streampark.console.core.enums.UserTypeEnum; import org.apache.streampark.console.core.service.application.FlinkApplicationManageService; +import org.apache.streampark.console.core.service.application.SparkApplicationManageService; import org.apache.streampark.console.core.util.ServiceHelper; import org.apache.streampark.console.system.entity.Member; import org.apache.streampark.console.system.entity.User; @@ -55,6 +57,9 @@ public class PermissionAspect { @Autowired private FlinkApplicationManageService applicationManageService; + @Autowired + private SparkApplicationManageService sparkApplicationManageService; + @Pointcut("@annotation(org.apache.streampark.console.core.annotation.Permission)") public void permissionPointcut() { } @@ -89,12 +94,13 @@ public RestResponse permissionAction(ProceedingJoinPoint joinPoint) throws Throw Long appId = getId(joinPoint, methodSignature, permission.app()); if (appId != null) { FlinkApplication app = applicationManageService.getById(appId); - ApiAlertException.throwIfTrue(app == null, "Invalid operation, application is null"); - if (!currentUser.getUserId().equals(app.getUserId())) { - Member member = memberService.getByTeamIdUserName(app.getTeamId(), currentUser.getUsername()); + if (app != null) { + checkAppTeamAccess(currentUser, app.getUserId(), app.getTeamId()); + } else { + SparkApplication sparkApp = sparkApplicationManageService.getById(appId); ApiAlertException.throwIfTrue( - member == null, - "Permission denied, this job not created by the current user, And the job cannot be found in the current user's team."); + sparkApp == null, "Invalid operation, application is null"); + checkAppTeamAccess(currentUser, sparkApp.getUserId(), sparkApp.getTeamId()); } } } @@ -102,6 +108,15 @@ public RestResponse permissionAction(ProceedingJoinPoint joinPoint) throws Throw return (RestResponse) joinPoint.proceed(); } + private void checkAppTeamAccess(User currentUser, Long ownerId, Long teamId) { + if (!currentUser.getUserId().equals(ownerId)) { + Member member = memberService.getByTeamIdUserName(teamId, currentUser.getUsername()); + ApiAlertException.throwIfTrue( + member == null, + "Permission denied, this job not created by the current user, And the job cannot be found in the current user's team."); + } + } + private Long getId(ProceedingJoinPoint joinPoint, MethodSignature methodSignature, String expr) { if (StringUtils.isEmpty(expr)) { return null; diff --git a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkApplicationController.java b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkApplicationController.java index 0d9e87d4a4..be1f8b7ba3 100644 --- a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkApplicationController.java +++ b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/SparkApplicationController.java @@ -23,6 +23,7 @@ import org.apache.streampark.console.base.domain.RestResponse; import org.apache.streampark.console.base.exception.InternalException; import org.apache.streampark.console.core.annotation.AppChangeEvent; +import org.apache.streampark.console.core.annotation.Permission; import org.apache.streampark.console.core.entity.ApplicationLog; import org.apache.streampark.console.core.entity.FlinkApplicationBackup; import org.apache.streampark.console.core.entity.SparkApplication; @@ -75,12 +76,14 @@ public class SparkApplicationController { private ResourceService resourceService; @PostMapping("get") + @Permission(app = "#app.id") @RequiresPermissions("app:detail") public RestResponse get(SparkApplication app) { SparkApplication application = applicationManageService.getApp(app.getId()); return RestResponse.success(application); } + @Permission(team = "#app.teamId") @PostMapping("create") @RequiresPermissions("app:create") public RestResponse create(SparkApplication app) throws IOException { @@ -88,6 +91,7 @@ public RestResponse create(SparkApplication app) throws IOException { return RestResponse.success(saved); } + @Permission(app = "#app.id", team = "#app.teamId") @PostMapping("copy") @RequiresPermissions("app:copy") public RestResponse copy(SparkApplication app) throws IOException { @@ -96,6 +100,7 @@ public RestResponse copy(SparkApplication app) throws IOException { } @AppChangeEvent + @Permission(app = "#app.id") @PostMapping("update") @RequiresPermissions("app:update") public RestResponse update(SparkApplication app) { @@ -104,12 +109,14 @@ public RestResponse update(SparkApplication app) { } @PostMapping("dashboard") + @Permission(team = "#teamId") public RestResponse dashboard(Long teamId) { Map dashboardMap = applicationInfoService.getDashboardDataMap(teamId); return RestResponse.success(dashboardMap); } @PostMapping("list") + @Permission(team = "#app.teamId") @RequiresPermissions("app:view") public RestResponse list(SparkApplication app, RestRequest request) { IPage applicationList = applicationManageService.page(app, request); @@ -118,6 +125,7 @@ public RestResponse list(SparkApplication app, RestRequest request) { @AppChangeEvent @PostMapping("mapping") + @Permission(app = "#app.id") @RequiresPermissions("app:mapping") public RestResponse mapping(SparkApplication app) { boolean flag = applicationManageService.mapping(app); @@ -125,6 +133,7 @@ public RestResponse mapping(SparkApplication app) { } @AppChangeEvent + @Permission(app = "#app.id") @PostMapping("revoke") @RequiresPermissions("app:release") public RestResponse revoke(SparkApplication app) { @@ -132,6 +141,7 @@ public RestResponse revoke(SparkApplication app) { return RestResponse.success(); } + @Permission(app = "#app.id", team = "#app.teamId") @PostMapping("check/start") @RequiresPermissions("app:start") public RestResponse checkStart(SparkApplication app) { @@ -139,6 +149,7 @@ public RestResponse checkStart(SparkApplication app) { return RestResponse.success(stateEnum.get()); } + @Permission(app = "#app.id", team = "#app.teamId") @PostMapping("start") @RequiresPermissions("app:start") public RestResponse start(SparkApplication app) { @@ -150,6 +161,7 @@ public RestResponse start(SparkApplication app) { } } + @Permission(app = "#app.id", team = "#app.teamId") @PostMapping("cancel") @RequiresPermissions("app:cancel") public RestResponse cancel(SparkApplication app) throws Exception { @@ -158,6 +170,7 @@ public RestResponse cancel(SparkApplication app) throws Exception { } @AppChangeEvent + @Permission(app = "#app.id") @PostMapping("clean") @RequiresPermissions("app:clean") public RestResponse clean(SparkApplication app) { @@ -165,6 +178,7 @@ public RestResponse clean(SparkApplication app) { return RestResponse.success(true); } + @Permission(app = "#app.id") @PostMapping("forcedStop") @RequiresPermissions("app:cancel") public RestResponse forcedStop(SparkApplication app) { @@ -178,12 +192,14 @@ public RestResponse yarn() { } @PostMapping("name") + @Permission(app = "#app.id", team = "#app.teamId") public RestResponse yarnName(SparkApplication app) { String yarnName = applicationInfoService.getYarnName(app.getConfig()); return RestResponse.success(yarnName); } @PostMapping("check/name") + @Permission(app = "#app.id", team = "#app.teamId") public RestResponse checkName(SparkApplication app) { AppExistsStateEnum exists = applicationInfoService.checkExists(app); return RestResponse.success(exists.get()); @@ -196,24 +212,28 @@ public RestResponse readConf(SparkApplication app) throws IOException { } @PostMapping("backups") + @Permission(app = "#backUp.appId", team = "#backUp.teamId") public RestResponse backups(FlinkApplicationBackup backUp, RestRequest request) { IPage backups = backUpService.getPage(backUp, request); return RestResponse.success(backups); } @PostMapping("opt_log") + @Permission(app = "#applicationLog.appId", team = "#applicationLog.teamId") public RestResponse optionlog(ApplicationLog applicationLog, RestRequest request) { IPage applicationList = applicationLogService.getPage(applicationLog, request); return RestResponse.success(applicationList); } + @Permission(app = "#applicationLog.appId", team = "#applicationLog.teamId") @PostMapping("delete/opt_log") @RequiresPermissions("app:delete") - public RestResponse deleteOperationLog(Long id) { - Boolean deleted = applicationLogService.removeById(id); + public RestResponse deleteOperationLog(ApplicationLog applicationLog) { + Boolean deleted = applicationLogService.delete(applicationLog); return RestResponse.success(deleted); } + @Permission(app = "#app.id", team = "#app.teamId") @PostMapping("delete") @RequiresPermissions("app:delete") public RestResponse delete(SparkApplication app) throws InternalException { @@ -221,6 +241,7 @@ public RestResponse delete(SparkApplication app) throws InternalException { return RestResponse.success(deleted); } + @Permission(app = "#backUp.appId") @PostMapping("delete/bak") public RestResponse deleteBak(FlinkApplicationBackup backUp) throws InternalException { Boolean deleted = backUpService.removeById(backUp.getId());