...

Source file src/github.com/Azure/azure-sdk-for-go/storage/blobsasuri.go

Documentation: github.com/Azure/azure-sdk-for-go/storage

     1  package storage
     2  
     3  // Copyright (c) Microsoft Corporation. All rights reserved.
     4  // Licensed under the MIT License. See License.txt in the project root for license information.
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"net/url"
    10  	"strings"
    11  	"time"
    12  )
    13  
    14  // OverrideHeaders defines overridable response heaedrs in
    15  // a request using a SAS URI.
    16  // See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
    17  type OverrideHeaders struct {
    18  	CacheControl       string
    19  	ContentDisposition string
    20  	ContentEncoding    string
    21  	ContentLanguage    string
    22  	ContentType        string
    23  }
    24  
    25  // BlobSASOptions are options to construct a blob SAS
    26  // URI.
    27  // See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
    28  type BlobSASOptions struct {
    29  	BlobServiceSASPermissions
    30  	OverrideHeaders
    31  	SASOptions
    32  }
    33  
    34  // BlobServiceSASPermissions includes the available permissions for
    35  // blob service SAS URI.
    36  type BlobServiceSASPermissions struct {
    37  	Read   bool
    38  	Add    bool
    39  	Create bool
    40  	Write  bool
    41  	Delete bool
    42  }
    43  
    44  func (p BlobServiceSASPermissions) buildString() string {
    45  	permissions := ""
    46  	if p.Read {
    47  		permissions += "r"
    48  	}
    49  	if p.Add {
    50  		permissions += "a"
    51  	}
    52  	if p.Create {
    53  		permissions += "c"
    54  	}
    55  	if p.Write {
    56  		permissions += "w"
    57  	}
    58  	if p.Delete {
    59  		permissions += "d"
    60  	}
    61  	return permissions
    62  }
    63  
    64  // GetSASURI creates an URL to the blob which contains the Shared
    65  // Access Signature with the specified options.
    66  //
    67  // See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
    68  func (b *Blob) GetSASURI(options BlobSASOptions) (string, error) {
    69  	uri := b.GetURL()
    70  	signedResource := "b"
    71  	canonicalizedResource, err := b.Container.bsc.client.buildCanonicalizedResource(uri, b.Container.bsc.auth, true)
    72  	if err != nil {
    73  		return "", err
    74  	}
    75  
    76  	permissions := options.BlobServiceSASPermissions.buildString()
    77  	return b.Container.bsc.client.blobAndFileSASURI(options.SASOptions, uri, permissions, canonicalizedResource, signedResource, options.OverrideHeaders)
    78  }
    79  
    80  func (c *Client) blobAndFileSASURI(options SASOptions, uri, permissions, canonicalizedResource, signedResource string, headers OverrideHeaders) (string, error) {
    81  	start := ""
    82  	if options.Start != (time.Time{}) {
    83  		start = options.Start.UTC().Format(time.RFC3339)
    84  	}
    85  
    86  	expiry := options.Expiry.UTC().Format(time.RFC3339)
    87  
    88  	// We need to replace + with %2b first to avoid being treated as a space (which is correct for query strings, but not the path component).
    89  	canonicalizedResource = strings.Replace(canonicalizedResource, "+", "%2b", -1)
    90  	canonicalizedResource, err := url.QueryUnescape(canonicalizedResource)
    91  	if err != nil {
    92  		return "", err
    93  	}
    94  
    95  	protocols := ""
    96  	if options.UseHTTPS {
    97  		protocols = "https"
    98  	}
    99  	stringToSign, err := blobSASStringToSign(permissions, start, expiry, canonicalizedResource, options.Identifier, options.IP, protocols, c.apiVersion, signedResource, "", headers)
   100  	if err != nil {
   101  		return "", err
   102  	}
   103  
   104  	sig := c.computeHmac256(stringToSign)
   105  	sasParams := url.Values{
   106  		"sv":  {c.apiVersion},
   107  		"se":  {expiry},
   108  		"sr":  {signedResource},
   109  		"sp":  {permissions},
   110  		"sig": {sig},
   111  	}
   112  
   113  	if start != "" {
   114  		sasParams.Add("st", start)
   115  	}
   116  
   117  	if c.apiVersion >= "2015-04-05" {
   118  		if protocols != "" {
   119  			sasParams.Add("spr", protocols)
   120  		}
   121  		if options.IP != "" {
   122  			sasParams.Add("sip", options.IP)
   123  		}
   124  	}
   125  
   126  	// Add override response hedaers
   127  	addQueryParameter(sasParams, "rscc", headers.CacheControl)
   128  	addQueryParameter(sasParams, "rscd", headers.ContentDisposition)
   129  	addQueryParameter(sasParams, "rsce", headers.ContentEncoding)
   130  	addQueryParameter(sasParams, "rscl", headers.ContentLanguage)
   131  	addQueryParameter(sasParams, "rsct", headers.ContentType)
   132  
   133  	sasURL, err := url.Parse(uri)
   134  	if err != nil {
   135  		return "", err
   136  	}
   137  	sasURL.RawQuery = sasParams.Encode()
   138  	return sasURL.String(), nil
   139  }
   140  
   141  func blobSASStringToSign(signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedIP, protocols, signedVersion, signedResource, signedSnapshotTime string, headers OverrideHeaders) (string, error) {
   142  	rscc := headers.CacheControl
   143  	rscd := headers.ContentDisposition
   144  	rsce := headers.ContentEncoding
   145  	rscl := headers.ContentLanguage
   146  	rsct := headers.ContentType
   147  
   148  	if signedVersion >= "2015-02-21" {
   149  		canonicalizedResource = "/blob" + canonicalizedResource
   150  	}
   151  
   152  	// https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
   153  	if signedVersion >= "2018-11-09" {
   154  		return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedIP, protocols, signedVersion, signedResource, signedSnapshotTime, rscc, rscd, rsce, rscl, rsct), nil
   155  	}
   156  
   157  	// https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx#Anchor_12
   158  	if signedVersion >= "2015-04-05" {
   159  		return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedIP, protocols, signedVersion, rscc, rscd, rsce, rscl, rsct), nil
   160  	}
   161  
   162  	// reference: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
   163  	if signedVersion >= "2013-08-15" {
   164  		return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedVersion, rscc, rscd, rsce, rscl, rsct), nil
   165  	}
   166  
   167  	return "", errors.New("storage: not implemented SAS for versions earlier than 2013-08-15")
   168  }
   169  

View as plain text