HADOOP-16105. WASB in secure mode does not set connectingUsingSAS.

Contributed by Steve Loughran.
This commit is contained in:
Steve Loughran 2019-02-21 13:31:20 +00:00
parent 7c802c42dc
commit a868f59d52
No known key found for this signature in database
GPG Key ID: D22CF846DBB162A0
5 changed files with 83 additions and 6 deletions

View File

@ -910,15 +910,16 @@ private void connectToAzureStorageInSecureMode(String accountName,
String containerName, URI sessionUri) String containerName, URI sessionUri)
throws AzureException, StorageException, URISyntaxException { throws AzureException, StorageException, URISyntaxException {
LOG.debug("Connecting to Azure storage in Secure Mode");
// Assertion: storageInteractionLayer instance has to be a SecureStorageInterfaceImpl // Assertion: storageInteractionLayer instance has to be a SecureStorageInterfaceImpl
if (!(this.storageInteractionLayer instanceof SecureStorageInterfaceImpl)) { if (!(this.storageInteractionLayer instanceof SecureStorageInterfaceImpl)) {
throw new AssertionError("connectToAzureStorageInSASKeyMode() should be called only" throw new AssertionError("connectToAzureStorageInSecureMode() should be called only"
+ " for SecureStorageInterfaceImpl instances"); + " for SecureStorageInterfaceImpl instances");
} }
((SecureStorageInterfaceImpl) this.storageInteractionLayer). ((SecureStorageInterfaceImpl) this.storageInteractionLayer).
setStorageAccountName(accountName); setStorageAccountName(accountName);
connectingUsingSAS = true;
container = storageInteractionLayer.getContainerReference(containerName); container = storageInteractionLayer.getContainerReference(containerName);
rootDirectory = container.getDirectoryReference(""); rootDirectory = container.getDirectoryReference("");

View File

@ -43,6 +43,8 @@
import com.microsoft.azure.storage.blob.CloudBlobClient; import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer; import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob; import com.microsoft.azure.storage.blob.CloudBlockBlob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*** /***
* Local SAS Key Generation implementation. This class resides in * Local SAS Key Generation implementation. This class resides in
@ -54,6 +56,9 @@
public class LocalSASKeyGeneratorImpl extends SASKeyGeneratorImpl { public class LocalSASKeyGeneratorImpl extends SASKeyGeneratorImpl {
public static final Logger LOG = LoggerFactory.getLogger(
LocalSASKeyGeneratorImpl.class);
/** /**
* Map to cache CloudStorageAccount instances. * Map to cache CloudStorageAccount instances.
*/ */
@ -75,6 +80,7 @@ public LocalSASKeyGeneratorImpl(Configuration conf) {
public URI getContainerSASUri(String accountName, String container) public URI getContainerSASUri(String accountName, String container)
throws SASKeyGenerationException { throws SASKeyGenerationException {
LOG.debug("Retrieving Container SAS URI For {}@{}", container, accountName);
try { try {
CachedSASKeyEntry cacheKey = new CachedSASKeyEntry(accountName, container, "/"); CachedSASKeyEntry cacheKey = new CachedSASKeyEntry(accountName, container, "/");
@ -113,7 +119,7 @@ public URI getContainerSASUri(String accountName, String container)
*/ */
private CloudStorageAccount getSASKeyBasedStorageAccountInstance( private CloudStorageAccount getSASKeyBasedStorageAccountInstance(
String accountName) throws SASKeyGenerationException { String accountName) throws SASKeyGenerationException {
LOG.debug("Creating SAS key from account instance {}", accountName);
try { try {
String accountNameWithoutDomain = String accountNameWithoutDomain =
@ -223,6 +229,10 @@ private CloudStorageAccount getStorageAccountInstance(String accountName,
String accountKey) throws SASKeyGenerationException { String accountKey) throws SASKeyGenerationException {
if (!storageAccountMap.containsKey(accountName)) { if (!storageAccountMap.containsKey(accountName)) {
if (accountKey == null || accountKey.isEmpty()) {
throw new SASKeyGenerationException(
"No key for Storage account " + accountName);
}
CloudStorageAccount account = null; CloudStorageAccount account = null;
try { try {
@ -282,4 +292,4 @@ private EnumSet<SharedAccessAccountPermissions> getDefaultAccoutSASKeyPermission
SharedAccessAccountPermissions.UPDATE, SharedAccessAccountPermissions.UPDATE,
SharedAccessAccountPermissions.WRITE); SharedAccessAccountPermissions.WRITE);
} }
} }

View File

@ -83,8 +83,10 @@ public SecureStorageInterfaceImpl(boolean useLocalSASKeyMode,
Configuration conf) throws SecureModeException { Configuration conf) throws SecureModeException {
if (useLocalSASKeyMode) { if (useLocalSASKeyMode) {
LOG.debug("Authenticating with SecureStorage and local SAS key");
this.sasKeyGenerator = new LocalSASKeyGeneratorImpl(conf); this.sasKeyGenerator = new LocalSASKeyGeneratorImpl(conf);
} else { } else {
LOG.debug("Authenticating with SecureStorage and remote SAS key generation");
RemoteSASKeyGeneratorImpl remoteSasKeyGenerator = RemoteSASKeyGeneratorImpl remoteSasKeyGenerator =
new RemoteSASKeyGeneratorImpl(conf); new RemoteSASKeyGeneratorImpl(conf);
try { try {
@ -96,6 +98,8 @@ public SecureStorageInterfaceImpl(boolean useLocalSASKeyMode,
this.sasKeyGenerator = remoteSasKeyGenerator; this.sasKeyGenerator = remoteSasKeyGenerator;
} }
this.useContainerSasKeyForAllAccess = conf.getBoolean(KEY_USE_CONTAINER_SASKEY_FOR_ALL_ACCESS, true); this.useContainerSasKeyForAllAccess = conf.getBoolean(KEY_USE_CONTAINER_SASKEY_FOR_ALL_ACCESS, true);
LOG.debug("Container SAS key {} be used for all access",
useContainerSasKeyForAllAccess ? "will" : "will not");
} }
@Override @Override

View File

@ -597,7 +597,10 @@ public static AzureBlobStorageTestAccount create(
} }
// Remove the account key from the configuration to make sure we don't // Remove the account key from the configuration to make sure we don't
// cheat and use that. // cheat and use that.
conf.set(ACCOUNT_KEY_PROPERTY_NAME + accountName, ""); // but only if not in secure mode, which requires that login
if (!conf.getBoolean(AzureNativeFileSystemStore.KEY_USE_SECURE_MODE, false)) {
conf.set(ACCOUNT_KEY_PROPERTY_NAME + accountName, "");
}
// Set the SAS key. // Set the SAS key.
conf.set(SAS_PROPERTY_NAME + containerName + "." + accountName, sas); conf.set(SAS_PROPERTY_NAME + containerName + "." + accountName, sas);
} }

View File

@ -19,6 +19,8 @@
package org.apache.hadoop.fs.azure; package org.apache.hadoop.fs.azure;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY; import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY;
import static org.apache.hadoop.test.LambdaTestUtils.intercept;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeNotNull;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -30,8 +32,10 @@
import java.util.Date; import java.util.Date;
import java.util.EnumSet; import java.util.EnumSet;
import java.io.File; import java.io.File;
import java.util.NoSuchElementException;
import org.apache.hadoop.fs.azure.integration.AzureTestUtils; import org.apache.hadoop.fs.azure.integration.AzureTestUtils;
import org.apache.hadoop.fs.contract.ContractTestUtils;
import org.apache.hadoop.security.ProviderUtils; import org.apache.hadoop.security.ProviderUtils;
import org.apache.hadoop.security.alias.CredentialProvider; import org.apache.hadoop.security.alias.CredentialProvider;
import org.apache.hadoop.security.alias.CredentialProviderFactory; import org.apache.hadoop.security.alias.CredentialProviderFactory;
@ -42,6 +46,8 @@
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.UnsupportedFileSystemException; import org.apache.hadoop.fs.UnsupportedFileSystemException;
import org.apache.hadoop.fs.azure.AzureBlobStorageTestAccount.CreateOptions; import org.apache.hadoop.fs.azure.AzureBlobStorageTestAccount.CreateOptions;
import org.apache.hadoop.test.GenericTestUtils;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Assume; import org.junit.Assume;
@ -50,8 +56,10 @@
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.CloudBlobContainer; import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob; import com.microsoft.azure.storage.blob.CloudBlockBlob;
import com.microsoft.azure.storage.core.SR;
public class ITestWasbUriAndConfiguration extends AbstractWasbTestWithTimeout { public class ITestWasbUriAndConfiguration extends AbstractWasbTestWithTimeout {
@ -173,6 +181,57 @@ public void testConnectUsingSASReadonly() throws Exception {
assertEquals(3, obtained[2]); assertEquals(3, obtained[2]);
} }
/**
* Use secure mode, which will automatically switch to SAS,
*/
@Test
public void testConnectUsingSecureSAS() throws Exception {
// Create the test account with SAS credentials.
Configuration conf = new Configuration();
conf.setBoolean(AzureNativeFileSystemStore.KEY_USE_SECURE_MODE, true);
testAccount = AzureBlobStorageTestAccount.create("",
EnumSet.of(CreateOptions.UseSas),
conf);
assumeNotNull(testAccount);
NativeAzureFileSystem fs = testAccount.getFileSystem();
AzureException ex = intercept(AzureException.class,
SR.ENUMERATION_ERROR,
() -> ContractTestUtils.writeTextFile(fs,
new Path("/testConnectUsingSecureSAS"),
"testConnectUsingSecureSAS",
true));
StorageException cause = getCause(StorageException.class,
getCause(NoSuchElementException.class, ex));
GenericTestUtils.assertExceptionContains(
"The specified container does not exist", cause);
}
/**
* Get an inner cause of an exception; require it to be of the given
* type.
* If there is a problem, an AssertionError is thrown, containing the
* outer or inner exception.
* @param clazz required class
* @param t exception
* @param <E> type of required exception
* @return the retrieved exception
* @throws AssertionError if there is no cause or it is of the wrong type.
*/
private <E extends Throwable> E getCause(
Class<E> clazz, Throwable t) {
Throwable e = t.getCause();
if (e == null) {
throw new AssertionError("No cause", t);
}
if (!clazz.isAssignableFrom(e.getClass())) {
throw new AssertionError("Wrong inner class", e);
} else {
return (E) e;
}
}
@Test @Test
public void testConnectUsingAnonymous() throws Exception { public void testConnectUsingAnonymous() throws Exception {
@ -324,7 +383,7 @@ public void testDefaultKeyProvider() throws Exception {
@Test @Test
public void testCredsFromCredentialProvider() throws Exception { public void testCredsFromCredentialProvider() throws Exception {
Assume.assumeFalse(runningInSASMode); assumeFalse(runningInSASMode);
String account = "testacct"; String account = "testacct";
String key = "testkey"; String key = "testkey";
// set up conf to have a cred provider // set up conf to have a cred provider