HADOOP-11337. KeyAuthorizationKeyProvider access checks need to be done atomically. Contributed by Dian Fu.

(cherry picked from commit 9fa2990257)
This commit is contained in:
Andrew Wang 2014-12-01 21:21:23 -08:00
parent d21ef79707
commit 084667aad9
2 changed files with 108 additions and 32 deletions

View File

@ -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

View File

@ -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 {
writeLock.lock();
try {
authorizeCreateKey(name, options, getUser()); authorizeCreateKey(name, options, getUser());
return provider.createKey(name, options); 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 {
writeLock.lock();
try {
authorizeCreateKey(name, options, getUser()); authorizeCreateKey(name, options, getUser());
return provider.createKey(name, material, options); 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 {
writeLock.lock();
try {
doAccessCheck(name, KeyOpType.MANAGEMENT); doAccessCheck(name, KeyOpType.MANAGEMENT);
return provider.rollNewVersion(name); return provider.rollNewVersion(name);
} finally {
writeLock.unlock();
}
} }
@Override @Override
public void deleteKey(String name) throws IOException { public void deleteKey(String name) throws IOException {
writeLock.lock();
try {
doAccessCheck(name, KeyOpType.MANAGEMENT); doAccessCheck(name, KeyOpType.MANAGEMENT);
provider.deleteKey(name); 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 {
writeLock.lock();
try {
doAccessCheck(name, KeyOpType.MANAGEMENT); doAccessCheck(name, KeyOpType.MANAGEMENT);
return provider.rollNewVersion(name, material); return provider.rollNewVersion(name, material);
} finally {
writeLock.unlock();
}
} }
@Override @Override
public void warmUpEncryptedKeys(String... names) throws IOException { public void warmUpEncryptedKeys(String... names) throws IOException {
readLock.lock();
try {
for (String name : names) { for (String name : names) {
doAccessCheck(name, KeyOpType.GENERATE_EEK); doAccessCheck(name, KeyOpType.GENERATE_EEK);
} }
provider.warmUpEncryptedKeys(names); provider.warmUpEncryptedKeys(names);
} finally {
readLock.unlock();
}
} }
@Override @Override
public EncryptedKeyVersion generateEncryptedKey(String encryptionKeyName) public EncryptedKeyVersion generateEncryptedKey(String encryptionKeyName)
throws IOException, GeneralSecurityException { throws IOException, GeneralSecurityException {
readLock.lock();
try {
doAccessCheck(encryptionKeyName, KeyOpType.GENERATE_EEK); doAccessCheck(encryptionKeyName, KeyOpType.GENERATE_EEK);
return provider.generateEncryptedKey(encryptionKeyName); 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 {
readLock.lock();
try {
verifyKeyVersionBelongsToKey(encryptedKeyVersion); verifyKeyVersionBelongsToKey(encryptedKeyVersion);
doAccessCheck( doAccessCheck(
encryptedKeyVersion.getEncryptionKeyName(), KeyOpType.DECRYPT_EEK); encryptedKeyVersion.getEncryptionKeyName(), KeyOpType.DECRYPT_EEK);
return provider.decryptEncryptedKey(encryptedKeyVersion); return provider.decryptEncryptedKey(encryptedKeyVersion);
} finally {
readLock.unlock();
}
} }
@Override @Override
public KeyVersion getKeyVersion(String versionName) throws IOException { public KeyVersion getKeyVersion(String versionName) throws IOException {
readLock.lock();
try {
KeyVersion keyVersion = provider.getKeyVersion(versionName); KeyVersion keyVersion = provider.getKeyVersion(versionName);
if (keyVersion != null) { if (keyVersion != null) {
doAccessCheck(keyVersion.getName(), KeyOpType.READ); doAccessCheck(keyVersion.getName(), KeyOpType.READ);
} }
return keyVersion; return keyVersion;
} finally {
readLock.unlock();
}
} }
@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 {
readLock.lock();
try {
doAccessCheck(name, KeyOpType.READ); doAccessCheck(name, KeyOpType.READ);
return provider.getKeyVersions(name); return provider.getKeyVersions(name);
} finally {
readLock.unlock();
}
} }
@Override @Override
public Metadata getMetadata(String name) throws IOException { public Metadata getMetadata(String name) throws IOException {
readLock.lock();
try {
doAccessCheck(name, KeyOpType.READ); doAccessCheck(name, KeyOpType.READ);
return provider.getMetadata(name); return provider.getMetadata(name);
} finally {
readLock.unlock();
}
} }
@Override @Override
public Metadata[] getKeysMetadata(String... names) throws IOException { public Metadata[] getKeysMetadata(String... names) throws IOException {
readLock.lock();
try {
for (String name : names) { for (String name : names) {
doAccessCheck(name, KeyOpType.READ); doAccessCheck(name, KeyOpType.READ);
} }
return provider.getKeysMetadata(names); return provider.getKeysMetadata(names);
} finally {
readLock.unlock();
}
} }
@Override @Override
public KeyVersion getCurrentKey(String name) throws IOException { public KeyVersion getCurrentKey(String name) throws IOException {
readLock.lock();
try {
doAccessCheck(name, KeyOpType.READ); doAccessCheck(name, KeyOpType.READ);
return provider.getCurrentKey(name); return provider.getCurrentKey(name);
} finally {
readLock.unlock();
}
} }
@Override @Override