Skip to content

Commit 8c4413e

Browse files
committed
fixed SAS at container level
1 parent 507086a commit 8c4413e

File tree

6 files changed

+91
-7
lines changed

6 files changed

+91
-7
lines changed

hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/AbfsConfiguration.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public class AbfsConfiguration{
8888

8989
private final Configuration rawConfig;
9090
private final String accountName;
91+
private final String fsName;
9192
// Service type identified from URL used to initialize FileSystem.
9293
private final AbfsServiceType fsConfiguredServiceType;
9394
private final boolean isSecure;
@@ -457,11 +458,13 @@ public class AbfsConfiguration{
457458
*/
458459
public AbfsConfiguration(final Configuration rawConfig,
459460
String accountName,
461+
String fsName,
460462
AbfsServiceType fsConfiguredServiceType)
461463
throws IllegalAccessException, IOException {
462464
this.rawConfig = ProviderUtils.excludeIncompatibleCredentialProviders(
463465
rawConfig, AzureBlobFileSystem.class);
464466
this.accountName = accountName;
467+
this.fsName = fsName;
465468
this.fsConfiguredServiceType = fsConfiguredServiceType;
466469
this.isSecure = getBoolean(FS_AZURE_SECURE_MODE, false);
467470

@@ -493,7 +496,7 @@ public AbfsConfiguration(final Configuration rawConfig,
493496
*/
494497
public AbfsConfiguration(final Configuration rawConfig, String accountName)
495498
throws IllegalAccessException, IOException {
496-
this(rawConfig, accountName, AbfsServiceType.DFS);
499+
this(rawConfig, accountName, EMPTY_STRING, AbfsServiceType.DFS);
497500
}
498501

499502
/**
@@ -589,6 +592,16 @@ public String accountConf(String key) {
589592
return key + "." + accountName;
590593
}
591594

595+
/**
596+
* Appends the container, account name to a configuration key yielding the
597+
* container-specific form.
598+
* @param key Account-agnostic configuration key
599+
* @return Container-specific configuration key
600+
*/
601+
public String containerConf(String key) {
602+
return key + "." + fsName + "." + accountName;
603+
}
604+
592605
/**
593606
* Returns the account-specific value if it exists, then looks for an
594607
* account-agnostic value.
@@ -644,16 +657,20 @@ public int getInt(String key, int defaultValue) {
644657
}
645658

646659
/**
647-
* Returns the account-specific password in string form if it exists, then
660+
* Returns the container-specific password if it exists,
661+
* else searches for the account-specific password, else finally
648662
* looks for an account-agnostic value.
649663
* @param key Account-agnostic configuration key
650664
* @return value in String form if one exists, else null
651665
* @throws IOException if parsing fails.
652666
*/
653667
public String getPasswordString(String key) throws IOException {
654-
char[] passchars = rawConfig.getPassword(accountConf(key));
668+
char[] passchars = rawConfig.getPassword(containerConf(key));
655669
if (passchars == null) {
656-
passchars = rawConfig.getPassword(key);
670+
passchars = rawConfig.getPassword(accountConf(key));
671+
if(passchars == null){
672+
passchars = rawConfig.getPassword(key);
673+
}
657674
}
658675
if (passchars != null) {
659676
return new String(passchars);

hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/AzureBlobFileSystemStore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ public AzureBlobFileSystemStore(
229229

230230
try {
231231
this.abfsConfiguration = new AbfsConfiguration(abfsStoreBuilder.configuration,
232-
accountName, getAbfsServiceTypeFromUrl());
232+
accountName, fileSystemName, getAbfsServiceTypeFromUrl());
233233
} catch (IllegalAccessException exception) {
234234
throw new FileSystemOperationUnhandledException(exception);
235235
}

hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/ConfigurationKeys.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,10 @@ public static String accountProperty(String property, String account) {
322322
return property + "." + account;
323323
}
324324

325+
public static String containerProperty(String property, String FsName, String account) {
326+
return property + "." + FsName + "." + account;
327+
}
328+
325329
public static final String FS_AZURE_ENABLE_DELEGATION_TOKEN = "fs.azure.enable.delegation.token";
326330
public static final String FS_AZURE_DELEGATION_TOKEN_PROVIDER_TYPE = "fs.azure.delegation.token.provider.type";
327331

hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/AbstractAbfsIntegrationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ protected AbstractAbfsIntegrationTest() throws Exception {
117117
final String abfsUrl = this.getFileSystemName() + "@" + this.getAccountName();
118118
URI defaultUri = null;
119119

120-
abfsConfig = new AbfsConfiguration(rawConfig, accountName, identifyAbfsServiceTypeFromUrl(abfsUrl));
120+
abfsConfig = new AbfsConfiguration(rawConfig, accountName, getFileSystemName(), identifyAbfsServiceTypeFromUrl(abfsUrl));
121121

122122
authType = abfsConfig.getEnum(FS_AZURE_ACCOUNT_AUTH_TYPE_PROPERTY_NAME, AuthType.SharedKey);
123123
assumeValidAuthConfigsPresent();

hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/ITestAzureBlobFileSystemChooseSAS.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@
3232
import org.apache.hadoop.fs.azurebfs.services.AuthType;
3333
import org.apache.hadoop.fs.azurebfs.services.FixedSASTokenProvider;
3434
import org.apache.hadoop.fs.azurebfs.utils.AccountSASGenerator;
35+
import org.apache.hadoop.fs.azurebfs.utils.ServiceSASGenerator;
3536
import org.apache.hadoop.fs.azurebfs.utils.Base64;
3637

3738
import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_SAS_FIXED_TOKEN;
3839
import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_SAS_TOKEN_PROVIDER_TYPE;
3940
import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.accountProperty;
41+
import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.containerProperty;
4042
import static org.apache.hadoop.fs.azurebfs.constants.TestConfigurationKeys.FS_AZURE_TEST_APP_ID;
4143
import static org.apache.hadoop.fs.azurebfs.constants.TestConfigurationKeys.FS_AZURE_TEST_APP_SECRET;
4244
import static org.apache.hadoop.fs.azurebfs.constants.TestConfigurationKeys.FS_AZURE_TEST_APP_SERVICE_PRINCIPAL_OBJECT_ID;
@@ -50,6 +52,7 @@
5052
public class ITestAzureBlobFileSystemChooseSAS extends AbstractAbfsIntegrationTest{
5153

5254
private String accountSAS = null;
55+
private String containerSAS = null;
5356
private static final String TEST_PATH = "testPath";
5457

5558
/**
@@ -69,6 +72,7 @@ public void setup() throws Exception {
6972
super.setup();
7073
createFilesystemWithTestFileForSASTests(new Path(TEST_PATH));
7174
generateAccountSAS();
75+
generateContainerSAS();
7276
}
7377

7478
/**
@@ -85,6 +89,22 @@ private void generateAccountSAS() throws AzureBlobFileSystemException {
8589
accountSAS = configAccountSASGenerator.getAccountSAS(getAccountName());
8690
}
8791

92+
/**
93+
* Generates a Container SAS Token using the Account Shared Key to be used as a fixed SAS Token.
94+
* Container SAS used here will have only read permissions to resources.
95+
* This will be used by individual tests to set in the configurations.
96+
* @throws AzureBlobFileSystemException
97+
*/
98+
private void generateContainerSAS() throws AzureBlobFileSystemException {
99+
final byte[] accountKey = Base64.decode(
100+
getConfiguration().getStorageAccountKey());
101+
ServiceSASGenerator configServiceSASGenerator = new ServiceSASGenerator(
102+
accountKey);
103+
// Setting only read permissions.
104+
configServiceSASGenerator.setPermissions("r");
105+
containerSAS = configServiceSASGenerator.getContainerSASWithFullControl(
106+
getAccountName(), getFileSystemName());
107+
}
88108
/**
89109
* Tests the scenario where both the custom SASTokenProvider and a fixed SAS token are configured.
90110
* Custom implementation of SASTokenProvider class should be chosen and User Delegation SAS should be used.
@@ -126,6 +146,38 @@ public void testBothProviderFixedTokenConfigured() throws Exception {
126146
}
127147
}
128148

149+
/**
150+
* Tests the implementation sequence if all fixed SAS configs are set.
151+
* The expected sequence is Container Specific Fixed SAS, Account Specific Fixed SAS, Account Agnostic Fixed SAS.
152+
* @throws IOException
153+
*/
154+
@Test
155+
public void testFixedTokenPreference() throws Exception {
156+
AbfsConfiguration testAbfsConfig = new AbfsConfiguration(
157+
getRawConfiguration(), this.getAccountName(), this.getFileSystemName(), getAbfsServiceType());
158+
159+
// setting all types of Fixed SAS configs (container-specific, account-specific, account-agnostic)
160+
removeAnyPresetConfiguration(testAbfsConfig);
161+
testAbfsConfig.set(containerProperty(FS_AZURE_SAS_FIXED_TOKEN, this.getFileSystemName(), this.getAccountName()), containerSAS);
162+
testAbfsConfig.set(accountProperty(FS_AZURE_SAS_FIXED_TOKEN, this.getAccountName()), accountSAS);
163+
testAbfsConfig.set(FS_AZURE_SAS_FIXED_TOKEN, accountSAS);
164+
String ContainerSASExpected = testAbfsConfig.getSASTokenProvider().getSASToken(this.getAccountName(), this.getFileSystemName(), getMethodName(), "read");
165+
166+
// Assert that Container Specific Fixed SAS is used
167+
Assertions.assertThat(ContainerSASExpected).contains("sr=c");
168+
169+
// Assert that Account Specific Fixed SAS is used if container SAS isn't set
170+
testAbfsConfig.unset(containerProperty(FS_AZURE_SAS_FIXED_TOKEN, this.getFileSystemName(), this.getAccountName()));
171+
String AccountSASExpected = testAbfsConfig.getSASTokenProvider().getSASToken(this.getAccountName(), this.getFileSystemName(), getMethodName(), "read");
172+
Assertions.assertThat(AccountSASExpected).contains("ss=bf");
173+
174+
//Assert that Account-Agnostic fixed SAS is used if no other fixed SAS configs are set.
175+
// The token is the same as the Account Specific Fixed SAS.
176+
testAbfsConfig.unset(FS_AZURE_SAS_FIXED_TOKEN);
177+
String AccountAgnosticSASExpected = testAbfsConfig.getSASTokenProvider().getSASToken(this.getAccountName(), this.getFileSystemName(), getMethodName(), "read");
178+
Assertions.assertThat(AccountAgnosticSASExpected).contains("ss=bf");
179+
}
180+
129181
/**
130182
* Tests the scenario where only the fixed token is configured, and no token provider class is set.
131183
* Account SAS Token configured as fixed SAS should be used.
@@ -189,5 +241,6 @@ private void removeAnyPresetConfiguration(AbfsConfiguration testAbfsConfig) {
189241
testAbfsConfig.unset(FS_AZURE_SAS_FIXED_TOKEN);
190242
testAbfsConfig.unset(accountProperty(FS_AZURE_SAS_TOKEN_PROVIDER_TYPE, this.getAccountName()));
191243
testAbfsConfig.unset(accountProperty(FS_AZURE_SAS_FIXED_TOKEN, this.getAccountName()));
244+
testAbfsConfig.unset(containerProperty(FS_AZURE_SAS_FIXED_TOKEN, this.getFileSystemName(), this.getAccountName()));
192245
}
193246
}

hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/utils/ServiceSASGenerator.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ public ServiceSASGenerator(byte[] accountKey) {
3737
super(accountKey);
3838
}
3939

40+
private String permissions = "racwdl";
4041
public String getContainerSASWithFullControl(String accountName, String containerName) throws
4142
InvalidConfigurationValueException {
4243
accountName = getCanonicalAccountName(accountName);
43-
String sp = "rcwdl";
44+
String sp = permissions;
4445
String sv = AuthenticationVersion.Feb20.toString();
4546
String sr = "c";
4647
String st = ISO_8601_FORMATTER.format(Instant.now().minus(FIVE_MINUTES));
@@ -96,4 +97,13 @@ private String computeSignatureForSAS(String sp, String st, String se, String sv
9697
LOG.debug("Service SAS stringToSign: " + stringToSign.replace("\n", "."));
9798
return computeHmac256(stringToSign);
9899
}
100+
101+
/**
102+
* By default, Container SAS has all the available permissions. Use this to
103+
* override the default permissions and set as per the requirements.
104+
* @param permissions
105+
*/
106+
public void setPermissions(final String permissions) {
107+
this.permissions = permissions;
108+
}
99109
}

0 commit comments

Comments
 (0)