/
sas_service.go
156 lines (141 loc) · 4.2 KB
/
sas_service.go
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
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package aztables
import (
"bytes"
"fmt"
"strings"
"time"
)
// SASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Table instance.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/constructing-a-service-sas
type SASSignatureValues struct {
Version string // If not specified, this defaults to SASVersion
Protocol SASProtocol // See the SASProtocol* constants
StartTime time.Time // Not specified if IsZero
ExpiryTime time.Time // Not specified if IsZero
Permissions string // Create by initializing a ContainerSASPermissions or TableSASPermissions and then call String()
IPRange IPRange
Identifier string
TableName string
StartPartitionKey string
StartRowKey string
EndPartitionKey string
EndRowKey string
}
// NewSASQueryParameters uses an account's SharedKeyCredential to sign this signature values to produce
// the proper SAS query parameters.
func (v SASSignatureValues) NewSASQueryParameters(credential *SharedKeyCredential) (SASQueryParameters, error) {
resource := ""
if v.Version != "" {
//Make sure the permission characters are in the correct order
perms := &SASPermissions{}
if err := perms.Parse(v.Permissions); err != nil {
return SASQueryParameters{}, err
}
v.Permissions = perms.String()
} else if v.TableName == "" {
// Make sure the permission characters are in the correct order
perms := &SASPermissions{}
if err := perms.Parse(v.Permissions); err != nil {
return SASQueryParameters{}, err
}
v.Permissions = perms.String()
} else {
// Make sure the permission characters are in the correct order
perms := &SASPermissions{}
if err := perms.Parse(v.Permissions); err != nil {
return SASQueryParameters{}, err
}
v.Permissions = perms.String()
}
if v.Version == "" {
v.Version = SASVersion
}
startTime, expiryTime := FormatTimesForSASSigning(v.StartTime, v.ExpiryTime)
signedIdentifier := v.Identifier
lowerCaseTableName := strings.ToLower(v.TableName)
p := SASQueryParameters{
// Common SAS parameters
version: v.Version,
protocol: v.Protocol,
startTime: v.StartTime,
expiryTime: v.ExpiryTime,
permissions: v.Permissions,
ipRange: v.IPRange,
tableName: lowerCaseTableName,
// Table SAS parameters
resource: resource,
identifier: v.Identifier,
}
canonicalName := "/" + "table" + "/" + credential.AccountName() + "/" + lowerCaseTableName
// String to sign: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx
stringToSign := strings.Join([]string{
v.Permissions,
startTime,
expiryTime,
canonicalName,
signedIdentifier,
v.IPRange.String(),
string(v.Protocol),
v.Version,
v.StartPartitionKey,
v.StartRowKey,
v.EndPartitionKey,
v.EndRowKey,
},
"\n",
)
signature, err := credential.ComputeHMACSHA256(stringToSign)
p.signature = signature
return p, err
}
// The SASPermissions type simplifies creating the permissions string for an Azure Table.
// Initialize an instance of this type and then call its String method to set TableSASSignatureValues's Permissions field.
type SASPermissions struct {
Read bool
Add bool
Update bool
Delete bool
StartPartitionKey string
StartRowKey string
EndPartitionKey string
EndRowKey string
}
// String produces the SAS permissions string for an Azure Storage blob.
// Call this method to set TableSASSignatureValues's Permissions field.
func (p SASPermissions) String() string {
var b bytes.Buffer
if p.Read {
b.WriteRune('r')
}
if p.Add {
b.WriteRune('a')
}
if p.Update {
b.WriteRune('u')
}
if p.Delete {
b.WriteRune('d')
}
return b.String()
}
// Parse initializes the TableSASPermissions's fields from a string.
func (p *SASPermissions) Parse(s string) error {
*p = SASPermissions{} // Clear the flags
for _, r := range s {
switch r {
case 'r':
p.Read = true
case 'a':
p.Add = true
case 'u':
p.Update = true
case 'd':
p.Delete = true
default:
return fmt.Errorf("invalid permission: '%v'", r)
}
}
return nil
}