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 2016/09/26 15:47:59 UTC
incubator-ranger git commit: RANGER-1174 - Add tests for KMS Service
and plugin
Repository: incubator-ranger
Updated Branches:
refs/heads/master eed536b13 -> 868c62b72
RANGER-1174 - Add tests for KMS Service and plugin
Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/868c62b7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/868c62b7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/868c62b7
Branch: refs/heads/master
Commit: 868c62b729bb67b8b9db3f2146db1ea442b53ea8
Parents: eed536b
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Mon Sep 26 11:53:44 2016 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Mon Sep 26 16:40:26 2016 +0100
----------------------------------------------------------------------
kms/pom.xml | 6 +
.../crypto/key/kms/server/DerbyTestUtils.java | 66 +++
.../kms/server/RangerKeyStoreProviderTest.java | 154 +++++++
.../key/kms/server/RangerMasterKeyTest.java | 112 +++++
kms/src/test/resources/kms/dbks-site.xml | 65 +++
kms/src/test/resources/kms/kms-site.xml | 192 +++++++++
plugin-kms/pom.xml | 24 ++
.../kms/authorizer/DerbyTestUtils.java | 66 +++
.../kms/authorizer/RangerAdminClientImpl.java | 84 ++++
.../kms/authorizer/RangerKmsAuthorizerTest.java | 422 +++++++++++++++++++
plugin-kms/src/test/resources/kms-policies.json | 311 ++++++++++++++
plugin-kms/src/test/resources/kms/dbks-site.xml | 65 +++
plugin-kms/src/test/resources/kms/kms-site.xml | 192 +++++++++
.../src/test/resources/ranger-kms-security.xml | 61 +++
pom.xml | 2 +
15 files changed, 1822 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/kms/pom.xml
----------------------------------------------------------------------
diff --git a/kms/pom.xml b/kms/pom.xml
index e73dd01..c2c24ba 100644
--- a/kms/pom.xml
+++ b/kms/pom.xml
@@ -428,6 +428,12 @@
<artifactId>solr-solrj</artifactId>
<version>${solr.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <version>${derby.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<pluginManagement>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/DerbyTestUtils.java
----------------------------------------------------------------------
diff --git a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/DerbyTestUtils.java b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/DerbyTestUtils.java
new file mode 100644
index 0000000..b8d11dd
--- /dev/null
+++ b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/DerbyTestUtils.java
@@ -0,0 +1,66 @@
+/*
+ * 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.hadoop.crypto.key.kms.server;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+
+public final class DerbyTestUtils {
+
+ public static void startDerby() throws Exception {
+ // Start Apache Derby
+ Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
+
+ Properties props = new Properties();
+ Connection conn = DriverManager.getConnection("jdbc:derby:memory:derbyDB;create=true", props);
+
+ Statement statement = conn.createStatement();
+ statement.execute("CREATE SCHEMA KMSADMIN");
+
+ statement.execute("SET SCHEMA KMSADMIN");
+
+ // Create masterkey table
+ statement.execute("CREATE SEQUENCE RANGER_MASTERKEY_SEQ START WITH 1 INCREMENT BY 1");
+ String tableCreationString = "CREATE TABLE ranger_masterkey (id VARCHAR(20) NOT NULL PRIMARY KEY, create_time DATE,"
+ + "update_time DATE, added_by_id VARCHAR(20), upd_by_id VARCHAR(20),"
+ + "cipher VARCHAR(255), bitlength VARCHAR(11), masterkey VARCHAR(2048))";
+ statement.execute(tableCreationString);
+
+ // Create keys table
+ statement.execute("CREATE SEQUENCE RANGER_KEYSTORE_SEQ START WITH 1 INCREMENT BY 1");
+ statement.execute("CREATE TABLE ranger_keystore(id VARCHAR(20) NOT NULL PRIMARY KEY, create_time DATE,"
+ + "update_time DATE, added_by_id VARCHAR(20), upd_by_id VARCHAR(20),"
+ + "kms_alias VARCHAR(255) NOT NULL, kms_createdDate VARCHAR(20), kms_cipher VARCHAR(255),"
+ + "kms_bitLength VARCHAR(20), kms_description VARCHAR(512), kms_version VARCHAR(20),"
+ + "kms_attributes VARCHAR(1024), kms_encoded VARCHAR(2048))");
+
+ conn.close();
+ }
+
+ public static void stopDerby() throws Exception {
+ try {
+ DriverManager.getConnection("jdbc:derby:memory:derbyDB;drop=true");
+ } catch (SQLException ex) {
+ // expected
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
----------------------------------------------------------------------
diff --git a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
new file mode 100644
index 0000000..ff2fb2a
--- /dev/null
+++ b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.hadoop.crypto.key.kms.server;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.crypto.key.KeyProvider.KeyVersion;
+import org.apache.hadoop.crypto.key.KeyProvider.Options;
+import org.apache.hadoop.crypto.key.RangerKeyStoreProvider;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * A test for the RangerKeyStoreProvider, which is an implementation of the Hadoop KeyProvider interface, which stores keys in a database.
+ * Apache Derby is used to create the relevant tables to store the keys in for this test.
+ */
+public class RangerKeyStoreProviderTest {
+ private static final boolean UNRESTRICTED_POLICIES_INSTALLED;
+ static {
+ boolean ok = false;
+ try {
+ byte[] data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
+
+ SecretKey key192 = new SecretKeySpec(
+ new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17},
+ "AES");
+ Cipher c = Cipher.getInstance("AES");
+ c.init(Cipher.ENCRYPT_MODE, key192);
+ c.doFinal(data);
+ ok = true;
+ } catch (Exception e) {
+ //
+ }
+ UNRESTRICTED_POLICIES_INSTALLED = ok;
+ }
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+ DerbyTestUtils.startDerby();
+ }
+
+ @AfterClass
+ public static void stopServers() throws Exception {
+ if (UNRESTRICTED_POLICIES_INSTALLED) {
+ DerbyTestUtils.stopDerby();
+ }
+ }
+
+ @Test
+ public void testCreateDeleteKey() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Create a key
+ Options options = new Options(conf);
+ options.setBitLength(128);
+ options.setCipher("AES");
+ KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+ Assert.assertEquals("newkey1", keyVersion.getName());
+ Assert.assertEquals(128 / 8, keyVersion.getMaterial().length);
+ Assert.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+ keyProvider.flush();
+ Assert.assertEquals(1, keyProvider.getKeys().size());
+ keyProvider.deleteKey("newkey1");
+
+ keyProvider.flush();
+ Assert.assertEquals(0, keyProvider.getKeys().size());
+
+ // Try to delete a key that isn't there
+ try {
+ keyProvider.deleteKey("newkey2");
+ Assert.fail("Failure expected on trying to delete an unknown key");
+ } catch (IOException ex) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testRolloverKey() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, configDir.toFile().getAbsolutePath());
+
+ Configuration conf = new Configuration();
+ RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+ // Create a key
+ Options options = new Options(conf);
+ options.setBitLength(192);
+ options.setCipher("AES");
+ KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+ Assert.assertEquals("newkey1", keyVersion.getName());
+ Assert.assertEquals(192 / 8, keyVersion.getMaterial().length);
+ Assert.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+ keyProvider.flush();
+
+ // Rollover a new key
+ byte[] oldKey = keyVersion.getMaterial();
+ keyVersion = keyProvider.rollNewVersion("newkey1");
+ Assert.assertEquals("newkey1", keyVersion.getName());
+ Assert.assertEquals(192 / 8, keyVersion.getMaterial().length);
+ Assert.assertEquals("newkey1@1", keyVersion.getVersionName());
+ Assert.assertFalse(Arrays.equals(oldKey, keyVersion.getMaterial()));
+
+ keyProvider.deleteKey("newkey1");
+
+ keyProvider.flush();
+ Assert.assertEquals(0, keyProvider.getKeys().size());
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerMasterKeyTest.java
----------------------------------------------------------------------
diff --git a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerMasterKeyTest.java b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerMasterKeyTest.java
new file mode 100644
index 0000000..9e86b4b
--- /dev/null
+++ b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerMasterKeyTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.hadoop.crypto.key.kms.server;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.hadoop.crypto.key.RangerKMSDB;
+import org.apache.hadoop.crypto.key.RangerKeyStoreProvider;
+import org.apache.hadoop.crypto.key.RangerMasterKey;
+import org.apache.ranger.kms.dao.DaoManager;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * A test for the RangerMasterKey.
+ */
+public class RangerMasterKeyTest {
+ private static final boolean UNRESTRICTED_POLICIES_INSTALLED;
+ static {
+ boolean ok = false;
+ try {
+ byte[] data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
+
+ SecretKey key192 = new SecretKeySpec(
+ new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17},
+ "AES");
+ Cipher c = Cipher.getInstance("AES");
+ c.init(Cipher.ENCRYPT_MODE, key192);
+ c.doFinal(data);
+ ok = true;
+ } catch (Exception e) {
+ //
+ }
+ UNRESTRICTED_POLICIES_INSTALLED = ok;
+ }
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+ DerbyTestUtils.startDerby();
+ }
+
+ @AfterClass
+ public static void stopServers() throws Exception {
+ if (UNRESTRICTED_POLICIES_INSTALLED) {
+ DerbyTestUtils.stopDerby();
+ }
+ }
+
+ @Test
+ public void testRangerMasterKey() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, configDir.toFile().getAbsolutePath());
+
+ RangerKMSDB rangerkmsDb = new RangerKMSDB(RangerKeyStoreProvider.getDBKSConf());
+ DaoManager daoManager = rangerkmsDb.getDaoManager();
+
+ String masterKeyPassword = "password0password0password0password0password0password0password0password0"
+ + "password0password0password0password0password0password0password0password0password0password0"
+ + "password0password0password0password0password0password0password0password0password0password0";
+
+ RangerMasterKey rangerMasterKey = new RangerMasterKey(daoManager);
+ Assert.assertTrue(rangerMasterKey.generateMasterKey(masterKeyPassword));
+ Assert.assertNotNull(rangerMasterKey.getMasterKey(masterKeyPassword));
+
+ try {
+ rangerMasterKey.getMasterKey("badpass");
+ Assert.fail("Failure expected on retrieving a key with the wrong password");
+ } catch (Throwable t) {
+ // expected
+ }
+
+ Assert.assertNotNull(rangerMasterKey.getMasterSecretKey(masterKeyPassword));
+
+ try {
+ rangerMasterKey.getMasterSecretKey("badpass");
+ Assert.fail("Failure expected on retrieving a key with the wrong password");
+ } catch (Throwable t) {
+ // expected
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/kms/src/test/resources/kms/dbks-site.xml
----------------------------------------------------------------------
diff --git a/kms/src/test/resources/kms/dbks-site.xml b/kms/src/test/resources/kms/dbks-site.xml
new file mode 100755
index 0000000..dbc9576
--- /dev/null
+++ b/kms/src/test/resources/kms/dbks-site.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<configuration>
+
+ <!-- Encryption key Password -->
+
+ <property>
+ <name>ranger.db.encrypt.key.password</name>
+ <value>Str0ngPassw0rd</value>
+ <description>
+ Password used for encrypting Master Key
+ </description>
+ </property>
+
+ <!-- db Details -->
+
+ <property>
+ <name>ranger.ks.jpa.jdbc.url</name>
+ <value>jdbc:derby:memory:derbyDB;create=true</value>
+ <description>
+ URL for Database
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.ks.jpa.jdbc.user</name>
+ <value>kmsadmin</value>
+ <description>
+ Database username used for operation
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.ks.jpa.jdbc.password</name>
+ <value>kmsadmin</value>
+ <description>
+ Database user's password
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.ks.jpa.jdbc.driver</name>
+ <value>org.apache.derby.jdbc.EmbeddedDriver</value>
+ <description>
+ Driver used for database
+ </description>
+ </property>
+
+</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/kms/src/test/resources/kms/kms-site.xml
----------------------------------------------------------------------
diff --git a/kms/src/test/resources/kms/kms-site.xml b/kms/src/test/resources/kms/kms-site.xml
new file mode 100644
index 0000000..5f2575a
--- /dev/null
+++ b/kms/src/test/resources/kms/kms-site.xml
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<configuration>
+
+ <!-- KMS Backend KeyProvider -->
+
+ <property>
+ <name>hadoop.kms.key.provider.uri</name>
+ <value>dbks://http@localhost:9292/kms</value>
+ <description>
+ URI of the backing KeyProvider for the KMS.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.security.keystore.JavaKeyStoreProvider.password</name>
+ <value>none</value>
+ <description>
+ If using the JavaKeyStoreProvider, the password for the keystore file.
+ </description>
+ </property>
+
+ <!-- KMS Cache -->
+
+ <property>
+ <name>hadoop.kms.cache.enable</name>
+ <value>true</value>
+ <description>
+ Whether the KMS will act as a cache for the backing KeyProvider.
+ When the cache is enabled, operations like getKeyVersion, getMetadata,
+ and getCurrentKey will sometimes return cached data without consulting
+ the backing KeyProvider. Cached values are flushed when keys are deleted
+ or modified.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.cache.timeout.ms</name>
+ <value>600000</value>
+ <description>
+ Expiry time for the KMS key version and key metadata cache, in
+ milliseconds. This affects getKeyVersion and getMetadata.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.current.key.cache.timeout.ms</name>
+ <value>30000</value>
+ <description>
+ Expiry time for the KMS current key cache, in milliseconds. This
+ affects getCurrentKey operations.
+ </description>
+ </property>
+
+ <!-- KMS Audit -->
+
+ <property>
+ <name>hadoop.kms.audit.aggregation.window.ms</name>
+ <value>10000</value>
+ <description>
+ Duplicate audit log events within the aggregation window (specified in
+ ms) are quashed to reduce log traffic. A single message for aggregated
+ events is printed at the end of the window, along with a count of the
+ number of aggregated events.
+ </description>
+ </property>
+
+ <!-- KMS Security -->
+
+ <property>
+ <name>hadoop.kms.authentication.type</name>
+ <value>simple</value>
+ <description>
+ Authentication type for the KMS. Can be either "simple"
+ or "kerberos".
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.kerberos.keytab</name>
+ <value>${user.home}/kms.keytab</value>
+ <description>
+ Path to the keytab with credentials for the configured Kerberos principal.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.kerberos.principal</name>
+ <value>HTTP/localhost</value>
+ <description>
+ The Kerberos principal to use for the HTTP endpoint.
+ The principal must start with 'HTTP/' as per the Kerberos HTTP SPNEGO specification.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.kerberos.name.rules</name>
+ <value>DEFAULT</value>
+ <description>
+ Rules used to resolve Kerberos principal names.
+ </description>
+ </property>
+
+ <!-- Authentication cookie signature source -->
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider</name>
+ <value>random</value>
+ <description>
+ Indicates how the secret to sign the authentication cookies will be
+ stored. Options are 'random' (default), 'string' and 'zookeeper'.
+ If using a setup with multiple KMS instances, 'zookeeper' should be used.
+ </description>
+ </property>
+
+ <!-- Configuration for 'zookeeper' authentication cookie signature source -->
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.path</name>
+ <value>/hadoop-kms/hadoop-auth-signature-secret</value>
+ <description>
+ The Zookeeper ZNode path where the KMS instances will store and retrieve
+ the secret from.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.connection.string</name>
+ <value>#HOSTNAME#:#PORT#,...</value>
+ <description>
+ The Zookeeper connection string, a list of hostnames and port comma
+ separated.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.auth.type</name>
+ <value>kerberos</value>
+ <description>
+ The Zookeeper authentication type, 'none' or 'sasl' (Kerberos).
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.keytab</name>
+ <value>/etc/hadoop/conf/kms.keytab</value>
+ <description>
+ The absolute path for the Kerberos keytab with the credentials to
+ connect to Zookeeper.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.principal</name>
+ <value>kms/#HOSTNAME#</value>
+ <description>
+ The Kerberos service principal used to connect to Zookeeper.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.security.authorization.manager</name>
+ <value>org.apache.ranger.authorization.kms.authorizer.RangerKmsAuthorizer</value>
+ </property>
+
+ <property>
+ <name>hadoop.kms.proxyuser.ranger.groups</name>
+ <value>*</value>
+ </property>
+
+ <property>
+ <name>hadoop.kms.proxyuser.ranger.hosts</name>
+ <value>*</value>
+ </property>
+
+ <property>
+ <name>hadoop.kms.proxyuser.ranger.users</name>
+ <value>*</value>
+ </property>
+</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/plugin-kms/pom.xml
----------------------------------------------------------------------
diff --git a/plugin-kms/pom.xml b/plugin-kms/pom.xml
index 5ac7b20..c2a0439 100644
--- a/plugin-kms/pom.xml
+++ b/plugin-kms/pom.xml
@@ -56,5 +56,29 @@
<artifactId>httpcore</artifactId>
<version>${httpcomponents.httpcore.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <version>${derby.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>${easymock.version}</version>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
+ <build>
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ <filtering>true</filtering>
+ </testResource>
+ </testResources>
+ </build>
</project>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/DerbyTestUtils.java
----------------------------------------------------------------------
diff --git a/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/DerbyTestUtils.java b/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/DerbyTestUtils.java
new file mode 100644
index 0000000..6899da6
--- /dev/null
+++ b/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/DerbyTestUtils.java
@@ -0,0 +1,66 @@
+/*
+ * 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.kms.authorizer;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+
+public final class DerbyTestUtils {
+
+ public static void startDerby() throws Exception {
+ // Start Apache Derby
+ Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
+
+ Properties props = new Properties();
+ Connection conn = DriverManager.getConnection("jdbc:derby:memory:derbyDB;create=true", props);
+
+ Statement statement = conn.createStatement();
+ statement.execute("CREATE SCHEMA KMSADMIN");
+
+ statement.execute("SET SCHEMA KMSADMIN");
+
+ // Create masterkey table
+ statement.execute("CREATE SEQUENCE RANGER_MASTERKEY_SEQ START WITH 1 INCREMENT BY 1");
+ String tableCreationString = "CREATE TABLE ranger_masterkey (id VARCHAR(20) NOT NULL PRIMARY KEY, create_time DATE,"
+ + "update_time DATE, added_by_id VARCHAR(20), upd_by_id VARCHAR(20),"
+ + "cipher VARCHAR(255), bitlength VARCHAR(11), masterkey VARCHAR(2048))";
+ statement.execute(tableCreationString);
+
+ // Create keys table
+ statement.execute("CREATE SEQUENCE RANGER_KEYSTORE_SEQ START WITH 1 INCREMENT BY 1");
+ statement.execute("CREATE TABLE ranger_keystore(id VARCHAR(20) NOT NULL PRIMARY KEY, create_time DATE,"
+ + "update_time DATE, added_by_id VARCHAR(20), upd_by_id VARCHAR(20),"
+ + "kms_alias VARCHAR(255) NOT NULL, kms_createdDate VARCHAR(20), kms_cipher VARCHAR(255),"
+ + "kms_bitLength VARCHAR(20), kms_description VARCHAR(512), kms_version VARCHAR(20),"
+ + "kms_attributes VARCHAR(1024), kms_encoded VARCHAR(2048))");
+
+ conn.close();
+ }
+
+ public static void stopDerby() throws Exception {
+ try {
+ DriverManager.getConnection("jdbc:derby:memory:derbyDB;drop=true");
+ } catch (SQLException ex) {
+ // expected
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerAdminClientImpl.java
----------------------------------------------------------------------
diff --git a/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerAdminClientImpl.java b/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerAdminClientImpl.java
new file mode 100644
index 0000000..ebc1991
--- /dev/null
+++ b/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerAdminClientImpl.java
@@ -0,0 +1,84 @@
+/*
+ * 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.kms.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 final static String cacheFilename = "kms-policies.json";
+ private Gson gson;
+
+ 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;
+ }
+
+ public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion) 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);
+ }
+
+ public void grantAccess(GrantRevokeRequest request) throws Exception {
+
+ }
+
+ public void revokeAccess(GrantRevokeRequest request) throws Exception {
+
+ }
+
+ public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception {
+ return null;
+
+ }
+
+ public List<String> getTagTypes(String tagTypePattern) throws Exception {
+ return null;
+ }
+
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerKmsAuthorizerTest.java
----------------------------------------------------------------------
diff --git a/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerKmsAuthorizerTest.java b/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerKmsAuthorizerTest.java
new file mode 100644
index 0000000..7fef432
--- /dev/null
+++ b/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerKmsAuthorizerTest.java
@@ -0,0 +1,422 @@
+/*
+ * 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.kms.authorizer;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.PrivilegedExceptionAction;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+
+import org.apache.hadoop.crypto.key.kms.server.KMS.KMSOp;
+import org.apache.hadoop.crypto.key.kms.server.KMSACLsType.Type;
+import org.apache.hadoop.crypto.key.kms.server.KMSConfiguration;
+import org.apache.hadoop.crypto.key.kms.server.KMSWebApp;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authorize.AuthorizationException;
+import org.easymock.EasyMock;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Policies available from admin via:
+ *
+ * http://localhost:6080/service/plugins/policies/download/KMSTest
+ *
+ * The user "bob" can do anything. The group "IT" can only call the "get" methods
+ */
+public class RangerKmsAuthorizerTest {
+
+ private static KMSWebApp kmsWebapp;
+ private static final boolean UNRESTRICTED_POLICIES_INSTALLED;
+ static {
+ boolean ok = false;
+ try {
+ byte[] data = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
+
+ SecretKey key192 = new SecretKeySpec(
+ new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17},
+ "AES");
+ Cipher c = Cipher.getInstance("AES");
+ c.init(Cipher.ENCRYPT_MODE, key192);
+ c.doFinal(data);
+ ok = true;
+ } catch (Exception e) {
+ //
+ }
+ UNRESTRICTED_POLICIES_INSTALLED = ok;
+ }
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+ DerbyTestUtils.startDerby();
+
+ Path configDir = Paths.get("src/test/resources/kms");
+ System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, configDir.toFile().getAbsolutePath());
+
+ // Start KMSWebApp
+ ServletContextEvent servletContextEvent = EasyMock.createMock(ServletContextEvent.class);
+ ServletContext servletContext = EasyMock.createMock(ServletContext.class);
+ EasyMock.expect(servletContextEvent.getServletContext()).andReturn(servletContext).anyTimes();
+ EasyMock.replay(servletContextEvent);
+
+ kmsWebapp = new KMSWebApp();
+ kmsWebapp.contextInitialized(servletContextEvent);
+ }
+
+ @AfterClass
+ public static void stopServers() throws Exception {
+ DerbyTestUtils.stopDerby();
+ }
+
+ @Test
+ public void testCreateKeys() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ // bob should have permission to create
+ final UserGroupInformation ugi = UserGroupInformation.createRemoteUser("bob");
+ ugi.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ KMSWebApp.getACLs().assertAccess(Type.CREATE, ugi, KMSOp.CREATE_KEY, "newkey1", "127.0.0.1");
+ return null;
+ }
+ });
+
+ // "eve" should not have permission to create
+ final UserGroupInformation ugi2 = UserGroupInformation.createRemoteUser("eve");
+ ugi2.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.CREATE, ugi2, KMSOp.CREATE_KEY, "newkey2", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ // the IT group should not have permission to create
+ final UserGroupInformation ugi3 = UserGroupInformation.createUserForTesting("alice", new String[]{"IT"});
+ ugi3.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.CREATE, ugi3, KMSOp.CREATE_KEY, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+ }
+
+ @Test
+ public void testDeleteKeys() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ // bob should have permission to delete
+ final UserGroupInformation ugi = UserGroupInformation.createRemoteUser("bob");
+ ugi.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ KMSWebApp.getACLs().assertAccess(Type.DELETE, ugi, KMSOp.DELETE_KEY, "newkey1", "127.0.0.1");
+ return null;
+ }
+ });
+
+ // "eve" should not have permission to delete
+ final UserGroupInformation ugi2 = UserGroupInformation.createRemoteUser("eve");
+ ugi2.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.DELETE, ugi2, KMSOp.DELETE_KEY, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ // the IT group should not have permission to delete
+ final UserGroupInformation ugi3 = UserGroupInformation.createUserForTesting("alice", new String[]{"IT"});
+ ugi3.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.DELETE, ugi3, KMSOp.DELETE_KEY, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ }
+
+ @Test
+ public void testRollover() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ // bob should have permission to rollover
+ final UserGroupInformation ugi = UserGroupInformation.createRemoteUser("bob");
+ ugi.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ KMSWebApp.getACLs().assertAccess(Type.ROLLOVER, ugi, KMSOp.ROLL_NEW_VERSION, "newkey1", "127.0.0.1");
+ return null;
+ }
+ });
+
+ // "eve" should not have permission to rollover
+ final UserGroupInformation ugi2 = UserGroupInformation.createRemoteUser("eve");
+ ugi2.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.ROLLOVER, ugi2, KMSOp.ROLL_NEW_VERSION, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ // the IT group should not have permission to rollover
+ final UserGroupInformation ugi3 = UserGroupInformation.createUserForTesting("alice", new String[]{"IT"});
+ ugi3.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.ROLLOVER, ugi3, KMSOp.ROLL_NEW_VERSION, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ }
+
+ @Test
+ public void testGetKeys() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ // bob should have permission to get keys
+ final UserGroupInformation ugi = UserGroupInformation.createRemoteUser("bob");
+ ugi.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ KMSWebApp.getACLs().assertAccess(Type.GET_KEYS, ugi, KMSOp.GET_KEYS, "newkey1", "127.0.0.1");
+ return null;
+ }
+ });
+
+ // "eve" should not have permission to get keys
+ final UserGroupInformation ugi2 = UserGroupInformation.createRemoteUser("eve");
+ ugi2.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.GET_KEYS, ugi2, KMSOp.GET_KEYS, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ // the IT group should have permission to get keys
+ final UserGroupInformation ugi3 = UserGroupInformation.createUserForTesting("alice", new String[]{"IT"});
+ ugi3.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ KMSWebApp.getACLs().assertAccess(Type.GET_KEYS, ugi3, KMSOp.GET_KEYS, "newkey1", "127.0.0.1");
+ return null;
+ }
+ });
+ }
+
+ @Test
+ public void testGetMetadata() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ // bob should have permission to get the metadata
+ final UserGroupInformation ugi = UserGroupInformation.createRemoteUser("bob");
+ ugi.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ KMSWebApp.getACLs().assertAccess(Type.GET_METADATA, ugi, KMSOp.GET_METADATA, "newkey1", "127.0.0.1");
+ return null;
+ }
+ });
+
+ // "eve" should not have permission to get the metadata
+ final UserGroupInformation ugi2 = UserGroupInformation.createRemoteUser("eve");
+ ugi2.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.GET_METADATA, ugi2, KMSOp.GET_METADATA, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ // the IT group should have permission to get the metadata
+ final UserGroupInformation ugi3 = UserGroupInformation.createUserForTesting("alice", new String[]{"IT"});
+ ugi3.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ KMSWebApp.getACLs().assertAccess(Type.GET_METADATA, ugi3, KMSOp.GET_METADATA, "newkey1", "127.0.0.1");
+ return null;
+ }
+ });
+
+ }
+
+ @Test
+ public void testGenerateEEK() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ // bob should have permission to generate EEK
+ final UserGroupInformation ugi = UserGroupInformation.createRemoteUser("bob");
+ ugi.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ KMSWebApp.getACLs().assertAccess(Type.GENERATE_EEK, ugi, KMSOp.GENERATE_EEK, "newkey1", "127.0.0.1");
+ return null;
+ }
+ });
+
+ // "eve" should not have permission to generate EEK
+ final UserGroupInformation ugi2 = UserGroupInformation.createRemoteUser("eve");
+ ugi2.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.GENERATE_EEK, ugi2, KMSOp.GENERATE_EEK, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ // the IT group should not have permission to generate EEK
+ final UserGroupInformation ugi3 = UserGroupInformation.createUserForTesting("alice", new String[]{"IT"});
+ ugi3.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.GENERATE_EEK, ugi3, KMSOp.GENERATE_EEK, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ }
+
+ @Test
+ public void testDecryptEEK() throws Throwable {
+ if (!UNRESTRICTED_POLICIES_INSTALLED) {
+ return;
+ }
+
+ // bob should have permission to generate EEK
+ final UserGroupInformation ugi = UserGroupInformation.createRemoteUser("bob");
+ ugi.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ KMSWebApp.getACLs().assertAccess(Type.DECRYPT_EEK, ugi, KMSOp.DECRYPT_EEK, "newkey1", "127.0.0.1");
+ return null;
+ }
+ });
+
+ // "eve" should not have permission to decrypt EEK
+ final UserGroupInformation ugi2 = UserGroupInformation.createRemoteUser("eve");
+ ugi2.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.DECRYPT_EEK, ugi2, KMSOp.DECRYPT_EEK, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ // the IT group should not have permission to decrypt EEK
+ final UserGroupInformation ugi3 = UserGroupInformation.createUserForTesting("alice", new String[]{"IT"});
+ ugi3.doAs(new PrivilegedExceptionAction<Void>() {
+
+ public Void run() throws Exception {
+ try {
+ KMSWebApp.getACLs().assertAccess(Type.DECRYPT_EEK, ugi3, KMSOp.DECRYPT_EEK, "newkey1", "127.0.0.1");
+ Assert.fail("Failure expected");
+ } catch (AuthorizationException ex) {
+ // expected
+ }
+ return null;
+ }
+ });
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/plugin-kms/src/test/resources/kms-policies.json
----------------------------------------------------------------------
diff --git a/plugin-kms/src/test/resources/kms-policies.json b/plugin-kms/src/test/resources/kms-policies.json
new file mode 100644
index 0000000..479f98e
--- /dev/null
+++ b/plugin-kms/src/test/resources/kms-policies.json
@@ -0,0 +1,311 @@
+{
+ "serviceName": "KMSTest",
+ "serviceId": 17,
+ "policyVersion": 3,
+ "policyUpdateTime": "20160804-09:51:46.000-+0100",
+ "policies": [
+ {
+ "service": "KMSTest",
+ "name": "KMSTest-1-20160727162811",
+ "description": "Default Policy for Service: KMSTest",
+ "resourceSignature": "d135a88a4f4ed3a8ac7278891f15c780",
+ "isAuditEnabled": true,
+ "resources": {
+ "keyname": {
+ "values": [
+ "*"
+ ],
+ "isExcludes": false,
+ "isRecursive": false
+ }
+ },
+ "policyItems": [
+ {
+ "accesses": [
+ {
+ "type": "create",
+ "isAllowed": true
+ },
+ {
+ "type": "delete",
+ "isAllowed": true
+ },
+ {
+ "type": "rollover",
+ "isAllowed": true
+ },
+ {
+ "type": "setkeymaterial",
+ "isAllowed": true
+ },
+ {
+ "type": "get",
+ "isAllowed": true
+ },
+ {
+ "type": "getkeys",
+ "isAllowed": true
+ },
+ {
+ "type": "getmetadata",
+ "isAllowed": true
+ },
+ {
+ "type": "generateeek",
+ "isAllowed": true
+ },
+ {
+ "type": "decrypteek",
+ "isAllowed": true
+ }
+ ],
+ "users": [
+ "keyadmin"
+ ],
+ "groups": [],
+ "conditions": [],
+ "delegateAdmin": true
+ }
+ ],
+ "denyPolicyItems": [],
+ "allowExceptions": [],
+ "denyExceptions": [],
+ "dataMaskPolicyItems": [],
+ "rowFilterPolicyItems": [],
+ "id": 51,
+ "guid": "1469636891164_121_393",
+ "isEnabled": true,
+ "createdBy": "keyadmin",
+ "updatedBy": "keyadmin",
+ "createTime": "20160727-17:28:11.000-+0100",
+ "updateTime": "20160727-17:28:11.000-+0100",
+ "version": 1
+ },
+ {
+ "service": "KMSTest",
+ "name": "NewKeyPolicy",
+ "description": "",
+ "resourceSignature": "4b688c2712bb70da6227646b1948a086",
+ "isAuditEnabled": true,
+ "resources": {
+ "keyname": {
+ "values": [
+ "newkey*"
+ ],
+ "isExcludes": false,
+ "isRecursive": false
+ }
+ },
+ "policyItems": [
+ {
+ "accesses": [
+ {
+ "type": "create",
+ "isAllowed": true
+ },
+ {
+ "type": "delete",
+ "isAllowed": true
+ },
+ {
+ "type": "rollover",
+ "isAllowed": true
+ },
+ {
+ "type": "setkeymaterial",
+ "isAllowed": true
+ },
+ {
+ "type": "get",
+ "isAllowed": true
+ },
+ {
+ "type": "getkeys",
+ "isAllowed": true
+ },
+ {
+ "type": "getmetadata",
+ "isAllowed": true
+ },
+ {
+ "type": "generateeek",
+ "isAllowed": true
+ },
+ {
+ "type": "decrypteek",
+ "isAllowed": true
+ }
+ ],
+ "users": [
+ "bob"
+ ],
+ "groups": [],
+ "conditions": [],
+ "delegateAdmin": false
+ },
+ {
+ "accesses": [
+ {
+ "type": "get",
+ "isAllowed": true
+ },
+ {
+ "type": "getkeys",
+ "isAllowed": true
+ },
+ {
+ "type": "getmetadata",
+ "isAllowed": true
+ }
+ ],
+ "users": [],
+ "groups": [
+ "IT"
+ ],
+ "conditions": [],
+ "delegateAdmin": false
+ }
+ ],
+ "denyPolicyItems": [],
+ "allowExceptions": [],
+ "denyExceptions": [],
+ "dataMaskPolicyItems": [],
+ "rowFilterPolicyItems": [],
+ "id": 52,
+ "guid": "1470224184963_204_597",
+ "isEnabled": true,
+ "createdBy": "keyadmin",
+ "updatedBy": "keyadmin",
+ "createTime": "20160803-12:36:24.000-+0100",
+ "updateTime": "20160804-09:51:46.000-+0100",
+ "version": 2
+ }
+ ],
+ "serviceDef": {
+ "name": "kms",
+ "implClass": "org.apache.ranger.services.kms.RangerServiceKMS",
+ "label": "KMS",
+ "description": "KMS",
+ "options": {},
+ "configs": [
+ {
+ "itemId": 1,
+ "name": "provider",
+ "type": "string",
+ "mandatory": true,
+ "label": "KMS URL"
+ },
+ {
+ "itemId": 2,
+ "name": "username",
+ "type": "string",
+ "mandatory": true,
+ "label": "Username"
+ },
+ {
+ "itemId": 3,
+ "name": "password",
+ "type": "password",
+ "mandatory": true,
+ "label": "Password"
+ }
+ ],
+ "resources": [
+ {
+ "itemId": 1,
+ "name": "keyname",
+ "type": "string",
+ "level": 10,
+ "mandatory": true,
+ "lookupSupported": true,
+ "recursiveSupported": false,
+ "excludesSupported": false,
+ "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+ "matcherOptions": {
+ "wildCard": "true",
+ "ignoreCase": "false"
+ },
+ "validationRegEx": "",
+ "validationMessage": "",
+ "uiHint": "",
+ "label": "Key Name",
+ "description": "Key Name"
+ }
+ ],
+ "accessTypes": [
+ {
+ "itemId": 1,
+ "name": "create",
+ "label": "Create",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 2,
+ "name": "delete",
+ "label": "Delete",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 3,
+ "name": "rollover",
+ "label": "Rollover",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 4,
+ "name": "setkeymaterial",
+ "label": "Set Key Material",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 5,
+ "name": "get",
+ "label": "Get",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 6,
+ "name": "getkeys",
+ "label": "Get Keys",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 7,
+ "name": "getmetadata",
+ "label": "Get Metadata",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 8,
+ "name": "generateeek",
+ "label": "Generate EEK",
+ "impliedGrants": []
+ },
+ {
+ "itemId": 9,
+ "name": "decrypteek",
+ "label": "Decrypt EEK",
+ "impliedGrants": []
+ }
+ ],
+ "policyConditions": [],
+ "contextEnrichers": [],
+ "enums": [],
+ "dataMaskDef": {
+ "maskTypes": [],
+ "accessTypes": [],
+ "resources": []
+ },
+ "rowFilterDef": {
+ "accessTypes": [],
+ "resources": []
+ },
+ "id": 7,
+ "guid": "1457966375677_148_0",
+ "isEnabled": true,
+ "createTime": "20160314-14:39:35.000-+0000",
+ "updateTime": "20160314-14:39:35.000-+0000",
+ "version": 1
+ },
+ "auditMode": "audit-default"
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/plugin-kms/src/test/resources/kms/dbks-site.xml
----------------------------------------------------------------------
diff --git a/plugin-kms/src/test/resources/kms/dbks-site.xml b/plugin-kms/src/test/resources/kms/dbks-site.xml
new file mode 100755
index 0000000..dbc9576
--- /dev/null
+++ b/plugin-kms/src/test/resources/kms/dbks-site.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<configuration>
+
+ <!-- Encryption key Password -->
+
+ <property>
+ <name>ranger.db.encrypt.key.password</name>
+ <value>Str0ngPassw0rd</value>
+ <description>
+ Password used for encrypting Master Key
+ </description>
+ </property>
+
+ <!-- db Details -->
+
+ <property>
+ <name>ranger.ks.jpa.jdbc.url</name>
+ <value>jdbc:derby:memory:derbyDB;create=true</value>
+ <description>
+ URL for Database
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.ks.jpa.jdbc.user</name>
+ <value>kmsadmin</value>
+ <description>
+ Database username used for operation
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.ks.jpa.jdbc.password</name>
+ <value>kmsadmin</value>
+ <description>
+ Database user's password
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.ks.jpa.jdbc.driver</name>
+ <value>org.apache.derby.jdbc.EmbeddedDriver</value>
+ <description>
+ Driver used for database
+ </description>
+ </property>
+
+</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/plugin-kms/src/test/resources/kms/kms-site.xml
----------------------------------------------------------------------
diff --git a/plugin-kms/src/test/resources/kms/kms-site.xml b/plugin-kms/src/test/resources/kms/kms-site.xml
new file mode 100644
index 0000000..5f2575a
--- /dev/null
+++ b/plugin-kms/src/test/resources/kms/kms-site.xml
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<configuration>
+
+ <!-- KMS Backend KeyProvider -->
+
+ <property>
+ <name>hadoop.kms.key.provider.uri</name>
+ <value>dbks://http@localhost:9292/kms</value>
+ <description>
+ URI of the backing KeyProvider for the KMS.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.security.keystore.JavaKeyStoreProvider.password</name>
+ <value>none</value>
+ <description>
+ If using the JavaKeyStoreProvider, the password for the keystore file.
+ </description>
+ </property>
+
+ <!-- KMS Cache -->
+
+ <property>
+ <name>hadoop.kms.cache.enable</name>
+ <value>true</value>
+ <description>
+ Whether the KMS will act as a cache for the backing KeyProvider.
+ When the cache is enabled, operations like getKeyVersion, getMetadata,
+ and getCurrentKey will sometimes return cached data without consulting
+ the backing KeyProvider. Cached values are flushed when keys are deleted
+ or modified.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.cache.timeout.ms</name>
+ <value>600000</value>
+ <description>
+ Expiry time for the KMS key version and key metadata cache, in
+ milliseconds. This affects getKeyVersion and getMetadata.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.current.key.cache.timeout.ms</name>
+ <value>30000</value>
+ <description>
+ Expiry time for the KMS current key cache, in milliseconds. This
+ affects getCurrentKey operations.
+ </description>
+ </property>
+
+ <!-- KMS Audit -->
+
+ <property>
+ <name>hadoop.kms.audit.aggregation.window.ms</name>
+ <value>10000</value>
+ <description>
+ Duplicate audit log events within the aggregation window (specified in
+ ms) are quashed to reduce log traffic. A single message for aggregated
+ events is printed at the end of the window, along with a count of the
+ number of aggregated events.
+ </description>
+ </property>
+
+ <!-- KMS Security -->
+
+ <property>
+ <name>hadoop.kms.authentication.type</name>
+ <value>simple</value>
+ <description>
+ Authentication type for the KMS. Can be either "simple"
+ or "kerberos".
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.kerberos.keytab</name>
+ <value>${user.home}/kms.keytab</value>
+ <description>
+ Path to the keytab with credentials for the configured Kerberos principal.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.kerberos.principal</name>
+ <value>HTTP/localhost</value>
+ <description>
+ The Kerberos principal to use for the HTTP endpoint.
+ The principal must start with 'HTTP/' as per the Kerberos HTTP SPNEGO specification.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.kerberos.name.rules</name>
+ <value>DEFAULT</value>
+ <description>
+ Rules used to resolve Kerberos principal names.
+ </description>
+ </property>
+
+ <!-- Authentication cookie signature source -->
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider</name>
+ <value>random</value>
+ <description>
+ Indicates how the secret to sign the authentication cookies will be
+ stored. Options are 'random' (default), 'string' and 'zookeeper'.
+ If using a setup with multiple KMS instances, 'zookeeper' should be used.
+ </description>
+ </property>
+
+ <!-- Configuration for 'zookeeper' authentication cookie signature source -->
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.path</name>
+ <value>/hadoop-kms/hadoop-auth-signature-secret</value>
+ <description>
+ The Zookeeper ZNode path where the KMS instances will store and retrieve
+ the secret from.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.connection.string</name>
+ <value>#HOSTNAME#:#PORT#,...</value>
+ <description>
+ The Zookeeper connection string, a list of hostnames and port comma
+ separated.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.auth.type</name>
+ <value>kerberos</value>
+ <description>
+ The Zookeeper authentication type, 'none' or 'sasl' (Kerberos).
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.keytab</name>
+ <value>/etc/hadoop/conf/kms.keytab</value>
+ <description>
+ The absolute path for the Kerberos keytab with the credentials to
+ connect to Zookeeper.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.authentication.signer.secret.provider.zookeeper.kerberos.principal</name>
+ <value>kms/#HOSTNAME#</value>
+ <description>
+ The Kerberos service principal used to connect to Zookeeper.
+ </description>
+ </property>
+
+ <property>
+ <name>hadoop.kms.security.authorization.manager</name>
+ <value>org.apache.ranger.authorization.kms.authorizer.RangerKmsAuthorizer</value>
+ </property>
+
+ <property>
+ <name>hadoop.kms.proxyuser.ranger.groups</name>
+ <value>*</value>
+ </property>
+
+ <property>
+ <name>hadoop.kms.proxyuser.ranger.hosts</name>
+ <value>*</value>
+ </property>
+
+ <property>
+ <name>hadoop.kms.proxyuser.ranger.users</name>
+ <value>*</value>
+ </property>
+</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/plugin-kms/src/test/resources/ranger-kms-security.xml
----------------------------------------------------------------------
diff --git a/plugin-kms/src/test/resources/ranger-kms-security.xml b/plugin-kms/src/test/resources/ranger-kms-security.xml
new file mode 100644
index 0000000..2fdf614
--- /dev/null
+++ b/plugin-kms/src/test/resources/ranger-kms-security.xml
@@ -0,0 +1,61 @@
+<?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.kms.policy.rest.url</name>
+ <value>http://localhost:6080</value>
+ <description>
+ URL to Ranger Admin
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.plugin.kms.service.name</name>
+ <value>KMSTest</value>
+ <description>
+ Name of the Ranger service containing policies for this SampleApp instance
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.plugin.kms.policy.source.impl</name>
+ <value>org.apache.ranger.authorization.kms.authorizer.RangerAdminClientImpl</value>
+ <!-- <value>org.apache.ranger.admin.client.RangerAdminRESTClient</value>-->
+ <description>
+ Policy source.
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.plugin.kms.policy.pollIntervalMs</name>
+ <value>30000</value>
+ <description>
+ How often to poll for changes in policies?
+ </description>
+ </property>
+
+ <property>
+ <name>ranger.plugin.kms.policy.cache.dir</name>
+ <value>${project.build.directory}</value>
+ <description>
+ Directory where Ranger policies are cached after successful retrieval from the source
+ </description>
+ </property>
+
+</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/868c62b7/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 59f7da6..6e39ace 100644
--- a/pom.xml
+++ b/pom.xml
@@ -150,6 +150,8 @@
<commons.net.version>3.3</commons.net.version>
<commons.pool.version>1.6</commons.pool.version>
<curator.test.version>2.7.0</curator.test.version>
+ <derby.version>10.11.1.1</derby.version>
+ <easymock.version>3.4</easymock.version>
<eclipse.jpa.version>2.5.2</eclipse.jpa.version>
<findbugs.plugin.version>3.0.3</findbugs.plugin.version>
<google.guava.version>17.0</google.guava.version>