123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- package storage
- // Copyright 2017 Microsoft Corporation
- //
- // Licensed 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.
- import (
- "errors"
- "fmt"
- "net/url"
- "strings"
- "time"
- )
- // QueueSASOptions are options to construct a blob SAS
- // URI.
- // See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
- type QueueSASOptions struct {
- QueueSASPermissions
- SASOptions
- }
- // QueueSASPermissions includes the available permissions for
- // a queue SAS URI.
- type QueueSASPermissions struct {
- Read bool
- Add bool
- Update bool
- Process bool
- }
- func (q QueueSASPermissions) buildString() string {
- permissions := ""
- if q.Read {
- permissions += "r"
- }
- if q.Add {
- permissions += "a"
- }
- if q.Update {
- permissions += "u"
- }
- if q.Process {
- permissions += "p"
- }
- return permissions
- }
- // GetSASURI creates an URL to the specified queue which contains the Shared
- // Access Signature with specified permissions and expiration time.
- //
- // See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
- func (q *Queue) GetSASURI(options QueueSASOptions) (string, error) {
- canonicalizedResource, err := q.qsc.client.buildCanonicalizedResource(q.buildPath(), q.qsc.auth, true)
- if err != nil {
- return "", err
- }
- // "The canonicalizedresouce portion of the string is a canonical path to the signed resource.
- // It must include the service name (blob, table, queue or file) for version 2015-02-21 or
- // later, the storage account name, and the resource name, and must be URL-decoded.
- // -- https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
- // 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).
- canonicalizedResource = strings.Replace(canonicalizedResource, "+", "%2b", -1)
- canonicalizedResource, err = url.QueryUnescape(canonicalizedResource)
- if err != nil {
- return "", err
- }
- signedStart := ""
- if options.Start != (time.Time{}) {
- signedStart = options.Start.UTC().Format(time.RFC3339)
- }
- signedExpiry := options.Expiry.UTC().Format(time.RFC3339)
- protocols := "https,http"
- if options.UseHTTPS {
- protocols = "https"
- }
- permissions := options.QueueSASPermissions.buildString()
- stringToSign, err := queueSASStringToSign(q.qsc.client.apiVersion, canonicalizedResource, signedStart, signedExpiry, options.IP, permissions, protocols, options.Identifier)
- if err != nil {
- return "", err
- }
- sig := q.qsc.client.computeHmac256(stringToSign)
- sasParams := url.Values{
- "sv": {q.qsc.client.apiVersion},
- "se": {signedExpiry},
- "sp": {permissions},
- "sig": {sig},
- }
- if q.qsc.client.apiVersion >= "2015-04-05" {
- sasParams.Add("spr", protocols)
- addQueryParameter(sasParams, "sip", options.IP)
- }
- uri := q.qsc.client.getEndpoint(queueServiceName, q.buildPath(), nil)
- sasURL, err := url.Parse(uri)
- if err != nil {
- return "", err
- }
- sasURL.RawQuery = sasParams.Encode()
- return sasURL.String(), nil
- }
- func queueSASStringToSign(signedVersion, canonicalizedResource, signedStart, signedExpiry, signedIP, signedPermissions, protocols, signedIdentifier string) (string, error) {
- if signedVersion >= "2015-02-21" {
- canonicalizedResource = "/queue" + canonicalizedResource
- }
- // https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx#Anchor_12
- if signedVersion >= "2015-04-05" {
- return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
- signedPermissions,
- signedStart,
- signedExpiry,
- canonicalizedResource,
- signedIdentifier,
- signedIP,
- protocols,
- signedVersion), nil
- }
- // reference: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
- if signedVersion >= "2013-08-15" {
- return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedVersion), nil
- }
- return "", errors.New("storage: not implemented SAS for versions earlier than 2013-08-15")
- }
|