HADOOP-11337. KeyAuthorizationKeyProvider access checks need to be done atomically. Contributed by Dian Fu.
(cherry picked from commit 9fa2990257
)
This commit is contained in:
parent
d21ef79707
commit
084667aad9
|
@ -116,6 +116,9 @@ Release 2.7.0 - UNRELEASED
|
||||||
HADOOP-11333. Fix deadlock in DomainSocketWatcher when the notification
|
HADOOP-11333. Fix deadlock in DomainSocketWatcher when the notification
|
||||||
pipe is full (zhaoyunjiong via cmccabe)
|
pipe is full (zhaoyunjiong via cmccabe)
|
||||||
|
|
||||||
|
HADOOP-11337. KeyAuthorizationKeyProvider access checks need to be done
|
||||||
|
atomically. (Dian Fu via wang)
|
||||||
|
|
||||||
Release 2.6.0 - 2014-11-18
|
Release 2.6.0 - 2014-11-18
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
|
@ -23,6 +23,9 @@ import java.security.GeneralSecurityException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
import org.apache.hadoop.crypto.key.KeyProvider;
|
import org.apache.hadoop.crypto.key.KeyProvider;
|
||||||
import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension;
|
import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension;
|
||||||
|
@ -83,6 +86,8 @@ public class KeyAuthorizationKeyProvider extends KeyProviderCryptoExtension {
|
||||||
|
|
||||||
private final KeyProviderCryptoExtension provider;
|
private final KeyProviderCryptoExtension provider;
|
||||||
private final KeyACLs acls;
|
private final KeyACLs acls;
|
||||||
|
private Lock readLock;
|
||||||
|
private Lock writeLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The constructor takes a {@link KeyProviderCryptoExtension} and an
|
* The constructor takes a {@link KeyProviderCryptoExtension} and an
|
||||||
|
@ -96,6 +101,9 @@ public class KeyAuthorizationKeyProvider extends KeyProviderCryptoExtension {
|
||||||
super(keyProvider, null);
|
super(keyProvider, null);
|
||||||
this.provider = keyProvider;
|
this.provider = keyProvider;
|
||||||
this.acls = acls;
|
this.acls = acls;
|
||||||
|
ReadWriteLock lock = new ReentrantReadWriteLock(true);
|
||||||
|
readLock = lock.readLock();
|
||||||
|
writeLock = lock.writeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method first checks if "key.acl.name" attribute is present as an
|
// This method first checks if "key.acl.name" attribute is present as an
|
||||||
|
@ -146,50 +154,85 @@ public class KeyAuthorizationKeyProvider extends KeyProviderCryptoExtension {
|
||||||
@Override
|
@Override
|
||||||
public KeyVersion createKey(String name, Options options)
|
public KeyVersion createKey(String name, Options options)
|
||||||
throws NoSuchAlgorithmException, IOException {
|
throws NoSuchAlgorithmException, IOException {
|
||||||
authorizeCreateKey(name, options, getUser());
|
writeLock.lock();
|
||||||
return provider.createKey(name, options);
|
try {
|
||||||
|
authorizeCreateKey(name, options, getUser());
|
||||||
|
return provider.createKey(name, options);
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyVersion createKey(String name, byte[] material, Options options)
|
public KeyVersion createKey(String name, byte[] material, Options options)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
authorizeCreateKey(name, options, getUser());
|
writeLock.lock();
|
||||||
return provider.createKey(name, material, options);
|
try {
|
||||||
|
authorizeCreateKey(name, options, getUser());
|
||||||
|
return provider.createKey(name, material, options);
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyVersion rollNewVersion(String name)
|
public KeyVersion rollNewVersion(String name)
|
||||||
throws NoSuchAlgorithmException, IOException {
|
throws NoSuchAlgorithmException, IOException {
|
||||||
doAccessCheck(name, KeyOpType.MANAGEMENT);
|
writeLock.lock();
|
||||||
return provider.rollNewVersion(name);
|
try {
|
||||||
|
doAccessCheck(name, KeyOpType.MANAGEMENT);
|
||||||
|
return provider.rollNewVersion(name);
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteKey(String name) throws IOException {
|
public void deleteKey(String name) throws IOException {
|
||||||
doAccessCheck(name, KeyOpType.MANAGEMENT);
|
writeLock.lock();
|
||||||
provider.deleteKey(name);
|
try {
|
||||||
|
doAccessCheck(name, KeyOpType.MANAGEMENT);
|
||||||
|
provider.deleteKey(name);
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyVersion rollNewVersion(String name, byte[] material)
|
public KeyVersion rollNewVersion(String name, byte[] material)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
doAccessCheck(name, KeyOpType.MANAGEMENT);
|
writeLock.lock();
|
||||||
return provider.rollNewVersion(name, material);
|
try {
|
||||||
|
doAccessCheck(name, KeyOpType.MANAGEMENT);
|
||||||
|
return provider.rollNewVersion(name, material);
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void warmUpEncryptedKeys(String... names) throws IOException {
|
public void warmUpEncryptedKeys(String... names) throws IOException {
|
||||||
for (String name : names) {
|
readLock.lock();
|
||||||
doAccessCheck(name, KeyOpType.GENERATE_EEK);
|
try {
|
||||||
|
for (String name : names) {
|
||||||
|
doAccessCheck(name, KeyOpType.GENERATE_EEK);
|
||||||
|
}
|
||||||
|
provider.warmUpEncryptedKeys(names);
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
}
|
}
|
||||||
provider.warmUpEncryptedKeys(names);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EncryptedKeyVersion generateEncryptedKey(String encryptionKeyName)
|
public EncryptedKeyVersion generateEncryptedKey(String encryptionKeyName)
|
||||||
throws IOException, GeneralSecurityException {
|
throws IOException, GeneralSecurityException {
|
||||||
doAccessCheck(encryptionKeyName, KeyOpType.GENERATE_EEK);
|
readLock.lock();
|
||||||
return provider.generateEncryptedKey(encryptionKeyName);
|
try {
|
||||||
|
doAccessCheck(encryptionKeyName, KeyOpType.GENERATE_EEK);
|
||||||
|
return provider.generateEncryptedKey(encryptionKeyName);
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyKeyVersionBelongsToKey(EncryptedKeyVersion ekv)
|
private void verifyKeyVersionBelongsToKey(EncryptedKeyVersion ekv)
|
||||||
|
@ -206,19 +249,29 @@ public class KeyAuthorizationKeyProvider extends KeyProviderCryptoExtension {
|
||||||
@Override
|
@Override
|
||||||
public KeyVersion decryptEncryptedKey(EncryptedKeyVersion encryptedKeyVersion)
|
public KeyVersion decryptEncryptedKey(EncryptedKeyVersion encryptedKeyVersion)
|
||||||
throws IOException, GeneralSecurityException {
|
throws IOException, GeneralSecurityException {
|
||||||
verifyKeyVersionBelongsToKey(encryptedKeyVersion);
|
readLock.lock();
|
||||||
doAccessCheck(
|
try {
|
||||||
encryptedKeyVersion.getEncryptionKeyName(), KeyOpType.DECRYPT_EEK);
|
verifyKeyVersionBelongsToKey(encryptedKeyVersion);
|
||||||
return provider.decryptEncryptedKey(encryptedKeyVersion);
|
doAccessCheck(
|
||||||
|
encryptedKeyVersion.getEncryptionKeyName(), KeyOpType.DECRYPT_EEK);
|
||||||
|
return provider.decryptEncryptedKey(encryptedKeyVersion);
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyVersion getKeyVersion(String versionName) throws IOException {
|
public KeyVersion getKeyVersion(String versionName) throws IOException {
|
||||||
KeyVersion keyVersion = provider.getKeyVersion(versionName);
|
readLock.lock();
|
||||||
if (keyVersion != null) {
|
try {
|
||||||
doAccessCheck(keyVersion.getName(), KeyOpType.READ);
|
KeyVersion keyVersion = provider.getKeyVersion(versionName);
|
||||||
|
if (keyVersion != null) {
|
||||||
|
doAccessCheck(keyVersion.getName(), KeyOpType.READ);
|
||||||
|
}
|
||||||
|
return keyVersion;
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
}
|
}
|
||||||
return keyVersion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -228,28 +281,48 @@ public class KeyAuthorizationKeyProvider extends KeyProviderCryptoExtension {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<KeyVersion> getKeyVersions(String name) throws IOException {
|
public List<KeyVersion> getKeyVersions(String name) throws IOException {
|
||||||
doAccessCheck(name, KeyOpType.READ);
|
readLock.lock();
|
||||||
return provider.getKeyVersions(name);
|
try {
|
||||||
|
doAccessCheck(name, KeyOpType.READ);
|
||||||
|
return provider.getKeyVersions(name);
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Metadata getMetadata(String name) throws IOException {
|
public Metadata getMetadata(String name) throws IOException {
|
||||||
doAccessCheck(name, KeyOpType.READ);
|
readLock.lock();
|
||||||
return provider.getMetadata(name);
|
try {
|
||||||
|
doAccessCheck(name, KeyOpType.READ);
|
||||||
|
return provider.getMetadata(name);
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Metadata[] getKeysMetadata(String... names) throws IOException {
|
public Metadata[] getKeysMetadata(String... names) throws IOException {
|
||||||
for (String name : names) {
|
readLock.lock();
|
||||||
doAccessCheck(name, KeyOpType.READ);
|
try {
|
||||||
|
for (String name : names) {
|
||||||
|
doAccessCheck(name, KeyOpType.READ);
|
||||||
|
}
|
||||||
|
return provider.getKeysMetadata(names);
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
}
|
}
|
||||||
return provider.getKeysMetadata(names);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyVersion getCurrentKey(String name) throws IOException {
|
public KeyVersion getCurrentKey(String name) throws IOException {
|
||||||
doAccessCheck(name, KeyOpType.READ);
|
readLock.lock();
|
||||||
return provider.getCurrentKey(name);
|
try {
|
||||||
|
doAccessCheck(name, KeyOpType.READ);
|
||||||
|
return provider.getCurrentKey(name);
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue