You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by co...@apache.org on 2018/03/28 14:07:38 UTC
ranger git commit: RANGER-1808:Write unit test for RANGER-1672 kylin
plugin
Repository: ranger
Updated Branches:
refs/heads/master 6da244d6f -> 2b5a72ea7
RANGER-1808:Write unit test for RANGER-1672 kylin plugin
Signed-off-by: Colm O hEigeartaigh <co...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/ranger/commit/2b5a72ea
Tree: http://git-wip-us.apache.org/repos/asf/ranger/tree/2b5a72ea
Diff: http://git-wip-us.apache.org/repos/asf/ranger/diff/2b5a72ea
Branch: refs/heads/master
Commit: 2b5a72ea7ce9ea33dd12a223edc2ce0287f37973
Parents: 6da244d
Author: zhangqiang2 <zh...@zte.com.cn>
Authored: Wed Mar 28 16:38:37 2018 +0800
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Wed Mar 28 14:55:45 2018 +0100
----------------------------------------------------------------------
plugin-kylin/pom.xml | 14 +
.../kylin/authorizer/RangerAdminClientImpl.java | 92 ++++
.../authorizer/RangerKylinAuthorizerTest.java | 537 +++++++++++++++++++
.../src/test/resources/applicationContext.xml | 50 ++
.../src/test/resources/kylin-policies.json | 281 ++++++++++
.../src/test/resources/kylin.properties | 21 +
.../src/test/resources/kylinSecurity.xml | 77 +++
.../src/test/resources/log4j.properties | 34 ++
.../test/resources/ranger-kylin-security.xml | 60 +++
9 files changed, 1166 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ranger/blob/2b5a72ea/plugin-kylin/pom.xml
----------------------------------------------------------------------
diff --git a/plugin-kylin/pom.xml b/plugin-kylin/pom.xml
index bfce4c1..1397d11 100644
--- a/plugin-kylin/pom.xml
+++ b/plugin-kylin/pom.xml
@@ -33,6 +33,20 @@
</parent>
<dependencies>
<dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-test</artifactId>
+ <version>${springframework.security.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.kylin</groupId>
<artifactId>kylin-server-base</artifactId>
<version>${kylin.version}</version>
http://git-wip-us.apache.org/repos/asf/ranger/blob/2b5a72ea/plugin-kylin/src/test/java/org/apache/ranger/authorization/kylin/authorizer/RangerAdminClientImpl.java
----------------------------------------------------------------------
diff --git a/plugin-kylin/src/test/java/org/apache/ranger/authorization/kylin/authorizer/RangerAdminClientImpl.java b/plugin-kylin/src/test/java/org/apache/ranger/authorization/kylin/authorizer/RangerAdminClientImpl.java
new file mode 100644
index 0000000..0c465b3
--- /dev/null
+++ b/plugin-kylin/src/test/java/org/apache/ranger/authorization/kylin/authorizer/RangerAdminClientImpl.java
@@ -0,0 +1,92 @@
+/*
+ * 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.ranger.authorization.kylin.authorizer;
+
+import java.io.File;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.util.List;
+
+import org.apache.ranger.admin.client.RangerAdminClient;
+import org.apache.ranger.plugin.util.GrantRevokeRequest;
+import org.apache.ranger.plugin.util.ServicePolicies;
+import org.apache.ranger.plugin.util.ServiceTags;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * A test implementation of the RangerAdminClient interface that just reads
+ * policies in from a file and returns them.
+ */
+public class RangerAdminClientImpl implements RangerAdminClient {
+ private static final Logger LOG = LoggerFactory.getLogger(RangerAdminClientImpl.class);
+ private static final String cacheFilename = "kylin-policies.json";
+ private Gson gson;
+
+ @Override
+ public void init(String serviceName, String appId, String configPropertyPrefix) {
+ Gson gson = null;
+ try {
+ gson = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").setPrettyPrinting().create();
+ } catch (Throwable excp) {
+ LOG.error("RangerAdminClientImpl: failed to create GsonBuilder object", excp);
+ }
+ this.gson = gson;
+ }
+
+ @Override
+ public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis)
+ throws Exception {
+
+ String basedir = System.getProperty("basedir");
+ if (basedir == null) {
+ basedir = new File(".").getCanonicalPath();
+ }
+
+ java.nio.file.Path cachePath = FileSystems.getDefault()
+ .getPath(basedir, "/src/test/resources/" + cacheFilename);
+ byte[] cacheBytes = Files.readAllBytes(cachePath);
+
+ return gson.fromJson(new String(cacheBytes), ServicePolicies.class);
+ }
+
+ @Override
+ public void grantAccess(GrantRevokeRequest request) throws Exception {
+
+ }
+
+ @Override
+ public void revokeAccess(GrantRevokeRequest request) throws Exception {
+
+ }
+
+ @Override
+ public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
+ return null;
+
+ }
+
+ @Override
+ public List<String> getTagTypes(String tagTypePattern) throws Exception {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ranger/blob/2b5a72ea/plugin-kylin/src/test/java/org/apache/ranger/authorization/kylin/authorizer/RangerKylinAuthorizerTest.java
----------------------------------------------------------------------
diff --git a/plugin-kylin/src/test/java/org/apache/ranger/authorization/kylin/authorizer/RangerKylinAuthorizerTest.java b/plugin-kylin/src/test/java/org/apache/ranger/authorization/kylin/authorizer/RangerKylinAuthorizerTest.java
new file mode 100644
index 0000000..5efbb79
--- /dev/null
+++ b/plugin-kylin/src/test/java/org/apache/ranger/authorization/kylin/authorizer/RangerKylinAuthorizerTest.java
@@ -0,0 +1,537 @@
+/*
+ * 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.ranger.authorization.kylin.authorizer;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.RandomStringUtils;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.metadata.project.ProjectInstance;
+import org.apache.kylin.metadata.project.ProjectManager;
+import org.apache.kylin.metadata.project.RealizationEntry;
+import org.apache.kylin.rest.util.AclEvaluate;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+/**
+*
+* Here we plug the Ranger RangerKylinAuthorizer into Kylin.
+*
+* A custom RangerAdminClient is plugged into Ranger in turn, which loads security policies from a local file.
+* These policies were generated in the Ranger Admin UI for a kylin service called "kylinTest":
+*
+* a) A user "kylin" can do all permissions(contains "ADMIN", "MANAGEMENT", "OPERATION", "QUERY")
+* on all kylin projects;
+* b) A user "zhangqiang" can do a "ADMIN" on the project "test_project",
+* and do a "OPERATION" on the project "kylin_project";
+* c) A user "yuwen" can do a "ADMIN" on the project "test_project",
+* and do a "OPERATION" on the project "kylin_project";
+* d) A user "admin" has role "ROLE_ADMIN",
+* and the others have role "ROLE_USER" by mock for test.
+*
+*/
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = { "classpath*:applicationContext.xml", "classpath*:kylinSecurity.xml" })
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class RangerKylinAuthorizerTest {
+ private static final Map<String, ProjectInstance> uuid2Projects = new HashMap<>();
+
+ private static final Map<String, ProjectInstance> name2Projects = new HashMap<>();
+
+ private static final String ADMIN = "admin";
+
+ private static final String KYLIN = "kylin";
+
+ private static final String ZHANGQIANG = "zhangqiang";
+
+ private static final String YUWEN = "yuwen";
+
+ private static final String LEARN_PROJECT = "learn_project";
+
+ private static final String TEST_PROJECT = "test_project";
+
+ private static final String KYLIN_PROJECT = "kylin_project";
+
+ private static final String[] PROJECTNAMES = new String[] { LEARN_PROJECT, TEST_PROJECT, KYLIN_PROJECT };
+
+ private static final String ROLE_ADMIN = "ADMIN";
+
+ private static final String ROLE_USER = "USER";
+
+ @Autowired
+ private AclEvaluate aclEvaluate;
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ // set kylin conf path
+ System.setProperty(KylinConfig.KYLIN_CONF, "src/test/resources");
+
+ // init kylin projects
+ initKylinProjects();
+
+ // mock kylin projects, to match projectUuid and projectName for kylin
+ mockKylinProjects();
+ }
+
+ @AfterClass
+ public static void cleanup() throws Exception {
+ // do nothing
+ }
+
+ /**
+ * Help function: init kylin projects
+ */
+ private static void initKylinProjects() {
+ for (String projectName : PROJECTNAMES) {
+ ProjectInstance projectInstance = getProjectInstance(projectName);
+ name2Projects.put(projectName, projectInstance);
+
+ uuid2Projects.put(projectInstance.getUuid(), projectInstance);
+ }
+ }
+
+ /**
+ * Help function: mock kylin projects, to match projectUuid and projectName
+ */
+ private static void mockKylinProjects() {
+ KylinConfig kylinConfig = KylinConfig.getInstanceFromEnv();
+ ProjectManager projectManager = mock(ProjectManager.class);
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ Map<Class, Object> managersCache = (Map<Class, Object>) ReflectionTestUtils.getField(kylinConfig,
+ "managersCache");
+ managersCache.put(ProjectManager.class, projectManager);
+
+ Answer<ProjectInstance> answer = new Answer<ProjectInstance>() {
+ @Override
+ public ProjectInstance answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ if (args == null || args.length == 0) {
+ return null;
+ }
+ String uuid = (String) args[0];
+ return uuid2Projects.get(uuid);
+ }
+ };
+ when(projectManager.getPrjByUuid(anyString())).thenAnswer(answer);
+ }
+
+ /**
+ * Help function: get random project instance for test
+ */
+ private static ProjectInstance getRandomProjectInstance() {
+ String name = RandomStringUtils.randomAlphanumeric(10) + "-project";
+ return getProjectInstance(name);
+ }
+
+ /**
+ * Help function: get specific project instance for test
+ */
+ private static ProjectInstance getProjectInstance(String name) {
+ String owner = null;
+ String description = null;
+ LinkedHashMap<String, String> overrideProps = null;
+ List<RealizationEntry> realizationEntries = null;
+ List<String> models = null;
+
+ return ProjectInstance.create(name, owner, description, overrideProps, realizationEntries, models);
+ }
+
+ // No.1 hasProjectReadPermission test start
+ /**
+ * no credentials read any project failed
+ */
+ @Test(expected = AuthenticationCredentialsNotFoundException.class)
+ public void readProjectAnyWithoutCredentials() {
+ ProjectInstance project = getRandomProjectInstance();
+ aclEvaluate.hasProjectReadPermission(project);
+ }
+
+ /**
+ * admin read all projects sueecss
+ */
+ @Test
+ @WithMockUser(username = ADMIN, roles = { ROLE_ADMIN })
+ public void readProjectAllAsRoleAdmin() {
+ for (ProjectInstance project : uuid2Projects.values()) {
+ boolean result = aclEvaluate.hasProjectReadPermission(project);
+ Assert.assertTrue(result);
+ }
+ }
+
+ /**
+ * kylin read all projects success
+ */
+ @Test
+ @WithMockUser(username = KYLIN, roles = { ROLE_USER })
+ public void readProjectAllWithAdminPermission() {
+ for (ProjectInstance project : uuid2Projects.values()) {
+ boolean result = aclEvaluate.hasProjectReadPermission(project);
+ Assert.assertTrue(result);
+ }
+ }
+
+ /**
+ * zhangqiang read test_project success
+ */
+ @Test
+ @WithMockUser(username = ZHANGQIANG, roles = { ROLE_USER })
+ public void readProjectTestWithAdminPermission() {
+ ProjectInstance project = name2Projects.get(TEST_PROJECT);
+ boolean result = aclEvaluate.hasProjectReadPermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * zhangqiang read kylin_project success
+ */
+ @Test
+ @WithMockUser(username = ZHANGQIANG, roles = { ROLE_USER })
+ public void readProjectKylinWithOperationPermission() {
+ ProjectInstance project = name2Projects.get(KYLIN_PROJECT);
+ boolean result = aclEvaluate.hasProjectReadPermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * yuwen read test_project success
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void readProjectTestWithManagementPermission() {
+ ProjectInstance project = name2Projects.get(TEST_PROJECT);
+ boolean result = aclEvaluate.hasProjectReadPermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * yuwen read kylin_project success
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void readProjectKylinWithQueryPermission() {
+ ProjectInstance project = name2Projects.get(KYLIN_PROJECT);
+ boolean result = aclEvaluate.hasProjectReadPermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * yuwen read learn_project failed
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void readProjectLearnWithoutPermission() {
+ ProjectInstance project = name2Projects.get(LEARN_PROJECT);
+ boolean result = aclEvaluate.hasProjectReadPermission(project);
+ Assert.assertFalse(result);
+ }
+
+ // No.1 hasProjectReadPermission test end
+
+ // No.2 hasProjectOperationPermission test start
+ /**
+ * no credentials operation any project failed
+ */
+ @Test(expected = AuthenticationCredentialsNotFoundException.class)
+ public void operationProjectAnyWithoutCredentials() {
+ ProjectInstance project = getRandomProjectInstance();
+ aclEvaluate.hasProjectOperationPermission(project);
+ }
+
+ /**
+ * admin operation all projects sueecss
+ */
+ @Test
+ @WithMockUser(username = ADMIN, roles = { ROLE_ADMIN })
+ public void operationProjectAllAsRoleAdmin() {
+ for (ProjectInstance project : uuid2Projects.values()) {
+ boolean result = aclEvaluate.hasProjectOperationPermission(project);
+ Assert.assertTrue(result);
+ }
+ }
+
+ /**
+ * kylin operation all projects success
+ */
+ @Test
+ @WithMockUser(username = KYLIN, roles = { ROLE_USER })
+ public void operationProjectAllWithAdminPermission() {
+ for (ProjectInstance project : uuid2Projects.values()) {
+ boolean result = aclEvaluate.hasProjectOperationPermission(project);
+ Assert.assertTrue(result);
+ }
+ }
+
+ /**
+ * zhangqiang operation test_project success
+ */
+ @Test
+ @WithMockUser(username = ZHANGQIANG, roles = { ROLE_USER })
+ public void operationProjectTestWithAdminPermission() {
+ ProjectInstance project = name2Projects.get(TEST_PROJECT);
+ boolean result = aclEvaluate.hasProjectOperationPermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * zhangqiang operation kylin_project success
+ */
+ @Test
+ @WithMockUser(username = ZHANGQIANG, roles = { ROLE_USER })
+ public void operationProjectKylinWithOperationPermission() {
+ ProjectInstance project = name2Projects.get(KYLIN_PROJECT);
+ boolean result = aclEvaluate.hasProjectOperationPermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * yuwen operation test_project success
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void operationProjectTestWithManagementPermission() {
+ ProjectInstance project = name2Projects.get(TEST_PROJECT);
+ boolean result = aclEvaluate.hasProjectOperationPermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * yuwen operation kylin_project failed
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void operationProjectKylinWithoutPermission() {
+ ProjectInstance project = name2Projects.get(KYLIN_PROJECT);
+ boolean result = aclEvaluate.hasProjectOperationPermission(project);
+ Assert.assertFalse(result);
+ }
+
+ /**
+ * yuwen operation learn_project failed
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void operationProjectLearnWithoutPermission() {
+ ProjectInstance project = name2Projects.get(LEARN_PROJECT);
+ boolean result = aclEvaluate.hasProjectOperationPermission(project);
+ Assert.assertFalse(result);
+ }
+
+ // No.2 hasProjectOperationPermission test end
+
+ // No.3 hasProjectWritePermission test start
+ /**
+ * no credentials write any project failed
+ */
+ @Test(expected = AuthenticationCredentialsNotFoundException.class)
+ public void writeProjectAnyWithoutCredentials() {
+ ProjectInstance project = getRandomProjectInstance();
+ aclEvaluate.hasProjectWritePermission(project);
+ }
+
+ /**
+ * admin write all projects sueecss
+ */
+ @Test
+ @WithMockUser(username = ADMIN, roles = { ROLE_ADMIN })
+ public void writeProjectAllAsRoleAdmin() {
+ for (ProjectInstance project : uuid2Projects.values()) {
+ boolean result = aclEvaluate.hasProjectWritePermission(project);
+ Assert.assertTrue(result);
+ }
+ }
+
+ /**
+ * kylin write all projects success
+ */
+ @Test
+ @WithMockUser(username = KYLIN, roles = { ROLE_USER })
+ public void writeProjectAllWithAdminPermission() {
+ for (ProjectInstance project : uuid2Projects.values()) {
+ boolean result = aclEvaluate.hasProjectWritePermission(project);
+ Assert.assertTrue(result);
+ }
+ }
+
+ /**
+ * zhangqiang write test_project success
+ */
+ @Test
+ @WithMockUser(username = ZHANGQIANG, roles = { ROLE_USER })
+ public void writeProjectTestWithAdminPermission() {
+ ProjectInstance project = name2Projects.get(TEST_PROJECT);
+ boolean result = aclEvaluate.hasProjectWritePermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * zhangqiang write kylin_project failed
+ */
+ @Test
+ @WithMockUser(username = ZHANGQIANG, roles = { ROLE_USER })
+ public void writeProjectKylinWithoutPermission() {
+ ProjectInstance project = name2Projects.get(KYLIN_PROJECT);
+ boolean result = aclEvaluate.hasProjectWritePermission(project);
+ Assert.assertFalse(result);
+ }
+
+ /**
+ * yuwen write test_project success
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void writeProjectTestWithManagementPermission() {
+ ProjectInstance project = name2Projects.get(TEST_PROJECT);
+ boolean result = aclEvaluate.hasProjectWritePermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * yuwen write kylin_project failed
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void writeProjectKylinWithoutPermission2() {
+ ProjectInstance project = name2Projects.get(KYLIN_PROJECT);
+ boolean result = aclEvaluate.hasProjectWritePermission(project);
+ Assert.assertFalse(result);
+ }
+
+ /**
+ * yuwen write learn_project failed
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void writeProjectLearnWithoutPermission() {
+ ProjectInstance project = name2Projects.get(LEARN_PROJECT);
+ boolean result = aclEvaluate.hasProjectWritePermission(project);
+ Assert.assertFalse(result);
+ }
+
+ // No.3 hasProjectWritePermission test end
+
+ // No.4 hasProjectAdminPermission test start
+ /**
+ * no credentials admin any project failed
+ */
+ @Test(expected = AuthenticationCredentialsNotFoundException.class)
+ public void adminProjectAnyWithoutCredentials() {
+ ProjectInstance project = getRandomProjectInstance();
+ aclEvaluate.hasProjectAdminPermission(project);
+ }
+
+ /**
+ * admin admin all projects sueecss
+ */
+ @Test
+ @WithMockUser(username = ADMIN, roles = { ROLE_ADMIN })
+ public void adminProjectAllAsRoleAdmin() {
+ for (ProjectInstance project : uuid2Projects.values()) {
+ boolean result = aclEvaluate.hasProjectAdminPermission(project);
+ Assert.assertTrue(result);
+ }
+ }
+
+ /**
+ * kylin admin all projects success
+ */
+ @Test
+ @WithMockUser(username = KYLIN, roles = { ROLE_USER })
+ public void adminProjectAllWithAdminPermission() {
+ for (ProjectInstance project : uuid2Projects.values()) {
+ boolean result = aclEvaluate.hasProjectAdminPermission(project);
+ Assert.assertTrue(result);
+ }
+ }
+
+ /**
+ * zhangqiang admin test_project success
+ */
+ @Test
+ @WithMockUser(username = ZHANGQIANG, roles = { ROLE_USER })
+ public void adminProjectTestWithAdminPermission() {
+ ProjectInstance project = name2Projects.get(TEST_PROJECT);
+ boolean result = aclEvaluate.hasProjectAdminPermission(project);
+ Assert.assertTrue(result);
+ }
+
+ /**
+ * zhangqiang admin kylin_project failed
+ */
+ @Test
+ @WithMockUser(username = ZHANGQIANG, roles = { ROLE_USER })
+ public void adminProjectKylinWithoutPermission() {
+ ProjectInstance project = name2Projects.get(KYLIN_PROJECT);
+ boolean result = aclEvaluate.hasProjectAdminPermission(project);
+ Assert.assertFalse(result);
+ }
+
+ /**
+ * yuwen admin test_project failed
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void adminProjectTestWithoutPermission() {
+ ProjectInstance project = name2Projects.get(TEST_PROJECT);
+ boolean result = aclEvaluate.hasProjectAdminPermission(project);
+ Assert.assertFalse(result);
+ }
+
+ /**
+ * yuwen admin kylin_project failed
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void adminProjectKylinWithoutPermission2() {
+ ProjectInstance project = name2Projects.get(KYLIN_PROJECT);
+ boolean result = aclEvaluate.hasProjectAdminPermission(project);
+ Assert.assertFalse(result);
+ }
+
+ /**
+ * yuwen admin learn_project failed
+ */
+ @Test
+ @WithMockUser(username = YUWEN, roles = { ROLE_USER })
+ public void adminProjectLearnWithoutPermission() {
+ ProjectInstance project = name2Projects.get(LEARN_PROJECT);
+ boolean result = aclEvaluate.hasProjectAdminPermission(project);
+ Assert.assertFalse(result);
+ }
+ // No.4 hasProjectAdminPermission test end
+}
http://git-wip-us.apache.org/repos/asf/ranger/blob/2b5a72ea/plugin-kylin/src/test/resources/applicationContext.xml
----------------------------------------------------------------------
diff --git a/plugin-kylin/src/test/resources/applicationContext.xml b/plugin-kylin/src/test/resources/applicationContext.xml
new file mode 100644
index 0000000..e4ce60b
--- /dev/null
+++ b/plugin-kylin/src/test/resources/applicationContext.xml
@@ -0,0 +1,50 @@
+<!--
+ Licensed 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. See accompanying LICENSE file.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:mvc="http://www.springframework.org/schema/mvc"
+ xmlns:task="http://www.springframework.org/schema/task"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xmlns:cache="http://www.springframework.org/schema/cache"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-4.3.xsd
+ http://www.springframework.org/schema/task
+ http://www.springframework.org/schema/task/spring-task-4.3.xsd
+ http://www.springframework.org/schema/mvc
+ http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
+ http://www.springframework.org/schema/aop
+ http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
+ http://www.springframework.org/schema/cache
+ http://www.springframework.org/schema/cache/spring-cache.xsd">
+
+ <description>UT test for kylin security service</description>
+
+ <context:annotation-config/>
+ <mvc:annotation-driven/>
+ <aop:aspectj-autoproxy/>
+
+ <context:component-scan base-package="org.apache.kylin.rest"
+ use-default-filters="false">
+ <context:include-filter type="assignable"
+ expression="org.apache.kylin.rest.util.AclEvaluate"/>
+ <context:include-filter type="assignable"
+ expression="org.apache.kylin.rest.util.AclUtil"/>
+ </context:component-scan>
+
+</beans>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ranger/blob/2b5a72ea/plugin-kylin/src/test/resources/kylin-policies.json
----------------------------------------------------------------------
diff --git a/plugin-kylin/src/test/resources/kylin-policies.json b/plugin-kylin/src/test/resources/kylin-policies.json
new file mode 100644
index 0000000..3009827
--- /dev/null
+++ b/plugin-kylin/src/test/resources/kylin-policies.json
@@ -0,0 +1,281 @@
+{
+ "serviceName": "kylinTest",
+ "serviceId": 2,
+ "policyVersion": 8,
+ "policyUpdateTime": "20171208-11:03:31.000-+0800",
+ "policies": [
+ {
+ "service": "kylinTest",
+ "name": "all - project",
+ "policyType": 0,
+ "description": "Policy for all - project",
+ "isAuditEnabled": true,
+ "resources": {
+ "project": {
+ "values": [
+ "*"
+ ],
+ "isExcludes": false,
+ "isRecursive": false
+ }
+ },
+ "policyItems": [
+ {
+ "accesses": [
+ {
+ "type": "QUERY",
+ "isAllowed": true
+ },
+ {
+ "type": "OPERATION",
+ "isAllowed": true
+ },
+ {
+ "type": "MANAGEMENT",
+ "isAllowed": true
+ },
+ {
+ "type": "ADMIN",
+ "isAllowed": true
+ }
+ ],
+ "users": [
+ "kylin"
+ ],
+ "groups": [],
+ "conditions": [],
+ "delegateAdmin": false
+ }
+ ],
+ "denyPolicyItems": [],
+ "allowExceptions": [],
+ "denyExceptions": [],
+ "dataMaskPolicyItems": [],
+ "rowFilterPolicyItems": [],
+ "id": 4,
+ "guid": "a38ec5dc-a788-48f2-87d1-c522ea8f996e",
+ "isEnabled": true,
+ "version": 2
+ },
+ {
+ "service": "kylinTest",
+ "name": "accessTestProject",
+ "policyType": 0,
+ "description": "",
+ "isAuditEnabled": true,
+ "resources": {
+ "project": {
+ "values": [
+ "test_project"
+ ],
+ "isExcludes": false,
+ "isRecursive": false
+ }
+ },
+ "policyItems": [
+ {
+ "accesses": [
+ {
+ "type": "ADMIN",
+ "isAllowed": true
+ }
+ ],
+ "users": [
+ "zhangqiang"
+ ],
+ "groups": [],
+ "conditions": [],
+ "delegateAdmin": false
+ },
+ {
+ "accesses": [
+ {
+ "type": "MANAGEMENT",
+ "isAllowed": true
+ }
+ ],
+ "users": [
+ "yuwen"
+ ],
+ "groups": [],
+ "conditions": [],
+ "delegateAdmin": false
+ }
+ ],
+ "denyPolicyItems": [],
+ "allowExceptions": [],
+ "denyExceptions": [],
+ "dataMaskPolicyItems": [],
+ "rowFilterPolicyItems": [],
+ "id": 5,
+ "guid": "072bdf13-6af0-45dd-8670-003e88ae2e54",
+ "isEnabled": true,
+ "version": 3
+ },
+ {
+ "service": "kylinTest",
+ "name": "accessKylinProject",
+ "policyType": 0,
+ "description": "",
+ "isAuditEnabled": true,
+ "resources": {
+ "project": {
+ "values": [
+ "kylin_project"
+ ],
+ "isExcludes": false,
+ "isRecursive": false
+ }
+ },
+ "policyItems": [
+ {
+ "accesses": [
+ {
+ "type": "OPERATION",
+ "isAllowed": true
+ }
+ ],
+ "users": [
+ "zhangqiang"
+ ],
+ "groups": [],
+ "conditions": [],
+ "delegateAdmin": false
+ },
+ {
+ "accesses": [
+ {
+ "type": "QUERY",
+ "isAllowed": true
+ }
+ ],
+ "users": [
+ "yuwen"
+ ],
+ "groups": [],
+ "conditions": [],
+ "delegateAdmin": false
+ }
+ ],
+ "denyPolicyItems": [],
+ "allowExceptions": [],
+ "denyExceptions": [],
+ "dataMaskPolicyItems": [],
+ "rowFilterPolicyItems": [],
+ "id": 6,
+ "guid": "9974c4bd-4c99-4eb1-b626-1d037c2c8567",
+ "isEnabled": true,
+ "version": 2
+ }
+ ],
+ "serviceDef": {
+ "name": "kylin",
+ "implClass": "org.apache.ranger.services.kylin.RangerServiceKylin",
+ "label": "KYLIN",
+ "description": "KYLIN",
+ "options": {
+ "enableDenyAndExceptionsInPolicies": "false"
+ },
+ "configs": [
+ {
+ "itemId": 1,
+ "name": "username",
+ "type": "string",
+ "mandatory": true,
+ "validationRegEx": "",
+ "validationMessage": "",
+ "uiHint": "",
+ "label": "Username"
+ },
+ {
+ "itemId": 2,
+ "name": "password",
+ "type": "password",
+ "mandatory": true,
+ "validationRegEx": "",
+ "validationMessage": "",
+ "uiHint": "",
+ "label": "Password"
+ },
+ {
+ "itemId": 3,
+ "name": "kylin.url",
+ "type": "string",
+ "mandatory": true,
+ "defaultValue": "",
+ "validationRegEx": "",
+ "validationMessage": "",
+ "uiHint": "{\"TextFieldWithIcon\":true, \"info\": \"eg. \u0027http://\u0026lt;ipaddr\u0026gt;:7070\u0027\"}",
+ "label": "Kylin URL"
+ }
+ ],
+ "resources": [
+ {
+ "itemId": 1,
+ "name": "project",
+ "type": "string",
+ "level": 10,
+ "mandatory": true,
+ "lookupSupported": true,
+ "recursiveSupported": false,
+ "excludesSupported": false,
+ "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+ "matcherOptions": {
+ "wildCard": "true",
+ "ignoreCase": "true"
+ },
+ "validationRegEx": "",
+ "validationMessage": "",
+ "uiHint": "",
+ "label": "Kylin Project",
+ "description": "Kylin Project",
+ "accessTypeRestrictions": []
+ }
+ ],
+ "accessTypes": [
+ {
+ "itemId": 1,
+ "name": "QUERY",
+ "label": "QUERY",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 2,
+ "name": "OPERATION",
+ "label": "OPERATION",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 3,
+ "name": "MANAGEMENT",
+ "label": "MANAGEMENT",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 4,
+ "name": "ADMIN",
+ "label": "ADMIN",
+ "impliedGrants": []
+ }
+ ],
+ "policyConditions": [],
+ "contextEnrichers": [],
+ "enums": [],
+ "dataMaskDef": {
+ "maskTypes": [],
+ "accessTypes": [],
+ "resources": []
+ },
+ "rowFilterDef": {
+ "accessTypes": [],
+ "resources": []
+ },
+ "id": 12,
+ "guid": "88ab8471-3e27-40c2-8bd8-458b5b1a9b25",
+ "isEnabled": true,
+ "createTime": "20171128-09:52:41.000-+0800",
+ "updateTime": "20171128-09:52:41.000-+0800",
+ "version": 1
+ },
+ "auditMode": "audit-default"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ranger/blob/2b5a72ea/plugin-kylin/src/test/resources/kylin.properties
----------------------------------------------------------------------
diff --git a/plugin-kylin/src/test/resources/kylin.properties b/plugin-kylin/src/test/resources/kylin.properties
new file mode 100644
index 0000000..9f26bd9
--- /dev/null
+++ b/plugin-kylin/src/test/resources/kylin.properties
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+
+#
+# Authorization configuration
+#
+kylin.server.external-acl-provider=org.apache.ranger.authorization.kylin.authorizer.RangerKylinAuthorizer
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ranger/blob/2b5a72ea/plugin-kylin/src/test/resources/kylinSecurity.xml
----------------------------------------------------------------------
diff --git a/plugin-kylin/src/test/resources/kylinSecurity.xml b/plugin-kylin/src/test/resources/kylinSecurity.xml
new file mode 100644
index 0000000..4d6eacd
--- /dev/null
+++ b/plugin-kylin/src/test/resources/kylinSecurity.xml
@@ -0,0 +1,77 @@
+<!--
+ Licensed 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. See accompanying LICENSE file.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:scr="http://www.springframework.org/schema/security"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
+ http://www.springframework.org/schema/security
+ http://www.springframework.org/schema/security/spring-security.xsd
+ http://www.springframework.org/schema/util
+ http://www.springframework.org/schema/util/spring-util-4.3.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context.xsd">
+
+ <scr:global-method-security pre-post-annotations="enabled">
+ <scr:expression-handler ref="expressionHandler"/>
+ </scr:global-method-security>
+
+ <!-- acl config -->
+ <bean id="aclPermissionFactory" class="org.apache.kylin.rest.security.AclPermissionFactory"/>
+
+ <bean id="expressionHandler"
+ class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
+ <property name="permissionEvaluator" ref="permissionEvaluator"/>
+ </bean>
+
+ <bean id="permissionEvaluator"
+ class="org.apache.kylin.rest.security.KylinAclPermissionEvaluator">
+ <constructor-arg type="org.apache.kylin.rest.service.AclService">
+ <null/>
+ </constructor-arg>
+ <constructor-arg ref="aclPermissionFactory"/>
+ </bean>
+
+ <bean id="aclAuthorizationStrategy"
+ class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
+ <constructor-arg>
+ <list>
+ <bean
+ class="org.springframework.security.core.authority.SimpleGrantedAuthority">
+ <constructor-arg value="ROLE_ADMIN"/>
+ </bean>
+ <bean
+ class="org.springframework.security.core.authority.SimpleGrantedAuthority">
+ <constructor-arg value="ROLE_ADMIN"/>
+ </bean>
+ <bean
+ class="org.springframework.security.core.authority.SimpleGrantedAuthority">
+ <constructor-arg value="ROLE_ADMIN"/>
+ </bean>
+ </list>
+ </constructor-arg>
+ </bean>
+
+ <bean id="auditLogger"
+ class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
+
+ <bean id="permissionGrantingStrategy"
+ class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
+ <constructor-arg ref="auditLogger"/>
+ </bean>
+
+</beans>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ranger/blob/2b5a72ea/plugin-kylin/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/plugin-kylin/src/test/resources/log4j.properties b/plugin-kylin/src/test/resources/log4j.properties
new file mode 100644
index 0000000..f7ab2ba
--- /dev/null
+++ b/plugin-kylin/src/test/resources/log4j.properties
@@ -0,0 +1,34 @@
+# 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.
+
+##-- To prevent junits from cluttering the build run by default all test runs send output to null appender
+log4j.appender.devnull=org.apache.log4j.varia.NullAppender
+ranger.root.logger=FATAL,devnull
+
+##-- uncomment the following line during during development/debugging so see debug messages during test run to be emitted to console
+# ranger.root.logger=DEBUG,console
+log4j.rootLogger=${ranger.root.logger}
+
+# Logging Threshold
+log4j.threshold=ALL
+
+#
+# console
+# Add "console" to rootlogger above if you want to use this
+#
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.target=System.err
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2}: %m%n
http://git-wip-us.apache.org/repos/asf/ranger/blob/2b5a72ea/plugin-kylin/src/test/resources/ranger-kylin-security.xml
----------------------------------------------------------------------
diff --git a/plugin-kylin/src/test/resources/ranger-kylin-security.xml b/plugin-kylin/src/test/resources/ranger-kylin-security.xml
new file mode 100644
index 0000000..e8609f9
--- /dev/null
+++ b/plugin-kylin/src/test/resources/ranger-kylin-security.xml
@@ -0,0 +1,60 @@
+<?xml version="1.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.
+-->
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<configuration xmlns:xi="http://www.w3.org/2001/XInclude">
+ <property>
+ <name>ranger.plugin.kylin.policy.rest.url</name>
+ <value>http://localhost:6080</value>
+ <description>
+ URL to Ranger Admin
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.plugin.kylin.service.name</name>
+ <value>kylinTest</value>
+ <description>
+ Name of the Ranger service containing policies for this SampleApp instance
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.plugin.kylin.policy.source.impl</name>
+ <value>org.apache.ranger.authorization.kylin.authorizer.RangerAdminClientImpl</value>
+ <description>
+ Policy source.
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.plugin.kylin.policy.pollIntervalMs</name>
+ <value>30000</value>
+ <description>
+ How often to poll for changes in policies?
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.plugin.kylin.policy.cache.dir</name>
+ <value>./target</value>
+ <description>
+ Directory where Ranger policies are cached after successful retrieval from the source
+ </description>
+ </property>
+
+</configuration>