This is an automated email from the ASF dual-hosted git repository.
benjobs pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampark.git
The following commit(s) were added to refs/heads/dev by this push:
new a9e778b80 [Improve] Add more constraints the user permission (#2634)
a9e778b80 is described below
commit a9e778b80b1d7e757da11530061b399723d3a012
Author: zhoulii <[email protected]>
AuthorDate: Sun Apr 16 17:54:25 2023 +0800
[Improve] Add more constraints the user permission (#2634)
Co-authored-by: zhoulii <[email protected]>
---
.../console/core/annotation/CheckApp.java | 29 ++++++
.../console/core/annotation/CheckTeam.java | 29 ++++++
.../console/core/annotation/CheckUser.java | 29 ++++++
.../console/core/aspect/StreamParkAspect.java | 108 +++++++++++++++++++++
.../ApplicationBuildPipelineController.java | 2 +
.../core/controller/ApplicationController.java | 13 +++
.../system/controller/MemberController.java | 4 +
.../console/system/controller/UserController.java | 2 +
8 files changed, 216 insertions(+)
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/CheckApp.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/CheckApp.java
new file mode 100644
index 000000000..ae683b6aa
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/CheckApp.java
@@ -0,0 +1,29 @@
+/*
+ * 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.streampark.console.core.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CheckApp {
+ String value() default "";
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/CheckTeam.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/CheckTeam.java
new file mode 100644
index 000000000..7c69b6046
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/CheckTeam.java
@@ -0,0 +1,29 @@
+/*
+ * 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.streampark.console.core.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CheckTeam {
+ String value() default "";
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/CheckUser.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/CheckUser.java
new file mode 100644
index 000000000..b3dd6dce7
--- /dev/null
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/annotation/CheckUser.java
@@ -0,0 +1,29 @@
+/*
+ * 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.streampark.console.core.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CheckUser {
+ String value() default "";
+}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/StreamParkAspect.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/StreamParkAspect.java
index d6dbc5676..ce06b9009 100644
---
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/StreamParkAspect.java
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/aspect/StreamParkAspect.java
@@ -22,9 +22,19 @@ package org.apache.streampark.console.core.aspect;
import org.apache.streampark.console.base.domain.RestResponse;
import org.apache.streampark.console.base.exception.ApiAlertException;
import org.apache.streampark.console.core.annotation.ApiAccess;
+import org.apache.streampark.console.core.annotation.CheckApp;
+import org.apache.streampark.console.core.annotation.CheckTeam;
+import org.apache.streampark.console.core.annotation.CheckUser;
+import org.apache.streampark.console.core.entity.Application;
+import org.apache.streampark.console.core.enums.UserType;
+import org.apache.streampark.console.core.service.ApplicationService;
+import org.apache.streampark.console.core.service.CommonService;
import org.apache.streampark.console.core.task.FlinkRESTAPIWatcher;
import org.apache.streampark.console.system.entity.AccessToken;
+import org.apache.streampark.console.system.entity.User;
+import org.apache.streampark.console.system.service.MemberService;
+import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
@@ -34,6 +44,11 @@ import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.Expression;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.util.Objects;
@@ -44,6 +59,9 @@ import java.util.Objects;
public class StreamParkAspect {
@Autowired private FlinkRESTAPIWatcher flinkRESTAPIWatcher;
+ @Autowired private CommonService commonService;
+ @Autowired private MemberService memberService;
+ @Autowired private ApplicationService applicationService;
@Pointcut(
"execution(public"
@@ -78,4 +96,94 @@ public class StreamParkAspect {
flinkRESTAPIWatcher.init();
return target;
}
+
+
@Pointcut("@annotation(org.apache.streampark.console.core.annotation.CheckUser)")
+ public void checkUser() {}
+
+ @Around("checkUser()")
+ public RestResponse checkUser(ProceedingJoinPoint joinPoint) throws
Throwable {
+ MethodSignature methodSignature = (MethodSignature)
joinPoint.getSignature();
+ CheckUser checkUser =
methodSignature.getMethod().getAnnotation(CheckUser.class);
+ String spELString = checkUser.value();
+
+ Long paramUserId = getId(joinPoint, methodSignature, spELString);
+ User currentUser = commonService.getCurrentUser();
+ if (currentUser == null
+ || (currentUser.getUserType() != UserType.ADMIN
+ && !currentUser.getUserId().equals(paramUserId))) {
+ throw new ApiAlertException(
+ "Permission denied, only ADMIN user or user himself can access this
permission");
+ }
+
+ return (RestResponse) joinPoint.proceed();
+ }
+
+
@Pointcut("@annotation(org.apache.streampark.console.core.annotation.CheckTeam)")
+ public void checkTeam() {}
+
+ @Around("checkTeam()")
+ public RestResponse checkTeam(ProceedingJoinPoint joinPoint) throws
Throwable {
+ MethodSignature methodSignature = (MethodSignature)
joinPoint.getSignature();
+ CheckTeam checkTeam =
methodSignature.getMethod().getAnnotation(CheckTeam.class);
+ String spELString = checkTeam.value();
+
+ Long paramTeamId = getId(joinPoint, methodSignature, spELString);
+ User currentUser = commonService.getCurrentUser();
+ if (currentUser == null
+ || (currentUser.getUserType() != UserType.ADMIN
+ && memberService.findByUserName(paramTeamId,
currentUser.getUsername()) == null)) {
+ throw new ApiAlertException(
+ "Permission denied, only ADMIN user or user belongs to this team can
access this permission");
+ }
+
+ return (RestResponse) joinPoint.proceed();
+ }
+
+
@Pointcut("@annotation(org.apache.streampark.console.core.annotation.CheckApp)")
+ public void checkApp() {}
+
+ @Around("checkApp()")
+ public RestResponse checkApp(ProceedingJoinPoint joinPoint) throws Throwable
{
+ MethodSignature methodSignature = (MethodSignature)
joinPoint.getSignature();
+ CheckApp checkApp =
methodSignature.getMethod().getAnnotation(CheckApp.class);
+ String spELString = checkApp.value();
+
+ Long paramAppId = getId(joinPoint, methodSignature, spELString);
+ Application app = applicationService.getById(paramAppId);
+ User currentUser = commonService.getCurrentUser();
+ if (currentUser == null
+ || (app != null
+ && currentUser.getUserType() != UserType.ADMIN
+ && memberService.findByUserName(app.getTeamId(),
currentUser.getUsername()) == null)) {
+ throw new ApiAlertException(
+ "Permission denied, only ADMIN user or user belongs to this team can
access this permission");
+ }
+
+ return (RestResponse) joinPoint.proceed();
+ }
+
+ private Long getId(
+ ProceedingJoinPoint joinPoint, MethodSignature methodSignature, String
spELString) {
+ SpelExpressionParser parser = new SpelExpressionParser();
+ Expression expression = parser.parseExpression(spELString);
+ EvaluationContext context = new StandardEvaluationContext();
+ Object[] args = joinPoint.getArgs();
+ DefaultParameterNameDiscoverer discoverer = new
DefaultParameterNameDiscoverer();
+ String[] parameterNames =
discoverer.getParameterNames(methodSignature.getMethod());
+ for (int i = 0; i < parameterNames.length; i++) {
+ context.setVariable(parameterNames[i], args[i]);
+ }
+ Object value = expression.getValue(context);
+
+ if (value == null || StringUtils.isBlank(value.toString())) {
+ return null;
+ }
+
+ try {
+ return Long.parseLong(value.toString());
+ } catch (NumberFormatException e) {
+ throw new ApiAlertException(
+ "Wrong use of annotation on method " + methodSignature.getName(), e);
+ }
+ }
}
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationBuildPipelineController.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationBuildPipelineController.java
index 69ca3b28a..1d4927b61 100644
---
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationBuildPipelineController.java
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationBuildPipelineController.java
@@ -21,6 +21,7 @@ import
org.apache.streampark.console.base.domain.ApiDocConstant;
import org.apache.streampark.console.base.domain.RestResponse;
import org.apache.streampark.console.base.exception.ApiAlertException;
import org.apache.streampark.console.core.annotation.ApiAccess;
+import org.apache.streampark.console.core.annotation.CheckApp;
import org.apache.streampark.console.core.bean.AppBuildDockerResolvedDetail;
import org.apache.streampark.console.core.entity.AppBuildPipeline;
import org.apache.streampark.console.core.entity.Application;
@@ -90,6 +91,7 @@ public class ApplicationBuildPipelineController {
schema = @Schema(defaultValue = "false", implementation =
boolean.class))
})
@ApiAccess
+ @CheckApp("#appId")
@PostMapping(value = "build")
@RequiresPermissions("app:create")
public RestResponse buildApplication(Long appId, boolean forceBuild) {
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
index 73ca135d1..0639fb392 100644
---
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/core/controller/ApplicationController.java
@@ -25,6 +25,8 @@ import org.apache.streampark.console.base.domain.RestResponse;
import org.apache.streampark.console.base.exception.InternalException;
import org.apache.streampark.console.core.annotation.ApiAccess;
import org.apache.streampark.console.core.annotation.AppUpdated;
+import org.apache.streampark.console.core.annotation.CheckApp;
+import org.apache.streampark.console.core.annotation.CheckTeam;
import org.apache.streampark.console.core.bean.AppControl;
import org.apache.streampark.console.core.entity.Application;
import org.apache.streampark.console.core.entity.ApplicationBackUp;
@@ -89,6 +91,7 @@ public class ApplicationController {
@Operation(summary = "Create application")
@ApiAccess
+ @CheckTeam("#app.teamId")
@PostMapping("create")
@RequiresPermissions("app:create")
public RestResponse create(Application app) throws IOException {
@@ -114,6 +117,7 @@ public class ApplicationController {
@Parameter(name = "args", description = "new application args", in =
ParameterIn.QUERY)
})
@ApiAccess
+ @CheckApp("#app.id")
@PostMapping(value = "copy")
@RequiresPermissions("app:copy")
public RestResponse copy(@Parameter(hidden = true) Application app) throws
IOException {
@@ -127,6 +131,7 @@ public class ApplicationController {
@Operation(summary = "Update application")
@AppUpdated
+ @CheckApp("#app.id")
@PostMapping("update")
@RequiresPermissions("app:update")
public RestResponse update(Application app) {
@@ -189,6 +194,7 @@ public class ApplicationController {
@Operation(summary = "Revoke application")
@AppUpdated
+ @CheckApp("#app.id")
@PostMapping("revoke")
@RequiresPermissions("app:release")
public RestResponse revoke(Application app) {
@@ -227,6 +233,7 @@ public class ApplicationController {
schema = @Schema(implementation = boolean.class, defaultValue =
"false"))
})
@ApiAccess
+ @CheckApp("#app.id")
@PostMapping(value = "start")
@RequiresPermissions("app:start")
public RestResponse start(@Parameter(hidden = true) Application app) {
@@ -271,6 +278,7 @@ public class ApplicationController {
example = "false",
schema = @Schema(implementation = boolean.class, defaultValue =
"false"))
})
+ @CheckApp("#app.id")
@PostMapping(value = "cancel")
@RequiresPermissions("app:cancel")
public RestResponse cancel(@Parameter(hidden = true) Application app) throws
Exception {
@@ -281,6 +289,7 @@ public class ApplicationController {
@Operation(summary = "Clean application")
@AppUpdated
@ApiAccess
+ @CheckApp("#app.id")
@PostMapping("clean")
@RequiresPermissions("app:clean")
public RestResponse clean(Application app) {
@@ -290,6 +299,7 @@ public class ApplicationController {
/** force stop(stop normal start or in progress) */
@Operation(summary = "Force stop application")
+ @CheckApp("#app.id")
@PostMapping("forcedStop")
@RequiresPermissions("app:cancel")
public RestResponse forcedStop(Application app) {
@@ -346,6 +356,7 @@ public class ApplicationController {
}
@Operation(summary = "Delete application operation log")
+ @CheckApp("#applicationLog.appId")
@PostMapping("deleteOperationLog")
@RequiresPermissions("app:delete")
public RestResponse deleteOperationLog(ApplicationLog applicationLog) {
@@ -354,6 +365,7 @@ public class ApplicationController {
}
@Operation(summary = "Delete application")
+ @CheckApp("#app.id")
@PostMapping("delete")
@RequiresPermissions("app:delete")
public RestResponse delete(Application app) throws InternalException {
@@ -362,6 +374,7 @@ public class ApplicationController {
}
@Operation(summary = "Backup application when deleted")
+ @CheckApp("#backUp.appId")
@PostMapping("deletebak")
public RestResponse deleteBak(ApplicationBackUp backUp) throws
InternalException {
Boolean deleted = backUpService.delete(backUp.getId());
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MemberController.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MemberController.java
index c92df03f8..462c38431 100644
---
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MemberController.java
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/MemberController.java
@@ -19,6 +19,7 @@ package org.apache.streampark.console.system.controller;
import org.apache.streampark.console.base.domain.RestRequest;
import org.apache.streampark.console.base.domain.RestResponse;
+import org.apache.streampark.console.core.annotation.CheckTeam;
import org.apache.streampark.console.system.entity.Member;
import org.apache.streampark.console.system.entity.Team;
import org.apache.streampark.console.system.entity.User;
@@ -81,6 +82,7 @@ public class MemberController {
}
@Operation(summary = "Create member")
+ @CheckTeam("#member.teamId")
@PostMapping("post")
@RequiresPermissions("member:add")
public RestResponse create(@Valid Member member) {
@@ -89,6 +91,7 @@ public class MemberController {
}
@Operation(summary = "Delete member")
+ @CheckTeam("#member.teamId")
@DeleteMapping("delete")
@RequiresPermissions("member:delete")
public RestResponse delete(Member member) {
@@ -97,6 +100,7 @@ public class MemberController {
}
@Operation(summary = "Update member")
+ @CheckTeam("#member.teamId")
@PutMapping("update")
@RequiresPermissions("member:update")
public RestResponse update(Member member) {
diff --git
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
index 202c513b7..0985c3d0f 100644
---
a/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
+++
b/streampark-console/streampark-console-service/src/main/java/org/apache/streampark/console/system/controller/UserController.java
@@ -21,6 +21,7 @@ import org.apache.streampark.console.base.domain.ResponseCode;
import org.apache.streampark.console.base.domain.RestRequest;
import org.apache.streampark.console.base.domain.RestResponse;
import org.apache.streampark.console.base.exception.ApiAlertException;
+import org.apache.streampark.console.core.annotation.CheckUser;
import org.apache.streampark.console.core.enums.LoginType;
import org.apache.streampark.console.core.enums.UserType;
import org.apache.streampark.console.core.service.CommonService;
@@ -114,6 +115,7 @@ public class UserController {
}
@Operation(summary = "Update password")
+ @CheckUser("#user.userId")
@PutMapping("password")
public RestResponse updatePassword(User user) throws Exception {
userService.updatePassword(user);