/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.fs.azure; import java.net.URI; import java.net.URISyntaxException; import java.security.InvalidKeyException; import java.util.Calendar; import java.util.Date; import java.util.EnumSet; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import java.util.TimeZone; import org.apache.hadoop.conf.Configuration; import com.microsoft.azure.storage.CloudStorageAccount; import com.microsoft.azure.storage.SharedAccessAccountPermissions; import com.microsoft.azure.storage.SharedAccessAccountPolicy; import com.microsoft.azure.storage.SharedAccessAccountResourceType; import com.microsoft.azure.storage.SharedAccessAccountService; import com.microsoft.azure.storage.StorageCredentialsAccountAndKey; import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature; import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.blob.CloudBlobClient; import com.microsoft.azure.storage.blob.CloudBlobContainer; import com.microsoft.azure.storage.blob.CloudBlockBlob; /*** * Local SAS Key Generation implementation. This class resides in * the same address space as the WASB driver. * * This class gets typically used for testing purposes. * */ public class LocalSASKeyGeneratorImpl extends SASKeyGeneratorImpl { /** * Map to cache CloudStorageAccount instances. */ private Map<String, CloudStorageAccount> storageAccountMap; private static final int HOURS_IN_DAY = 24; public LocalSASKeyGeneratorImpl(Configuration conf) { super(conf); storageAccountMap = new HashMap<String, CloudStorageAccount>(); } /** * Implementation to generate SAS Key for a container */ @Override public URI getContainerSASUri(String accountName, String container) throws SASKeyGenerationException { try { CloudStorageAccount account = getSASKeyBasedStorageAccountInstance(accountName); CloudBlobClient client = account.createCloudBlobClient(); return client.getCredentials().transformUri( client.getContainerReference(container).getUri()); } catch (StorageException stoEx) { throw new SASKeyGenerationException("Encountered StorageException while" + " generating SAS Key for container " + container + " inside " + "storage account " + accountName, stoEx); } catch (URISyntaxException uriSyntaxEx) { throw new SASKeyGenerationException("Encountered URISyntaxException while" + " generating SAS Key for container " + container + " inside storage" + " account " + accountName, uriSyntaxEx); } } /** * Helper method that creates a CloudStorageAccount instance based on * SAS key for accountName * * @param accountName Storage Account Name * @return CloudStorageAccount instance created using SAS key for * the Storage Account. * @throws SASKeyGenerationException */ private CloudStorageAccount getSASKeyBasedStorageAccountInstance( String accountName) throws SASKeyGenerationException { try { String accountNameWithoutDomain = getAccountNameWithoutDomain(accountName); CloudStorageAccount account = getStorageAccountInstance(accountNameWithoutDomain, AzureNativeFileSystemStore.getAccountKeyFromConfiguration( accountName, getConf())); return new CloudStorageAccount( new StorageCredentialsSharedAccessSignature( account.generateSharedAccessSignature( getDefaultAccountAccessPolicy())), false, account.getEndpointSuffix(), accountNameWithoutDomain); } catch (KeyProviderException keyProviderEx) { throw new SASKeyGenerationException("Encountered KeyProviderException" + " while retrieving Storage key from configuration for account " + accountName, keyProviderEx); } catch (InvalidKeyException invalidKeyEx) { throw new SASKeyGenerationException("Encoutered InvalidKeyException " + "while generating Account level SAS key for account" + accountName, invalidKeyEx); } catch(StorageException storeEx) { throw new SASKeyGenerationException("Encoutered StorageException while " + "generating Account level SAS key for account" + accountName, storeEx); } catch(URISyntaxException uriSyntaxEx) { throw new SASKeyGenerationException("Encountered URISyntaxException for" + " account " + accountName, uriSyntaxEx); } } /** * Implementation for generation of Relative Path Blob SAS Uri. */ @Override public URI getRelativeBlobSASUri(String accountName, String container, String relativePath) throws SASKeyGenerationException { CloudBlobContainer sc = null; CloudBlobClient client = null; try { CloudStorageAccount account = getSASKeyBasedStorageAccountInstance(accountName); client = account.createCloudBlobClient(); sc = client.getContainerReference(container); } catch (URISyntaxException uriSyntaxEx) { throw new SASKeyGenerationException("Encountered URISyntaxException " + "while getting container references for container " + container + " inside storage account : " + accountName, uriSyntaxEx); } catch (StorageException stoEx) { throw new SASKeyGenerationException("Encountered StorageException while " + "getting container references for container " + container + " inside storage account : " + accountName, stoEx); } CloudBlockBlob blob = null; try { blob = sc.getBlockBlobReference(relativePath); } catch (URISyntaxException uriSyntaxEx) { throw new SASKeyGenerationException("Encountered URISyntaxException while " + "getting Block Blob references for container " + container + " inside storage account : " + accountName, uriSyntaxEx); } catch (StorageException stoEx) { throw new SASKeyGenerationException("Encountered StorageException while " + "getting Block Blob references for container " + container + " inside storage account : " + accountName, stoEx); } try { return client.getCredentials().transformUri(blob.getUri()); } catch (StorageException stoEx) { throw new SASKeyGenerationException("Encountered StorageException while " + "generating SAS key for Blob: " + relativePath + " inside " + "container : " + container + " in Storage Account : " + accountName, stoEx); } catch (URISyntaxException uriSyntaxEx) { throw new SASKeyGenerationException("Encountered URISyntaxException " + "while generating SAS key for Blob: " + relativePath + " inside " + "container: " + container + " in Storage Account : " + accountName, uriSyntaxEx); } } /** * Helper method that creates CloudStorageAccount Instance using the * storage account key. * @param accountName Name of the storage account * @param accountKey Storage Account key * @return CloudStorageAccount instance for the storage account. * @throws SASKeyGenerationException */ private CloudStorageAccount getStorageAccountInstance(String accountName, String accountKey) throws SASKeyGenerationException { if (!storageAccountMap.containsKey(accountName)) { CloudStorageAccount account = null; try { account = new CloudStorageAccount(new StorageCredentialsAccountAndKey( accountName, accountKey)); } catch (URISyntaxException uriSyntaxEx) { throw new SASKeyGenerationException("Encountered URISyntaxException " + "for account " + accountName, uriSyntaxEx); } storageAccountMap.put(accountName, account); } return storageAccountMap.get(accountName); } /** * Helper method that returns the Storage account name without * the domain name suffix. * @param fullAccountName Storage account name with domain name suffix * @return String */ private String getAccountNameWithoutDomain(String fullAccountName) { StringTokenizer tokenizer = new StringTokenizer(fullAccountName, "."); return tokenizer.nextToken(); } /** * Helper method to generate Access Policy for the Storage Account SAS Key * @return SharedAccessAccountPolicy */ private SharedAccessAccountPolicy getDefaultAccountAccessPolicy() { SharedAccessAccountPolicy ap = new SharedAccessAccountPolicy(); Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); cal.setTime(new Date()); cal.add(Calendar.HOUR, (int) getSasKeyExpiryPeriod() * HOURS_IN_DAY); ap.setSharedAccessExpiryTime(cal.getTime()); ap.setPermissions(getDefaultAccoutSASKeyPermissions()); ap.setResourceTypes(EnumSet.of(SharedAccessAccountResourceType.CONTAINER, SharedAccessAccountResourceType.OBJECT)); ap.setServices(EnumSet.of(SharedAccessAccountService.BLOB)); return ap; } private EnumSet<SharedAccessAccountPermissions> getDefaultAccoutSASKeyPermissions() { return EnumSet.of(SharedAccessAccountPermissions.ADD, SharedAccessAccountPermissions.CREATE, SharedAccessAccountPermissions.DELETE, SharedAccessAccountPermissions.LIST, SharedAccessAccountPermissions.READ, SharedAccessAccountPermissions.UPDATE, SharedAccessAccountPermissions.WRITE); } }