DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • How to Convert Files to Thumbnail Images in Java
  • How to Change PDF Paper Sizes With an API in Java
  • How To Convert Common Documents to PNG Image Arrays in Java
  • How To Compare DOCX Documents in Java

Trending

  • What Is Plagiarism? How to Avoid It and Cite Sources
  • Implementing an IaC Platform With Terraform, Ansible, and GitLab
  • Exploring the Sidecar Pattern in Cloud-Native Architecture
  • Augmenting the Client With HTMX
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. Construct Azure Shared Access Signature URL to Download File From Azure Blob Storage

Construct Azure Shared Access Signature URL to Download File From Azure Blob Storage

Learn how to construct an Azure Shared Access Signature URL to download a particular file from the Azure Blob Storage container.

By 
Chaitanya Kapure user avatar
Chaitanya Kapure
·
Aug. 20, 24 · Code Snippet
Like (1)
Save
Tweet
Share
4.8K Views

Join the DZone community and get the full member experience.

Join For Free

In any web portal, to access a file stored in an Azure Blob Storage account container, we need to connect to the Azure Blob Storage Account and construct the download link for the specified file using its name and Azure storage account details. Constructed Azure Blob URLs can also be used to upload a file and delete a file from the web portal using Java code. 

A shared access signature (SAS) enables you to grant limited access to containers and blobs in your storage account. When you create a SAS, you specify its constraints, including which Azure Storage resources a client is allowed to access, what permissions they have on those resources, and how long the SAS is valid.

Implementation

For example, we can use a Java application to connect to Azure and obtain the download link:

Java
 
@Resource
private DocumentManagementFacade documentManagementFacade;

@PostMapping(value = "/downloadDocument.ajax")
@ResponseBody
public JSONObject downloadDocument(@RequestParam(name = "documentName", required = true) String documentName, final Model model) throws JSONException {
    final JSONObject result = new JSONObject();
    String blobUrl = documentManagementFacade.getBlobUrl();
    String downloadUrl = addFileNameToBlobUrl(blobUrl,documentName);
    result.append("downloadUrl", downloadUrl); // this url brower can directly use for downloading file
    return result;
}

/* Method used to add the document name to the blob url
 * @param blobUrl - blob url
 * @param documentName - document name
 * @return String - URL of the file
*/
 private String addFileNameToBlobUrl(String blobUrl, String documentName) {
      int indexOfQueryString = blobUrl.indexOf("?");
      return blobUrl.substring(0, indexOfQueryString) + "/" + documentName + blobUrl.substring(indexOfQueryString);
 }


We have implemented the above AJAX call from the front end to enable document downloads in the portal.

Then, we need to write the facade method "getBlobUrl" as called in the above controller to get the Blob URL. This Blob URL can also be used to upload or delete a file from a specific Azure storage account container. 

Java
 
@Override
public String getBlobUrl() {
    BlobUrlData blobUrlData = new BlobUrlData();
    blobUrlData.setStorageAccountName(getConfiguration().getString(STORAGE_ACCOUNT_NAME));
    blobUrlData.setContainerName(getConfiguration().getString(CONTAINER_NAME));
    String sasToken = azureStorageBlobSASIntegrationService.getSasTokenForAzureConnection();
    blobUrlData.setAccountSasToken(sasToken);
    return blobUrlDataBeanPatternFormatter.format(blobUrlData);
}


In this above facade code, we need to configure the Azure storage account name and container name in an application properties file. Then, we need to call the integration service method to get a secure access token from Azure Blob storage and format the download URL with the provided values.

  • Sample Azure Blob storage URL as follows:  https://{storageAccountName}.blob.core.windows.net/{containerName}?{accountSasToken}
  • The storageAccountName and containerName are retrieved from the application's properties file.
  • In the code below, we can see how to construct the accountSasToken value. 
Java
 
private static final String API_KEY = "APIKey";
private static final String STORAGE_ACCOUNT_NAME = // storage account name from properties file
private static final String SHARED_ACCESS_KEY = // storage account shared access key from properties file which you can get from Azure
private static final String CONTAINER_NAME = // container name from properties file
private static final String UTC_DATE_FORMATTER = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final String SIGNED_PERMISSION = "racwd";
private static final String SIGNED_SERVICES = "c";
private static final String SIGNED_PROTOCOL = "https";
private static final String AZURE_API_VERSION = "2022-11-02";
private static final String SECRET_KEY_ALGORITHM = "HmacSHA256";
private static final String SLASH = "/";

@Autowired
private ConfigurationService configurationService;

@Autowired
private BeanPatternFormatter<SasTokenUrlData> sasTokenUrlFormatter;


@Override
public String getSasTokenForAzureConnection() {
    String signedPermission = configurationService.getConfiguration().getString(SIGNED_PERMISSION);
    String signedServices = configurationService.getConfiguration().getString(SIGNED_SERVICES);
    String signedExpiryIntervalMinutes = configurationService.getConfiguration().getString(EXPIRY_INTERVAL);
    ZonedDateTime signedStart = ZonedDateTime.now(ZoneOffset.UTC);
    ZonedDateTime signedExpiry = signedStart.plusMinutes(signedExpiryIntervalMinutes == null ? SIGNED_EXPIRY_INTERVAL_MINUTES : Long.parseLong(signedExpiryIntervalMinutes));

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(UTC_DATE_FORMATTER);

    String formattedSignedStart = signedStart.format(formatter);
  
    String formattedSignedExpiry = signedExpiry.format(formatter);
    //Set Signature String
    String stringToSign = getStringToSign(signedPermission, formattedSignedStart, formattedSignedExpiry, signedServices);

    String signature = getHMAC256(stringToSign);

    return getSasTokenString(signature, formattedSignedStart, formattedSignedExpiry, signedPermission, signedServices);
}

    /**
     * Constructs a string to be signed for generating a Shared Access Signature (SAS) token for Azure Blob Storage.
     *
     * @param signedPermission The permissions associated with the SAS token.
     *                         This could be read (r), write (w), delete (d), list (l), add (a), create (c), update (u) and process (p).
     * @param formattedSignedStart The start time for the SAS token, formatted as a UTC string in the format "yyyy-MM-dd'T'HH:mm:ss'Z'".
     * @param formattedSignedExpiry The expiry time for the SAS token, formatted as a UTC string in the format "yyyy-MM-dd'T'HH:mm:ss'Z'".
     * @param signedServices The services accessible with the SAS token. This could be blob (b), file (f), queue (q), and table (t).
     * @return A string that needs to be signed to generate a SAS token.
     */
    private String getStringToSign(String signedPermission, String formattedSignedStart, String formattedSignedExpiry, String signedServices) {
        String accountName = configurationService.getConfiguration().getString(STORAGE_ACCOUNT_NAME);
        String containerName = configurationService.getConfiguration().getString(CONTAINER_NAME);
        String canonicalResource = BLOB + accountName + SLASH + containerName;
        return signedPermission + "\n" + formattedSignedStart + "\n" + formattedSignedExpiry + "\n" +
                canonicalResource + "\n" + SIGNED_PROTOCOL + "\n" +
                AZURE_API_VERSION + "\n" + signedServices + "\n";
    }

   /**
     * Generates a HMAC256 signature for a given string using the shared access key.
     *
     * @param signStr The string to be signed.
     * @return The HMAC256 signature of the input string. If an error occurs during the process or the shared access key is empty, an empty string is returned.
     */
    private String getHMAC256(String signStr) {
        String sharedAccessKey = configurationService.getConfiguration().getString(SHARED_ACCESS_KEY);
        if (StringUtils.isEmpty(sharedAccessKey)) {
            LOG.error("Shared Access Key is empty");
            return StringUtils.EMPTY;
        }
        try {
            SecretKeySpec secretKey = new SecretKeySpec(Base64.decode(sharedAccessKey), SECRET_KEY_ALGORITHM);
            Mac sha256HMAC = Mac.getInstance(SECRET_KEY_ALGORITHM);
            sha256HMAC.init(secretKey);
            return  Base64.encodeBytes(sha256HMAC.doFinal(signStr.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            LOG.error("Exception occurred while converting signature {}", e.getMessage());
            return StringUtils.EMPTY;
        }
    }

    /**
     * Constructs a Shared Access Signature (SAS) token string for Azure Blob Storage.
     *
     * @param signature The HMAC256 signature of the string to sign.
     * @param signedStartTime The start time for the SAS token, formatted as a UTC string in the format "yyyy-MM-dd'T'HH:mm:ss'Z'".
     * @param signedExpiryTime The expiry time for the SAS token, formatted as a UTC string in the format "yyyy-MM-dd'T'HH:mm:ss'Z'".
     * @param signedPermission The permissions associated with the SAS token.
     *                         This could be read (r), write (w), delete (d), list (l), add (a), create (c), update (u) and process (p).
     * @param signedServices The services accessible with the SAS token. This could be blob (b), file (f), queue (q), and table (t).
     * @return A SAS token string that can be used to access Azure Blob Storage.
     */
    private String getSasTokenString(String signature, String signedStartTime, String signedExpiryTime, String signedPermission, String signedServices) {
        SasTokenUrlData sasTokenUrlData = new SasTokenUrlData();
        sasTokenUrlData.setSignedPermission(signedPermission);
        sasTokenUrlData.setSignedStartTime(signedStartTime);
        sasTokenUrlData.setSignedExpiryTime(signedExpiryTime);
        sasTokenUrlData.setSignedServices(signedServices);
        sasTokenUrlData.setSignedProtocol(SIGNED_PROTOCOL);
        sasTokenUrlData.setSignature(URLEncoder.encode(signature, StandardCharsets.UTF_8));
        return sasTokenUrlFormatter.format(sasTokenUrlData);
    }


Once Azure URL is created we are just opening this URL in a new window from JavaScript.

JavaScript
 
downloadDocumentCallbackSuccess : function(data) {
   let parsedData = JSON.parse(data);
   window.open(parsedData.downloadUrl);
},


Document Download azure Java (programming language) SAS (software)

Published at DZone with permission of Chaitanya Kapure. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • How to Convert Files to Thumbnail Images in Java
  • How to Change PDF Paper Sizes With an API in Java
  • How To Convert Common Documents to PNG Image Arrays in Java
  • How To Compare DOCX Documents in Java

Partner Resources


Comments

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: