Search code examples
azurestorageazure-blob-storageazure-java-sdkazure-sas

Azure sdk for Java How to Setup User Delegation Key and Shared Authentication Signatures SAS


The following code throws an exception at the last line:

            // Create a BlobServiceClient object which will be used to create a container client
            System.out.println(String.format("Connection String %s", connectStr));
            blobServiceClient = new BlobServiceClientBuilder().connectionString(connectStr).buildClient();

            // Get a user delegation key for the Blob service that's valid for seven days.
            // You can use the key to generate any number of shared access signatures over the lifetime of the key.
            keyStart = OffsetDateTime.now();
            keyExpiry = OffsetDateTime.now().plusHours(7);
 error ->   userDelegationKey = blobServiceClient.getUserDelegationKey(keyStart, keyExpiry);

Exception: </Message><AuthenticationErrorDetail>Only authentication scheme Bearer is supported</AuthenticationErrorDetail></Error>"

Caused by: com.azure.storage.blob.models.BlobStorageException: Status code 403, "<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:d375b3bf-b01e-0044-1191-9c75a8000000

I tried to adapt the .NET tutorial to Java but no luck so far.

It seems this error is related towards REST API calls, any ideas?


Solution

  • So after many attempts, to use User Delegation Keys using the Connection String of the storage account does not work. I had to register an app and add new app environment variables. Finally, check for the right Persmission in the IAM dashboard.

    In my case I'm using Azure with Spring,

    1. Added the following dependencies only:
            <dependency>
                <groupId>com.azure</groupId>
                <artifactId>azure-storage-blob</artifactId>
                <version>12.8.0</version>
            </dependency>
            <dependency>
                <groupId>com.azure</groupId>
                <artifactId>azure-identity</artifactId>
                <version>1.1.2</version>
            </dependency>
    
    1. Create/Register an app on Azure
    2. Create Client Secret of app with certificates & secrets.
    3. Store app- client id, tenant id and client secret in environment variables i.e. on macos:
    export AZURE_CLIENT_ID="xxxxxxx"
    launchctl setenv AZURE_CLIENT_ID $AZURE_CLIENT_ID
    
    export AZURE_TENANT_ID="xxxxxxx"
    launchctl setenv AZURE_TENANT_ID $AZURE_TENANT_ID 
    
    export AZURE_CLIENT_SECRET="xxxxxxx"
    launchctl setenv AZURE_CLIENT_SECRET $AZURE_CLIENT_SECRET
    
    1. add correct role assignments of Storage Blob Data Contributor to the user and app for the storage account. see this

    2. Now can use following code for generating user delegation key and an example container SAS:

    String endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", "accountName");
    
    // Create a BlobServiceClient object which will be used to create a container client
    blobServiceClient = new BlobServiceClientBuilder().endpoint(endpoint)
            .credential(new DefaultAzureCredentialBuilder().build()).buildClient();
    
    // Get a user delegation key for the Blob service that's valid for seven days.
    // You can use the key to generate any number of shared access signatures over the lifetime of the key.
    keyStart = OffsetDateTime.now();
    keyExpiry = OffsetDateTime.now().plusDays(7);
    userDelegationKey = blobServiceClient.getUserDelegationKey(keyStart, keyExpiry);
    
    BlobContainerSasPermission blobContainerSas = new BlobContainerSasPermission();
    blobContainerSas.setReadPermission(true);
    BlobServiceSasSignatureValues blobServiceSasSignatureValues = new BlobServiceSasSignatureValues(keyExpiry,
            blobContainerSas);
    BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient("containerName");
    if (!blobContainerClient.exists())
        blobContainerClient.create();
    
    String sas = blobContainerClient
            .generateUserDelegationSas(blobServiceSasSignatureValues, userDelegationKey);
    

    Hope this helps anyone else!