aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/Azure/azure-storage-blob-go/2018-03-28/azblob/sas_service.go
blob: d0b12bc17a89e7ef00f0b2264668b25c41167939 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package azblob

import (
    "bytes"
    "fmt"
    "strings"
    "time"
)

// BlobSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage container or blob.
type BlobSASSignatureValues struct {
    Version            string      `param:"sv"`  // If not specified, this defaults to SASVersion
    Protocol           SASProtocol `param:"spr"` // See the SASProtocol* constants
    StartTime          time.Time   `param:"st"`  // Not specified if IsZero
    ExpiryTime         time.Time   `param:"se"`  // Not specified if IsZero
    Permissions        string      `param:"sp"`  // Create by initializing a ContainerSASPermissions or BlobSASPermissions and then call String()
    IPRange            IPRange     `param:"sip"`
    Identifier         string      `param:"si"`
    ContainerName      string
    BlobName           string // Use "" to create a Container SAS
    CacheControl       string // rscc
    ContentDisposition string // rscd
    ContentEncoding    string // rsce
    ContentLanguage    string // rscl
    ContentType        string // rsct
}

// NewSASQueryParameters uses an account's shared key credential to sign this signature values to produce
// the proper SAS query parameters.
func (v BlobSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *SharedKeyCredential) SASQueryParameters {
    if sharedKeyCredential == nil {
        panic("sharedKeyCredential can't be nil")
    }

    resource := "c"
    if v.BlobName == "" {
        // Make sure the permission characters are in the correct order
        perms := &ContainerSASPermissions{}
        if err := perms.Parse(v.Permissions); err != nil {
            panic(err)
        }
        v.Permissions = perms.String()
    } else {
        resource = "b"
        // Make sure the permission characters are in the correct order
        perms := &BlobSASPermissions{}
        if err := perms.Parse(v.Permissions); err != nil {
            panic(err)
        }
        v.Permissions = perms.String()
    }
    if v.Version == "" {
        v.Version = SASVersion
    }
    startTime, expiryTime := FormatTimesForSASSigning(v.StartTime, v.ExpiryTime)

    // String to sign: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
    stringToSign := strings.Join([]string{
        v.Permissions,
        startTime,
        expiryTime,
        getCanonicalName(sharedKeyCredential.AccountName(), v.ContainerName, v.BlobName),
        v.Identifier,
        v.IPRange.String(),
        string(v.Protocol),
        v.Version,
        v.CacheControl,       // rscc
        v.ContentDisposition, // rscd
        v.ContentEncoding,    // rsce
        v.ContentLanguage,    // rscl
        v.ContentType},       // rsct
        "\n")
    signature := sharedKeyCredential.ComputeHMACSHA256(stringToSign)

    p := SASQueryParameters{
        // Common SAS parameters
        version:     v.Version,
        protocol:    v.Protocol,
        startTime:   v.StartTime,
        expiryTime:  v.ExpiryTime,
        permissions: v.Permissions,
        ipRange:     v.IPRange,

        // Container/Blob-specific SAS parameters
        resource:   resource,
        identifier: v.Identifier,

        // Calculated SAS signature
        signature: signature,
    }
    return p
}

// getCanonicalName computes the canonical name for a container or blob resource for SAS signing.
func getCanonicalName(account string, containerName string, blobName string) string {
    // Container: "/blob/account/containername"
    // Blob:      "/blob/account/containername/blobname"
    elements := []string{"/blob/", account, "/", containerName}
    if blobName != "" {
        elements = append(elements, "/", strings.Replace(blobName, "\\", "/", -1))
    }
    return strings.Join(elements, "")
}

// The ContainerSASPermissions type simplifies creating the permissions string for an Azure Storage container SAS.
// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field.
type ContainerSASPermissions struct {
    Read, Add, Create, Write, Delete, List bool
}

// String produces the SAS permissions string for an Azure Storage container.
// Call this method to set BlobSASSignatureValues's Permissions field.
func (p ContainerSASPermissions) String() string {
    var b bytes.Buffer
    if p.Read {
        b.WriteRune('r')
    }
    if p.Add {
        b.WriteRune('a')
    }
    if p.Create {
        b.WriteRune('c')
    }
    if p.Write {
        b.WriteRune('w')
    }
    if p.Delete {
        b.WriteRune('d')
    }
    if p.List {
        b.WriteRune('l')
    }
    return b.String()
}

// Parse initializes the ContainerSASPermissions's fields from a string.
func (p *ContainerSASPermissions) Parse(s string) error {
    *p = ContainerSASPermissions{} // Clear the flags
    for _, r := range s {
        switch r {
        case 'r':
            p.Read = true
        case 'a':
            p.Add = true
        case 'c':
            p.Create = true
        case 'w':
            p.Write = true
        case 'd':
            p.Delete = true
        case 'l':
            p.List = true
        default:
            return fmt.Errorf("Invalid permission: '%v'", r)
        }
    }
    return nil
}

// The BlobSASPermissions type simplifies creating the permissions string for an Azure Storage blob SAS.
// Initialize an instance of this type and then call its String method to set BlobSASSignatureValues's Permissions field.
type BlobSASPermissions struct{ Read, Add, Create, Write, Delete bool }

// String produces the SAS permissions string for an Azure Storage blob.
// Call this method to set BlobSASSignatureValues's Permissions field.
func (p BlobSASPermissions) String() string {
    var b bytes.Buffer
    if p.Read {
        b.WriteRune('r')
    }
    if p.Add {
        b.WriteRune('a')
    }
    if p.Create {
        b.WriteRune('c')
    }
    if p.Write {
        b.WriteRune('w')
    }
    if p.Delete {
        b.WriteRune('d')
    }
    return b.String()
}

// Parse initializes the BlobSASPermissions's fields from a string.
func (p *BlobSASPermissions) Parse(s string) error {
    *p = BlobSASPermissions{} // Clear the flags
    for _, r := range s {
        switch r {
        case 'r':
            p.Read = true
        case 'a':
            p.Add = true
        case 'c':
            p.Create = true
        case 'w':
            p.Write = true
        case 'd':
            p.Delete = true
        default:
            return fmt.Errorf("Invalid permission: '%v'", r)
        }
    }
    return nil
}