diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AuthorizationType.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AuthorizationType.java new file mode 100644 index 0000000000..1c371e799e --- /dev/null +++ b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AuthorizationType.java @@ -0,0 +1,50 @@ +/* + * 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.dolphinscheduler.common.enums; + +import com.baomidou.mybatisplus.annotation.EnumValue; + +/** + * Authorization type + */ +public enum AuthorizationType { + /** + * 0 RESOURCE_FILE; + * 1 DATASOURCE; + * 2 UDF; + */ + RESOURCE_FILE(0, "resource file"), + DATASOURCE(1, "data source"), + UDF(2, "udf function"); + + AuthorizationType(int code, String descp){ + this.code = code; + this.descp = descp; + } + + @EnumValue + private final int code; + private final String descp; + + public int getCode() { + return code; + } + + public String getDescp() { + return descp; + } +} diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/ProcessDao.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/ProcessDao.java index a45fbfff6f..76e9d0b2ff 100644 --- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/ProcessDao.java +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/ProcessDao.java @@ -18,6 +18,7 @@ package org.apache.dolphinscheduler.dao; import com.alibaba.fastjson.JSONObject; import com.cronutils.model.Cron; +import org.apache.commons.lang.ArrayUtils; import org.apache.dolphinscheduler.common.Constants; import org.apache.dolphinscheduler.common.enums.*; import org.apache.dolphinscheduler.common.model.DateInterval; @@ -25,7 +26,6 @@ import org.apache.dolphinscheduler.common.model.TaskNode; import org.apache.dolphinscheduler.common.process.Property; import org.apache.dolphinscheduler.common.queue.ITaskQueue; import org.apache.dolphinscheduler.common.task.subprocess.SubProcessParameters; -import org.apache.dolphinscheduler.common.utils.ArrayUtils; import org.apache.dolphinscheduler.common.utils.DateUtils; import org.apache.dolphinscheduler.common.utils.IpUtils; import org.apache.dolphinscheduler.common.utils.JSONUtils; @@ -44,6 +44,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toSet; import static org.apache.dolphinscheduler.common.Constants.*; /** @@ -462,12 +463,9 @@ public class ProcessDao { return null; } - if(null == tenant){ + if(tenant == null){ User user = userMapper.selectById(userId); - - if (null != user) { - tenant = tenantMapper.queryById(user.getTenantId()); - } + tenant = tenantMapper.queryById(user.getTenantId()); } return tenant; } @@ -974,6 +972,9 @@ public class ProcessDao { public Boolean submitTaskToQueue(TaskInstance taskInstance) { try{ + if(taskInstance.isSubProcess()){ + return true; + } if(taskInstance.getState().typeIsFinished()){ logger.info(String.format("submit to task queue, but task [%s] state [%s] is already finished. ", taskInstance.getName(), taskInstance.getState().toString())); return true; @@ -1770,5 +1771,47 @@ public class ProcessDao { return projectIdList; } + /** + * list unauthorized udf function + * @param userId user id + * @param needChecks data source id array + * @return unauthorized udf function list + */ + public List listUnauthorized(int userId,T[] needChecks,AuthorizationType authorizationType){ + List resultList = new ArrayList(); + + if (!ArrayUtils.isEmpty(needChecks)) { + Set originResSet = new HashSet(Arrays.asList(needChecks)); + + switch (authorizationType){ + case RESOURCE_FILE: + Set authorizedResources = resourceMapper.listAuthorizedResource(userId, needChecks).stream().map(t -> t.getAlias()).collect(toSet()); + originResSet.removeAll(authorizedResources); + break; + case DATASOURCE: + Set authorizedDatasources = dataSourceMapper.listAuthorizedDataSource(userId,needChecks).stream().map(t -> t.getId()).collect(toSet()); + originResSet.removeAll(authorizedDatasources); + break; + case UDF: + Set authorizedUdfs = udfFuncMapper.listAuthorizedUdfFunc(userId, needChecks).stream().map(t -> t.getId()).collect(toSet()); + originResSet.removeAll(authorizedUdfs); + break; + } + + resultList.addAll(originResSet); + } + + return resultList; + } + + /** + * get user by user id + * @param userId user id + * @return User + */ + public User getUserById(int userId){ + return userMapper.queryDetailsById(userId); + } + } diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/DataSourceMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/DataSourceMapper.java index 2b4944dd61..f95fbc7a4d 100644 --- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/DataSourceMapper.java +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/DataSourceMapper.java @@ -77,4 +77,13 @@ public interface DataSourceMapper extends BaseMapper { List listAllDataSourceByType(@Param("type") Integer type); + /** + * list authorized UDF function + * @param userId userId + * @param dataSourceIds data source id array + * @return UDF function list + */ + List listAuthorizedDataSource(@Param("userId") int userId,@Param("dataSourceIds")T[] dataSourceIds); + + } diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ResourceMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ResourceMapper.java index 4e3d9c3f45..cf65e5d08a 100644 --- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ResourceMapper.java +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/ResourceMapper.java @@ -83,4 +83,12 @@ public interface ResourceMapper extends BaseMapper { * @return tenant code */ String queryTenantCodeByResourceName(@Param("resName") String resName); + + /** + * list authorized resource + * @param userId userId + * @param resNames resource names + * @return resource list + */ + List listAuthorizedResource(@Param("userId") int userId,@Param("resNames")T[] resNames); } diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.java index 03ad58da86..5a8734233c 100644 --- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.java +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.java @@ -78,5 +78,12 @@ public interface UdfFuncMapper extends BaseMapper { */ List queryAuthedUdfFunc(@Param("userId") int userId); + /** + * list authorized UDF function + * @param userId userId + * @param udfIds UDF function id array + * @return UDF function list + */ + List listAuthorizedUdfFunc (@Param("userId") int userId,@Param("udfIds")T[] udfIds); } diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/permission/PermissionCheck.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/permission/PermissionCheck.java new file mode 100644 index 0000000000..63d4c1c8af --- /dev/null +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/permission/PermissionCheck.java @@ -0,0 +1,157 @@ +/* + * 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.dolphinscheduler.dao.permission; + +import org.apache.dolphinscheduler.common.enums.AuthorizationType; +import org.apache.dolphinscheduler.common.enums.UserType; +import org.apache.dolphinscheduler.common.utils.CollectionUtils; +import org.apache.dolphinscheduler.dao.ProcessDao; +import org.apache.dolphinscheduler.dao.entity.User; +import org.slf4j.Logger; + +import java.util.List; + +public class PermissionCheck { + /** + * logger + */ + private Logger logger; + /** + * Authorization Type + */ + private AuthorizationType authorizationType; + + /** + * Authorization Type + */ + private ProcessDao processDao; + + /** + * need check array + */ + private T[] needChecks; + + /** + * user id + */ + private int userId; + + /** + * permission check + * @param authorizationType authorization type + * @param processDao process dao + */ + public PermissionCheck(AuthorizationType authorizationType, ProcessDao processDao) { + this.authorizationType = authorizationType; + this.processDao = processDao; + } + + /** + * permission check + * @param authorizationType + * @param processDao + * @param needChecks + * @param userId + */ + public PermissionCheck(AuthorizationType authorizationType, ProcessDao processDao, T[] needChecks, int userId) { + this.authorizationType = authorizationType; + this.processDao = processDao; + this.needChecks = needChecks; + this.userId = userId; + } + + /** + * permission check + * @param authorizationType + * @param processDao + * @param needChecks + * @param userId + * @param logger + */ + public PermissionCheck(AuthorizationType authorizationType, ProcessDao processDao, T[] needChecks, int userId,Logger logger) { + this.authorizationType = authorizationType; + this.processDao = processDao; + this.needChecks = needChecks; + this.userId = userId; + this.logger = logger; + } + + public AuthorizationType getAuthorizationType() { + return authorizationType; + } + + public void setAuthorizationType(AuthorizationType authorizationType) { + this.authorizationType = authorizationType; + } + + public ProcessDao getProcessDao() { + return processDao; + } + + public void setProcessDao(ProcessDao processDao) { + this.processDao = processDao; + } + + public T[] getNeedChecks() { + return needChecks; + } + + public void setNeedChecks(T[] needChecks) { + this.needChecks = needChecks; + } + + public int getUserId() { + return userId; + } + + public void setUserId(int userId) { + this.userId = userId; + } + + /** + * has permission + * @return true if has permission + */ + public boolean hasPermission(){ + try { + checkPermission(); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * check permission + * @throws Exception exception + */ + public void checkPermission() throws Exception{ + if(this.needChecks.length > 0){ + // get user type in order to judge whether the user is admin + User user = processDao.getUserById(userId); + if (user.getUserType() != UserType.ADMIN_USER){ + List unauthorizedList = processDao.listUnauthorized(userId,needChecks,authorizationType); + // if exist unauthorized resource + if(CollectionUtils.isNotEmpty(unauthorizedList)){ + logger.error("user {} didn't has permission of {}: {}", user.getUserName(), authorizationType.getDescp(),unauthorizedList.toString()); + throw new RuntimeException(String.format("user %s didn't has permission of %s %s", user.getUserName(), authorizationType.getDescp(), unauthorizedList.get(0))); + } + } + } + } + +} diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/DataSourceMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/DataSourceMapper.xml index b296d5fc3e..15536ae652 100644 --- a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/DataSourceMapper.xml +++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/DataSourceMapper.xml @@ -74,6 +74,19 @@ from t_ds_datasource where type = #{type} + \ No newline at end of file diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.xml index 8a041babf0..0aa10607c4 100644 --- a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.xml +++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapper.xml @@ -74,4 +74,17 @@ WHERE u.id = rel.udf_id AND rel.user_id = #{userId} + \ No newline at end of file diff --git a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/DataSourceMapperTest.java b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/DataSourceMapperTest.java index c826236239..92df6cc45c 100644 --- a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/DataSourceMapperTest.java +++ b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/DataSourceMapperTest.java @@ -17,12 +17,14 @@ package org.apache.dolphinscheduler.dao.mapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.dolphinscheduler.common.enums.DbType; +import org.apache.dolphinscheduler.common.enums.UserType; import org.apache.dolphinscheduler.common.utils.DateUtils; import org.apache.dolphinscheduler.dao.entity.DataSource; import org.apache.dolphinscheduler.dao.entity.DatasourceUser; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.dolphinscheduler.dao.entity.User; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,7 +36,9 @@ import org.springframework.transaction.annotation.Transactional; import java.util.*; -import static org.hamcrest.Matchers.*; +import static java.util.stream.Collectors.toList; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.junit.Assert.*; /** @@ -58,6 +62,9 @@ public class DataSourceMapperTest { @Autowired DataSourceUserMapper dataSourceUserMapper; + @Autowired + private UserMapper userMapper; + /** * test insert */ @@ -244,6 +251,33 @@ public class DataSourceMapperTest { } } + @Test + public void testListAuthorizedDataSource(){ + //create general user + User generalUser1 = createGeneralUser("user1"); + User generalUser2 = createGeneralUser("user2"); + + //create data source + DataSource dataSource = createDataSource(generalUser1.getId(), "ds-1"); + DataSource unauthorizdDataSource = createDataSource(generalUser2.getId(), "ds-2"); + + + //data source ids + Integer[] dataSourceIds = new Integer[]{dataSource.getId(),unauthorizdDataSource.getId()}; + + List authorizedDataSource = dataSourceMapper.listAuthorizedDataSource(generalUser1.getId(), dataSourceIds); + + Assert.assertEquals(generalUser1.getId(),dataSource.getUserId()); + Assert.assertNotEquals(generalUser1.getId(),unauthorizdDataSource.getUserId()); + Assert.assertFalse(authorizedDataSource.stream().map(t -> t.getId()).collect(toList()).containsAll(Arrays.asList(dataSourceIds))); + + //authorize object unauthorizdDataSource to generalUser1 + createUserDataSource(generalUser1, unauthorizdDataSource); + authorizedDataSource = dataSourceMapper.listAuthorizedDataSource(generalUser1.getId(), dataSourceIds); + + Assert.assertTrue(authorizedDataSource.stream().map(t -> t.getId()).collect(toList()).containsAll(Arrays.asList(dataSourceIds))); + } + /** * create datasource relation * @param userId @@ -289,7 +323,6 @@ public class DataSourceMapperTest { return dataSourceMap; } - /** * create datasource * @return datasource @@ -330,5 +363,41 @@ public class DataSourceMapperTest { return dataSource; } + /** + * create general user + * @return User + */ + private User createGeneralUser(String userName){ + User user = new User(); + user.setUserName(userName); + user.setUserPassword("1"); + user.setEmail("xx@123.com"); + user.setUserType(UserType.GENERAL_USER); + user.setCreateTime(new Date()); + user.setTenantId(1); + user.setUpdateTime(new Date()); + userMapper.insert(user); + return user; + } + + /** + * create the relation of user and data source + * @param user user + * @param dataSource data source + * @return DatasourceUser + */ + private DatasourceUser createUserDataSource(User user,DataSource dataSource){ + DatasourceUser datasourceUser = new DatasourceUser(); + + datasourceUser.setDatasourceId(dataSource.getId()); + datasourceUser.setUserId(user.getId()); + datasourceUser.setPerm(7); + datasourceUser.setCreateTime(DateUtils.getCurrentDate()); + datasourceUser.setUpdateTime(DateUtils.getCurrentDate()); + + dataSourceUserMapper.insert(datasourceUser); + return datasourceUser; + } + } \ No newline at end of file diff --git a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/ResourceMapperTest.java b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/ResourceMapperTest.java index 7c0101612c..aaf5129c02 100644 --- a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/ResourceMapperTest.java +++ b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/ResourceMapperTest.java @@ -17,22 +17,36 @@ package org.apache.dolphinscheduler.dao.mapper; -import org.apache.dolphinscheduler.common.enums.ResourceType; -import org.apache.dolphinscheduler.dao.entity.*; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.dolphinscheduler.common.enums.ResourceType; +import org.apache.dolphinscheduler.common.enums.UserType; +import org.apache.dolphinscheduler.dao.entity.Resource; +import org.apache.dolphinscheduler.dao.entity.ResourcesUser; +import org.apache.dolphinscheduler.dao.entity.Tenant; +import org.apache.dolphinscheduler.dao.entity.User; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.Rollback; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; +import java.util.Arrays; import java.util.Date; import java.util.List; +import static java.util.stream.Collectors.toList; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + @RunWith(SpringRunner.class) @SpringBootTest +@Transactional +@Rollback(true) public class ResourceMapperTest { @Autowired @@ -61,6 +75,59 @@ public class ResourceMapperTest { return resource; } + /** + * create resource by user + * @param user user + * @return Resource + */ + private Resource createResource(User user){ + //insertOne + Resource resource = new Resource(); + resource.setAlias(String.format("ut resource %s",user.getUserName())); + resource.setType(ResourceType.FILE); + resource.setUserId(user.getId()); + resourceMapper.insert(resource); + return resource; + } + + /** + * create user + * @return User + */ + private User createGeneralUser(String userName){ + User user = new User(); + user.setUserName(userName); + user.setUserPassword("1"); + user.setEmail("xx@123.com"); + user.setUserType(UserType.GENERAL_USER); + user.setCreateTime(new Date()); + user.setTenantId(1); + user.setUpdateTime(new Date()); + userMapper.insert(user); + return user; + } + + /** + * create resource user + * @return ResourcesUser + */ + private ResourcesUser createResourcesUser(Resource resource,User user){ + //insertOne + ResourcesUser resourcesUser = new ResourcesUser(); + resourcesUser.setCreateTime(new Date()); + resourcesUser.setUpdateTime(new Date()); + resourcesUser.setUserId(user.getId()); + resourcesUser.setResourcesId(resource.getId()); + resourceUserMapper.insert(resourcesUser); + return resourcesUser; + } + + @Test + public void testInsert(){ + Resource resource = insertOne(); + assertNotNull(resource.getId()); + assertThat(resource.getId(),greaterThan(0)); + } /** * test update */ @@ -230,4 +297,30 @@ public class ResourceMapperTest { resourceMapper.deleteById(resource.getId()); } + + @Test + public void testListAuthorizedResource(){ + // create a general user + User generalUser1 = createGeneralUser("user1"); + User generalUser2 = createGeneralUser("user2"); + // create one resource + Resource resource = createResource(generalUser2); + Resource unauthorizedResource = createResource(generalUser2); + + // need download resources + String[] resNames = new String[]{resource.getAlias(), unauthorizedResource.getAlias()}; + + List resources = resourceMapper.listAuthorizedResource(generalUser2.getId(), resNames); + + Assert.assertEquals(generalUser2.getId(),resource.getUserId()); + Assert.assertFalse(resources.stream().map(t -> t.getAlias()).collect(toList()).containsAll(Arrays.asList(resNames))); + + + + // authorize object unauthorizedResource to generalUser + createResourcesUser(unauthorizedResource,generalUser2); + List authorizedResources = resourceMapper.listAuthorizedResource(generalUser2.getId(), resNames); + Assert.assertTrue(authorizedResources.stream().map(t -> t.getAlias()).collect(toList()).containsAll(Arrays.asList(resNames))); + + } } \ No newline at end of file diff --git a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapperTest.java b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapperTest.java index d608c841c7..0dd06484d8 100644 --- a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapperTest.java +++ b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/mapper/UdfFuncMapperTest.java @@ -29,13 +29,20 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.Rollback; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; +import java.util.Arrays; import java.util.Date; import java.util.List; +import static java.util.stream.Collectors.toList; + @RunWith(SpringRunner.class) @SpringBootTest +@Transactional +@Rollback(true) public class UdfFuncMapperTest { @Autowired @@ -133,6 +140,23 @@ public class UdfFuncMapperTest { return udfUser; } + /** + * create general user + * @return User + */ + private User createGeneralUser(String userName){ + User user = new User(); + user.setUserName(userName); + user.setUserPassword("1"); + user.setEmail("xx@123.com"); + user.setUserType(UserType.GENERAL_USER); + user.setCreateTime(new Date()); + user.setTenantId(1); + user.setUpdateTime(new Date()); + userMapper.insert(user); + return user; + } + /** * test update */ @@ -268,4 +292,30 @@ public class UdfFuncMapperTest { udfUserMapper.deleteById(udfUser.getId()); Assert.assertNotEquals(udfFuncList.size(), 0); } + + @Test + public void testListAuthorizedUdfFunc(){ + //create general user + User generalUser1 = createGeneralUser("user1"); + User generalUser2 = createGeneralUser("user2"); + + //create udf function + UdfFunc udfFunc = insertOne(generalUser1); + UdfFunc unauthorizdUdfFunc = insertOne(generalUser2); + + //udf function ids + Integer[] udfFuncIds = new Integer[]{udfFunc.getId(),unauthorizdUdfFunc.getId()}; + + List authorizedUdfFunc = udfFuncMapper.listAuthorizedUdfFunc(generalUser1.getId(), udfFuncIds); + + Assert.assertEquals(generalUser1.getId(),udfFunc.getUserId()); + Assert.assertNotEquals(generalUser1.getId(),unauthorizdUdfFunc.getUserId()); + Assert.assertFalse(authorizedUdfFunc.stream().map(t -> t.getId()).collect(toList()).containsAll(Arrays.asList(udfFuncIds))); + + + //authorize object unauthorizdUdfFunc to generalUser1 + insertOneUDFUser(generalUser1,unauthorizdUdfFunc); + authorizedUdfFunc = udfFuncMapper.listAuthorizedUdfFunc(generalUser1.getId(), udfFuncIds); + Assert.assertTrue(authorizedUdfFunc.stream().map(t -> t.getId()).collect(toList()).containsAll(Arrays.asList(udfFuncIds))); + } } \ No newline at end of file diff --git a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/worker/runner/TaskScheduleThread.java b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/worker/runner/TaskScheduleThread.java index bb7a773d48..5f66c3477d 100644 --- a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/worker/runner/TaskScheduleThread.java +++ b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/worker/runner/TaskScheduleThread.java @@ -21,6 +21,7 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.sift.SiftingAppender; import com.alibaba.fastjson.JSONObject; import org.apache.dolphinscheduler.common.Constants; +import org.apache.dolphinscheduler.common.enums.AuthorizationType; import org.apache.dolphinscheduler.common.enums.ExecutionStatus; import org.apache.dolphinscheduler.common.enums.TaskType; import org.apache.dolphinscheduler.common.model.TaskNode; @@ -33,6 +34,7 @@ import org.apache.dolphinscheduler.common.utils.TaskParametersUtils; import org.apache.dolphinscheduler.dao.ProcessDao; import org.apache.dolphinscheduler.dao.entity.ProcessInstance; import org.apache.dolphinscheduler.dao.entity.TaskInstance; +import org.apache.dolphinscheduler.dao.permission.PermissionCheck; import org.apache.dolphinscheduler.server.utils.LoggerUtils; import org.apache.dolphinscheduler.server.worker.log.TaskLogDiscriminator; import org.apache.dolphinscheduler.server.worker.task.AbstractTask; @@ -42,7 +44,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @@ -94,12 +95,15 @@ public class TaskScheduleThread implements Runnable { // task node TaskNode taskNode = JSONObject.parseObject(taskInstance.getTaskJson(), TaskNode.class); + // get resource files + List resourceFiles = createProjectResFiles(taskNode); // copy hdfs/minio file to local - copyHdfsToLocal(processDao, + downloadResource( taskInstance.getExecutePath(), - createProjectResFiles(taskNode), + resourceFiles, logger); + // get process instance according to tak instance ProcessInstance processInstance = taskInstance.getProcessInstance(); @@ -204,8 +208,8 @@ public class TaskScheduleThread implements Runnable { } /** - * get task log path - * @return + * get task log path + * @return log path */ private String getTaskLogPath() { String baseLog = ((TaskLogDiscriminator) ((SiftingAppender) ((LoggerContext) LoggerFactory.getILoggerFactory()) @@ -294,14 +298,14 @@ public class TaskScheduleThread implements Runnable { } /** - * copy hdfs file to local + * download resource file * - * @param processDao * @param execLocalPath * @param projectRes * @param logger */ - private void copyHdfsToLocal(ProcessDao processDao, String execLocalPath, List projectRes, Logger logger) throws IOException { + private void downloadResource(String execLocalPath, List projectRes, Logger logger) throws Exception { + checkDownloadPermission(projectRes); for (String res : projectRes) { File resFile = new File(execLocalPath, res); if (!resFile.exists()) { @@ -321,4 +325,16 @@ public class TaskScheduleThread implements Runnable { } } } + + /** + * check download resource permission + * @param projectRes resource name list + * @throws Exception exception + */ + private void checkDownloadPermission(List projectRes) throws Exception { + int userId = taskInstance.getProcessInstance().getExecutorId(); + String[] resNames = projectRes.toArray(new String[projectRes.size()]); + PermissionCheck permissionCheck = new PermissionCheck<>(AuthorizationType.RESOURCE_FILE,processDao,resNames,userId,logger); + permissionCheck.checkPermission(); + } } \ No newline at end of file diff --git a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/worker/task/sql/SqlTask.java b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/worker/task/sql/SqlTask.java index bacb3f22eb..e8a97fecc5 100644 --- a/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/worker/task/sql/SqlTask.java +++ b/dolphinscheduler-server/src/main/java/org/apache/dolphinscheduler/server/worker/task/sql/SqlTask.java @@ -19,8 +19,11 @@ package org.apache.dolphinscheduler.server.worker.task.sql; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; import org.apache.dolphinscheduler.alert.utils.MailUtils; import org.apache.dolphinscheduler.common.Constants; +import org.apache.dolphinscheduler.common.enums.AuthorizationType; import org.apache.dolphinscheduler.common.enums.ShowType; import org.apache.dolphinscheduler.common.enums.TaskTimeoutStrategy; import org.apache.dolphinscheduler.common.enums.UdfType; @@ -38,6 +41,7 @@ import org.apache.dolphinscheduler.dao.entity.DataSource; import org.apache.dolphinscheduler.dao.entity.ProcessInstance; import org.apache.dolphinscheduler.dao.entity.UdfFunc; import org.apache.dolphinscheduler.dao.entity.User; +import org.apache.dolphinscheduler.dao.permission.PermissionCheck; import org.apache.dolphinscheduler.server.utils.ParamUtils; import org.apache.dolphinscheduler.server.utils.UDFUtils; import org.apache.dolphinscheduler.server.worker.task.AbstractTask; @@ -119,13 +123,6 @@ public class SqlTask extends AbstractTask { } dataSource= processDao.findDataSourceById(sqlParameters.getDatasource()); - - if (null == dataSource){ - logger.error("datasource not exists"); - exitStatusCode = -1; - return; - } - logger.info("datasource name : {} , type : {} , desc : {} , user_id : {} , parameter : {}", dataSource.getName(), dataSource.getType(), @@ -133,6 +130,12 @@ public class SqlTask extends AbstractTask { dataSource.getUserId(), dataSource.getConnectionParams()); + if (dataSource == null){ + logger.error("datasource not exists"); + exitStatusCode = -1; + return; + } + Connection con = null; List createFuncs = null; try { @@ -164,6 +167,8 @@ public class SqlTask extends AbstractTask { for(int i=0;i udfFuncList = processDao.queryUdfFunListByids(idsArray); createFuncs = UDFUtils.createFuncs(udfFuncList, taskProps.getTenantCode(), logger); } @@ -449,4 +454,33 @@ public class SqlTask extends AbstractTask { } logger.info(logPrint.toString()); } + + /** + * check udf function permission + * @param udfFunIds udf functions + * @return if has download permission return true else false + */ + private void checkUdfPermission(Integer[] udfFunIds) throws Exception{ + // process instance + ProcessInstance processInstance = processDao.findProcessInstanceByTaskId(taskProps.getTaskInstId()); + int userId = processInstance.getExecutorId(); + + PermissionCheck permissionCheckUdf = new PermissionCheck(AuthorizationType.UDF,processDao,udfFunIds,userId,logger); + permissionCheckUdf.checkPermission(); + } + + /** + * check data source permission + * @param dataSourceId data source id + * @return if has download permission return true else false + */ + private void checkDataSourcePermission(int dataSourceId) throws Exception{ + // process instance + ProcessInstance processInstance = processDao.findProcessInstanceByTaskId(taskProps.getTaskInstId()); + int userId = processInstance.getExecutorId(); + + PermissionCheck permissionCheckDataSource = new PermissionCheck(AuthorizationType.DATASOURCE,processDao,new Integer[]{dataSourceId},userId,logger); + permissionCheckDataSource.checkPermission(); + } + }