|
@@ -21,7 +21,6 @@ package org.apache.hadoop.fs.s3a;
|
|
import java.io.File;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
import java.net.URI;
|
|
import java.net.URI;
|
|
-import java.util.concurrent.Callable;
|
|
|
|
|
|
|
|
import org.junit.Assert;
|
|
import org.junit.Assert;
|
|
import org.junit.Rule;
|
|
import org.junit.Rule;
|
|
@@ -41,9 +40,14 @@ import static org.apache.hadoop.test.LambdaTestUtils.*;
|
|
|
|
|
|
/**
|
|
/**
|
|
* Test SSE setup operations and errors raised.
|
|
* Test SSE setup operations and errors raised.
|
|
|
|
+ * Tests related to secret providers and AWS credentials are also
|
|
|
|
+ * included, as they share some common setup operations.
|
|
*/
|
|
*/
|
|
public class TestSSEConfiguration extends Assert {
|
|
public class TestSSEConfiguration extends Assert {
|
|
|
|
|
|
|
|
+ /** Bucket to use for per-bucket options. */
|
|
|
|
+ public static final String BUCKET = "dataset-1";
|
|
|
|
+
|
|
@Rule
|
|
@Rule
|
|
public Timeout testTimeout = new Timeout(
|
|
public Timeout testTimeout = new Timeout(
|
|
S3ATestConstants.S3A_TEST_TIMEOUT
|
|
S3ATestConstants.S3A_TEST_TIMEOUT
|
|
@@ -54,12 +58,12 @@ public class TestSSEConfiguration extends Assert {
|
|
|
|
|
|
@Test
|
|
@Test
|
|
public void testSSECNoKey() throws Throwable {
|
|
public void testSSECNoKey() throws Throwable {
|
|
- assertExceptionTextEquals(SSE_C_NO_KEY_ERROR, SSE_C.getMethod(), null);
|
|
|
|
|
|
+ assertGetAlgorithmFails(SSE_C_NO_KEY_ERROR, SSE_C.getMethod(), null);
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
public void testSSECBlankKey() throws Throwable {
|
|
public void testSSECBlankKey() throws Throwable {
|
|
- assertExceptionTextEquals(SSE_C_NO_KEY_ERROR, SSE_C.getMethod(), "");
|
|
|
|
|
|
+ assertGetAlgorithmFails(SSE_C_NO_KEY_ERROR, SSE_C.getMethod(), "");
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
@@ -74,74 +78,67 @@ public class TestSSEConfiguration extends Assert {
|
|
|
|
|
|
@Test
|
|
@Test
|
|
public void testKMSGoodOldOptionName() throws Throwable {
|
|
public void testKMSGoodOldOptionName() throws Throwable {
|
|
- Configuration conf = new Configuration(false);
|
|
|
|
|
|
+ Configuration conf = emptyConf();
|
|
conf.set(SERVER_SIDE_ENCRYPTION_ALGORITHM, SSE_KMS.getMethod());
|
|
conf.set(SERVER_SIDE_ENCRYPTION_ALGORITHM, SSE_KMS.getMethod());
|
|
conf.set(OLD_S3A_SERVER_SIDE_ENCRYPTION_KEY, "kmskeyID");
|
|
conf.set(OLD_S3A_SERVER_SIDE_ENCRYPTION_KEY, "kmskeyID");
|
|
// verify key round trip
|
|
// verify key round trip
|
|
- assertEquals("kmskeyID", getServerSideEncryptionKey(conf));
|
|
|
|
|
|
+ assertEquals("kmskeyID", getServerSideEncryptionKey(BUCKET, conf));
|
|
// and that KMS lookup finds it
|
|
// and that KMS lookup finds it
|
|
- assertEquals(SSE_KMS, getEncryptionAlgorithm(conf));
|
|
|
|
|
|
+ assertEquals(SSE_KMS, getEncryptionAlgorithm(BUCKET, conf));
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
public void testAESKeySet() throws Throwable {
|
|
public void testAESKeySet() throws Throwable {
|
|
- assertExceptionTextEquals(SSE_S3_WITH_KEY_ERROR,
|
|
|
|
|
|
+ assertGetAlgorithmFails(SSE_S3_WITH_KEY_ERROR,
|
|
SSE_S3.getMethod(), "setkey");
|
|
SSE_S3.getMethod(), "setkey");
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
- public void testSSEEmptyKey() throws Throwable {
|
|
|
|
|
|
+ public void testSSEEmptyKey() {
|
|
// test the internal logic of the test setup code
|
|
// test the internal logic of the test setup code
|
|
Configuration c = buildConf(SSE_C.getMethod(), "");
|
|
Configuration c = buildConf(SSE_C.getMethod(), "");
|
|
- assertEquals("", getServerSideEncryptionKey(c));
|
|
|
|
|
|
+ assertEquals("", getServerSideEncryptionKey(BUCKET, c));
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
public void testSSEKeyNull() throws Throwable {
|
|
public void testSSEKeyNull() throws Throwable {
|
|
// test the internal logic of the test setup code
|
|
// test the internal logic of the test setup code
|
|
final Configuration c = buildConf(SSE_C.getMethod(), null);
|
|
final Configuration c = buildConf(SSE_C.getMethod(), null);
|
|
- assertNull("", getServerSideEncryptionKey(c));
|
|
|
|
|
|
+ assertEquals("", getServerSideEncryptionKey(BUCKET, c));
|
|
|
|
|
|
intercept(IOException.class, SSE_C_NO_KEY_ERROR,
|
|
intercept(IOException.class, SSE_C_NO_KEY_ERROR,
|
|
- new Callable<S3AEncryptionMethods>() {
|
|
|
|
- @Override
|
|
|
|
- public S3AEncryptionMethods call() throws Exception {
|
|
|
|
- return getEncryptionAlgorithm(c);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
+ () -> getEncryptionAlgorithm(BUCKET, c));
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
public void testSSEKeyFromCredentialProvider() throws Exception {
|
|
public void testSSEKeyFromCredentialProvider() throws Exception {
|
|
// set up conf to have a cred provider
|
|
// set up conf to have a cred provider
|
|
- final Configuration conf = new Configuration();
|
|
|
|
- addFileProvider(conf);
|
|
|
|
|
|
+ final Configuration conf = confWithProvider();
|
|
String key = "provisioned";
|
|
String key = "provisioned";
|
|
- provisionSSEKey(conf, SERVER_SIDE_ENCRYPTION_KEY, key);
|
|
|
|
|
|
+ setProviderOption(conf, SERVER_SIDE_ENCRYPTION_KEY, key);
|
|
// let's set the password in config and ensure that it uses the credential
|
|
// let's set the password in config and ensure that it uses the credential
|
|
// provider provisioned value instead.
|
|
// provider provisioned value instead.
|
|
conf.set(SERVER_SIDE_ENCRYPTION_KEY, "keyInConfObject");
|
|
conf.set(SERVER_SIDE_ENCRYPTION_KEY, "keyInConfObject");
|
|
|
|
|
|
- String sseKey = getServerSideEncryptionKey(conf);
|
|
|
|
|
|
+ String sseKey = getServerSideEncryptionKey(BUCKET, conf);
|
|
assertNotNull("Proxy password should not retrun null.", sseKey);
|
|
assertNotNull("Proxy password should not retrun null.", sseKey);
|
|
assertEquals("Proxy password override did NOT work.", key, sseKey);
|
|
assertEquals("Proxy password override did NOT work.", key, sseKey);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Very that the old key is picked up via the properties
|
|
|
|
|
|
+ * Very that the old key is picked up via the properties.
|
|
* @throws Exception failure
|
|
* @throws Exception failure
|
|
*/
|
|
*/
|
|
@Test
|
|
@Test
|
|
public void testOldKeyFromCredentialProvider() throws Exception {
|
|
public void testOldKeyFromCredentialProvider() throws Exception {
|
|
// set up conf to have a cred provider
|
|
// set up conf to have a cred provider
|
|
- final Configuration conf = new Configuration();
|
|
|
|
- addFileProvider(conf);
|
|
|
|
|
|
+ final Configuration conf = confWithProvider();
|
|
String key = "provisioned";
|
|
String key = "provisioned";
|
|
- provisionSSEKey(conf, OLD_S3A_SERVER_SIDE_ENCRYPTION_KEY, key);
|
|
|
|
|
|
+ setProviderOption(conf, OLD_S3A_SERVER_SIDE_ENCRYPTION_KEY, key);
|
|
// let's set the password in config and ensure that it uses the credential
|
|
// let's set the password in config and ensure that it uses the credential
|
|
// provider provisioned value instead.
|
|
// provider provisioned value instead.
|
|
//conf.set(OLD_S3A_SERVER_SIDE_ENCRYPTION_KEY, "oldKeyInConf");
|
|
//conf.set(OLD_S3A_SERVER_SIDE_ENCRYPTION_KEY, "oldKeyInConf");
|
|
- String sseKey = getServerSideEncryptionKey(conf);
|
|
|
|
|
|
+ String sseKey = getServerSideEncryptionKey(BUCKET, conf);
|
|
assertNotNull("Proxy password should not retrun null.", sseKey);
|
|
assertNotNull("Proxy password should not retrun null.", sseKey);
|
|
assertEquals("Proxy password override did NOT work.", key, sseKey);
|
|
assertEquals("Proxy password override did NOT work.", key, sseKey);
|
|
}
|
|
}
|
|
@@ -161,38 +158,35 @@ public class TestSSEConfiguration extends Assert {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Set the SSE Key via the provision API, not the config itself.
|
|
|
|
|
|
+ * Set the an option under the configuration via the
|
|
|
|
+ * {@link CredentialProviderFactory} APIs.
|
|
* @param conf config
|
|
* @param conf config
|
|
* @param option option name
|
|
* @param option option name
|
|
- * @param key key to set
|
|
|
|
|
|
+ * @param value value to set option to.
|
|
* @throws Exception failure
|
|
* @throws Exception failure
|
|
*/
|
|
*/
|
|
- void provisionSSEKey(final Configuration conf,
|
|
|
|
- String option, String key) throws Exception {
|
|
|
|
|
|
+ void setProviderOption(final Configuration conf,
|
|
|
|
+ String option, String value) throws Exception {
|
|
// add our password to the provider
|
|
// add our password to the provider
|
|
final CredentialProvider provider =
|
|
final CredentialProvider provider =
|
|
CredentialProviderFactory.getProviders(conf).get(0);
|
|
CredentialProviderFactory.getProviders(conf).get(0);
|
|
provider.createCredentialEntry(option,
|
|
provider.createCredentialEntry(option,
|
|
- key.toCharArray());
|
|
|
|
|
|
+ value.toCharArray());
|
|
provider.flush();
|
|
provider.flush();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Assert that the exception text from a config contains the expected string
|
|
|
|
- * @param expected expected substring
|
|
|
|
|
|
+ * Assert that the exception text from {@link #getAlgorithm(String, String)}
|
|
|
|
+ * is as expected.
|
|
|
|
+ * @param expected expected substring in error
|
|
* @param alg algorithm to ask for
|
|
* @param alg algorithm to ask for
|
|
* @param key optional key value
|
|
* @param key optional key value
|
|
* @throws Exception anything else which gets raised
|
|
* @throws Exception anything else which gets raised
|
|
*/
|
|
*/
|
|
- public void assertExceptionTextEquals(String expected,
|
|
|
|
|
|
+ public void assertGetAlgorithmFails(String expected,
|
|
final String alg, final String key) throws Exception {
|
|
final String alg, final String key) throws Exception {
|
|
intercept(IOException.class, expected,
|
|
intercept(IOException.class, expected,
|
|
- new Callable<S3AEncryptionMethods>() {
|
|
|
|
- @Override
|
|
|
|
- public S3AEncryptionMethods call() throws Exception {
|
|
|
|
- return getAlgorithm(alg, key);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
+ () -> getAlgorithm(alg, key));
|
|
}
|
|
}
|
|
|
|
|
|
private S3AEncryptionMethods getAlgorithm(S3AEncryptionMethods algorithm,
|
|
private S3AEncryptionMethods getAlgorithm(S3AEncryptionMethods algorithm,
|
|
@@ -203,11 +197,18 @@ public class TestSSEConfiguration extends Assert {
|
|
|
|
|
|
private S3AEncryptionMethods getAlgorithm(String algorithm, String key)
|
|
private S3AEncryptionMethods getAlgorithm(String algorithm, String key)
|
|
throws IOException {
|
|
throws IOException {
|
|
- return getEncryptionAlgorithm(buildConf(algorithm, key));
|
|
|
|
|
|
+ return getEncryptionAlgorithm(BUCKET, buildConf(algorithm, key));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Build a new configuration with the given S3-SSE algorithm
|
|
|
|
+ * and key.
|
|
|
|
+ * @param algorithm algorithm to use, may be null
|
|
|
|
+ * @param key key, may be null
|
|
|
|
+ * @return the new config.
|
|
|
|
+ */
|
|
private Configuration buildConf(String algorithm, String key) {
|
|
private Configuration buildConf(String algorithm, String key) {
|
|
- Configuration conf = new Configuration(false);
|
|
|
|
|
|
+ Configuration conf = emptyConf();
|
|
if (algorithm != null) {
|
|
if (algorithm != null) {
|
|
conf.set(SERVER_SIDE_ENCRYPTION_ALGORITHM, algorithm);
|
|
conf.set(SERVER_SIDE_ENCRYPTION_ALGORITHM, algorithm);
|
|
} else {
|
|
} else {
|
|
@@ -220,4 +221,92 @@ public class TestSSEConfiguration extends Assert {
|
|
}
|
|
}
|
|
return conf;
|
|
return conf;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Create an empty conf: no -default or -site values.
|
|
|
|
+ * @return an empty configuration
|
|
|
|
+ */
|
|
|
|
+ private Configuration emptyConf() {
|
|
|
|
+ return new Configuration(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Create a configuration with no defaults and bonded to a file
|
|
|
|
+ * provider, so that
|
|
|
|
+ * {@link #setProviderOption(Configuration, String, String)}
|
|
|
|
+ * can be used to set a secret.
|
|
|
|
+ * @return the configuration
|
|
|
|
+ * @throws Exception any failure
|
|
|
|
+ */
|
|
|
|
+ private Configuration confWithProvider() throws Exception {
|
|
|
|
+ final Configuration conf = emptyConf();
|
|
|
|
+ addFileProvider(conf);
|
|
|
|
+ return conf;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ private static final String SECRET = "*secret*";
|
|
|
|
+
|
|
|
|
+ private static final String BUCKET_PATTERN = FS_S3A_BUCKET_PREFIX + "%s.%s";
|
|
|
|
+
|
|
|
|
+ @Test
|
|
|
|
+ public void testGetPasswordFromConf() throws Throwable {
|
|
|
|
+ final Configuration conf = emptyConf();
|
|
|
|
+ conf.set(SECRET_KEY, SECRET);
|
|
|
|
+ assertEquals(SECRET, lookupPassword(conf, SECRET_KEY, ""));
|
|
|
|
+ assertEquals(SECRET, lookupPassword(conf, SECRET_KEY, "defVal"));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Test
|
|
|
|
+ public void testGetPasswordFromProvider() throws Throwable {
|
|
|
|
+ final Configuration conf = confWithProvider();
|
|
|
|
+ setProviderOption(conf, SECRET_KEY, SECRET);
|
|
|
|
+ assertEquals(SECRET, lookupPassword(conf, SECRET_KEY, ""));
|
|
|
|
+ assertSecretKeyEquals(conf, null, SECRET, "");
|
|
|
|
+ assertSecretKeyEquals(conf, null, "overidden", "overidden");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Test
|
|
|
|
+ public void testGetBucketPasswordFromProvider() throws Throwable {
|
|
|
|
+ final Configuration conf = confWithProvider();
|
|
|
|
+ URI bucketURI = new URI("s3a://"+ BUCKET +"/");
|
|
|
|
+ setProviderOption(conf, SECRET_KEY, "unbucketed");
|
|
|
|
+
|
|
|
|
+ String bucketedKey = String.format(BUCKET_PATTERN, BUCKET, SECRET_KEY);
|
|
|
|
+ setProviderOption(conf, bucketedKey, SECRET);
|
|
|
|
+ String overrideVal;
|
|
|
|
+ overrideVal = "";
|
|
|
|
+ assertSecretKeyEquals(conf, BUCKET, SECRET, overrideVal);
|
|
|
|
+ assertSecretKeyEquals(conf, bucketURI.getHost(), SECRET, "");
|
|
|
|
+ assertSecretKeyEquals(conf, bucketURI.getHost(), "overidden", "overidden");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Assert that a secret key is as expected.
|
|
|
|
+ * @param conf configuration to examine
|
|
|
|
+ * @param bucket bucket name
|
|
|
|
+ * @param expected expected value
|
|
|
|
+ * @param overrideVal override value in {@code S3AUtils.lookupPassword()}
|
|
|
|
+ * @throws IOException IO problem
|
|
|
|
+ */
|
|
|
|
+ private void assertSecretKeyEquals(Configuration conf,
|
|
|
|
+ String bucket,
|
|
|
|
+ String expected, String overrideVal) throws IOException {
|
|
|
|
+ assertEquals(expected,
|
|
|
|
+ S3AUtils.lookupPassword(bucket, conf, SECRET_KEY, overrideVal));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Test
|
|
|
|
+ public void testGetBucketPasswordFromProviderShort() throws Throwable {
|
|
|
|
+ final Configuration conf = confWithProvider();
|
|
|
|
+ URI bucketURI = new URI("s3a://"+ BUCKET +"/");
|
|
|
|
+ setProviderOption(conf, SECRET_KEY, "unbucketed");
|
|
|
|
+
|
|
|
|
+ String bucketedKey = String.format(BUCKET_PATTERN, BUCKET, "secret.key");
|
|
|
|
+ setProviderOption(conf, bucketedKey, SECRET);
|
|
|
|
+ assertSecretKeyEquals(conf, BUCKET, SECRET, "");
|
|
|
|
+ assertSecretKeyEquals(conf, bucketURI.getHost(), SECRET, "");
|
|
|
|
+ assertSecretKeyEquals(conf, bucketURI.getHost(), "overidden", "overidden");
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|