From cbdad3d47150ef01440515128241af6bfd47a3ec Mon Sep 17 00:00:00 2001 From: Owen O'Malley Date: Mon, 6 Jan 2014 23:43:08 +0000 Subject: [PATCH] HADOOP-10201. Add listing to KeyProvider API. (Larry McCay via omalley) git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1556072 13f79535-47bb-0310-9956-ffa450edef68 --- .../hadoop-common/CHANGES.txt | 2 + .../crypto/key/JavaKeyStoreProvider.java | 44 ++++++++++++++++++- .../apache/hadoop/crypto/key/KeyProvider.java | 14 ++++++ .../hadoop/crypto/key/UserProvider.java | 30 +++++++++++++ .../apache/hadoop/security/Credentials.java | 30 +++++++++---- .../crypto/key/TestKeyProviderFactory.java | 11 +++++ 6 files changed, 121 insertions(+), 10 deletions(-) diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index cdff25522ec..6dd74fbe20a 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -108,6 +108,8 @@ Trunk (Unreleased) HADOOP-10141. Create KeyProvider API to separate encryption key storage from the applications. (omalley) + HADOOP-10201. Add listing to KeyProvider API. (Larry McCay via omalley) + BUG FIXES HADOOP-9451. Fault single-layer config if node group topology is enabled. diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/JavaKeyStoreProvider.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/JavaKeyStoreProvider.java index 3c82563628e..93a47deaa73 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/JavaKeyStoreProvider.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/JavaKeyStoreProvider.java @@ -36,8 +36,11 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; +import java.util.ArrayList; import java.util.Date; +import java.util.Enumeration; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -56,6 +59,7 @@ import java.util.Map; */ @InterfaceAudience.Private public class JavaKeyStoreProvider extends KeyProvider { + private static final String KEY_METADATA = "KeyMetadata"; public static final String SCHEME_NAME = "jceks"; public static final String KEYSTORE_PASSWORD_NAME = "HADOOP_KEYSTORE_PASSWORD"; @@ -117,6 +121,44 @@ public class JavaKeyStoreProvider extends KeyProvider { return new KeyVersion(versionName, key.getEncoded()); } + @Override + public List getKeys() throws IOException { + ArrayList list = new ArrayList(); + String alias = null; + try { + Enumeration e = keyStore.aliases(); + while (e.hasMoreElements()) { + alias = e.nextElement(); + // only include the metadata key names in the list of names + if (!alias.contains("@")) { + list.add(alias); + } + } + } catch (KeyStoreException e) { + throw new IOException("Can't get key " + alias + " from " + path, e); + } + return list; + } + + @Override + public List getKeyVersions(String name) throws IOException { + List list = new ArrayList(); + Metadata km = getMetadata(name); + if (km != null) { + int latestVersion = km.getVersions(); + KeyVersion v = null; + String versionName = null; + for (int i = 0; i < latestVersion; i++) { + versionName = buildVersionName(name, i); + v = getKeyVersion(versionName); + if (v != null) { + list.add(v); + } + } + } + return list; + } + @Override public Metadata getMetadata(String name) throws IOException { if (cache.containsKey(name)) { @@ -288,7 +330,7 @@ public class JavaKeyStoreProvider extends KeyProvider { @Override public String getFormat() { - return "KeyMetadata"; + return KEY_METADATA; } @Override diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/KeyProvider.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/KeyProvider.java index a8e95e5eb6e..6f9f016f62c 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/KeyProvider.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/KeyProvider.java @@ -254,6 +254,20 @@ public abstract class KeyProvider { public abstract KeyVersion getKeyVersion(String versionName ) throws IOException; + /** + * Get the key names for all keys. + * @return the list of key names + * @throws IOException + */ + public abstract List getKeys() throws IOException; + + /** + * Get the key material for all versions of a specific key name. + * @return the list of key material + * @throws IOException + */ + public abstract List getKeyVersions(String name) throws IOException; + /** * Get the current version of the key, which should be used for encrypting new * data. diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/UserProvider.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/UserProvider.java index 42ce69341d1..424e7ca8503 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/UserProvider.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/UserProvider.java @@ -20,8 +20,10 @@ package org.apache.hadoop.crypto.key; import java.io.IOException; import java.net.URI; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.hadoop.classification.InterfaceAudience; @@ -142,4 +144,32 @@ public class UserProvider extends KeyProvider { return null; } } + + @Override + public List getKeys() throws IOException { + List list = new ArrayList(); + List keys = credentials.getAllSecretKeys(); + for (Text key : keys) { + if (key.find("@") == -1) { + list.add(key.toString()); + } + } + return list; + } + + @Override + public List getKeyVersions(String name) throws IOException { + List list = new ArrayList(); + Metadata km = getMetadata(name); + if (km != null) { + int latestVersion = km.getVersions(); + for (int i = 0; i < latestVersion; i++) { + KeyVersion v = getKeyVersion(buildVersionName(name, i)); + if (v != null) { + list.add(v); + } + } + } + return list; + } } diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/Credentials.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/Credentials.java index 88f54de61af..b796743eaa1 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/Credentials.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/Credentials.java @@ -29,7 +29,9 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -73,15 +75,6 @@ public class Credentials implements Writable { this.addAll(credentials); } - /** - * Returns the key bytes for the alias - * @param alias the alias for the key - * @return key for this alias - */ - public byte[] getSecretKey(Text alias) { - return secretKeysMap.get(alias); - } - /** * Returns the Token object for the alias * @param alias the alias for the Token @@ -117,6 +110,15 @@ public class Credentials implements Writable { public int numberOfTokens() { return tokenMap.size(); } + + /** + * Returns the key bytes for the alias + * @param alias the alias for the key + * @return key for this alias + */ + public byte[] getSecretKey(Text alias) { + return secretKeysMap.get(alias); + } /** * @return number of keys in the in-memory map @@ -142,6 +144,16 @@ public class Credentials implements Writable { secretKeysMap.remove(alias); } + /** + * Return all the secret key entries in the in-memory map + */ + public List getAllSecretKeys() { + List list = new java.util.ArrayList(); + list.addAll(secretKeysMap.keySet()); + + return list; + } + /** * Convenience method for reading a token storage file, and loading the Tokens * therein in the passed UGI diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestKeyProviderFactory.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestKeyProviderFactory.java index 8d073f7d514..b2964af6f80 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestKeyProviderFactory.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/key/TestKeyProviderFactory.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; import java.util.List; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.crypto.key.KeyProvider.KeyVersion; import org.apache.hadoop.io.Text; import org.apache.hadoop.security.Credentials; import org.apache.hadoop.security.UserGroupInformation; @@ -160,6 +161,16 @@ public class TestKeyProviderFactory { provider.getCurrentKey("key4").getMaterial()); assertArrayEquals(key3, provider.getCurrentKey("key3").getMaterial()); assertEquals("key3@0", provider.getCurrentKey("key3").getVersionName()); + + List keys = provider.getKeys(); + assertTrue("Keys should have been returned.", keys.size() == 2); + assertTrue("Returned Keys should have included key3.", keys.contains("key3")); + assertTrue("Returned Keys should have included key4.", keys.contains("key4")); + + List kvl = provider.getKeyVersions("key3"); + assertTrue("KeyVersions should have been returned for key3.", kvl.size() == 1); + assertTrue("KeyVersions should have included key3@0.", kvl.get(0).getVersionName().equals("key3@0")); + assertArrayEquals(key3, kvl.get(0).getMaterial()); } @Test