HADOOP-10427. KeyProvider implementations should be thread safe. (tucu)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1586103 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9a2ec694fe
commit
98a98ea0c5
@ -130,6 +130,8 @@ Trunk (Unreleased)
|
||||
HADOOP-10432. Refactor SSLFactory to expose static method to determine
|
||||
HostnameVerifier. (tucu)
|
||||
|
||||
HADOOP-10427. KeyProvider implementations should be thread safe. (tucu)
|
||||
|
||||
BUG FIXES
|
||||
|
||||
HADOOP-9451. Fault single-layer config if node group topology is enabled.
|
||||
|
@ -43,6 +43,9 @@
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* KeyProvider based on Java's KeyStore file format. The file may be stored in
|
||||
@ -73,6 +76,8 @@ public class JavaKeyStoreProvider extends KeyProvider {
|
||||
private final KeyStore keyStore;
|
||||
private final char[] password;
|
||||
private boolean changed = false;
|
||||
private Lock readLock;
|
||||
private Lock writeLock;
|
||||
|
||||
private final Map<String, Metadata> cache = new HashMap<String, Metadata>();
|
||||
|
||||
@ -107,10 +112,15 @@ private JavaKeyStoreProvider(URI uri, Configuration conf) throws IOException {
|
||||
} catch (CertificateException e) {
|
||||
throw new IOException("Can't load keystore " + path, e);
|
||||
}
|
||||
ReadWriteLock lock = new ReentrantReadWriteLock(true);
|
||||
readLock = lock.readLock();
|
||||
writeLock = lock.writeLock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion getKeyVersion(String versionName) throws IOException {
|
||||
readLock.lock();
|
||||
try {
|
||||
SecretKeySpec key = null;
|
||||
try {
|
||||
if (!keyStore.containsAlias(versionName)) {
|
||||
@ -127,10 +137,15 @@ public KeyVersion getKeyVersion(String versionName) throws IOException {
|
||||
throw new IOException("Can't recover key " + key + " from " + path, e);
|
||||
}
|
||||
return new KeyVersion(versionName, key.getEncoded());
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getKeys() throws IOException {
|
||||
readLock.lock();
|
||||
try {
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
String alias = null;
|
||||
try {
|
||||
@ -146,10 +161,15 @@ public List<String> getKeys() throws IOException {
|
||||
throw new IOException("Can't get key " + alias + " from " + path, e);
|
||||
}
|
||||
return list;
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyVersion> getKeyVersions(String name) throws IOException {
|
||||
readLock.lock();
|
||||
try {
|
||||
List<KeyVersion> list = new ArrayList<KeyVersion>();
|
||||
Metadata km = getMetadata(name);
|
||||
if (km != null) {
|
||||
@ -165,10 +185,15 @@ public List<KeyVersion> getKeyVersions(String name) throws IOException {
|
||||
}
|
||||
}
|
||||
return list;
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata getMetadata(String name) throws IOException {
|
||||
readLock.lock();
|
||||
try {
|
||||
if (cache.containsKey(name)) {
|
||||
return cache.get(name);
|
||||
}
|
||||
@ -189,11 +214,16 @@ public Metadata getMetadata(String name) throws IOException {
|
||||
throw new IOException("Can't recover key for " + name +
|
||||
" from keystore " + path, e);
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion createKey(String name, byte[] material,
|
||||
Options options) throws IOException {
|
||||
writeLock.lock();
|
||||
try {
|
||||
try {
|
||||
if (keyStore.containsAlias(name) || cache.containsKey(name)) {
|
||||
throw new IOException("Key " + name + " already exists in " + this);
|
||||
@ -211,10 +241,15 @@ public KeyVersion createKey(String name, byte[] material,
|
||||
cache.put(name, meta);
|
||||
String versionName = buildVersionName(name, 0);
|
||||
return innerSetKeyVersion(versionName, material, meta.getCipher());
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteKey(String name) throws IOException {
|
||||
writeLock.lock();
|
||||
try {
|
||||
Metadata meta = getMetadata(name);
|
||||
if (meta == null) {
|
||||
throw new IOException("Key " + name + " does not exist in " + this);
|
||||
@ -239,6 +274,9 @@ public void deleteKey(String name) throws IOException {
|
||||
}
|
||||
cache.remove(name);
|
||||
changed = true;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
KeyVersion innerSetKeyVersion(String versionName, byte[] material,
|
||||
@ -257,6 +295,8 @@ KeyVersion innerSetKeyVersion(String versionName, byte[] material,
|
||||
@Override
|
||||
public KeyVersion rollNewVersion(String name,
|
||||
byte[] material) throws IOException {
|
||||
writeLock.lock();
|
||||
try {
|
||||
Metadata meta = getMetadata(name);
|
||||
if (meta == null) {
|
||||
throw new IOException("Key " + name + " not found");
|
||||
@ -268,10 +308,15 @@ public KeyVersion rollNewVersion(String name,
|
||||
int nextVersion = meta.addVersion();
|
||||
String versionName = buildVersionName(name, nextVersion);
|
||||
return innerSetKeyVersion(versionName, material, meta.getCipher());
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
writeLock.lock();
|
||||
try {
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
@ -298,6 +343,9 @@ public void flush() throws IOException {
|
||||
}
|
||||
out.close();
|
||||
changed = false;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,6 +39,8 @@
|
||||
* abstraction to separate key storage from users of encryption. It
|
||||
* is intended to support getting or storing keys in a variety of ways,
|
||||
* including third party bindings.
|
||||
* <P/>
|
||||
* <code>KeyProvider</code> implementations must be thread safe.
|
||||
*/
|
||||
@InterfaceAudience.Public
|
||||
@InterfaceStability.Unstable
|
||||
|
@ -55,7 +55,7 @@ public boolean isTransient() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion getKeyVersion(String versionName) {
|
||||
public synchronized KeyVersion getKeyVersion(String versionName) {
|
||||
byte[] bytes = credentials.getSecretKey(new Text(versionName));
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
@ -64,7 +64,7 @@ public KeyVersion getKeyVersion(String versionName) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata getMetadata(String name) throws IOException {
|
||||
public synchronized Metadata getMetadata(String name) throws IOException {
|
||||
if (cache.containsKey(name)) {
|
||||
return cache.get(name);
|
||||
}
|
||||
@ -78,7 +78,7 @@ public Metadata getMetadata(String name) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion createKey(String name, byte[] material,
|
||||
public synchronized KeyVersion createKey(String name, byte[] material,
|
||||
Options options) throws IOException {
|
||||
Text nameT = new Text(name);
|
||||
if (credentials.getSecretKey(nameT) != null) {
|
||||
@ -98,7 +98,7 @@ public KeyVersion createKey(String name, byte[] material,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteKey(String name) throws IOException {
|
||||
public synchronized void deleteKey(String name) throws IOException {
|
||||
Metadata meta = getMetadata(name);
|
||||
if (meta == null) {
|
||||
throw new IOException("Key " + name + " does not exist in " + this);
|
||||
@ -111,7 +111,7 @@ public void deleteKey(String name) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion rollNewVersion(String name,
|
||||
public synchronized KeyVersion rollNewVersion(String name,
|
||||
byte[] material) throws IOException {
|
||||
Metadata meta = getMetadata(name);
|
||||
if (meta == null) {
|
||||
@ -134,7 +134,7 @@ public String toString() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
public synchronized void flush() {
|
||||
user.addCredentials(credentials);
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ public KeyProvider createProvider(URI providerName,
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getKeys() throws IOException {
|
||||
public synchronized List<String> getKeys() throws IOException {
|
||||
List<String> list = new ArrayList<String>();
|
||||
List<Text> keys = credentials.getAllSecretKeys();
|
||||
for (Text key : keys) {
|
||||
@ -163,7 +163,7 @@ public List<String> getKeys() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyVersion> getKeyVersions(String name) throws IOException {
|
||||
public synchronized List<KeyVersion> getKeyVersions(String name) throws IOException {
|
||||
List<KeyVersion> list = new ArrayList<KeyVersion>();
|
||||
Metadata km = getMetadata(name);
|
||||
if (km != null) {
|
||||
|
Loading…
Reference in New Issue
Block a user