http://git-wip-us.apache.org/repos/asf/kylin/blob/7a9f74c8/server-base/src/main/java/org/apache/kylin/rest/service/TableService.java ---------------------------------------------------------------------- diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/TableService.java b/server-base/src/main/java/org/apache/kylin/rest/service/TableService.java index 751d014..30ee99c 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/service/TableService.java +++ b/server-base/src/main/java/org/apache/kylin/rest/service/TableService.java @@ -43,11 +43,11 @@ import org.apache.kylin.metadata.model.ColumnDesc; import org.apache.kylin.metadata.model.TableDesc; import org.apache.kylin.metadata.model.TableExtDesc; import org.apache.kylin.metadata.streaming.StreamingConfig; -import org.apache.kylin.rest.constant.Constant; import org.apache.kylin.rest.exception.BadRequestException; import org.apache.kylin.rest.msg.Message; import org.apache.kylin.rest.msg.MsgPicker; import org.apache.kylin.rest.response.TableDescResponse; +import org.apache.kylin.rest.util.AclEvaluate; import org.apache.kylin.source.ISourceMetadataExplorer; import org.apache.kylin.source.SourceFactory; import org.apache.kylin.source.hive.cardinality.HiveColumnCardinalityJob; @@ -57,7 +57,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; @@ -88,27 +87,34 @@ public class TableService extends BasicService { @Qualifier("kafkaMgmtService") private KafkaConfigService kafkaConfigService; + @Autowired + private AclEvaluate aclEvaluate; + public List<TableDesc> getTableDescByProject(String project, boolean withExt) throws IOException { + aclEvaluate.checkProjectReadPermission(project); List<TableDesc> tables = getProjectManager().listDefinedTables(project); if (null == tables) { return Collections.emptyList(); } if (withExt) { + aclEvaluate.checkProjectWritePermission(project); tables = cloneTableDesc(tables, project); } return tables; } public TableDesc getTableDescByName(String tableName, boolean withExt, String prj) { + aclEvaluate.checkProjectReadPermission(prj); TableDesc table = getMetadataManager().getTableDesc(tableName, prj); if (withExt) { + aclEvaluate.checkProjectWritePermission(prj); table = cloneTableDesc(table, prj); } return table; } - @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN) public String[] loadHiveTablesToProject(String[] tables, String project) throws Exception { + aclEvaluate.checkProjectWritePermission(project); // de-dup SetMultimap<String, String> db2tables = LinkedHashMultimap.create(); for (String fullTableName : tables) { @@ -176,6 +182,7 @@ public class TableService extends BasicService { } public Map<String, String[]> loadHiveTables(String[] tableNames, String project, boolean isNeedProfile) throws Exception { + aclEvaluate.checkProjectWritePermission(project); String submitter = SecurityContextHolder.getContext().getAuthentication().getName(); Map<String, String[]> result = new HashMap<String, String[]>(); @@ -198,6 +205,7 @@ public class TableService extends BasicService { } public Map<String, String[]> unloadHiveTables(String[] tableNames, String project) throws IOException { + aclEvaluate.checkProjectWritePermission(project); Set<String> unLoadSuccess = Sets.newHashSet(); Set<String> unLoadFail = Sets.newHashSet(); Map<String, String[]> result = new HashMap<String, String[]>(); @@ -231,8 +239,8 @@ public class TableService extends BasicService { * @param project * @return */ - @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN) public boolean unLoadHiveTable(String tableName, String project) throws IOException { + aclEvaluate.checkProjectWritePermission(project); Message msg = MsgPicker.getMsg(); boolean rtn = false; @@ -266,9 +274,9 @@ public class TableService extends BasicService { KafkaConfig kafkaConfig = null; try { config = streamingService.getStreamingManager().getStreamingConfig(tableName); - kafkaConfig = kafkaConfigService.getKafkaConfig(tableName); - streamingService.dropStreamingConfig(config); - kafkaConfigService.dropKafkaConfig(kafkaConfig); + kafkaConfig = kafkaConfigService.getKafkaConfig(tableName, project); + streamingService.dropStreamingConfig(config, project); + kafkaConfigService.dropKafkaConfig(kafkaConfig, project); rtn = true; } catch (Exception e) { rtn = false; @@ -284,8 +292,8 @@ public class TableService extends BasicService { * @param project * @throws IOException */ - @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN) public void addStreamingTable(TableDesc desc, String project) throws IOException { + aclEvaluate.checkProjectWritePermission(project); desc.setUuid(UUID.randomUUID().toString()); getMetadataManager().saveSourceTable(desc, project); syncTableToProject(new String[] { desc.getIdentity() }, project); @@ -351,7 +359,6 @@ public class TableService extends BasicService { return descs; } - @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN) public void calculateCardinalityIfNotPresent(String[] tables, String submitter, String prj) throws Exception { MetadataManager metaMgr = getMetadataManager(); ExecutableManager exeMgt = ExecutableManager.getInstance(getConfig()); @@ -370,8 +377,8 @@ public class TableService extends BasicService { * * @param tableName */ - @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN) public void calculateCardinality(String tableName, String submitter, String prj) throws Exception { + aclEvaluate.checkProjectWritePermission(prj); Message msg = MsgPicker.getMsg(); tableName = normalizeHiveTableName(tableName);
http://git-wip-us.apache.org/repos/asf/kylin/blob/7a9f74c8/server-base/src/main/java/org/apache/kylin/rest/util/AclEvaluate.java ---------------------------------------------------------------------- diff --git a/server-base/src/main/java/org/apache/kylin/rest/util/AclEvaluate.java b/server-base/src/main/java/org/apache/kylin/rest/util/AclEvaluate.java new file mode 100644 index 0000000..8ef7423 --- /dev/null +++ b/server-base/src/main/java/org/apache/kylin/rest/util/AclEvaluate.java @@ -0,0 +1,131 @@ +/* + * 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.kylin.rest.util; + +import org.apache.kylin.common.KylinConfig; +import org.apache.kylin.cube.CubeInstance; +import org.apache.kylin.cube.CubeManager; +import org.apache.kylin.engine.mr.CubingJob; +import org.apache.kylin.job.JobInstance; +import org.apache.kylin.job.execution.AbstractExecutable; +import org.apache.kylin.job.execution.ExecutableManager; +import org.apache.kylin.metadata.project.ProjectInstance; +import org.apache.kylin.metadata.project.ProjectManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("aclEvaluate") +public class AclEvaluate { + @Autowired + private AclUtil aclUtil; + + private ProjectInstance getProjectInstance(String projectName) { + return ProjectManager.getInstance(KylinConfig.getInstanceFromEnv()).getProject(projectName); + } + + private ProjectInstance getProjectInstanceByCubeName(String cube) { + CubeInstance cubeInstance = CubeManager.getInstance(KylinConfig.getInstanceFromEnv()).getCube(cube); + return cubeInstance.getProjectInstance(); + } + + private ProjectInstance getProjectByJob(JobInstance job) { + AbstractExecutable executable = ExecutableManager.getInstance(KylinConfig.getInstanceFromEnv()) + .getJob(job.getUuid()); + String projectName = ((CubingJob) executable).getProjectName(); + return getProjectInstance(projectName); + } + + public boolean checkProjectAdminPermission(String projectName) { + ProjectInstance projectInstance = getProjectInstance(projectName); + return aclUtil.hasProjectAdminPermission(projectInstance); + } + + //for raw project + public boolean checkProjectReadPermission(String projectName) { + ProjectInstance projectInstance = getProjectInstance(projectName); + return aclUtil.hasProjectReadPermission(projectInstance); + } + + public boolean checkProjectWritePermission(String projectName) { + ProjectInstance projectInstance = getProjectInstance(projectName); + return aclUtil.hasProjectWritePermission(projectInstance); + } + + public boolean checkProjectOperationPermission(String projectName) { + ProjectInstance projectInstance = getProjectInstance(projectName); + return aclUtil.hasProjectOperationPermission(projectInstance); + } + + //for cube acl entity + public boolean checkProjectReadPermission(CubeInstance cube) { + return aclUtil.hasProjectReadPermission(cube.getProjectInstance()); + } + + + public boolean checkProjectWritePermission(CubeInstance cube) { + return aclUtil.hasProjectWritePermission(cube.getProjectInstance()); + } + + public boolean checkProjectOperationPermission(CubeInstance cube) { + return aclUtil.hasProjectOperationPermission(cube.getProjectInstance()); + } + + //for job acl entity + public boolean checkProjectReadPermission(JobInstance job) { + return aclUtil.hasProjectReadPermission(getProjectByJob(job)); + } + + public boolean checkProjectWritePermission(JobInstance job) { + return aclUtil.hasProjectWritePermission(getProjectByJob(job)); + } + + public boolean checkProjectOperationPermission(JobInstance job) { + return aclUtil.hasProjectOperationPermission(getProjectByJob(job)); + } + + // ACL util's method, so that you can use AclEvaluate + public String getCurrentUserName() { + return aclUtil.getCurrentUserName(); + } + + public boolean hasCubeReadPermission(CubeInstance cube) { + return hasProjectReadPermission(cube.getProjectInstance()); + } + + public boolean hasProjectReadPermission(ProjectInstance project) { + return aclUtil.hasProjectReadPermission(project); + } + + public boolean hasProjectOperationPermission(ProjectInstance project) { + return aclUtil.hasProjectOperationPermission(project); + } + + public boolean hasProjectWritePermission(ProjectInstance project) { + return aclUtil.hasProjectWritePermission(project); + } + + public boolean hasProjectAdminPermission(ProjectInstance project) { + return aclUtil.hasProjectAdminPermission(project); + } + + public boolean checkIsGlobalAdmin() { + return aclUtil.checkIsGlobalAdmin(); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/kylin/blob/7a9f74c8/server-base/src/main/java/org/apache/kylin/rest/util/AclUtil.java ---------------------------------------------------------------------- diff --git a/server-base/src/main/java/org/apache/kylin/rest/util/AclUtil.java b/server-base/src/main/java/org/apache/kylin/rest/util/AclUtil.java index 3b47288..602079e 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/util/AclUtil.java +++ b/server-base/src/main/java/org/apache/kylin/rest/util/AclUtil.java @@ -18,7 +18,6 @@ package org.apache.kylin.rest.util; -import org.apache.kylin.cube.CubeInstance; import org.apache.kylin.metadata.project.ProjectInstance; import org.apache.kylin.rest.constant.Constant; import org.springframework.security.access.prepost.PreAuthorize; @@ -27,20 +26,44 @@ import org.springframework.stereotype.Component; @Component("aclUtil") public class AclUtil { + String getCurrentUserName() { + return SecurityContextHolder.getContext().getAuthentication().getName(); + } //such method MUST NOT be called from within same class - @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#cube, 'ADMINISTRATION') or hasPermission(#cube, 'MANAGEMENT')" + " or hasPermission(#cube, 'OPERATION') or hasPermission(#cube, 'READ')") - public boolean hasCubeReadPermission(CubeInstance cube) { + //do not change public to package private + @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + + " or hasPermission(#project, 'ADMINISTRATION')" + + " or hasPermission(#project, 'MANAGEMENT')" + + " or hasPermission(#project, 'OPERATION')" + + " or hasPermission(#project, 'READ')") + public boolean hasProjectReadPermission(ProjectInstance project) { return true; } - //such method MUST NOT be called from within same class - @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#project, 'ADMINISTRATION') or hasPermission(#project, 'MANAGEMENT')" + " or hasPermission(#project, 'OPERATION') or hasPermission(#project, 'READ')") - public boolean hasProjectReadPermission(ProjectInstance project) { + @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + + " or hasPermission(#project, 'ADMINISTRATION')" + + " or hasPermission(#project, 'MANAGEMENT')" + + " or hasPermission(#project, 'OPERATION')") + public boolean hasProjectOperationPermission(ProjectInstance project) { return true; } - public String getCurrentUserName() { - return SecurityContextHolder.getContext().getAuthentication().getName(); + @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + + " or hasPermission(#project, 'ADMINISTRATION')" + + " or hasPermission(#project, 'MANAGEMENT')") + public boolean hasProjectWritePermission(ProjectInstance project) { + return true; + } + + @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + + " or hasPermission(#project, 'ADMINISTRATION')") + public boolean hasProjectAdminPermission(ProjectInstance project) { + return true; + } + + @PreAuthorize("hasRole('ROLE_ADMIN')") + public boolean checkIsGlobalAdmin() { + return true; } } http://git-wip-us.apache.org/repos/asf/kylin/blob/7a9f74c8/server-base/src/test/java/org/apache/kylin/rest/bean/BeanTest.java ---------------------------------------------------------------------- diff --git a/server-base/src/test/java/org/apache/kylin/rest/bean/BeanTest.java b/server-base/src/test/java/org/apache/kylin/rest/bean/BeanTest.java index 27c77c3..da41952 100644 --- a/server-base/src/test/java/org/apache/kylin/rest/bean/BeanTest.java +++ b/server-base/src/test/java/org/apache/kylin/rest/bean/BeanTest.java @@ -65,7 +65,12 @@ public class BeanTest { Assert.assertTrue(!coulmnMeta.isSigned()); Assert.assertEquals(Constant.ACCESS_HAS_ROLE_ADMIN, "hasRole('ROLE_ADMIN')"); - Assert.assertEquals(Constant.ACCESS_POST_FILTER_READ, "hasRole('ROLE_ADMIN') or hasPermission(filterObject, 'READ') or hasPermission(filterObject, 'MANAGEMENT') " + "or hasPermission(filterObject, 'OPERATION') or hasPermission(filterObject, 'ADMINISTRATION')"); + Assert.assertEquals(Constant.ACCESS_POST_FILTER_READ, + "hasRole('ROLE_ADMIN') " + + " or hasPermission(filterObject, 'ADMINISTRATION')"+ + " or hasPermission(filterObject, 'MANAGEMENT')" + + " or hasPermission(filterObject, 'OPERATION')" + + " or hasPermission(filterObject, 'READ')"); Assert.assertEquals(Constant.FakeCatalogName, "defaultCatalog"); Assert.assertEquals(Constant.FakeSchemaName, "defaultSchema"); Assert.assertEquals(Constant.IDENTITY_ROLE, "role"); http://git-wip-us.apache.org/repos/asf/kylin/blob/7a9f74c8/server/src/test/java/org/apache/kylin/rest/controller/AccessControllerTest.java ---------------------------------------------------------------------- diff --git a/server/src/test/java/org/apache/kylin/rest/controller/AccessControllerTest.java b/server/src/test/java/org/apache/kylin/rest/controller/AccessControllerTest.java index 18fbd06..059dfdb 100644 --- a/server/src/test/java/org/apache/kylin/rest/controller/AccessControllerTest.java +++ b/server/src/test/java/org/apache/kylin/rest/controller/AccessControllerTest.java @@ -154,7 +154,12 @@ public class AccessControllerTest extends ServiceTestBase implements AclEntityTy assertTrue(cubes.size() > 0); CubeInstance cube = cubes.get(0); swichToAnalyst(); - cubes = cubeController.getCubes(null, null, null, 100000, 0); + cubes.clear(); + try { + cubes = cubeController.getCubes(null, null, null, 100000, 0); + } catch (AccessDeniedException e) { + //correct + } assertTrue(cubes.size() == 0); //grant auth @@ -166,24 +171,30 @@ public class AccessControllerTest extends ServiceTestBase implements AclEntityTy //correct } swichToAdmin(); - List<AccessEntryResponse> aes = accessController.grant(CUBE_INSTANCE, cube.getUuid(), accessRequest); + List<ProjectInstance> projects = projectController.getProjects(10000, 0); + List<AccessEntryResponse> aes = accessController.grant(PROJECT_INSTANCE, projects.get(0).getUuid(), accessRequest); Assert.assertTrue(aes.size() == 1); swichToAnalyst(); - cubes = cubeController.getCubes(null, null, null, 100000, 0); - assertEquals(1, cubes.size()); + cubes = cubeController.getCubes(null, null, "default", 100000, 0); + assertTrue(cubes.size() > 0); + cubes.clear(); //revoke auth try { - accessController.revoke(CUBE_INSTANCE, cube.getUuid(), accessRequest); + accessController.revoke(PROJECT_INSTANCE, projects.get(0).getUuid(), accessRequest); fail("ANALYST should not have auth to revoke"); } catch (AccessDeniedException e) { //correct } swichToAdmin(); accessRequest.setAccessEntryId((Long) aes.get(0).getId()); - accessController.revoke(CUBE_INSTANCE, cube.getUuid(), accessRequest); + accessController.revoke(PROJECT_INSTANCE, projects.get(0).getUuid(), accessRequest); swichToAnalyst(); - cubes = cubeController.getCubes(null, null, null, 10000, 0); + try { + cubes = cubeController.getCubes(null, null, null, 10000, 0); + } catch (AccessDeniedException e) { + //correct + } assertEquals(0, cubes.size()); }