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>