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 <cohei...@apache.org> Authored: Mon Sep 26 11:53:44 2016 +0100 Committer: Colm O hEigeartaigh <cohei...@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>