Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagepowershell
titleList, read and write blobs with Shared Access Signatures
linenumberstrue
collapsetrue
# inspired by:
#   https://stackoverflow.com/questions/53653473/generating-an-sas-token-in-java-to-download-a-file-in-an-azure-data-storage-cont?rq=1
#   https://docs.microsoft.com/en-us/rest/api/storageservices/create-account-sas#constructing-the-signature-string

function Create-SASToken( [string] $Account, [string] $AccessKey, [string] $Version, [DateTime] $Now, [DateTime] $Expires, [string] $Permissions='r', $ResourceTypes='o', [string] $Services='b' )
{
    [Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null

    [string] $nowIso = (Get-Date (Get-Date $Now).ToUniversalTime() -Format "u").Replace( ' ', 'T' )
    [string] $expiresIso = (Get-Date (Get-Date $Expires).ToUniversalTime() -Format "u").Replace( ' ', 'T' )

    $stringToSign = $Account + "`n" `
                             + $Permissions + "`n" `
                             + $Services + "`n" `
                             + $ResourceTypes + "`n" `
                             + $nowIso + "`n" `
                             + $expiresIso + "`n" `
                             + "`n" `
                             + "https" + "`n" `
                             + $Version + "`n"
   
    $hmac = New-Object System.Security.Cryptography.HMACSHA256
    $hmac.key = [Convert]::FromBase64String( $AccessKey )
    
    $signature = $hmac.ComputeHash( [Text.Encoding]::UTF8.GetBytes( $stringToSign ) )
    $signature = [Convert]::ToBase64String( $signature )
    
    $sasToken = "sv=$Version" `
              + "&ss=$Services" `
              + "&srt=$ResourceTypes" `
              + "&sp=$Permissions" `
              + "&se=" + [System.Web.HttpUtility]::UrlEncode( $expiresIso ) `
              + "&st=" + [System.Web.HttpUtility]::UrlEncode( $nowIso ) `
              + "&spr=https" `
              + "&sig=" + [System.Web.HttpUtility]::UrlEncode( $signature )

    Write-Debug "now: $nowIso"
    Write-Debug "expires: $expiresIso"
    Write-Debug "stringToSign: $stringToSign"
    Write-Debug "sasToken: $sasToken"

    $signature, $sasToken
}

function Invoke-BlobRequest( [Uri] $Uri, [DateTime] $Now, [string] $Version, [string] $Method='GET', [string] $FilePath='' )
{
    $requestParams = @{}
    $requestParams.Add( 'Uri', $Uri )
    $requestParams.Add( 'Method', $Method )
    
    if ( $FilePath )
    {
        $requestParams.Add( 'Infile', $FilePath )
    }
    
    $requestParams.Add( 'Headers', @{ `
                                      'x-ms-blob-type' = 'BlockBlob'; `
                                      'x-ms-date' = "$(Get-Date (Get-Date $Now).ToUniversalTime() -Format 'R')"; `
                                      'x-ms-version' = $Version `
                                    } `
                      )

    Write-Debug ".... Invoke-WebRequest: $Uri"
    
    $requestParams.Keys | % {
        if ( $_ -eq 'Headers' )
        {
            $item = $_
            $requestParams.Item($_).Keys | % {
                Write-Debug "...... Headers $_ : $($requestParams.Item($item).Item($_))"
            }
        } else {
            Write-Debug "...... $_  $($requestParams.Item($_))"
        }
    }

    # run the web service request
    $response = Invoke-WebRequest @requestParams
    $response
}


# ---------- ---------- ----------
# Main
# ---------- ---------- ----------

$ownerAccount     = '<storage account>'
$ownerAccessKey   = '<storage account access key>'
$requesterAccount = '<requester account>'
$version          = '2019-10-10'


# consider badly synchronized server time and start 3 minutes in the past
$now = (Get-Date).ToUniversalTime().AddMinutes(-3)
# set the SAS token lifetime to 1 day
$expires = $now.AddDays(1).ToUniversalTime()

# consider the following values when creating SAS tokens
#   Permission: (r)ead, (w)rite, (d)elete, (l)ist
#   ResourceTypes: (o)bject, (c)ontainer, (s)ervice
#   Services: (b)lob, (q)ueue, (t)able, (f)ile


Write-Host "`n"
Write-Host "# ++++++++++++++++++++++++++++++"
Write-Host "# Get Access Token"
Write-Host "# ++++++++++++++++++++++++++++++"

# step 1: create signature and SAS token for any operation (read, write, delete, list) on any resources (container, object) of the blob service
$signature, $sasToken = Create-SASToken -Account $ownerAccount -AccessKey $accessKey$ownerAccessKey -Version $version -Now $now -Expires $expires `
                                        -Permissions 'rwdl' -ResourceTypes 'oc' -Services 'b'
    Write-Host "Signature: $signature"
    Write-Host "SAS Token: $sasToken"


Write-Host "`n"
Write-Host "# ++++++++++++++++++++++++++++++"
Write-Host "# List Blobs in Container"
Write-Host "# ++++++++++++++++++++++++++++++"

<#
# step 1: create signature and SAS token for list operation on container resources of the blob service
$signature, $sasToken = Create-SASToken -Account $ownerAccount -AccessKey $accessKey$ownerAccessKey -Version $version -Now $now -Expires $expires `
                                        -Permissions 'l' -ResourceTypes 'c' -Services 'b'  
    Write-Host "Signature: $signature"
    Write-Host "SAS Token: $sasToken"
#>

# step 2: send web service request
$container = 'yade'
$uri       = "https://$($ownerAccount).blob.core.windows.net/$($container)?restype=container&comp=list"
$response  = Invoke-BlobRequest -Uri ($uri + '"&'" + $sasToken) -Now $now -Version $version -Method 'GET' 

    Write-Host "Status Code: $($response.StatusCode)"
    Write-Host $response.Content


Write-Host "`n"
Write-Host "# ++++++++++++++++++++++++++++++"
Write-Host "# Get Blob from Container"
Write-Host "# ++++++++++++++++++++++++++++++"

<#
# step 1: create signature and SAS token for read operation on object resources of the blob service
$signature, $sasToken = Create-SASToken -Account $ownerAccount -AccessKey $accessKey$ownerAccessKey -Version $version -Now $now -Expires $expires `
                                        -Permissions 'r' -ResourceTypes 'o' -Services 'b'
    Write-Host "Signature: $signature"
    Write-Host "SAS Token: $sasToken"
#>

# step 2: send web service request
$container = 'yade'
$blob      = 'test.txt'
$uri       = "https://$($ownerAccount).blob.core.windows.net/$($container)/$($blob)"
$response  = Invoke-BlobRequest -Uri ($uri + '?' + $sasToken) -Now $now -Version $version -Method 'GET'

    Write-Host "Status Code: $($response.StatusCode)"
    Write-Host $response.Content


Write-Host "`n"
Write-Host "# ++++++++++++++++++++++++++++++"
Write-Host "# Write Blob to Container"
Write-Host "# ++++++++++++++++++++++++++++++"

<#
# step 1: create signature and SAS token for write operation on object resources of the blob service
$signature, $sasToken = Create-SASToken -Account $ownerAccount -AccessKey $accessKey$ownerAccessKey -Version $version -Now $now -Expires $expires `
                                        -Permissions 'w' -ResourceTypes 'o' -Services 'b'
    Write-Host "Signature: $signature"
    Write-Host "SAS Token: $sasToken"
#>

# step 2: send web service request
$container = 'yade'
$filePath  = "/tmp/some_blob.txt"
$blob      = (Get-Item $filePath).Name
$uri       = "https://$($ownerAccount).blob.core.windows.net/$($container)/$($blob)"
$response  = Invoke-BlobRequest -Uri ($uri + '?' + $sasToken) -Now $now -Version $version -Method 'PUT' -FilePath $filePath

    Write-Host "Status Code: $($response.StatusCode)"
    Write-Host $response.Content

...