Browse Source

[Improvement][api-server] Update the project owner (#5394)

* [Bug][api-server] delete the user ,when query the project by join the table of t_ds_user will return null. (#5326)

* when delete a user, do project ownership check

* fix ut

* fix vulnerability
pull/3/MERGE
ruanwenjun 3 years ago committed by GitHub
parent
commit
cbbe9c333c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectController.java
  2. 1
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
  3. 3
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProjectService.java
  4. 18
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectServiceImpl.java
  5. 12
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java
  6. 3
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/ProjectControllerTest.java
  7. 15
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProjectServiceTest.java
  8. 13
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java
  9. 23
      dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/list/_source/createProject.vue

9
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/ProjectController.java

@ -112,7 +112,8 @@ public class ProjectController extends BaseController {
@ApiImplicitParams({
@ApiImplicitParam(name = "projectId", value = "PROJECT_ID", dataType = "Int", example = "100"),
@ApiImplicitParam(name = "projectName", value = "PROJECT_NAME", dataType = "String"),
@ApiImplicitParam(name = "description", value = "PROJECT_DESC", dataType = "String")
@ApiImplicitParam(name = "description", value = "PROJECT_DESC", dataType = "String"),
@ApiImplicitParam(name = "userName", value = "USER_NAME", dataType = "String"),
})
@PostMapping(value = "/update")
@ResponseStatus(HttpStatus.OK)
@ -120,9 +121,9 @@ public class ProjectController extends BaseController {
public Result updateProject(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@RequestParam("projectId") Integer projectId,
@RequestParam("projectName") String projectName,
@RequestParam(value = "description", required = false) String description) {
logger.info("login user {} , updateProcessInstance project name: {}, desc: {}", loginUser.getUserName(), projectName, description);
Map<String, Object> result = projectService.update(loginUser, projectId, projectName, description);
@RequestParam(value = "description", required = false) String description,
@RequestParam(value = "userName") String userName) {
Map<String, Object> result = projectService.update(loginUser, projectId, projectName, description, userName);
return returnDataList(result);
}

1
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java

@ -210,6 +210,7 @@ public enum Status {
DELETE_WORKER_GROUP_FORBIDDEN_IN_DOCKER(10176, "delete worker group forbidden in docker ", "删除worker分组在docker中禁止"),
WORKER_ADDRESS_INVALID(10177, "worker address {0} invalid", "worker地址[{0}]无效"),
QUERY_WORKER_ADDRESS_LIST_FAIL(10178, "query worker address list fail ", "查询worker地址列表失败"),
TRANSFORM_PROJECT_OWNERSHIP(10179, "Please transform project ownership [{0}]", "请先转移项目所有权[{0}]"),
UDF_FUNCTION_NOT_EXIST(20001, "UDF function not found", "UDF函数不存在"),
UDF_FUNCTION_EXISTS(20002, "UDF function already exists", "UDF函数已存在"),

3
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProjectService.java

@ -84,9 +84,10 @@ public interface ProjectService {
* @param projectId project id
* @param projectName project name
* @param desc description
* @param userName project owner
* @return update result code
*/
Map<String, Object> update(User loginUser, Integer projectId, String projectName, String desc);
Map<String, Object> update(User loginUser, Integer projectId, String projectName, String desc, String userName);
/**
* query unauthorized project

18
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProjectServiceImpl.java

@ -31,6 +31,7 @@ import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectUserMapper;
import org.apache.dolphinscheduler.dao.mapper.UserMapper;
import java.util.ArrayList;
import java.util.Date;
@ -40,6 +41,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -61,6 +64,11 @@ public class ProjectServiceImpl extends BaseServiceImpl implements ProjectServic
@Autowired
private ProcessDefinitionMapper processDefinitionMapper;
@Autowired
private UserMapper userMapper;
private Logger logger = LoggerFactory.getLogger(ProjectServiceImpl.class);
/**
* create project
*
@ -255,10 +263,11 @@ public class ProjectServiceImpl extends BaseServiceImpl implements ProjectServic
* @param projectId project id
* @param projectName project name
* @param desc description
* @param userName project owner
* @return update result code
*/
@Override
public Map<String, Object> update(User loginUser, Integer projectId, String projectName, String desc) {
public Map<String, Object> update(User loginUser, Integer projectId, String projectName, String desc, String userName) {
Map<String, Object> result = new HashMap<>();
Map<String, Object> descCheck = checkDesc(desc);
@ -276,10 +285,15 @@ public class ProjectServiceImpl extends BaseServiceImpl implements ProjectServic
putMsg(result, Status.PROJECT_ALREADY_EXISTS, projectName);
return result;
}
User user = userMapper.queryByUserNameAccurately(userName);
if (user == null) {
putMsg(result, Status.USER_NOT_EXIST, userName);
return result;
}
project.setName(projectName);
project.setDescription(desc);
project.setUpdateTime(new Date());
project.setUserId(user.getId());
int update = projectMapper.updateById(project);
if (update > 0) {
putMsg(result, Status.SUCCESS);

12
dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java

@ -36,6 +36,7 @@ import org.apache.dolphinscheduler.common.utils.PropertyUtils;
import org.apache.dolphinscheduler.common.utils.StringUtils;
import org.apache.dolphinscheduler.dao.entity.AlertGroup;
import org.apache.dolphinscheduler.dao.entity.DatasourceUser;
import org.apache.dolphinscheduler.dao.entity.Project;
import org.apache.dolphinscheduler.dao.entity.ProjectUser;
import org.apache.dolphinscheduler.dao.entity.Resource;
import org.apache.dolphinscheduler.dao.entity.ResourcesUser;
@ -45,6 +46,7 @@ import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper;
import org.apache.dolphinscheduler.dao.mapper.DataSourceUserMapper;
import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectUserMapper;
import org.apache.dolphinscheduler.dao.mapper.ResourceMapper;
import org.apache.dolphinscheduler.dao.mapper.ResourceUserMapper;
@ -108,6 +110,9 @@ public class UsersServiceImpl extends BaseServiceImpl implements UsersService {
@Autowired
private ProcessDefinitionMapper processDefinitionMapper;
@Autowired
private ProjectMapper projectMapper;
/**
* create user, only system admin have permission
@ -490,6 +495,13 @@ public class UsersServiceImpl extends BaseServiceImpl implements UsersService {
putMsg(result, Status.USER_NOT_EXIST, id);
return result;
}
// check if is a project owner
List<Project> projects = projectMapper.queryProjectCreatedByUser(id);
if (CollectionUtils.isNotEmpty(projects)) {
String projectNames = projects.stream().map(Project::getName).collect(Collectors.joining(","));
putMsg(result, Status.TRANSFORM_PROJECT_OWNERSHIP, projectNames);
return result;
}
// delete user
User user = userMapper.queryTenantCodeByUserId(id);

3
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/ProjectControllerTest.java

@ -87,6 +87,7 @@ public class ProjectControllerTest extends AbstractControllerTest {
paramsMap.add("projectId", projectId);
paramsMap.add("projectName","project_test_update");
paramsMap.add("desc","the test project update");
paramsMap.add("userName", "the project owner");
MvcResult mvcResult = mockMvc.perform(post("/projects/update")
.header(SESSION_ID, sessionId)
@ -96,7 +97,7 @@ public class ProjectControllerTest extends AbstractControllerTest {
.andReturn();
Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
Assert.assertEquals(Status.SUCCESS.getCode(),result.getCode().intValue());
Assert.assertEquals(Status.USER_NOT_EXIST.getCode(),result.getCode().intValue());
logger.info("update project return result:{}", mvcResult.getResponse().getContentAsString());
}

15
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProjectServiceTest.java

@ -30,6 +30,7 @@ import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectUserMapper;
import org.apache.dolphinscheduler.dao.mapper.UserMapper;
import java.util.ArrayList;
import java.util.Collections;
@ -70,6 +71,9 @@ public class ProjectServiceTest {
@Mock
private ProcessDefinitionMapper processDefinitionMapper;
@Mock
private UserMapper userMapper;
private String projectName = "ProjectServiceTest";
private String userName = "ProjectServiceTest";
@ -240,19 +244,24 @@ public class ProjectServiceTest {
Mockito.when(projectMapper.queryByName(projectName)).thenReturn(project);
Mockito.when(projectMapper.selectById(1)).thenReturn(getProject());
// PROJECT_NOT_FOUNT
Map<String, Object> result = projectService.update(loginUser, 12, projectName, "desc");
Map<String, Object> result = projectService.update(loginUser, 12, projectName, "desc", "testUser");
logger.info(result.toString());
Assert.assertEquals(Status.PROJECT_NOT_FOUNT, result.get(Constants.STATUS));
//PROJECT_ALREADY_EXISTS
result = projectService.update(loginUser, 1, projectName, "desc");
result = projectService.update(loginUser, 1, projectName, "desc", "testUser");
logger.info(result.toString());
Assert.assertEquals(Status.PROJECT_ALREADY_EXISTS, result.get(Constants.STATUS));
Mockito.when(userMapper.queryByUserNameAccurately(Mockito.any())).thenReturn(null);
result = projectService.update(loginUser, 1, "test", "desc", "testuser");
Assert.assertEquals(Status.USER_NOT_EXIST, result.get(Constants.STATUS));
//success
Mockito.when(userMapper.queryByUserNameAccurately(Mockito.any())).thenReturn(new User());
project.setUserId(1);
Mockito.when(projectMapper.updateById(Mockito.any(Project.class))).thenReturn(1);
result = projectService.update(loginUser, 1, "test", "desc");
result = projectService.update(loginUser, 1, "test", "desc", "testUser");
logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));

13
dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java

@ -31,11 +31,13 @@ import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.dolphinscheduler.common.utils.CollectionUtils;
import org.apache.dolphinscheduler.common.utils.EncryptionUtils;
import org.apache.dolphinscheduler.dao.entity.AlertGroup;
import org.apache.dolphinscheduler.dao.entity.Project;
import org.apache.dolphinscheduler.dao.entity.Resource;
import org.apache.dolphinscheduler.dao.entity.Tenant;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper;
import org.apache.dolphinscheduler.dao.mapper.DataSourceUserMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper;
import org.apache.dolphinscheduler.dao.mapper.ProjectUserMapper;
import org.apache.dolphinscheduler.dao.mapper.ResourceMapper;
import org.apache.dolphinscheduler.dao.mapper.ResourceUserMapper;
@ -61,6 +63,7 @@ import org.slf4j.LoggerFactory;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
/**
* users service test
@ -97,6 +100,9 @@ public class UsersServiceTest {
@Mock
private UDFUserMapper udfUserMapper;
@Mock
private ProjectMapper projectMapper;
private String queueName = "UsersServiceTestQueue";
@Before
@ -292,7 +298,13 @@ public class UsersServiceTest {
logger.info(result.toString());
Assert.assertEquals(Status.USER_NOT_EXIST, result.get(Constants.STATUS));
// user is project owner
Mockito.when(projectMapper.queryProjectCreatedByUser(1)).thenReturn(Lists.newArrayList(new Project()));
result = usersService.deleteUserById(loginUser, 1);
Assert.assertEquals(Status.TRANSFORM_PROJECT_OWNERSHIP, result.get(Constants.STATUS));
//success
Mockito.when(projectMapper.queryProjectCreatedByUser(1)).thenReturn(null);
result = usersService.deleteUserById(loginUser, 1);
logger.info(result.toString());
Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
@ -301,7 +313,6 @@ public class UsersServiceTest {
Assert.assertTrue(false);
}
}
@Test

23
dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/list/_source/createProject.vue

@ -31,6 +31,18 @@
</el-input>
</template>
</m-list-box-f>
<m-list-box-f v-if="item">
<template slot="name"><strong>*</strong>{{ $t('Owned Users') }}</template>
<template slot="content">
<el-input
v-model="userName"
:placeholder="$t('Please enter user name')"
maxlength="60"
size="small"
type="input">
</el-input>
</template>
</m-list-box-f>
<m-list-box-f>
<template slot="name">{{ $t('Description') }}</template>
<template slot="content">
@ -59,7 +71,8 @@
return {
store,
description: '',
projectName: ''
projectName: '',
userName: ''
}
},
props: {
@ -73,7 +86,8 @@
let param = {
projectName: _.trim(this.projectName),
description: _.trim(this.description)
description: _.trim(this.description),
userName: _.trim(this.userName)
}
// edit
@ -104,6 +118,10 @@
this.$message.warning(`${i18n.$t('Please enter name')}`)
return false
}
if (this.item && !this.userName) {
this.$message.warning(`${i18n.$t('Please enter user name')}`)
return false
}
return true
}
},
@ -112,6 +130,7 @@
if (this.item) {
this.projectName = this.item.name
this.description = this.item.description
this.userName = this.item.userName
}
},
mounted () {

Loading…
Cancel
Save