This is an automated email from the ASF dual-hosted git repository.
arshad pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/seatunnel-web.git
The following commit(s) were added to refs/heads/main by this push:
new b343fdf7 [Feature] Add Support for Authorization (#285)
b343fdf7 is described below
commit b343fdf742df2954b06ffd53ed3dc93b7a470c7e
Author: Mohammad Arshad <[email protected]>
AuthorDate: Fri Apr 11 15:11:25 2025 +0530
[Feature] Add Support for Authorization (#285)
---
pom.xml | 1 +
seatunnel-server/seatunnel-app/pom.xml | 5 +
.../src/main/bin/seatunnel-backend-daemon.sh | 9 +-
.../seatunnel/app/adapter/SeatunnelWebAdapter.java | 3 +
.../app/controller/JobConfigController.java | 4 +-
.../seatunnel/app/dal/mapper/JobLineMapper.java | 2 -
.../seatunnel/app/dal/mapper/UserMapper.java | 2 +
.../app/interceptor/AuthenticationInterceptor.java | 8 +-
.../app/permission/ISeatunnelPermissonService.java | 60 --
.../SeatunnelAccessControllerConfig.java | 45 ++
.../SeatunnelAccessControllerDefaultImpl.java | 45 ++
.../permission/SeatunnelPermissionServiceImpl.java | 61 --
.../apache/seatunnel/app/security/UserContext.java | 3 +-
.../seatunnel/app/security/UserContextHolder.java | 6 +
.../seatunnel/app/service/IJobConfigService.java | 6 +-
.../app/service/ISeatunnelBaseService.java | 19 +-
.../seatunnel/app/service/WorkspaceService.java | 2 -
.../app/service/impl/DatasourceServiceImpl.java | 109 ++-
.../app/service/impl/JobConfigServiceImpl.java | 26 +-
.../app/service/impl/JobDefinitionServiceImpl.java | 53 +-
.../app/service/impl/JobInstanceServiceImpl.java | 11 +-
.../seatunnel/app/service/impl/JobServiceImpl.java | 20 +-
.../app/service/impl/SeatunnelBaseServiceImpl.java | 38 +-
.../app/service/impl/TaskInstanceServiceImpl.java | 26 +-
.../app/service/impl/UserServiceImpl.java | 41 +-
.../app/service/impl/VirtualTableServiceImpl.java | 52 +-
.../app/service/impl/WorkspaceServiceImpl.java | 48 +-
.../app/utils/GlobalExceptionHandler.java | 6 +
.../src/main/resources/application.yml | 1 +
.../server/common/SeatunnelErrorEnum.java | 3 +-
seatunnel-web-common/pom.xml | 25 +
.../common/access/AccessDeniedException.java | 27 +-
.../apache/seatunnel/common/access/AccessInfo.java | 18 +-
.../apache/seatunnel/common/access/AccessType.java | 22 +-
.../seatunnel/common/access/ResourceType.java | 23 +-
.../common/access/SeatunnelAccessController.java | 30 +-
.../app/common/AccessControllerTestingImp.java | 105 +++
.../app/common/ResourcePermissionData.java | 14 +-
.../controller/JobDefinitionControllerWrapper.java | 11 +
.../SeatunnelDatasourceControllerWrapper.java | 23 +
.../app/test/SeatunnelAccessControllerTest.java | 790 +++++++++++++++++++++
.../src/test/resources/application.yml | 1 +
42 files changed, 1420 insertions(+), 384 deletions(-)
diff --git a/pom.xml b/pom.xml
index 852f2f30..7be25220 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,6 +33,7 @@
<description>Production ready big data processing product based on Apache
Spark and Apache Flink.</description>
<modules>
+ <module>seatunnel-web-common</module>
<module>seatunnel-server</module>
<module>seatunnel-datasource</module>
<module>seatunnel-web-dist</module>
diff --git a/seatunnel-server/seatunnel-app/pom.xml
b/seatunnel-server/seatunnel-app/pom.xml
index 98d93670..f6ab19e4 100644
--- a/seatunnel-server/seatunnel-app/pom.xml
+++ b/seatunnel-server/seatunnel-app/pom.xml
@@ -45,6 +45,11 @@
<groupId>org.apache.seatunnel</groupId>
<artifactId>seatunnel-common</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.seatunnel</groupId>
+ <artifactId>seatunnel-web-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.seatunnel</groupId>
<artifactId>seatunnel-api</artifactId>
diff --git
a/seatunnel-server/seatunnel-app/src/main/bin/seatunnel-backend-daemon.sh
b/seatunnel-server/seatunnel-app/src/main/bin/seatunnel-backend-daemon.sh
index 98506c8d..582fcb46 100755
--- a/seatunnel-server/seatunnel-app/src/main/bin/seatunnel-backend-daemon.sh
+++ b/seatunnel-server/seatunnel-app/src/main/bin/seatunnel-backend-daemon.sh
@@ -54,9 +54,14 @@ start() {
fi
echo "$WORKDIR"
+ CLASSPATH="$WORKDIR/../conf:$WORKDIR/../libs/*:$WORKDIR/../datasource/*"
+ if [ -d "$WORKDIR/../ranger-seatunnel-plugin" ]; then
+ CLASSPATH="$CLASSPATH:$WORKDIR/../ranger-seatunnel-plugin/lib/*.jar"
+
CLASSPATH="$CLASSPATH:$WORKDIR/../ranger-seatunnel-plugin/lib/ranger-seatunnel-plugin-impl/*"
+ fi
+
nohup $JAVA_HOME/bin/java $JAVA_OPTS \
- -cp "$WORKDIR/../conf":"$WORKDIR/../libs/*":"$WORKDIR/../datasource/*" \
- $SPRING_OPTS \
+ -cp "$CLASSPATH" $SPRING_OPTS \
org.apache.seatunnel.app.SeatunnelApplication >> "${LOGDIR}/seatunnel.out"
2>&1 &
echo "seatunnel-web started"
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/adapter/SeatunnelWebAdapter.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/adapter/SeatunnelWebAdapter.java
index a20f5a8f..0974e456 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/adapter/SeatunnelWebAdapter.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/adapter/SeatunnelWebAdapter.java
@@ -42,6 +42,8 @@ public class SeatunnelWebAdapter implements WebMvcConfigurer {
public static final String LOGIN_INTERCEPTOR_PATH_PATTERN = "/**/*";
public static final String LOGIN_PATH_PATTERN =
"/seatunnel/api/v1/user/login**";
public static final String REGISTER_PATH_PATTERN = "/users/register";
+ private static final String RESOURCE_NAME_PATH_PATTERN =
+ "/seatunnel/api/v1/resources/workspace";
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
@@ -74,6 +76,7 @@ public class SeatunnelWebAdapter implements WebMvcConfigurer {
.excludePathPatterns(
LOGIN_PATH_PATTERN,
REGISTER_PATH_PATTERN,
+ RESOURCE_NAME_PATH_PATTERN,
"/swagger-resources/**",
"/webjars/**",
"/v2/**",
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobConfigController.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobConfigController.java
index 2ec31541..cdce8f6e 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobConfigController.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/controller/JobConfigController.java
@@ -46,7 +46,7 @@ public class JobConfigController {
@ApiParam(value = "jobVersionId", required = true) @PathVariable
long jobVersionId,
@ApiParam(value = "jobConfig", required = true) @RequestBody
JobConfig jobConfig)
throws JsonProcessingException {
- jobConfigService.updateJobConfig(jobVersionId, jobConfig);
+ jobConfigService.updateJobConfig(jobVersionId, jobConfig, false);
return Result.success();
}
@@ -55,6 +55,6 @@ public class JobConfigController {
Result<JobConfigRes> getJobConfig(
@ApiParam(value = "jobVersionId", required = true) @PathVariable
long jobVersionId)
throws JsonProcessingException {
- return Result.success(jobConfigService.getJobConfig(jobVersionId));
+ return Result.success(jobConfigService.getJobConfig(jobVersionId,
false));
}
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/JobLineMapper.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/JobLineMapper.java
index 9317520a..479f2749 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/JobLineMapper.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/JobLineMapper.java
@@ -27,7 +27,5 @@ import java.util.List;
public interface JobLineMapper extends BaseMapper<JobLine> {
- void deleteLinesByVersionId(@Param("versionId") long jobVersionId);
-
void insertBatchLines(@Param("lines") List<JobLine> lines);
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/UserMapper.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/UserMapper.java
index 9648ecd9..ff8131bd 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/UserMapper.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/UserMapper.java
@@ -49,4 +49,6 @@ public interface UserMapper {
@Param("authProvider") String authProvider);
List<User> queryEnabledUsers();
+
+ List<String> queryUserNames(@Param("searchName") String searchName);
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/interceptor/AuthenticationInterceptor.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/interceptor/AuthenticationInterceptor.java
index 07ccf566..78ee6a85 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/interceptor/AuthenticationInterceptor.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/interceptor/AuthenticationInterceptor.java
@@ -23,6 +23,7 @@ import org.apache.seatunnel.app.dal.entity.User;
import org.apache.seatunnel.app.dal.entity.UserLoginLog;
import org.apache.seatunnel.app.security.JwtUtils;
import org.apache.seatunnel.app.security.UserContext;
+import org.apache.seatunnel.common.access.AccessInfo;
import org.apache.commons.lang3.StringUtils;
@@ -106,7 +107,12 @@ public class AuthenticationInterceptor implements
HandlerInterceptor {
UserContext userContext = new UserContext();
userContext.setUser(user);
userContext.setWorkspaceId(workspaceIdFromToken);
- userContext.setWorkspaceName((String) map.get("workspaceName"));
+
+ AccessInfo accessInfo = new AccessInfo();
+ accessInfo.setUsername(user.getUsername());
+ accessInfo.setWorkspaceName((String) map.get("workspaceName"));
+ userContext.setAccessInfo(accessInfo);
+
request.setAttribute(Constants.SESSION_USER_CONTEXT, userContext);
request.setAttribute("userId", userId);
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/ISeatunnelPermissonService.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/ISeatunnelPermissonService.java
deleted file mode 100644
index 11d1eae0..00000000
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/ISeatunnelPermissonService.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.seatunnel.app.permission;
-
-import java.util.List;
-
-public interface ISeatunnelPermissonService {
-
- /**
- * func permission check
- *
- * @param permissionKey permissionKey
- * @param userId userId
- */
- void funcPermissionCheck(String permissionKey, int userId);
-
- /**
- * func permission and resource permission check
- *
- * @param permissionKey permissionKey
- * @param resourceType resourceType
- * @param resourceCodes resourceCodes
- * @param userId userId
- */
- void funcAndResourcePermissionCheck(
- String permissionKey, String resourceType, List<Object>
resourceCodes, int userId);
-
- /**
- * resource post handle
- *
- * @param resourceType resourceType
- * @param resourceCodes resourceCodes
- * @param userId userId
- */
- void resourcePostHandle(String resourceType, List<Object> resourceCodes,
int userId);
-
- /**
- * available resource range
- *
- * @param resourceType resourceType
- * @param userId userId
- * @return list
- */
- List<Object> availableResourceRange(String resourceType, int userId);
-}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/SeatunnelAccessControllerConfig.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/SeatunnelAccessControllerConfig.java
new file mode 100644
index 00000000..61576a82
--- /dev/null
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/SeatunnelAccessControllerConfig.java
@@ -0,0 +1,45 @@
+/*
+ * 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.seatunnel.app.permission;
+
+import org.apache.seatunnel.common.access.SeatunnelAccessController;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SeatunnelAccessControllerConfig {
+
+ @Value(
+
"${seatunnel-web.access-controller-class:org.apache.seatunnel.app.permission.SeatunnelAccessControllerDefaultImpl
org.apache.seatunnel.app.permission.DefaultSeatunnelAccessController}")
+ private String accessControllerClassName;
+
+ @Bean
+ public SeatunnelAccessController seatunnelAccessController() {
+ try {
+ Class<?> clazz = Class.forName(accessControllerClassName);
+ return (SeatunnelAccessController)
clazz.getDeclaredConstructor().newInstance();
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Failed to create SeatunnelAccessController instance for
class: "
+ + accessControllerClassName,
+ e);
+ }
+ }
+}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/SeatunnelAccessControllerDefaultImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/SeatunnelAccessControllerDefaultImpl.java
new file mode 100644
index 00000000..262be786
--- /dev/null
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/SeatunnelAccessControllerDefaultImpl.java
@@ -0,0 +1,45 @@
+/*
+ * 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.seatunnel.app.permission;
+
+import org.apache.seatunnel.common.access.AccessInfo;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
+import org.apache.seatunnel.common.access.SeatunnelAccessController;
+
+public class SeatunnelAccessControllerDefaultImpl implements
SeatunnelAccessController {
+
+ @Override
+ public void authorizeAccess(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo) {
+ // Default implementation: Allow all access
+ // You can add your custom logic here
+ }
+
+ @Override
+ public boolean hasPermission(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo) {
+ return true;
+ }
+}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/SeatunnelPermissionServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/SeatunnelPermissionServiceImpl.java
deleted file mode 100644
index d97d2019..00000000
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/permission/SeatunnelPermissionServiceImpl.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.seatunnel.app.permission;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-
-@Component
-public class SeatunnelPermissionServiceImpl implements
ISeatunnelPermissonService {
-
- private static final Logger LOGGER =
- LoggerFactory.getLogger(SeatunnelPermissionServiceImpl.class);
-
- @Autowired private AvailableResourceRangeService
availableResourceRangeService;
-
- @Override
- public void funcPermissionCheck(String permissionKey, int userId) {
- // user id will be replaced by shiro in ws when user id == 0
- LOGGER.warn("func permission check in seatunnel");
- }
-
- @Override
- public void funcAndResourcePermissionCheck(
- String permissionKey, String sourceType, List<Object> sourceCodes,
int userId) {
- // user id will be replaced by shiro in ws when user id == 0
- LOGGER.warn("func and resource permission check in seatunnel");
- }
-
- @Override
- public void resourcePostHandle(String sourceType, List<Object>
sourceCodes, int userId) {
- // user id will be replaced by shiro in ws when user id == 0
- LOGGER.warn("resource post handle in seatunnel");
- }
-
- @Override
- public List<Object> availableResourceRange(String sourceType, int userId) {
- // user id will be replaced by shiro in ws when user id == 0
- LOGGER.warn("query available resource range in seatunnel");
- return
availableResourceRangeService.queryAvailableResourceRangeBySourceType(
- sourceType, userId);
- }
-}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
index 8897779a..7857b1fc 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
@@ -17,6 +17,7 @@
package org.apache.seatunnel.app.security;
import org.apache.seatunnel.app.dal.entity.User;
+import org.apache.seatunnel.common.access.AccessInfo;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -28,5 +29,5 @@ import lombok.NoArgsConstructor;
public class UserContext {
User user;
Long workspaceId;
- String workspaceName;
+ AccessInfo accessInfo;
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContextHolder.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContextHolder.java
index bd6eb5c9..e23bc2ee 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContextHolder.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContextHolder.java
@@ -17,6 +17,7 @@
package org.apache.seatunnel.app.security;
import org.apache.seatunnel.app.dal.entity.User;
+import org.apache.seatunnel.common.access.AccessInfo;
public class UserContextHolder {
private static final ThreadLocal<UserContext> userContextHolder = new
ThreadLocal<>();
@@ -30,6 +31,11 @@ public class UserContextHolder {
return userContext.getUser();
}
+ public static AccessInfo getAccessInfo() {
+ UserContext userContext = getUserContext();
+ return userContext.getAccessInfo();
+ }
+
public static UserContext getUserContext() {
UserContext userContext = userContextHolder.get();
if (userContext == null) {
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/IJobConfigService.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/IJobConfigService.java
index 23891174..ee238f8c 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/IJobConfigService.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/IJobConfigService.java
@@ -22,7 +22,9 @@ import
org.apache.seatunnel.app.domain.response.job.JobConfigRes;
import com.fasterxml.jackson.core.JsonProcessingException;
public interface IJobConfigService {
- JobConfigRes getJobConfig(long jobVersionIdId) throws
JsonProcessingException;
+ JobConfigRes getJobConfig(long jobVersionIdId, boolean isPermissionChecked)
+ throws JsonProcessingException;
- void updateJobConfig(long jobVersionId, JobConfig jobConfig) throws
JsonProcessingException;
+ void updateJobConfig(long jobVersionId, JobConfig jobConfig, boolean
isPermissionChecked)
+ throws JsonProcessingException;
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/ISeatunnelBaseService.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/ISeatunnelBaseService.java
index aa7f38fa..0668f900 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/ISeatunnelBaseService.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/ISeatunnelBaseService.java
@@ -17,16 +17,23 @@
package org.apache.seatunnel.app.service;
-import java.util.List;
+import org.apache.seatunnel.common.access.AccessInfo;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
public interface ISeatunnelBaseService {
void funcPermissionCheck(String permissionKey, int userId);
- void funcAndResourcePermissionCheck(
- String permissionKey, String resourceType, List resourceCodes, int
userId);
+ void permissionCheck(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo);
- void resourcePostHandle(String sourceType, List resourceCodes, int userId);
-
- List availableResourceRange(String resourceType, int userId);
+ boolean hasPermission(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo);
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/WorkspaceService.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/WorkspaceService.java
index 7b413f1a..b8f5b385 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/WorkspaceService.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/WorkspaceService.java
@@ -37,7 +37,5 @@ public interface WorkspaceService {
Workspace getDefaultWorkspace();
- Long getWorkspaceIdOrDefault(Long workspaceId);
-
Long getWorkspaceIdOrCurrent(String workspaceName);
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/DatasourceServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/DatasourceServiceImpl.java
index 2a0d790c..a55bcded 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/DatasourceServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/DatasourceServiceImpl.java
@@ -31,7 +31,7 @@ import
org.apache.seatunnel.app.domain.response.datasource.DatasourceRes;
import
org.apache.seatunnel.app.domain.response.datasource.VirtualTableFieldRes;
import org.apache.seatunnel.app.dynamicforms.FormStructure;
import
org.apache.seatunnel.app.permission.constants.SeatunnelFuncPermissionKeyConstant;
-import
org.apache.seatunnel.app.permission.enums.SeatunnelResourcePermissionModuleEnum;
+import org.apache.seatunnel.app.security.UserContextHolder;
import org.apache.seatunnel.app.service.IDatasourceService;
import org.apache.seatunnel.app.service.IJobDefinitionService;
import org.apache.seatunnel.app.service.ITableSchemaService;
@@ -39,6 +39,8 @@ import
org.apache.seatunnel.app.thirdparty.datasource.DataSourceClientFactory;
import
org.apache.seatunnel.app.thirdparty.framework.SeaTunnelOptionRuleWrapper;
import org.apache.seatunnel.app.utils.ConfigShadeUtil;
import org.apache.seatunnel.app.utils.ServletUtils;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
import org.apache.seatunnel.common.utils.JsonUtils;
import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
import org.apache.seatunnel.datasource.plugin.api.DatasourcePluginTypeEnum;
@@ -106,7 +108,7 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
Map<String, String> datasourceConfig)
throws CodeGenerateUtils.CodeGenerateException {
Integer userId = ServletUtils.getCurrentUserId();
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.DATASOURCE_CREATE,
userId);
+ permCheck(datasourceName, AccessType.CREATE);
long uuid = CodeGenerateUtils.getInstance().genCode();
boolean unique =
datasourceDao.checkDatasourceNameUnique(datasourceName, 0L);
if (!unique) {
@@ -135,10 +137,6 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
.build();
boolean success = datasourceDao.insertDatasource(datasource);
if (success) {
- resourcePostHandle(
- SeatunnelResourcePermissionModuleEnum.DATASOURCE.name(),
- Collections.singletonList(datasource.getId()),
- userId);
return String.valueOf(uuid);
}
throw new
SeatunnelException(SeatunnelErrorEnum.DATASOURCE_CREATE_FAILED);
@@ -150,11 +148,6 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
String datasourceName,
String description,
Map<String, String> datasourceConfig) {
- funcAndResourcePermissionCheck(
- SeatunnelFuncPermissionKeyConstant.DATASOURCE_UPDATE,
- SeatunnelResourcePermissionModuleEnum.DATASOURCE.name(),
- Collections.singletonList(datasourceId),
- ServletUtils.getCurrentUserId());
if (datasourceId == null) {
throw new SeatunnelException(
SeatunnelErrorEnum.DATASOURCE_PRAM_NOT_ALLOWED_NULL,
"datasourceId");
@@ -172,6 +165,7 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
SeatunnelErrorEnum.DATASOURCE_NAME_ALREADY_EXISTS,
datasourceName);
}
}
+ permCheck(datasource.getDatasourceName(), AccessType.UPDATE);
datasource.setUpdateUserId(ServletUtils.getCurrentUserId());
datasource.setUpdateTime(new Date());
datasource.setDescription(description);
@@ -185,12 +179,6 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public boolean deleteDatasource(Long datasourceId) {
- // check role permission
- funcAndResourcePermissionCheck(
- SeatunnelFuncPermissionKeyConstant.DATASOURCE_DELETE,
- SeatunnelResourcePermissionModuleEnum.DATASOURCE.name(),
- Collections.singletonList(datasourceId),
- ServletUtils.getCurrentUserId());
// check has job task has used this datasource
List<JobTask> jobTaskList =
jobTaskDao.getJobTaskByDataSourceId(datasourceId);
if (!CollectionUtils.isEmpty(jobTaskList)) {
@@ -204,6 +192,11 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
if
(!jobDefinitionService.getJobVersionByDataSourceId(datasourceId).isEmpty()) {
throw new
SeatunnelException(SeatunnelErrorEnum.DATASOURCE_CAN_NOT_DELETE);
}
+ Datasource datasource =
datasourceDao.selectDatasourceById(datasourceId);
+ if (datasource == null) {
+ return true;
+ }
+ permCheck(datasource.getDatasourceName(), AccessType.DELETE);
return datasourceDao.deleteDatasourceById(datasourceId);
}
@@ -219,16 +212,12 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public boolean testDatasourceConnectionAble(Long datasourceId) {
- funcAndResourcePermissionCheck(
- SeatunnelFuncPermissionKeyConstant.DATASOURCE_TEST_CONNECT,
- SeatunnelResourcePermissionModuleEnum.DATASOURCE.name(),
- Collections.singletonList(datasourceId),
- ServletUtils.getCurrentUserId());
Datasource datasource =
datasourceDao.selectDatasourceById(datasourceId);
if (datasource == null) {
throw new SeatunnelException(
SeatunnelErrorEnum.DATASOURCE_NOT_FOUND,
datasourceId.toString());
}
+ permCheck(datasource.getDatasourceName(), AccessType.EXECUTE);
String configJson = datasource.getDatasourceConfig();
Map<String, String> datasourceConfig =
JsonUtils.toMap(configJson, String.class, String.class);
@@ -301,7 +290,6 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public List<String> queryTableNames(
String datasourceName, String databaseName, String filterName,
Integer size) {
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.DATASOURCE_TABLE, 0);
Datasource datasource =
datasourceDao.queryDatasourceByName(datasourceName);
if (null == datasource) {
throw new
SeatunnelException(SeatunnelErrorEnum.DATASOURCE_NOT_FOUND, datasourceName);
@@ -323,7 +311,6 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public List<String> queryTableNames(String datasourceName, String
databaseName) {
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.DATASOURCE_TABLE, 0);
Datasource datasource =
datasourceDao.queryDatasourceByName(datasourceName);
if (null == datasource) {
throw new
SeatunnelException(SeatunnelErrorEnum.DATASOURCE_NOT_FOUND, datasourceName);
@@ -344,7 +331,6 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public List<TableField> queryTableSchema(
String datasourceName, String databaseName, String tableName) {
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.DATASOURCE_TABLE_SCHEMA,
0);
Datasource datasource =
datasourceDao.queryDatasourceByName(datasourceName);
if (null == datasource) {
throw new
SeatunnelException(SeatunnelErrorEnum.DATASOURCE_NOT_FOUND, datasourceName);
@@ -399,18 +385,22 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public PageInfo<DatasourceRes> queryDatasourceList(
String searchVal, String pluginName, Integer pageNo, Integer
pageSize) {
- Integer userId = ServletUtils.getCurrentUserId();
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.DATASOURCE_LIST, userId);
Page<Datasource> page = new Page<>(pageNo, pageSize);
PageInfo<DatasourceRes> pageInfo = new PageInfo<>();
- List<Long> ids =
- availableResourceRange(
-
SeatunnelResourcePermissionModuleEnum.DATASOURCE.name(), userId);
- if (org.springframework.util.CollectionUtils.isEmpty(ids)) {
+ IPage<Datasource> datasourceWithoutAuthorization =
+ datasourceDao.selectDatasourceByParam(page, null, searchVal,
pluginName);
+
+ List<Long> filteredIds =
+ datasourceWithoutAuthorization.getRecords().stream()
+ .filter(datasource ->
hasReadPerm(datasource.getDatasourceName()))
+ .map(Datasource::getId)
+ .collect(Collectors.toList());
+
+ if (org.springframework.util.CollectionUtils.isEmpty(filteredIds)) {
return pageInfo;
}
IPage<Datasource> datasourcePage =
- datasourceDao.selectDatasourceByParam(page, ids, searchVal,
pluginName);
+ datasourceDao.selectDatasourceByParam(page, filteredIds,
searchVal, pluginName);
pageInfo = new PageInfo<>();
pageInfo.setPageNo((int) datasourcePage.getPages());
pageInfo.setPageSize((int) datasourcePage.getSize());
@@ -419,15 +409,6 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
pageInfo.setData(new ArrayList<>());
return pageInfo;
}
- List<Integer> userIds = new ArrayList<>();
- datasourcePage
- .getRecords()
- .forEach(
- datasource -> {
- userIds.add(datasource.getCreateUserId());
- userIds.add(datasource.getUpdateUserId());
- });
-
List<DatasourceRes> datasourceResList =
datasourcePage.getRecords().stream()
.map(
@@ -554,11 +535,6 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
if (CollectionUtils.isEmpty(datasourceIds)) {
return new ArrayList<>();
}
- funcAndResourcePermissionCheck(
- SeatunnelFuncPermissionKeyConstant.DATASOURCE_DETAIL_LIST,
- SeatunnelResourcePermissionModuleEnum.DATASOURCE.name(),
- datasourceIds,
- 0);
List<Long> datasourceIdsLong =
datasourceIds.stream().map(Long::parseLong).collect(Collectors.toList());
List<Datasource> datasourceList =
datasourceDao.selectDatasourceByIds(datasourceIdsLong);
@@ -570,22 +546,13 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
if (CollectionUtils.isEmpty(datasourceList)) {
return new ArrayList<>();
}
- List<Integer> userIds = new ArrayList<>();
- datasourceList.forEach(
- datasource -> {
- if (null != datasource.getCreateUserId()) {
- userIds.add(datasource.getCreateUserId());
- }
- if (null != datasource.getUpdateUserId()) {
- userIds.add(datasource.getUpdateUserId());
- }
- });
List<DatasourceDetailRes> datasourceDetailResList = new ArrayList<>();
-
- datasourceList.forEach(
- datasource -> {
-
datasourceDetailResList.add(getDatasourceDetailRes(datasource));
- });
+ datasourceList.stream()
+ .filter(datasource ->
hasReadPerm(datasource.getDatasourceName()))
+ .forEach(
+ datasource -> {
+
datasourceDetailResList.add(getDatasourceDetailRes(datasource));
+ });
return datasourceDetailResList;
}
@@ -597,7 +564,7 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public DatasourceDetailRes queryDatasourceDetailByDatasourceName(String
datasourceName) {
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.DATASOURCE_DETAIL, 0);
+ permCheck(datasourceName, AccessType.READ);
Datasource datasource =
datasourceDao.queryDatasourceByName(datasourceName);
// @cc liuli
if (null == datasource) {
@@ -627,11 +594,11 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public DatasourceDetailRes queryDatasourceDetailById(String datasourceId) {
long datasourceIdLong = Long.parseLong(datasourceId);
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.DATASOURCE_DETAIL, 0);
Datasource datasource =
datasourceDao.selectDatasourceById(datasourceIdLong);
if (null == datasource) {
throw new
SeatunnelException(SeatunnelErrorEnum.DATASOURCE_NOT_FOUND, datasourceId);
}
+ permCheck(datasource.getDatasourceName(), AccessType.READ);
return getDatasourceDetailRes(datasource);
}
@@ -639,4 +606,20 @@ public class DatasourceServiceImpl extends
SeatunnelBaseServiceImpl
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
+
+ private void permCheck(String resourceName, AccessType accessType) {
+ permissionCheck(
+ resourceName,
+ ResourceType.DATASOURCE,
+ accessType,
+ UserContextHolder.getAccessInfo());
+ }
+
+ private boolean hasReadPerm(String resourceName) {
+ return hasPermission(
+ resourceName,
+ ResourceType.DATASOURCE,
+ AccessType.READ,
+ UserContextHolder.getAccessInfo());
+ }
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobConfigServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobConfigServiceImpl.java
index 97bf1884..add8e3b0 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobConfigServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobConfigServiceImpl.java
@@ -22,9 +22,11 @@ import org.apache.seatunnel.app.dal.entity.JobDefinition;
import org.apache.seatunnel.app.dal.entity.JobVersion;
import org.apache.seatunnel.app.domain.request.job.JobConfig;
import org.apache.seatunnel.app.domain.response.job.JobConfigRes;
-import
org.apache.seatunnel.app.permission.constants.SeatunnelFuncPermissionKeyConstant;
+import org.apache.seatunnel.app.security.UserContextHolder;
import org.apache.seatunnel.app.service.IJobConfigService;
import org.apache.seatunnel.app.utils.ServletUtils;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
import org.apache.seatunnel.common.constants.JobMode;
import org.apache.seatunnel.common.utils.JsonUtils;
import org.apache.seatunnel.server.common.SeatunnelErrorEnum;
@@ -48,14 +50,21 @@ public class JobConfigServiceImpl extends
SeatunnelBaseServiceImpl implements IJ
@Resource private IJobDefinitionDao jobDefinitionDao;
@Override
- public JobConfigRes getJobConfig(long jobVersionId) throws
JsonProcessingException {
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.JOB_CONFIG_DETAIL, 0);
+ public JobConfigRes getJobConfig(long jobVersionId, boolean
isPermissionChecked)
+ throws JsonProcessingException {
JobVersion jobVersion = jobVersionDao.getVersionById(jobVersionId);
if (jobVersion == null) {
throw new SeatunnelException(
SeatunnelErrorEnum.RESOURCE_NOT_FOUND, "job version not
found.");
}
JobDefinition jobDefinition =
jobDefinitionDao.getJob(jobVersion.getJobId());
+ if (!isPermissionChecked) {
+ permissionCheck(
+ jobDefinition.getName(),
+ ResourceType.JOB,
+ AccessType.READ,
+ UserContextHolder.getAccessInfo());
+ }
JobConfigRes jobConfigRes = new JobConfigRes();
jobConfigRes.setName(jobDefinition.getName());
jobConfigRes.setId(jobVersion.getId());
@@ -70,15 +79,22 @@ public class JobConfigServiceImpl extends
SeatunnelBaseServiceImpl implements IJ
@Override
@Transactional
- public void updateJobConfig(long jobVersionId, JobConfig jobConfig)
+ public void updateJobConfig(long jobVersionId, JobConfig jobConfig,
boolean isPermissionChecked)
throws JsonProcessingException {
Integer userId = ServletUtils.getCurrentUserId();
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.JOB_CONFIG_UPDATE, 0);
JobVersion version = jobVersionDao.getVersionById(jobVersionId);
if (version == null) {
throw new SeatunnelException(
SeatunnelErrorEnum.RESOURCE_NOT_FOUND, "job version not
found.");
}
+ JobDefinition existingJobDefinition =
jobDefinitionDao.getJob(version.getJobId());
+ if (!isPermissionChecked && existingJobDefinition != null) {
+ permissionCheck(
+ existingJobDefinition.getName(),
+ ResourceType.JOB,
+ AccessType.UPDATE,
+ UserContextHolder.getAccessInfo());
+ }
JobDefinition jobDefinition = new JobDefinition();
jobDefinition.setId(version.getJobId());
jobDefinition.setUpdateUserId(userId);
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobDefinitionServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobDefinitionServiceImpl.java
index 07c07125..915193a0 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobDefinitionServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobDefinitionServiceImpl.java
@@ -29,9 +29,11 @@ import
org.apache.seatunnel.app.domain.request.job.DataSourceOption;
import org.apache.seatunnel.app.domain.request.job.JobReq;
import org.apache.seatunnel.app.domain.response.PageInfo;
import org.apache.seatunnel.app.domain.response.job.JobDefinitionRes;
-import
org.apache.seatunnel.app.permission.constants.SeatunnelFuncPermissionKeyConstant;
+import org.apache.seatunnel.app.security.UserContextHolder;
import org.apache.seatunnel.app.service.IJobDefinitionService;
import org.apache.seatunnel.app.utils.ServletUtils;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
import org.apache.seatunnel.common.constants.JobMode;
import org.apache.seatunnel.common.utils.JsonUtils;
import org.apache.seatunnel.server.common.CodeGenerateUtils;
@@ -74,7 +76,7 @@ public class JobDefinitionServiceImpl extends
SeatunnelBaseServiceImpl
@Transactional
public long createJob(JobReq jobReq) throws
CodeGenerateUtils.CodeGenerateException {
Integer userId = ServletUtils.getCurrentUserId();
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.JOB_DEFINITION_CREATE,
userId);
+ permCheck(jobReq.getName(), AccessType.CREATE);
long uuid = CodeGenerateUtils.getInstance().genCode();
jobDefinitionDao.add(
JobDefinition.builder()
@@ -111,7 +113,6 @@ public class JobDefinitionServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public PageInfo<JobDefinitionRes> getJob(
String searchName, Integer pageNo, Integer pageSize, String
jobMode) {
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.JOB_DEFINITION_VIEW, 0);
if (StringUtils.isNotEmpty(jobMode)) {
try {
JobMode.valueOf(jobMode);
@@ -120,13 +121,27 @@ public class JobDefinitionServiceImpl extends
SeatunnelBaseServiceImpl
SeatunnelErrorEnum.ILLEGAL_STATE, "Unsupported
JobMode");
}
}
- return jobDefinitionDao.getJob(searchName, pageNo, pageSize, jobMode);
+ PageInfo<JobDefinitionRes> job =
+ jobDefinitionDao.getJob(searchName, pageNo, pageSize, jobMode);
+ if (CollectionUtils.isEmpty(job.getData())) {
+ return job;
+ }
+
+ List<JobDefinitionRes> filteredJobs =
+ job.getData().stream()
+ .filter(jobDefinitionRes ->
hasReadPerm(jobDefinitionRes.getName()))
+ .collect(Collectors.toList());
+
+ PageInfo<JobDefinitionRes> jobs = new PageInfo<>();
+ jobs.setData(filteredJobs);
+ jobs.setPageSize(pageSize);
+ jobs.setPageNo(pageNo);
+ jobs.setTotalCount(filteredJobs.size());
+ return jobs;
}
@Override
public Map<Long, String> getJob(@NonNull String name) {
-
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.JOB_DEFINITION_VIEW, 0);
List<JobDefinition> job = jobDefinitionDao.getJobList(name);
if (CollectionUtils.isEmpty(job)) {
return new HashMap<>();
@@ -135,7 +150,9 @@ public class JobDefinitionServiceImpl extends
SeatunnelBaseServiceImpl
Map<Long, String> jobDefineMap = new HashMap<>();
job.forEach(
jobDefine -> {
- jobDefineMap.put(jobDefine.getId(), jobDefine.getName());
+ if (hasReadPerm(jobDefine.getName())) {
+ jobDefineMap.put(jobDefine.getId(),
jobDefine.getName());
+ }
});
return jobDefineMap;
@@ -143,8 +160,11 @@ public class JobDefinitionServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public JobDefinition getJobDefinitionByJobId(long jobId) {
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.JOB_DEFINITION_DETAIL,
0);
- return jobDefinitionDao.getJob(jobId);
+ JobDefinition job = jobDefinitionDao.getJob(jobId);
+ if (null != job) {
+ permCheck(job.getName(), AccessType.READ);
+ }
+ return job;
}
@Override
@@ -179,7 +199,20 @@ public class JobDefinitionServiceImpl extends
SeatunnelBaseServiceImpl
@Override
public void deleteJob(long id) {
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.JOB_DEFINITION_DELETE,
0);
+ JobDefinition job = jobDefinitionDao.getJob(id);
+ if (job != null) {
+ permCheck(job.getName(), AccessType.DELETE);
+ }
jobDefinitionDao.delete(id);
}
+
+ private void permCheck(String resourceName, AccessType accessType) {
+ permissionCheck(
+ resourceName, ResourceType.JOB, accessType,
UserContextHolder.getAccessInfo());
+ }
+
+ private boolean hasReadPerm(String resourceName) {
+ return hasPermission(
+ resourceName, ResourceType.JOB, AccessType.READ,
UserContextHolder.getAccessInfo());
+ }
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobInstanceServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobInstanceServiceImpl.java
index cd453048..d0db526f 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobInstanceServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobInstanceServiceImpl.java
@@ -55,6 +55,7 @@ import
org.apache.seatunnel.app.domain.response.datasource.DatasourceDetailRes;
import
org.apache.seatunnel.app.domain.response.datasource.VirtualTableDetailRes;
import org.apache.seatunnel.app.domain.response.executor.JobExecutorRes;
import
org.apache.seatunnel.app.permission.constants.SeatunnelFuncPermissionKeyConstant;
+import org.apache.seatunnel.app.security.UserContextHolder;
import org.apache.seatunnel.app.service.IDatasourceService;
import org.apache.seatunnel.app.service.IJobInstanceService;
import org.apache.seatunnel.app.service.IJobMetricsService;
@@ -65,6 +66,8 @@ import org.apache.seatunnel.app.utils.ConfigShadeUtil;
import org.apache.seatunnel.app.utils.JobUtils;
import org.apache.seatunnel.app.utils.SeaTunnelConfigUtil;
import org.apache.seatunnel.app.utils.ServletUtils;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
import org.apache.seatunnel.common.constants.PluginType;
import org.apache.seatunnel.common.utils.ExceptionUtils;
import org.apache.seatunnel.common.utils.JsonUtils;
@@ -137,12 +140,17 @@ public class JobInstanceServiceImpl extends
SeatunnelBaseServiceImpl
public JobExecutorRes createExecuteResource(
@NonNull Long jobDefineId, JobExecParam executeParam) {
int userId = ServletUtils.getCurrentUserId();
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.JOB_EXECUTOR_RESOURCE,
userId);
log.info(
"receive createExecuteResource request, userId:{},
jobDefineId:{}",
userId,
jobDefineId);
JobDefinition job = jobDefinitionDao.getJob(jobDefineId);
+ permissionCheck(
+ job.getName(),
+ ResourceType.JOB,
+ AccessType.EXECUTE,
+ UserContextHolder.getAccessInfo());
+
JobVersion latestVersion = jobVersionDao.getLatestVersion(job.getId());
JobInstance jobInstance = new JobInstance();
String jobConfig = createJobConfig(latestVersion, executeParam);
@@ -370,7 +378,6 @@ public class JobInstanceServiceImpl extends
SeatunnelBaseServiceImpl
public void complete(
@NonNull Long jobInstanceId, @NonNull String jobEngineId,
JobResult jobResult) {
int userId = ServletUtils.getCurrentUserId();
-
funcPermissionCheck(SeatunnelFuncPermissionKeyConstant.JOB_EXECUTOR_COMPLETE,
userId);
JobInstance jobInstance =
jobInstanceDao.getJobInstanceMapper().selectById(jobInstanceId);
jobMetricsService.syncJobDataToDb(jobInstance, jobEngineId);
jobInstance.setJobStatus(jobResult.getStatus());
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobServiceImpl.java
index 8a2620f5..8838d1e2 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/JobServiceImpl.java
@@ -26,10 +26,13 @@ import
org.apache.seatunnel.app.domain.request.job.JobTaskInfo;
import org.apache.seatunnel.app.domain.request.job.PluginConfig;
import org.apache.seatunnel.app.domain.response.job.JobConfigRes;
import org.apache.seatunnel.app.domain.response.job.JobRes;
+import org.apache.seatunnel.app.security.UserContextHolder;
import org.apache.seatunnel.app.service.IJobConfigService;
import org.apache.seatunnel.app.service.IJobDefinitionService;
import org.apache.seatunnel.app.service.IJobService;
import org.apache.seatunnel.app.service.IJobTaskService;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
import org.apache.seatunnel.common.constants.JobMode;
import org.apache.seatunnel.server.common.CodeGenerateUtils;
import org.apache.seatunnel.server.common.ParamValidationException;
@@ -61,6 +64,11 @@ public class JobServiceImpl extends SeatunnelBaseServiceImpl
implements IJobServ
@Override
@Transactional
public long createJob(JobCreateReq jobCreateRequest) throws
JsonProcessingException {
+ permissionCheck(
+ jobCreateRequest.getJobConfig().getName(),
+ ResourceType.JOB,
+ AccessType.CREATE,
+ UserContextHolder.getAccessInfo());
JobReq jobDefinition =
getJobDefinition(jobCreateRequest.getJobConfig());
long jobId = jobService.createJob(jobDefinition);
createTasks(jobCreateRequest, jobId);
@@ -90,7 +98,7 @@ public class JobServiceImpl extends SeatunnelBaseServiceImpl
implements IJobServ
pluginNameVsPluginId.put(pluginIdKey, newPluginId);
}
}
- jobConfigService.updateJobConfig(jobId,
jobCreateRequest.getJobConfig());
+ jobConfigService.updateJobConfig(jobId,
jobCreateRequest.getJobConfig(), true);
JobDAG jobDAG = jobCreateRequest.getJobDAG();
// Replace the plugin name with plugin id
List<Edge> edges = jobDAG.getEdges();
@@ -136,13 +144,21 @@ public class JobServiceImpl extends
SeatunnelBaseServiceImpl implements IJobServ
@Override
public void updateJob(long jobVersionId, JobCreateReq jobCreateReq)
throws JsonProcessingException {
+ JobConfigRes jobConfig = jobConfigService.getJobConfig(jobVersionId,
true);
+ if (jobConfig != null) {
+ permissionCheck(
+ jobConfig.getName(),
+ ResourceType.JOB,
+ AccessType.UPDATE,
+ UserContextHolder.getAccessInfo());
+ }
jobTaskService.deleteTaskByVersionId(jobVersionId);
createTasks(jobCreateReq, jobVersionId);
}
@Override
public JobRes getJob(long jobVersionId) throws JsonProcessingException {
- JobConfigRes jobConfig = jobConfigService.getJobConfig(jobVersionId);
+ JobConfigRes jobConfig = jobConfigService.getJobConfig(jobVersionId,
false);
JobTaskInfo taskConfig = jobTaskService.getTaskConfig(jobVersionId);
return new JobRes(jobConfig, taskConfig.getPlugins(), new
JobDAG(taskConfig.getEdges()));
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/SeatunnelBaseServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/SeatunnelBaseServiceImpl.java
index d6341968..878458c3 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/SeatunnelBaseServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/SeatunnelBaseServiceImpl.java
@@ -16,38 +16,42 @@
*/
package org.apache.seatunnel.app.service.impl;
-import org.apache.seatunnel.app.permission.ISeatunnelPermissonService;
import org.apache.seatunnel.app.service.ISeatunnelBaseService;
+import org.apache.seatunnel.common.access.AccessInfo;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
+import org.apache.seatunnel.common.access.SeatunnelAccessController;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import java.util.List;
+import javax.annotation.Resource;
@Service
public class SeatunnelBaseServiceImpl implements ISeatunnelBaseService {
-
- @Autowired private ISeatunnelPermissonService iSeatunnelPermissonService;
+ @Resource private SeatunnelAccessController seatunnelAccessController;
@Override
public void funcPermissionCheck(String permissionKey, int userId) {
- iSeatunnelPermissonService.funcPermissionCheck(permissionKey, userId);
- }
-
- @Override
- public void funcAndResourcePermissionCheck(
- String permissionKey, String resourceType, List resourceCodes, int
userId) {
- iSeatunnelPermissonService.funcAndResourcePermissionCheck(
- permissionKey, resourceType, resourceCodes, userId);
+ // Placeholder method: To be removed after thorough analysis of all
references and usages.
}
@Override
- public void resourcePostHandle(String sourceType, List resourceCodes, int
userId) {
- iSeatunnelPermissonService.resourcePostHandle(sourceType,
resourceCodes, userId);
+ public void permissionCheck(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo) {
+ seatunnelAccessController.authorizeAccess(
+ resourceName, resourceType, accessType, accessInfo);
}
@Override
- public List availableResourceRange(String resourceType, int userId) {
- return iSeatunnelPermissonService.availableResourceRange(resourceType,
userId);
+ public boolean hasPermission(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo) {
+ return seatunnelAccessController.hasPermission(
+ resourceName, resourceType, accessType, accessInfo);
}
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/TaskInstanceServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/TaskInstanceServiceImpl.java
index f30ea239..778ee8ff 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/TaskInstanceServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/TaskInstanceServiceImpl.java
@@ -25,11 +25,14 @@ import org.apache.seatunnel.app.dal.entity.JobInstance;
import org.apache.seatunnel.app.domain.dto.job.SeaTunnelJobInstanceDto;
import org.apache.seatunnel.app.domain.response.executor.JobExecutionStatus;
import org.apache.seatunnel.app.domain.response.metrics.JobSummaryMetricsRes;
+import org.apache.seatunnel.app.security.UserContextHolder;
import org.apache.seatunnel.app.service.BaseService;
import org.apache.seatunnel.app.service.IJobDefinitionService;
import org.apache.seatunnel.app.service.IJobMetricsService;
import org.apache.seatunnel.app.service.ITaskInstanceService;
import org.apache.seatunnel.app.utils.PageInfo;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
import org.apache.seatunnel.common.constants.JobMode;
import org.apache.seatunnel.server.common.SeatunnelErrorEnum;
import org.apache.seatunnel.server.common.SeatunnelException;
@@ -50,10 +53,12 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
@Service
@Slf4j
-public class TaskInstanceServiceImpl implements
ITaskInstanceService<SeaTunnelJobInstanceDto> {
+public class TaskInstanceServiceImpl extends SeatunnelBaseServiceImpl
+ implements ITaskInstanceService<SeaTunnelJobInstanceDto> {
@Autowired IJobInstanceDao jobInstanceDao;
@@ -88,13 +93,19 @@ public class TaskInstanceServiceImpl implements
ITaskInstanceService<SeaTunnelJo
new Page<>(pageNo, pageSize), startDate, endDate,
jobDefineName, jobMode);
List<SeaTunnelJobInstanceDto> records = jobInstanceIPage.getRecords();
- if (CollectionUtils.isEmpty(records)) {
+ List<SeaTunnelJobInstanceDto> filteredRecords =
+ records.stream()
+ .filter(
+ jobDefinitionRes ->
+
hasReadPerm(jobDefinitionRes.getJobDefineName()))
+ .collect(Collectors.toList());
+ if (CollectionUtils.isEmpty(filteredRecords)) {
return result;
}
- addRunningTimeToResult(records);
- jobPipelineSummaryMetrics(records, jobMode);
+ addRunningTimeToResult(filteredRecords);
+ jobPipelineSummaryMetrics(filteredRecords, jobMode);
pageInfo.setTotal((int) jobInstanceIPage.getTotal());
- pageInfo.setTotalList(records);
+ pageInfo.setTotalList(filteredRecords);
result.setData(pageInfo);
return result;
}
@@ -215,4 +226,9 @@ public class TaskInstanceServiceImpl implements
ITaskInstanceService<SeaTunnelJo
jobInstanceDao.deleteById(jobInstanceId);
return Result.success();
}
+
+ private boolean hasReadPerm(String resourceName) {
+ return hasPermission(
+ resourceName, ResourceType.JOB, AccessType.READ,
UserContextHolder.getAccessInfo());
+ }
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/UserServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/UserServiceImpl.java
index 138ab4b5..2a47e299 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/UserServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/UserServiceImpl.java
@@ -34,6 +34,7 @@ import org.apache.seatunnel.app.domain.response.PageInfo;
import org.apache.seatunnel.app.domain.response.user.AddUserRes;
import org.apache.seatunnel.app.domain.response.user.UserSimpleInfoRes;
import org.apache.seatunnel.app.security.JwtUtils;
+import org.apache.seatunnel.app.security.UserContextHolder;
import
org.apache.seatunnel.app.security.authentication.strategy.IAuthenticationStrategy;
import
org.apache.seatunnel.app.security.authentication.strategy.impl.DBAuthenticationStrategy;
import
org.apache.seatunnel.app.security.authentication.strategy.impl.LDAPAuthenticationStrategy;
@@ -42,6 +43,8 @@ import org.apache.seatunnel.app.service.IUserService;
import org.apache.seatunnel.app.service.WorkspaceService;
import org.apache.seatunnel.app.utils.PasswordUtils;
import org.apache.seatunnel.app.utils.ServletUtils;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
import org.apache.seatunnel.server.common.PageData;
import org.apache.seatunnel.server.common.SeatunnelErrorEnum;
import org.apache.seatunnel.server.common.SeatunnelException;
@@ -97,9 +100,9 @@ public class UserServiceImpl extends
SeatunnelBaseServiceImpl implements IUserSe
@Override
@Transactional(rollbackFor = Exception.class)
public AddUserRes add(AddUserReq addReq) {
+ permCheck(addReq.getUsername(), AccessType.CREATE);
// 1. check duplicate user first
userDaoImpl.checkUserExists(addReq.getUsername());
-
// 2. add a new user.
final UpdateUserDto dto =
UpdateUserDto.builder()
@@ -123,6 +126,7 @@ public class UserServiceImpl extends
SeatunnelBaseServiceImpl implements IUserSe
@Override
public void update(UpdateUserReq updateReq) {
+ permCheck(updateReq.getUsername(), AccessType.UPDATE);
final UpdateUserDto dto =
UpdateUserDto.builder()
.id(updateReq.getUserId())
@@ -145,6 +149,11 @@ public class UserServiceImpl extends
SeatunnelBaseServiceImpl implements IUserSe
throw new SeatunnelException(
SeatunnelErrorEnum.INVALID_OPERATION, "Can't delete
yourself");
}
+ User user = userDaoImpl.getById(id);
+ if (user == null) {
+ return;
+ }
+ permCheck(user.getUsername(), AccessType.DELETE);
userDaoImpl.delete(id);
roleServiceImpl.deleteByUserId(id);
}
@@ -158,7 +167,10 @@ public class UserServiceImpl extends
SeatunnelBaseServiceImpl implements IUserSe
userDaoImpl.list(dto, userListReq.getRealPageNo(),
userListReq.getPageSize());
final List<UserSimpleInfoRes> data =
-
userPageData.getData().stream().map(this::translate).collect(Collectors.toList());
+ userPageData.getData().stream()
+ .filter(user -> hasReadPerm(user.getUsername()))
+ .map(this::translate)
+ .collect(Collectors.toList());
final PageInfo<UserSimpleInfoRes> pageInfo = new PageInfo<>();
pageInfo.setPageNo(userListReq.getPageNo());
pageInfo.setPageSize(userListReq.getPageSize());
@@ -170,12 +182,20 @@ public class UserServiceImpl extends
SeatunnelBaseServiceImpl implements IUserSe
@Override
public void enable(int id) {
- userDaoImpl.enable(id);
+ User user = userDaoImpl.getById(id);
+ if (user != null) {
+ permCheck(user.getUsername(), AccessType.UPDATE);
+ userDaoImpl.enable(id);
+ }
}
@Override
public void disable(int id) {
- userDaoImpl.disable(id);
+ User user = userDaoImpl.getById(id);
+ if (user != null) {
+ permCheck(user.getUsername(), AccessType.UPDATE);
+ userDaoImpl.disable(id);
+ }
}
@Override
@@ -224,4 +244,17 @@ public class UserServiceImpl extends
SeatunnelBaseServiceImpl implements IUserSe
info.setName(user.getUsername());
return info;
}
+
+ private void permCheck(String resourceName, AccessType accessType) {
+ permissionCheck(
+ resourceName, ResourceType.USER, accessType,
UserContextHolder.getAccessInfo());
+ }
+
+ private boolean hasReadPerm(String resourceName) {
+ return hasPermission(
+ resourceName,
+ ResourceType.USER,
+ AccessType.READ,
+ UserContextHolder.getAccessInfo());
+ }
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/VirtualTableServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/VirtualTableServiceImpl.java
index b3efb204..12e4ee41 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/VirtualTableServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/VirtualTableServiceImpl.java
@@ -33,6 +33,7 @@ import org.apache.seatunnel.app.dynamicforms.FormStructure;
import
org.apache.seatunnel.app.permission.constants.SeatunnelFuncPermissionKeyConstant;
import org.apache.seatunnel.app.service.IJobDefinitionService;
import org.apache.seatunnel.app.service.IVirtualTableService;
+import org.apache.seatunnel.app.service.WorkspaceService;
import org.apache.seatunnel.app.thirdparty.datasource.DataSourceClientFactory;
import
org.apache.seatunnel.app.thirdparty.framework.SeaTunnelOptionRuleWrapper;
import org.apache.seatunnel.app.utils.ServletUtils;
@@ -71,6 +72,8 @@ public class VirtualTableServiceImpl extends
SeatunnelBaseServiceImpl
@Resource(name = "datasourceDaoImpl")
IDatasourceDao datasourceDao;
+ @Autowired private WorkspaceService workspaceService;
+
@Autowired private ConnectorDataSourceMapperConfig dataSourceMapperConfig;
@Override
@@ -328,53 +331,4 @@ public class VirtualTableServiceImpl extends
SeatunnelBaseServiceImpl
Long datasourceIdLong = Long.valueOf(datasourceId);
return virtualTableDao.getVirtualDatabaseNames(datasourceIdLong);
}
-
- private VirtualTableFieldRes
convertVirtualTableFieldReq(VirtualTableFieldReq req) {
-
- return VirtualTableFieldRes.builder()
- .fieldName(req.getFieldName())
- .fieldType(req.getFieldType())
- .nullable(req.getNullable())
- .defaultValue(req.getDefaultValue())
- .fieldComment(req.getFieldComment())
- .primaryKey(req.getPrimaryKey())
- .build();
- }
-
- /* private VirtualTableDetailRes
convertVirtualTableDetailResponse(VirtualTableDetailResponse response) {
- VirtualTableDetailRes res = new VirtualTableDetailRes();
- res.setTableId(response.getId().toString());
- res.setTableName(response.getTableName());
- res.setDatabaseName(response.getDatabaseName());
- res.setDescription(response.getDescription());
- res.setCreateTime(response.getCreateTime());
- res.setUpdateTime(response.getUpdateTime());
-
- res.setFields(convertVirtualTableFieldResponse(response.getFields()));
-
- List<Integer> userIds = new ArrayList<>();
- userIds.add(Integer.parseInt(response.getCreateUserId()));
- userIds.add(Integer.parseInt(response.getUpdateUserId()));
- Map<Integer, String> userNames = queryUserNamesByIds(userIds);
-
res.setCreateUserName(userNames.get(Integer.parseInt(response.getCreateUserId())));
-
res.setUpdateUserName(userNames.get(Integer.parseInt(response.getUpdateUserId())));
- return res;
- }
-
- private List<VirtualTableFieldRes>
convertVirtualTableFieldResponse(List<VirtualTableFieldResponse>
fieldResponses) {
- List<VirtualTableFieldRes> fields = new ArrayList<>();
- if (fieldResponses != null && !fieldResponses.isEmpty()) {
- for (VirtualTableFieldResponse fieldResponse : fieldResponses) {
- VirtualTableFieldRes field = new VirtualTableFieldRes();
- field.setFieldName(fieldResponse.getName());
- field.setFieldType(fieldResponse.getType());
- field.setNullable(fieldResponse.getNullable());
- field.setDefaultValue(fieldResponse.getDefaultValue());
- field.setFieldComment(fieldResponse.getComment());
- field.setPrimaryKey(fieldResponse.getPrimaryKey());
- fields.add(field);
- }
- }
- return fields;
- }*/
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/WorkspaceServiceImpl.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/WorkspaceServiceImpl.java
index 2700c7d3..9406aada 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/WorkspaceServiceImpl.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/service/impl/WorkspaceServiceImpl.java
@@ -20,8 +20,11 @@ package org.apache.seatunnel.app.service.impl;
import org.apache.seatunnel.app.dal.dao.IWorkspaceDao;
import org.apache.seatunnel.app.dal.entity.Workspace;
import org.apache.seatunnel.app.domain.request.workspace.WorkspaceReq;
+import org.apache.seatunnel.app.security.UserContextHolder;
import org.apache.seatunnel.app.service.WorkspaceService;
import org.apache.seatunnel.app.utils.ServletUtils;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
import org.apache.seatunnel.server.common.CodeGenerateUtils;
import org.apache.seatunnel.server.common.ParamValidationException;
import org.apache.seatunnel.server.common.SeatunnelErrorEnum;
@@ -29,19 +32,22 @@ import
org.apache.seatunnel.server.common.SeatunnelException;
import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+
import java.util.Date;
import java.util.List;
+import java.util.stream.Collectors;
@Service
public class WorkspaceServiceImpl extends SeatunnelBaseServiceImpl implements
WorkspaceService {
- @Autowired private IWorkspaceDao workspaceDao;
+ @Resource private IWorkspaceDao workspaceDao;
@Override
public Long createWorkspace(WorkspaceReq workspaceReq) {
validateWorkspaceParam(workspaceReq);
+ permCheck(workspaceReq.getWorkspaceName(), AccessType.CREATE);
Workspace workspaceByName =
workspaceDao.selectWorkspaceByName(workspaceReq.getWorkspaceName());
if (workspaceByName != null) {
@@ -95,6 +101,7 @@ public class WorkspaceServiceImpl extends
SeatunnelBaseServiceImpl implements Wo
SeatunnelErrorEnum.RESOURCE_NOT_FOUND,
"Workspace with id " + id + " not found.");
}
+ permCheck(workspace.getWorkspaceName(), AccessType.UPDATE);
validateWorkspaceParam(workspaceReq);
// Check if the workspace name is being changed and if it already
exists in the database
@@ -115,6 +122,7 @@ public class WorkspaceServiceImpl extends
SeatunnelBaseServiceImpl implements Wo
public boolean deleteWorkspace(Long id) {
Workspace workspace = workspaceDao.selectWorkspaceById(id);
if (null != workspace) {
+ permCheck(workspace.getWorkspaceName(), AccessType.DELETE);
return workspaceDao.deleteWorkspaceById(id);
}
return false;
@@ -122,7 +130,9 @@ public class WorkspaceServiceImpl extends
SeatunnelBaseServiceImpl implements Wo
@Override
public List<Workspace> getAllWorkspaces() {
- return workspaceDao.selectAllWorkspaces();
+ return workspaceDao.selectAllWorkspaces().stream()
+ .filter(workspace -> hasReadPerm(workspace.getWorkspaceName()))
+ .collect(Collectors.toList());
}
@Override
@@ -130,22 +140,6 @@ public class WorkspaceServiceImpl extends
SeatunnelBaseServiceImpl implements Wo
return getWorkspace("default");
}
- @Override
- public Long getWorkspaceIdOrDefault(Long workspaceId) {
- if (workspaceId == null || workspaceId == 0 || workspaceId == 1) {
- return getDefaultWorkspace().getId();
- } else {
- // Check if the workspace exists
- Workspace workspaceById = getWorkspace(workspaceId);
- if (workspaceById == null) {
- throw new SeatunnelException(
- SeatunnelErrorEnum.RESOURCE_NOT_FOUND,
- "Workspace with id " + workspaceId + " not found.");
- }
- return workspaceById.getId();
- }
- }
-
public Long getWorkspaceIdOrCurrent(String workspaceName) {
if (StringUtils.isEmpty(workspaceName)) {
// get names from current workspace
@@ -154,4 +148,20 @@ public class WorkspaceServiceImpl extends
SeatunnelBaseServiceImpl implements Wo
return getWorkspace(workspaceName).getId();
}
}
+
+ private void permCheck(String resourceName, AccessType accessType) {
+ permissionCheck(
+ resourceName,
+ ResourceType.WORKSPACE,
+ accessType,
+ UserContextHolder.getAccessInfo());
+ }
+
+ private boolean hasReadPerm(String resourceName) {
+ return hasPermission(
+ resourceName,
+ ResourceType.WORKSPACE,
+ AccessType.READ,
+ UserContextHolder.getAccessInfo());
+ }
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/utils/GlobalExceptionHandler.java
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/utils/GlobalExceptionHandler.java
index f7d22b7d..f18ebe7f 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/utils/GlobalExceptionHandler.java
+++
b/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/utils/GlobalExceptionHandler.java
@@ -18,6 +18,7 @@
package org.apache.seatunnel.app.utils;
import org.apache.seatunnel.app.common.Result;
+import org.apache.seatunnel.common.access.AccessDeniedException;
import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginException;
import org.apache.seatunnel.server.common.ParamValidationException;
import org.apache.seatunnel.server.common.SeatunnelErrorEnum;
@@ -88,4 +89,9 @@ public class GlobalExceptionHandler {
private Result<String> paramValidationHandler(SeatunnelException e) {
return Result.failure(e);
}
+
+ @ExceptionHandler(value = AccessDeniedException.class)
+ private Result<String> paramValidationHandler(AccessDeniedException e) {
+ return Result.failure(SeatunnelErrorEnum.ACCESS_DENIED,
e.getMessage());
+ }
}
diff --git a/seatunnel-server/seatunnel-app/src/main/resources/application.yml
b/seatunnel-server/seatunnel-app/src/main/resources/application.yml
index a90a6366..57117794 100644
--- a/seatunnel-server/seatunnel-app/src/main/resources/application.yml
+++ b/seatunnel-server/seatunnel-app/src/main/resources/application.yml
@@ -59,6 +59,7 @@ seatunnel-web:
keys-to-encrypt:
- password
- auth
+ access-controller-class:
org.apache.seatunnel.app.permission.SeatunnelAccessControllerDefaultImpl
---
spring:
config:
diff --git
a/seatunnel-server/seatunnel-server-common/src/main/java/org/apache/seatunnel/server/common/SeatunnelErrorEnum.java
b/seatunnel-server/seatunnel-server-common/src/main/java/org/apache/seatunnel/server/common/SeatunnelErrorEnum.java
index 5318b550..77afcff9 100644
---
a/seatunnel-server/seatunnel-server-common/src/main/java/org/apache/seatunnel/server/common/SeatunnelErrorEnum.java
+++
b/seatunnel-server/seatunnel-server-common/src/main/java/org/apache/seatunnel/server/common/SeatunnelErrorEnum.java
@@ -140,7 +140,8 @@ public enum SeatunnelErrorEnum {
INVALID_PARAM(60019, "", "param [%s] is invalid. %s"),
TASK_NAME_ALREADY_EXISTS(60020, "task name already exists", "task [%s]
already exists"),
RESOURCE_NOT_FOUND(404, "", "%s"),
- RESOURCE_ALREADY_EXISTS(60021, "resource already exists", "resource [%s]
already exists");
+ RESOURCE_ALREADY_EXISTS(60021, "resource already exists", "resource [%s]
already exists"),
+ ACCESS_DENIED(403, "Access denied", "%s");
private final int code;
private final String msg;
diff --git a/seatunnel-web-common/pom.xml b/seatunnel-web-common/pom.xml
new file mode 100644
index 00000000..e74ae266
--- /dev/null
+++ b/seatunnel-web-common/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.seatunnel</groupId>
+ <artifactId>seatunnel-web</artifactId>
+ <version>${revision}</version>
+ </parent>
+ <artifactId>seatunnel-web-common</artifactId>
+</project>
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/AccessDeniedException.java
similarity index 56%
copy from
seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
copy to
seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/AccessDeniedException.java
index 8897779a..c18a3c02 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
+++
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/AccessDeniedException.java
@@ -14,19 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.seatunnel.app.security;
-import org.apache.seatunnel.app.dal.entity.User;
+package org.apache.seatunnel.common.access;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
+public class AccessDeniedException extends RuntimeException {
+ public AccessDeniedException(String message) {
+ super(message);
+ }
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class UserContext {
- User user;
- Long workspaceId;
- String workspaceName;
+ public static void accessDenied(
+ String userName,
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType) {
+ throw new AccessDeniedException(
+ String.format(
+ "Access denied: user=%s, resource=%s,
resource-type=%s, operation=%s",
+ userName, resourceName, resourceType.getName(),
accessType.getName()));
+ }
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/AccessInfo.java
similarity index 74%
copy from
seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
copy to
seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/AccessInfo.java
index 8897779a..7ed8f39c 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
+++
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/AccessInfo.java
@@ -14,19 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.seatunnel.app.security;
-import org.apache.seatunnel.app.dal.entity.User;
+package org.apache.seatunnel.common.access;
-import lombok.AllArgsConstructor;
import lombok.Data;
-import lombok.NoArgsConstructor;
+
+import java.util.Set;
@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class UserContext {
- User user;
- Long workspaceId;
- String workspaceName;
+public class AccessInfo {
+ private String username;
+ private String workspaceName;
+ private Set<String> userGroups;
+ private Set<String> userRoles;
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/AccessType.java
similarity index 71%
copy from
seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
copy to
seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/AccessType.java
index 8897779a..b8f12a99 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
+++
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/AccessType.java
@@ -14,19 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.seatunnel.app.security;
-import org.apache.seatunnel.app.dal.entity.User;
+package org.apache.seatunnel.common.access;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
+public enum AccessType {
+ CREATE,
+ READ,
+ UPDATE,
+ DELETE,
+ EXECUTE;
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class UserContext {
- User user;
- Long workspaceId;
- String workspaceName;
+ public String getName() {
+ return this.name().toLowerCase();
+ }
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/ResourceType.java
similarity index 71%
copy from
seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
copy to
seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/ResourceType.java
index 8897779a..2a1bc67b 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
+++
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/ResourceType.java
@@ -14,19 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.seatunnel.app.security;
+package org.apache.seatunnel.common.access;
-import org.apache.seatunnel.app.dal.entity.User;
+public enum ResourceType {
+ WORKSPACE,
+ DATASOURCE,
+ JOB,
+ USER,
+ VIRTUAL_TABLE;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class UserContext {
- User user;
- Long workspaceId;
- String workspaceName;
+ public String getName() {
+ return this.name().toLowerCase();
+ }
}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/JobLineMapper.java
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/SeatunnelAccessController.java
similarity index 65%
copy from
seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/JobLineMapper.java
copy to
seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/SeatunnelAccessController.java
index 9317520a..06a8ad4e 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/dal/mapper/JobLineMapper.java
+++
b/seatunnel-web-common/src/main/java/org/apache/seatunnel/common/access/SeatunnelAccessController.java
@@ -14,20 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package org.apache.seatunnel.app.dal.mapper;
-
-import org.apache.seatunnel.app.dal.entity.JobLine;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-
-import java.util.List;
-
-public interface JobLineMapper extends BaseMapper<JobLine> {
-
- void deleteLinesByVersionId(@Param("versionId") long jobVersionId);
-
- void insertBatchLines(@Param("lines") List<JobLine> lines);
+package org.apache.seatunnel.common.access;
+
+public interface SeatunnelAccessController {
+ void authorizeAccess(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo);
+
+ boolean hasPermission(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo);
}
diff --git
a/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/common/AccessControllerTestingImp.java
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/common/AccessControllerTestingImp.java
new file mode 100644
index 00000000..94e052cb
--- /dev/null
+++
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/common/AccessControllerTestingImp.java
@@ -0,0 +1,105 @@
+/*
+ * 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.seatunnel.app.common;
+
+import org.apache.seatunnel.common.access.AccessDeniedException;
+import org.apache.seatunnel.common.access.AccessInfo;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
+import org.apache.seatunnel.common.access.SeatunnelAccessController;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class is intended to provide basic access control functionality for
testing purposes, rather
+ * than simulating a full-fledged Ranger access controller.
+ */
+public class AccessControllerTestingImp implements SeatunnelAccessController {
+ private static boolean isAccessControllerEnabled = false;
+ private static final Map<String, List<ResourcePermissionData>>
permissionList = new HashMap<>();
+
+ public static void resetResourcePermission(String username,
ResourcePermissionData permission) {
+ clearPermission();
+ addResourcePermission(username, permission);
+ }
+
+ public static void addResourcePermission(String username,
ResourcePermissionData permission) {
+ List<ResourcePermissionData> resourcePermissionDataList =
+ permissionList.computeIfAbsent(username, k -> new
ArrayList<>());
+ resourcePermissionDataList.add(permission);
+ }
+
+ public static void enableAccessController() {
+ isAccessControllerEnabled = true;
+ }
+
+ public static void disableAccessController() {
+ isAccessControllerEnabled = false;
+ }
+
+ public static void clearPermission() {
+ permissionList.clear();
+ }
+
+ @Override
+ public void authorizeAccess(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo) {
+ if (!hasPermission(resourceName, resourceType, accessType,
accessInfo)) {
+ AccessDeniedException.accessDenied(
+ accessInfo.getUsername(), resourceName, resourceType,
accessType);
+ }
+ }
+
+ @Override
+ public boolean hasPermission(
+ String resourceName,
+ ResourceType resourceType,
+ AccessType accessType,
+ AccessInfo accessInfo) {
+ if (!isAccessControllerEnabled) {
+ return true;
+ }
+ List<ResourcePermissionData> permissions =
permissionList.get(accessInfo.getUsername());
+ if (permissions != null) {
+ for (ResourcePermissionData permission : permissions) {
+ if (resourceType == ResourceType.USER || resourceType ==
ResourceType.WORKSPACE) {
+ // Do not consider workspace name
+ if (permission.getResourceName().equals(resourceName)
+ && permission.getResourceType() == resourceType
+ &&
permission.getAccessTypes().contains(accessType)) {
+ return true;
+ }
+ } else {
+ if
(permission.getWorkspaceName().equals(accessInfo.getWorkspaceName())
+ &&
permission.getResourceName().equals(resourceName)
+ && permission.getResourceType() == resourceType
+ &&
permission.getAccessTypes().contains(accessType)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/common/ResourcePermissionData.java
similarity index 76%
copy from
seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
copy to
seatunnel-web-it/src/test/java/org/apache/seatunnel/app/common/ResourcePermissionData.java
index 8897779a..06e5050a 100644
---
a/seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/security/UserContext.java
+++
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/common/ResourcePermissionData.java
@@ -14,19 +14,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.seatunnel.app.security;
+package org.apache.seatunnel.app.common;
-import org.apache.seatunnel.app.dal.entity.User;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
+import java.util.List;
+
@Data
@AllArgsConstructor
@NoArgsConstructor
-public class UserContext {
- User user;
- Long workspaceId;
+public class ResourcePermissionData {
String workspaceName;
+ String resourceName;
+ ResourceType resourceType;
+ List<AccessType> accessTypes;
}
diff --git
a/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/controller/JobDefinitionControllerWrapper.java
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/controller/JobDefinitionControllerWrapper.java
index ccff9c3c..3a76371d 100644
---
a/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/controller/JobDefinitionControllerWrapper.java
+++
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/controller/JobDefinitionControllerWrapper.java
@@ -25,9 +25,11 @@ import
org.apache.seatunnel.app.domain.response.job.JobDefinitionRes;
import org.apache.seatunnel.app.utils.JSONTestUtils;
import org.apache.seatunnel.common.constants.JobMode;
import org.apache.seatunnel.common.utils.JsonUtils;
+import org.apache.seatunnel.server.common.SeatunnelErrorEnum;
import com.fasterxml.jackson.core.type.TypeReference;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class JobDefinitionControllerWrapper extends SeatunnelWebTestingBase {
@@ -48,6 +50,15 @@ public class JobDefinitionControllerWrapper extends
SeatunnelWebTestingBase {
return result.getData();
}
+ public void createJobExpectingFailure(String jobName) {
+ JobReq jobReq = new JobReq();
+ jobReq.setName(jobName);
+ jobReq.setDescription(jobName + " description");
+ jobReq.setJobType(BusinessMode.DATA_INTEGRATION);
+ Result<Long> result = createJobDefinition(jobReq);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
result.getCode());
+ }
+
public Result<PageInfo<JobDefinitionRes>> getJobDefinition(
String searchName, Integer pageNo, Integer pageSize, JobMode
jobMode) {
String response =
diff --git
a/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/controller/SeatunnelDatasourceControllerWrapper.java
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/controller/SeatunnelDatasourceControllerWrapper.java
index 3f2af1f2..d8fd642c 100644
---
a/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/controller/SeatunnelDatasourceControllerWrapper.java
+++
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/controller/SeatunnelDatasourceControllerWrapper.java
@@ -25,9 +25,13 @@ import
org.apache.seatunnel.app.domain.response.datasource.DatasourceDetailRes;
import org.apache.seatunnel.app.domain.response.datasource.DatasourceRes;
import org.apache.seatunnel.app.utils.JSONTestUtils;
import org.apache.seatunnel.common.utils.JsonUtils;
+import org.apache.seatunnel.server.common.SeatunnelErrorEnum;
import com.fasterxml.jackson.core.type.TypeReference;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class SeatunnelDatasourceControllerWrapper extends
SeatunnelWebTestingBase {
@@ -39,6 +43,12 @@ public class SeatunnelDatasourceControllerWrapper extends
SeatunnelWebTestingBas
return result.getData();
}
+ public void createDatasourceExpectingFailure(String datasourceName) {
+ DatasourceReq req = getFakeSourceDatasourceReq(datasourceName);
+ Result<String> result = createDatasource(req);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
result.getCode());
+ }
+
public String createConsoleDatasource(String datasourceName) {
DatasourceReq req = getConsoleDatasourceReq(datasourceName);
Result<String> result = createDatasource(req);
@@ -121,4 +131,17 @@ public class SeatunnelDatasourceControllerWrapper extends
SeatunnelWebTestingBas
"{\"url\":\"jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&allowPublicKeyRetrieval=true\",\"driver\":\"com.mysql.cj.jdbc.Driver\",\"user\":\"someUser\",\"password\":\"somePassword\"}");
return req;
}
+
+ public Result<List<String>> getDatasourceNames(String namePrefix) {
+ String response;
+ if (namePrefix == null) {
+ response = sendRequest(String.format("%s/datasource/names",
baseUrl));
+ } else {
+ response =
+ sendRequest(
+ String.format(
+ "%s/datasource/names?namePrefix=%s",
baseUrl, namePrefix));
+ }
+ return JSONTestUtils.parseObject(response, new
TypeReference<Result<List<String>>>() {});
+ }
}
diff --git
a/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/test/SeatunnelAccessControllerTest.java
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/test/SeatunnelAccessControllerTest.java
new file mode 100644
index 00000000..6aa69b69
--- /dev/null
+++
b/seatunnel-web-it/src/test/java/org/apache/seatunnel/app/test/SeatunnelAccessControllerTest.java
@@ -0,0 +1,790 @@
+/*
+ * 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.seatunnel.app.test;
+
+import org.apache.seatunnel.app.common.AccessControllerTestingImp;
+import org.apache.seatunnel.app.common.ResourcePermissionData;
+import org.apache.seatunnel.app.common.Result;
+import org.apache.seatunnel.app.common.SeaTunnelWebCluster;
+import org.apache.seatunnel.app.controller.JobConfigControllerWrapper;
+import org.apache.seatunnel.app.controller.JobControllerWrapper;
+import org.apache.seatunnel.app.controller.JobDefinitionControllerWrapper;
+import org.apache.seatunnel.app.controller.JobExecutorControllerWrapper;
+import
org.apache.seatunnel.app.controller.SeatunnelDatasourceControllerWrapper;
+import org.apache.seatunnel.app.controller.UserControllerWrapper;
+import org.apache.seatunnel.app.controller.WorkspaceControllerWrapper;
+import org.apache.seatunnel.app.dal.entity.Workspace;
+import org.apache.seatunnel.app.domain.request.datasource.DatasourceReq;
+import org.apache.seatunnel.app.domain.request.job.JobConfig;
+import org.apache.seatunnel.app.domain.request.job.JobCreateReq;
+import org.apache.seatunnel.app.domain.request.user.AddUserReq;
+import org.apache.seatunnel.app.domain.request.user.UpdateUserReq;
+import org.apache.seatunnel.app.domain.request.user.UserLoginReq;
+import org.apache.seatunnel.app.domain.request.workspace.WorkspaceReq;
+import org.apache.seatunnel.app.domain.response.PageInfo;
+import org.apache.seatunnel.app.domain.response.datasource.DatasourceDetailRes;
+import org.apache.seatunnel.app.domain.response.datasource.DatasourceRes;
+import org.apache.seatunnel.app.domain.response.job.JobConfigRes;
+import org.apache.seatunnel.app.domain.response.job.JobDefinitionRes;
+import org.apache.seatunnel.app.domain.response.job.JobRes;
+import org.apache.seatunnel.app.domain.response.user.AddUserRes;
+import org.apache.seatunnel.app.domain.response.user.UserSimpleInfoRes;
+import org.apache.seatunnel.app.utils.JobTestingUtils;
+import org.apache.seatunnel.common.access.AccessType;
+import org.apache.seatunnel.common.access.ResourceType;
+import org.apache.seatunnel.common.constants.JobMode;
+import org.apache.seatunnel.server.common.SeatunnelErrorEnum;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class SeatunnelAccessControllerTest {
+ private static final SeaTunnelWebCluster seaTunnelWebCluster = new
SeaTunnelWebCluster();
+ private static WorkspaceControllerWrapper workspaceControllerWrapper;
+ private static UserControllerWrapper userControllerWrapper;
+ private static SeatunnelDatasourceControllerWrapper
datasourceControllerWrapper;
+ private static JobDefinitionControllerWrapper
jobDefinitionControllerWrapper;
+ private static JobConfigControllerWrapper jobConfigControllerWrapper;
+ private static JobControllerWrapper jobControllerWrapper;
+ private static JobExecutorControllerWrapper jobExecutorControllerWrapper;
+ private static final String uniqueId = "_" + System.currentTimeMillis();
+
+ @BeforeAll
+ public static void setUp() {
+ seaTunnelWebCluster.start();
+ workspaceControllerWrapper = new WorkspaceControllerWrapper();
+ userControllerWrapper = new UserControllerWrapper();
+ datasourceControllerWrapper = new
SeatunnelDatasourceControllerWrapper();
+ jobDefinitionControllerWrapper = new JobDefinitionControllerWrapper();
+ jobConfigControllerWrapper = new JobConfigControllerWrapper();
+ jobControllerWrapper = new JobControllerWrapper();
+ jobExecutorControllerWrapper = new JobExecutorControllerWrapper();
+ AccessControllerTestingImp.enableAccessController();
+ }
+
+ @Test
+ public void testWorkspaceAccessPermission() {
+ String user1 = "admin";
+ String workspaceName = "workspace_access_workspace" + uniqueId;
+
+ Result<Long> createWorkspaceResult =
+ workspaceControllerWrapper.createWorkspace(workspaceName);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
createWorkspaceResult.getCode());
+
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ null,
+ workspaceName,
+ ResourceType.WORKSPACE,
+ Collections.singletonList(AccessType.CREATE)));
+ createWorkspaceResult =
workspaceControllerWrapper.createWorkspace(workspaceName);
+ assertTrue(createWorkspaceResult.isSuccess());
+
+ // Handle read operation
+ AccessControllerTestingImp.clearPermission();
+ Result<List<Workspace>> getWorkspaces =
workspaceControllerWrapper.getAllWorkspaces();
+ assertTrue(getWorkspaces.isSuccess());
+ assertEquals(0, getWorkspaces.getData().size());
+
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ null,
+ workspaceName,
+ ResourceType.WORKSPACE,
+ Collections.singletonList(AccessType.READ)));
+
+ getWorkspaces = workspaceControllerWrapper.getAllWorkspaces();
+ assertTrue(getWorkspaces.isSuccess());
+ assertEquals(1, getWorkspaces.getData().size());
+
+ String anotherWorkspace = "another_workspace_access" + uniqueId;
+ AccessControllerTestingImp.clearPermission();
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ null,
+ anotherWorkspace,
+ ResourceType.WORKSPACE,
+ Collections.singletonList(AccessType.CREATE)));
+ Result<Long> anotherCreateWorkspaceResult =
+ workspaceControllerWrapper.createWorkspace(anotherWorkspace);
+ assertTrue(anotherCreateWorkspaceResult.isSuccess());
+
+ getWorkspaces = workspaceControllerWrapper.getAllWorkspaces();
+ assertTrue(anotherCreateWorkspaceResult.isSuccess());
+ assertEquals(0, getWorkspaces.getData().size());
+
+ AccessControllerTestingImp.clearPermission();
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ null,
+ workspaceName,
+ ResourceType.WORKSPACE,
+ Collections.singletonList(AccessType.READ)));
+ AccessControllerTestingImp.addResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ null,
+ anotherWorkspace,
+ ResourceType.WORKSPACE,
+ Collections.singletonList(AccessType.READ)));
+ getWorkspaces = workspaceControllerWrapper.getAllWorkspaces();
+ assertTrue(anotherCreateWorkspaceResult.isSuccess());
+ assertEquals(2, getWorkspaces.getData().size());
+
+ // Handle update operation
+ AccessControllerTestingImp.clearPermission();
+ WorkspaceReq updateWorkspaceReq =
+ new WorkspaceReq(workspaceName + "_new", "new description");
+ Result<Boolean> updateResult =
+ workspaceControllerWrapper.updateWorkspace(
+ createWorkspaceResult.getData(), updateWorkspaceReq);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
updateResult.getCode());
+
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ null,
+ workspaceName,
+ ResourceType.WORKSPACE,
+ Collections.singletonList(AccessType.UPDATE)));
+ updateResult =
+ workspaceControllerWrapper.updateWorkspace(
+ createWorkspaceResult.getData(), updateWorkspaceReq);
+ assertTrue(updateResult.isSuccess(), updateResult.getMsg());
+
+ // Handle delete operation
+ AccessControllerTestingImp.clearPermission();
+ Result<Boolean> deleteResult =
+
workspaceControllerWrapper.deleteWorkspace(createWorkspaceResult.getData());
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
deleteResult.getCode());
+
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ null,
+ updateWorkspaceReq.getWorkspaceName(),
+ ResourceType.WORKSPACE,
+ Collections.singletonList(AccessType.DELETE)));
+ deleteResult =
workspaceControllerWrapper.deleteWorkspace(createWorkspaceResult.getData());
+ assertTrue(deleteResult.isSuccess(), deleteResult.getMsg());
+ }
+
+ @Test
+ public void testUserAccessPermission() {
+ String user1 = "user_access_user_1" + uniqueId;
+ String pass = "somePassword";
+ String workspaceName = "workspace_access_user" + uniqueId;
+
+ List<AccessType> accessTypes = new ArrayList<>();
+ accessTypes.add(AccessType.CREATE);
+
+ createWorkspaceAndUser(workspaceName, user1, pass);
+ login(new UserLoginReq(user1, pass, workspaceName));
+
+ // Handle create operation
+ accessTypes.clear();
+ String newUser = "new_user_access" + uniqueId;
+ Result<AddUserRes> addUserResult =
+ userControllerWrapper.addUser(getAddUserReq(newUser, pass));
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
addUserResult.getCode());
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, newUser,
ResourceType.USER, accessTypes));
+ // should be successful as user1 has access to create user
+ addUserResult = userControllerWrapper.addUser(getAddUserReq(newUser,
pass));
+ assertTrue(addUserResult.isSuccess());
+
+ // Handle read operation
+ Result<PageInfo<UserSimpleInfoRes>> getUsers =
userControllerWrapper.listUsers(newUser);
+ assertTrue(getUsers.isSuccess());
+ assertEquals(0, getUsers.getData().getData().size());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.READ);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, newUser,
ResourceType.USER, accessTypes));
+ getUsers = userControllerWrapper.listUsers(newUser);
+ assertTrue(getUsers.isSuccess());
+ assertEquals(1, getUsers.getData().getData().size());
+
+ String anotherUser = "another_user_access" + uniqueId;
+ accessTypes.clear();
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName, anotherUser, ResourceType.USER,
accessTypes));
+ Result<AddUserRes> anotherAddUserResult =
+ userControllerWrapper.addUser(getAddUserReq(anotherUser,
pass));
+ assertTrue(anotherAddUserResult.isSuccess());
+
+ Result<PageInfo<UserSimpleInfoRes>> listUsers =
userControllerWrapper.listUsers();
+ assertTrue(anotherAddUserResult.isSuccess());
+ assertEquals(0, listUsers.getData().getData().size());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.READ);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, newUser,
ResourceType.USER, accessTypes));
+ AccessControllerTestingImp.addResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName, anotherUser, ResourceType.USER,
accessTypes));
+ listUsers = userControllerWrapper.listUsers();
+ assertTrue(listUsers.isSuccess());
+ assertEquals(2, listUsers.getData().getData().size());
+
+ // Handle update operation
+ UpdateUserReq updateUserReq = new UpdateUserReq();
+ updateUserReq.setUsername(newUser);
+ updateUserReq.setUserId(addUserResult.getData().getId());
+ updateUserReq.setPassword("newPassword");
+ updateUserReq.setStatus((byte) 0);
+ updateUserReq.setType((byte) 0);
+ Result<Void> updateResult =
+ userControllerWrapper.updateUser(
+ String.valueOf(updateUserReq.getUserId()),
updateUserReq);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
updateResult.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.UPDATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, newUser,
ResourceType.USER, accessTypes));
+ updateResult =
+ userControllerWrapper.updateUser(
+ String.valueOf(updateUserReq.getUserId()),
updateUserReq);
+ assertTrue(updateResult.isSuccess(), updateResult.getMsg());
+
+ // Handle disable operation
+ AccessControllerTestingImp.clearPermission();
+ Result<Void> disableResult =
+
userControllerWrapper.disableUser(String.valueOf(updateUserReq.getUserId()));
+ assertEquals(
+ SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
+ disableResult.getCode(),
+ disableResult.getMsg());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.UPDATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, newUser,
ResourceType.USER, accessTypes));
+ disableResult =
+
userControllerWrapper.disableUser(String.valueOf(updateUserReq.getUserId()));
+ assertTrue(disableResult.isSuccess());
+
+ // Handle enable operation
+ AccessControllerTestingImp.clearPermission();
+ Result<Void> enableResult =
+
userControllerWrapper.enableUser(String.valueOf(updateUserReq.getUserId()));
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
enableResult.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.UPDATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, newUser,
ResourceType.USER, accessTypes));
+ enableResult =
userControllerWrapper.enableUser(String.valueOf(updateUserReq.getUserId()));
+ assertTrue(enableResult.isSuccess());
+
+ // Handle delete operation
+ AccessControllerTestingImp.clearPermission();
+ Result<Void> deleteResult =
+
userControllerWrapper.deleteUser(String.valueOf(addUserResult.getData().getId()));
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
deleteResult.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.DELETE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, newUser,
ResourceType.USER, accessTypes));
+ deleteResult =
+
userControllerWrapper.deleteUser(String.valueOf(addUserResult.getData().getId()));
+ assertTrue(deleteResult.isSuccess());
+ }
+
+ @Test
+ public void testDatasourceAccessPermission() {
+ String user1 = "user_access_datasource_1" + uniqueId;
+ String user2 = "user_access_datasource_2" + uniqueId;
+ String pass = "somePassword";
+ String workspaceName = "workspace_access_datasource" + uniqueId;
+
+ // create workspaces and users using admin credentials
+ createWorkspaceAndUser(workspaceName, user1, pass);
+ createUserAndVerify(user2, pass);
+
+ login(new UserLoginReq(user1, pass, workspaceName));
+
+ // Handle create operation
+ String datasourceName1 = "1_datasource_access" + uniqueId;
+
datasourceControllerWrapper.createDatasourceExpectingFailure(datasourceName1);
+ List<AccessType> accessTypes = new ArrayList<>();
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName, datasourceName1,
ResourceType.DATASOURCE, accessTypes));
+ // should be successful as user1 has access to create datasource
+ String datasourceId1 =
+
datasourceControllerWrapper.createFakeSourceDatasource(datasourceName1);
+
+ Result<DatasourceDetailRes> getDataSource =
+ datasourceControllerWrapper.getDatasource(datasourceId1);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
getDataSource.getCode());
+
+ // Handle read operation
+ accessTypes.clear();
+ accessTypes.add(AccessType.READ);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName, datasourceName1,
ResourceType.DATASOURCE, accessTypes));
+ getDataSource =
datasourceControllerWrapper.getDatasource(datasourceId1);
+ assertTrue(getDataSource.isSuccess());
+
+ // Handle update operation
+ DatasourceReq req = new DatasourceReq();
+ req.setDescription(getDataSource.getData().getDescription() + " new
description");
+ Result<Boolean> updateResult =
+ datasourceControllerWrapper.updateDatasource(datasourceId1,
req);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
updateResult.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.UPDATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName, datasourceName1,
ResourceType.DATASOURCE, accessTypes));
+ updateResult =
datasourceControllerWrapper.updateDatasource(datasourceId1, req);
+ assertTrue(updateResult.isSuccess());
+
+ // Handle delete operation
+ Result<Boolean> deleteResult =
datasourceControllerWrapper.deleteDatasource(datasourceId1);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
deleteResult.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.DELETE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName, datasourceName1,
ResourceType.DATASOURCE, accessTypes));
+ deleteResult =
datasourceControllerWrapper.deleteDatasource(datasourceId1);
+ assertTrue(deleteResult.isSuccess());
+
+ // create again to use in list datasource
+ accessTypes.clear();
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName, datasourceName1,
ResourceType.DATASOURCE, accessTypes));
+
datasourceControllerWrapper.createFakeSourceDatasource(datasourceName1);
+
+ // logout and login with another user
+ userControllerWrapper.logout();
+ login(new UserLoginReq(user2, pass, workspaceName));
+ // Handle list operation
+ String datasourceName2 = "2_datasource_access" + uniqueId;
+ accessTypes.clear();
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user2,
+ new ResourcePermissionData(
+ workspaceName, datasourceName2,
ResourceType.DATASOURCE, accessTypes));
+ String datasourceId2 =
+
datasourceControllerWrapper.createFakeSourceDatasource(datasourceName2);
+ Result<PageInfo<DatasourceRes>> datasourceList =
+ datasourceControllerWrapper.getDatasourceList(
+ "datasource_access" + uniqueId, "FakeSource", 1, 10);
+ assertTrue(datasourceList.isSuccess());
+ assertEquals(0, datasourceList.getData().getData().size());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.READ);
+ AccessControllerTestingImp.resetResourcePermission(
+ user2,
+ new ResourcePermissionData(
+ workspaceName, datasourceName2,
ResourceType.DATASOURCE, accessTypes));
+ datasourceList =
+ datasourceControllerWrapper.getDatasourceList(
+ "datasource_access" + uniqueId, "FakeSource", 1, 10);
+ assertTrue(datasourceList.isSuccess());
+ assertEquals(1, datasourceList.getData().getData().size());
+ assertEquals(datasourceId2,
datasourceList.getData().getData().get(0).getId());
+
+ // Give permission to user2 on datasource created by user1
+ AccessControllerTestingImp.addResourcePermission(
+ user2,
+ new ResourcePermissionData(
+ workspaceName, datasourceName1,
ResourceType.DATASOURCE, accessTypes));
+ datasourceList =
+ datasourceControllerWrapper.getDatasourceList(
+ "datasource_access" + uniqueId, "FakeSource", 1, 10);
+ assertTrue(datasourceList.isSuccess());
+ assertEquals(2, datasourceList.getData().getData().size());
+ }
+
+ @Test
+ public void testJobAccessPermission() {
+ String user1 = "user_access_job_1" + uniqueId;
+ String user2 = "user_access_job_2" + uniqueId;
+ String pass = "somePassword";
+ String workspaceName = "workspace_access_job" + uniqueId;
+
+ // create workspaces and users using admin credentials
+ createWorkspaceAndUser(workspaceName, user1, pass);
+ createUserAndVerify(user2, pass);
+
+ login(new UserLoginReq(user1, pass, workspaceName));
+
+ // Handle create operation
+ String jobName1 = "1_job_access" + uniqueId;
+ jobDefinitionControllerWrapper.createJobExpectingFailure(jobName1);
+ List<AccessType> accessTypes = new ArrayList<>();
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, jobName1,
ResourceType.JOB, accessTypes));
+ // should be successful as user1 has access to create job
+ Long jobId =
jobDefinitionControllerWrapper.createJobDefinition(jobName1);
+
+ // Handle read operation
+ Result<JobDefinitionRes> getJob =
+ jobDefinitionControllerWrapper.getJobDefinitionById(jobId);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
getJob.getCode());
+
+ Result<JobConfigRes> getJobConfig =
jobConfigControllerWrapper.getJobConfig(jobId);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
getJobConfig.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.READ);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, jobName1,
ResourceType.JOB, accessTypes));
+ getJob = jobDefinitionControllerWrapper.getJobDefinitionById(jobId);
+ assertTrue(getJob.isSuccess());
+
+ getJobConfig = jobConfigControllerWrapper.getJobConfig(jobId);
+ assertTrue(getJobConfig.isSuccess());
+
+ // Handle update operation
+ AccessControllerTestingImp.clearPermission();
+ JobConfig jobConfig =
jobConfigControllerWrapper.populateJobConfigObject(jobName1);
+ Result<Void> updateResult =
jobConfigControllerWrapper.updateJobConfig(jobId, jobConfig);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
updateResult.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.UPDATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, jobName1,
ResourceType.JOB, accessTypes));
+ updateResult = jobConfigControllerWrapper.updateJobConfig(jobId,
jobConfig);
+ assertTrue(updateResult.isSuccess());
+
+ // Handle delete operation
+ Result<Void> deleteResult =
jobDefinitionControllerWrapper.deleteJobDefinition(jobId);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
deleteResult.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.DELETE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, jobName1,
ResourceType.JOB, accessTypes));
+ deleteResult =
jobDefinitionControllerWrapper.deleteJobDefinition(jobId);
+ assertTrue(deleteResult.isSuccess());
+
+ // create again to use in list job
+ accessTypes.clear();
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, jobName1,
ResourceType.JOB, accessTypes));
+ jobDefinitionControllerWrapper.createJobDefinition(jobName1);
+
+ // logout and login with another user
+ userControllerWrapper.logout();
+ login(new UserLoginReq(user2, pass, workspaceName));
+ // Handle list operation
+ String jobName2 = "2_job_access" + uniqueId;
+ accessTypes.clear();
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user2,
+ new ResourcePermissionData(workspaceName, jobName2,
ResourceType.JOB, accessTypes));
+ Long jobId2 =
jobDefinitionControllerWrapper.createJobDefinition(jobName2);
+ Result<PageInfo<JobDefinitionRes>> jobList =
+ jobDefinitionControllerWrapper.getJobDefinition(
+ "job_access" + uniqueId, 1, 10, JobMode.BATCH);
+ assertTrue(jobList.isSuccess());
+ assertEquals(0, jobList.getData().getData().size());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.READ);
+ AccessControllerTestingImp.resetResourcePermission(
+ user2,
+ new ResourcePermissionData(workspaceName, jobName2,
ResourceType.JOB, accessTypes));
+ jobList =
+ jobDefinitionControllerWrapper.getJobDefinition(
+ "job_access" + uniqueId, 1, 10, JobMode.BATCH);
+ assertTrue(jobList.isSuccess());
+ assertEquals(1, jobList.getData().getData().size());
+ assertEquals(jobId2, jobList.getData().getData().get(0).getId());
+
+ // Give permission to user2 on job created by user1
+ AccessControllerTestingImp.addResourcePermission(
+ user2,
+ new ResourcePermissionData(workspaceName, jobName1,
ResourceType.JOB, accessTypes));
+ jobList =
+ jobDefinitionControllerWrapper.getJobDefinition(
+ "job_access" + uniqueId, 1, 10, JobMode.BATCH);
+ assertTrue(jobList.isSuccess());
+ assertEquals(2, jobList.getData().getData().size());
+ }
+
+ @Test
+ public void testJobExecutionAccessPermission() {
+ String userName = "jobExec_user_access" + uniqueId;
+ String pass = "somePassword";
+ String workspaceName = "jobExec_workspace_access" + uniqueId;
+
+ // create workspaces and users using admin credentials
+ createWorkspaceAndUser(workspaceName, userName, pass);
+
+ login(new UserLoginReq(userName, pass, workspaceName));
+
+ String jobName = "execJob_access" + uniqueId;
+ List<AccessType> accessTypes = new ArrayList<>();
+ accessTypes.add(AccessType.CREATE);
+ // job update api is called during job creation,
+ accessTypes.add(AccessType.UPDATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ userName,
+ new ResourcePermissionData(workspaceName, jobName,
ResourceType.JOB, accessTypes));
+ AccessControllerTestingImp.addResourcePermission(
+ userName,
+ new ResourcePermissionData(
+ workspaceName,
+ "source_" + jobName,
+ ResourceType.DATASOURCE,
+ Arrays.asList(AccessType.CREATE, AccessType.READ)));
+
+ AccessControllerTestingImp.addResourcePermission(
+ userName,
+ new ResourcePermissionData(
+ workspaceName,
+ "console_" + jobName,
+ ResourceType.DATASOURCE,
+ Arrays.asList(AccessType.CREATE, AccessType.READ)));
+
+ long jobVersionId = JobTestingUtils.createJob(jobName);
+
+ Result<Long> executionResult =
jobExecutorControllerWrapper.jobExecutor(jobVersionId);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
executionResult.getCode());
+
+ accessTypes.add(AccessType.EXECUTE);
+ AccessControllerTestingImp.resetResourcePermission(
+ userName,
+ new ResourcePermissionData(workspaceName, jobName,
ResourceType.JOB, accessTypes));
+ AccessControllerTestingImp.addResourcePermission(
+ userName,
+ new ResourcePermissionData(
+ workspaceName,
+ "source_" + jobName,
+ ResourceType.DATASOURCE,
+ Collections.singletonList(AccessType.READ)));
+
+ AccessControllerTestingImp.addResourcePermission(
+ userName,
+ new ResourcePermissionData(
+ workspaceName,
+ "console_" + jobName,
+ ResourceType.DATASOURCE,
+ Collections.singletonList(AccessType.READ)));
+ executionResult =
jobExecutorControllerWrapper.jobExecutor(jobVersionId);
+ assertTrue(executionResult.isSuccess(), executionResult.getMsg());
+ }
+
+ @Test
+ public void testJobAccessPermissionForSingleJobCreateAPI() {
+ String user1 = "user_access_single_job_1" + uniqueId;
+ String user2 = "user_access_single_job_2" + uniqueId;
+ String pass = "somePassword";
+ String workspaceName = "workspace_access_single_job" + uniqueId;
+
+ // create workspaces and users using admin credentials
+ createWorkspaceAndUser(workspaceName, user1, pass);
+ createUserAndVerify(user2, pass);
+
+ login(new UserLoginReq(user1, pass, workspaceName));
+
+ // Handle create operation
+ String jobName = "access_single_api" + uniqueId;
+ String fsdSourceName = "fake_source_create" + uniqueId;
+ String csSourceName = "console_create" + uniqueId;
+ List<AccessType> accessTypes = new ArrayList<>();
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName, fsdSourceName, ResourceType.DATASOURCE,
accessTypes));
+
+ AccessControllerTestingImp.addResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName, csSourceName, ResourceType.DATASOURCE,
accessTypes));
+ JobCreateReq jobCreateReq =
+ JobTestingUtils.populateJobCreateReqFromFile(jobName,
fsdSourceName, csSourceName);
+ Result<Long> jobCreation =
jobControllerWrapper.createJob(jobCreateReq);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
jobCreation.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.CREATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, jobName,
ResourceType.JOB, accessTypes));
+
+ AccessControllerTestingImp.addResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName,
+ fsdSourceName,
+ ResourceType.DATASOURCE,
+ Collections.singletonList(AccessType.READ)));
+
+ AccessControllerTestingImp.addResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName,
+ csSourceName,
+ ResourceType.DATASOURCE,
+ Collections.singletonList(AccessType.READ)));
+ jobCreation = jobControllerWrapper.createJob(jobCreateReq);
+ assertTrue(jobCreation.isSuccess());
+
+ // Handle read operation
+ Result<JobRes> getJobResponse =
jobControllerWrapper.getJob(jobCreation.getData());
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
getJobResponse.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.READ);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, jobName,
ResourceType.JOB, accessTypes));
+ getJobResponse = jobControllerWrapper.getJob(jobCreation.getData());
+ assertTrue(getJobResponse.isSuccess(), getJobResponse.getMsg());
+
+ // Handle update operation
+ JobCreateReq jobUpdateReq =
+
jobControllerWrapper.convertJobResToJobCreateReq(getJobResponse.getData());
+ Result<Void> updateResult =
+ jobControllerWrapper.updateJob(jobCreation.getData(),
jobUpdateReq);
+ assertEquals(SeatunnelErrorEnum.ACCESS_DENIED.getCode(),
updateResult.getCode());
+
+ accessTypes.clear();
+ accessTypes.add(AccessType.UPDATE);
+ AccessControllerTestingImp.resetResourcePermission(
+ user1,
+ new ResourcePermissionData(workspaceName, jobName,
ResourceType.JOB, accessTypes));
+ AccessControllerTestingImp.addResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName,
+ fsdSourceName,
+ ResourceType.DATASOURCE,
+ Collections.singletonList(AccessType.READ)));
+
+ AccessControllerTestingImp.addResourcePermission(
+ user1,
+ new ResourcePermissionData(
+ workspaceName,
+ csSourceName,
+ ResourceType.DATASOURCE,
+ Collections.singletonList(AccessType.READ)));
+ updateResult = jobControllerWrapper.updateJob(jobCreation.getData(),
jobUpdateReq);
+ assertTrue(updateResult.isSuccess(), updateResult.getMsg());
+ }
+
+ private void createWorkspaceAndUser(String workspaceName, String username,
String password) {
+ AccessControllerTestingImp.resetResourcePermission(
+ "admin",
+ new ResourcePermissionData(
+ null,
+ workspaceName,
+ ResourceType.WORKSPACE,
+ Arrays.asList(AccessType.CREATE, AccessType.UPDATE)));
+ workspaceControllerWrapper.createWorkspaceAndVerify(workspaceName);
+ createUserAndVerify(username, password);
+ }
+
+ private void createUserAndVerify(String username, String password) {
+ AccessControllerTestingImp.addResourcePermission(
+ "admin",
+ new ResourcePermissionData(
+ null,
+ username,
+ ResourceType.USER,
+ Collections.singletonList(AccessType.CREATE)));
+ Result<AddUserRes> result =
+ userControllerWrapper.addUser(getAddUserReq(username,
password));
+ assertTrue(result.isSuccess());
+ }
+
+ private static void login(UserLoginReq userLoginReq) {
+ Result<UserSimpleInfoRes> login =
userControllerWrapper.login(userLoginReq, null, true);
+ assertTrue(login.isSuccess());
+ }
+
+ private AddUserReq getAddUserReq(String user, String pass) {
+ AddUserReq addUserReq = new AddUserReq();
+ addUserReq.setUsername(user);
+ addUserReq.setPassword(pass);
+ addUserReq.setStatus((byte) 0);
+ addUserReq.setType((byte) 0);
+ return addUserReq;
+ }
+
+ @AfterEach
+ public void cleanup() {
+ userControllerWrapper.logout();
+ AccessControllerTestingImp.clearPermission();
+ }
+
+ @AfterAll
+ public static void tearDown() {
+ AccessControllerTestingImp.disableAccessController();
+ seaTunnelWebCluster.stop();
+ }
+}
diff --git a/seatunnel-web-it/src/test/resources/application.yml
b/seatunnel-web-it/src/test/resources/application.yml
index 752fbc7b..d691a712 100644
--- a/seatunnel-web-it/src/test/resources/application.yml
+++ b/seatunnel-web-it/src/test/resources/application.yml
@@ -55,6 +55,7 @@ seatunnel-web:
keys-to-encrypt:
- password
- auth
+ access-controller-class:
org.apache.seatunnel.app.common.AccessControllerTestingImp
---
spring: