1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* LICENSE: The MIT License (the "License") |
5
|
|
|
* you may not use this file except in compliance with the License. |
6
|
|
|
* You may obtain a copy of the License at |
7
|
|
|
* https://github.com/azure/azure-storage-php/LICENSE |
8
|
|
|
* |
9
|
|
|
* Unless required by applicable law or agreed to in writing, software |
10
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
11
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12
|
|
|
* See the License for the specific language governing permissions and |
13
|
|
|
* limitations under the License. |
14
|
|
|
* |
15
|
|
|
* PHP version 5 |
16
|
|
|
* |
17
|
|
|
* @category Microsoft |
18
|
|
|
* @package MicrosoftAzure\Storage\Common\Internal\Authentication |
19
|
|
|
* @author Azure Storage PHP SDK <[email protected]> |
20
|
|
|
* @copyright Microsoft Corporation |
21
|
|
|
* @license https://github.com/azure/azure-storage-php/LICENSE |
22
|
|
|
* @link https://github.com/azure/azure-storage-php |
23
|
|
|
*/ |
24
|
|
|
|
25
|
|
|
namespace MicrosoftAzure\Storage\Common; |
26
|
|
|
|
27
|
|
|
use MicrosoftAzure\Storage\Common\Internal\Resources; |
28
|
|
|
use MicrosoftAzure\Storage\Common\Internal\Utilities; |
29
|
|
|
use MicrosoftAzure\Storage\Common\Internal\Validate; |
30
|
|
|
use MicrosoftAzure\Storage\Common\Models\AccessPolicy; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Provides methods to generate Azure Storage Shared Access Signature |
34
|
|
|
* |
35
|
|
|
* @category Microsoft |
36
|
|
|
* @package MicrosoftAzure\Storage\Common\Internal\Authentication |
37
|
|
|
* @author Azure Storage PHP SDK <[email protected]> |
38
|
|
|
* @copyright 2017 Microsoft Corporation |
39
|
|
|
* @license https://github.com/azure/azure-storage-php/LICENSE |
40
|
|
|
* @link https://github.com/azure/azure-storage-php |
41
|
|
|
*/ |
42
|
|
|
class SharedAccessSignatureHelper |
43
|
|
|
{ |
44
|
|
|
protected $accountName; |
45
|
|
|
protected $accountKey; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Constructor. |
49
|
|
|
* |
50
|
|
|
* @param string $accountName the name of the storage account. |
51
|
|
|
* @param string $accountKey the shared key of the storage account |
52
|
|
|
* |
53
|
|
|
* @return |
|
|
|
|
54
|
|
|
* MicrosoftAzure\Storage\Common\SharedAccessSignatureHelper |
55
|
|
|
*/ |
56
|
|
|
public function __construct($accountName, $accountKey) |
57
|
|
|
{ |
58
|
|
|
Validate::isString($accountName, 'accountName'); |
59
|
|
|
Validate::notNullOrEmpty($accountName, 'accountName'); |
60
|
|
|
|
61
|
|
|
Validate::isString($accountKey, 'accountKey'); |
62
|
|
|
Validate::notNullOrEmpty($accountKey, 'accountKey'); |
63
|
|
|
|
64
|
|
|
$this->accountName = urldecode($accountName); |
65
|
|
|
$this->accountKey = $accountKey; |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Helper function to generate a service shared access signature. |
70
|
|
|
* |
71
|
|
|
* This only supports version 2015-04-05 and later. |
72
|
|
|
* |
73
|
|
|
* @param string $signedService The service type of the SAS. |
74
|
|
|
* @param string $signedResource Resource name to generate the |
75
|
|
|
* canonicalized resource. |
76
|
|
|
* @param string $resourceName The name of the resource. |
77
|
|
|
* @param string $signedPermissions Signed permissions. |
78
|
|
|
* @param string $signedExpiry Signed expiry date. |
79
|
|
|
* @param string $signedStart Signed start date. |
80
|
|
|
* @param string $signedIP Signed IP address. |
81
|
|
|
* @param string $signedProtocol Signed protocol. |
82
|
|
|
* @param string $signedIdentifier Signed identifier. |
83
|
|
|
* @param string $cacheControl Cache-Control header (rscc). |
84
|
|
|
* @param string $contentDisposition Content-Disposition header (rscd). |
85
|
|
|
* @param string $contentEncoding Content-Encoding header (rsce). |
86
|
|
|
* @param string $contentLanguage Content-Language header (rscl). |
87
|
|
|
* @param string $contentType Content-Type header (rsct). |
88
|
|
|
* @param string $startingPartitionKey Minimum partition key. |
89
|
|
|
* @param string $startingRowKey Minimum row key. |
90
|
|
|
* @param string $endingPartitionKey Maximum partition key. |
91
|
|
|
* @param string $endingRowKey Maximum row key. |
92
|
|
|
* |
93
|
|
|
* @see Constructing an service SAS at |
94
|
|
|
* https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas |
95
|
|
|
* @return string |
96
|
|
|
*/ |
97
|
|
|
private function generateServiceSharedAccessSignatureToken( |
98
|
|
|
$signedService, |
99
|
|
|
$signedResource, |
100
|
|
|
$resourceName, |
101
|
|
|
$signedPermissions, |
102
|
|
|
$signedExpiry, |
103
|
|
|
$signedStart = "", |
104
|
|
|
$signedIP = "", |
105
|
|
|
$signedProtocol = "", |
106
|
|
|
$signedIdentifier = "", |
107
|
|
|
$cacheControl = "", |
108
|
|
|
$contentDisposition = "", |
109
|
|
|
$contentEncoding = "", |
110
|
|
|
$contentLanguage = "", |
111
|
|
|
$contentType = "", |
112
|
|
|
$startingPartitionKey = "", |
113
|
|
|
$startingRowKey = "", |
114
|
|
|
$endingPartitionKey = "", |
115
|
|
|
$endingRowKey = "" |
116
|
|
|
) { |
117
|
|
|
//Since every version of client library should only be able to generate |
118
|
|
|
//the same service version as its targets, the signed version is fixed here. |
119
|
|
|
$signedVersion = Resources::STORAGE_API_LATEST_VERSION; |
120
|
|
|
// check that the resource name is valid. |
121
|
|
|
Validate::notNullOrEmpty($resourceName, 'resourceName'); |
122
|
|
|
Validate::isString($resourceName, 'resourceName'); |
123
|
|
|
// validate and sanitize signed permissions |
124
|
|
|
$signedPermissions = $this->validateAndSanitizeSignedPermissions( |
125
|
|
|
$signedPermissions, |
126
|
|
|
$signedResource |
127
|
|
|
); |
128
|
|
|
// check that expiracy is valid |
129
|
|
|
Validate::notNullOrEmpty($signedExpiry, 'signedExpiry'); |
130
|
|
|
Validate::isString($signedExpiry, 'signedExpiry'); |
131
|
|
|
Validate::isDateString($signedExpiry, 'signedExpiry'); |
132
|
|
|
// check that signed start is valid |
133
|
|
|
Validate::isString($signedStart, 'signedStart'); |
134
|
|
|
if (strlen($signedStart) > 0) { |
135
|
|
|
Validate::isDateString($signedStart, 'signedStart'); |
136
|
|
|
} |
137
|
|
|
// check that signed IP is valid |
138
|
|
|
Validate::isString($signedIP, 'signedIP'); |
139
|
|
|
// validate and sanitize signed protocol |
140
|
|
|
$signedProtocol = $this->validateAndSanitizeSignedProtocol($signedProtocol); |
141
|
|
|
// check that signed identifier is valid |
142
|
|
|
Validate::isString($signedIdentifier, 'signedIdentifier'); |
143
|
|
|
Validate::isTrue( |
144
|
|
|
strlen($signedIdentifier) <= 64, |
145
|
|
|
sprintf(Resources::INVALID_STRING_LENGTH, 'signedIdentifier', 'maximum 64') |
146
|
|
|
); |
147
|
|
|
//Categorize the type of the resource for future usage. |
148
|
|
|
$type = ''; |
149
|
|
|
if ($signedService == Resources::RESOURCE_TYPE_BLOB || |
150
|
|
|
$signedService == Resources::RESOURCE_TYPE_FILE |
151
|
|
|
) { |
152
|
|
|
$type = 'bf'; |
153
|
|
|
} elseif ($signedService == Resources::RESOURCE_TYPE_TABLE) { |
154
|
|
|
$type = 't'; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
if ($type === 'bf') { |
158
|
|
|
Validate::isString($cacheControl, 'cacheControl'); |
159
|
|
|
Validate::isString($contentDisposition, 'contentDisposition'); |
160
|
|
|
Validate::isString($contentEncoding, 'contentEncoding'); |
161
|
|
|
Validate::isString($contentLanguage, 'contentLanguage'); |
162
|
|
|
Validate::isString($contentType, 'contentType'); |
163
|
|
|
} elseif ($type === 't') { |
164
|
|
|
Validate::isString($startingPartitionKey, 'startingPartitionKey'); |
165
|
|
|
Validate::isString($startingRowKey, 'startingRowKey'); |
166
|
|
|
Validate::isString($endingPartitionKey, 'endingPartitionKey'); |
167
|
|
|
Validate::isString($endingRowKey, 'endingRowKey'); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
// construct an array with the parameters to generate the shared access signature at the account level |
171
|
|
|
$parameters = array(); |
172
|
|
|
$parameters[] = urldecode($signedPermissions); |
173
|
|
|
$parameters[] = urldecode($signedStart); |
174
|
|
|
$parameters[] = urldecode($signedExpiry); |
175
|
|
|
$parameters[] = urldecode(static::generateCanonicalResource( |
|
|
|
|
176
|
|
|
$this->accountName, |
177
|
|
|
$signedService, |
178
|
|
|
$resourceName |
179
|
|
|
)); |
180
|
|
|
$parameters[] = urldecode($signedIdentifier); |
181
|
|
|
$parameters[] = urldecode($signedIP); |
182
|
|
|
$parameters[] = urldecode($signedProtocol); |
183
|
|
|
$parameters[] = urldecode($signedVersion); |
184
|
|
|
if ($type === 'bf') { |
185
|
|
|
$parameters[] = urldecode($cacheControl); |
186
|
|
|
$parameters[] = urldecode($contentDisposition); |
187
|
|
|
$parameters[] = urldecode($contentEncoding); |
188
|
|
|
$parameters[] = urldecode($contentLanguage); |
189
|
|
|
$parameters[] = urldecode($contentType); |
190
|
|
|
} elseif ($type === 't') { |
191
|
|
|
$parameters[] = urldecode($startingPartitionKey); |
192
|
|
|
$parameters[] = urldecode($startingRowKey); |
193
|
|
|
$parameters[] = urldecode($endingPartitionKey); |
194
|
|
|
$parameters[] = urldecode($endingRowKey); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
// implode the parameters into a string |
198
|
|
|
$stringToSign = utf8_encode(implode("\n", $parameters)); |
199
|
|
|
// decode the account key from base64 |
200
|
|
|
$decodedAccountKey = base64_decode($this->accountKey); |
201
|
|
|
// create the signature with hmac sha256 |
202
|
|
|
$signature = hash_hmac("sha256", $stringToSign, $decodedAccountKey, true); |
203
|
|
|
// encode the signature as base64 |
204
|
|
|
$sig = urlencode(base64_encode($signature)); |
205
|
|
|
|
206
|
|
|
$buildOptQueryStr = function ($string, $abrv) { |
207
|
|
|
return $string === '' ? '' : $abrv . $string; |
208
|
|
|
}; |
209
|
|
|
//adding all the components for account SAS together. |
210
|
|
|
$sas = 'sv=' . $signedVersion; |
211
|
|
|
if ($type === 'bf') { |
212
|
|
|
$sas .= '&sr=' . $signedResource; |
213
|
|
|
$sas .= $buildOptQueryStr($cacheControl, '&rscc='); |
214
|
|
|
$sas .= $buildOptQueryStr($contentDisposition, '&rscd='); |
215
|
|
|
$sas .= $buildOptQueryStr($contentEncoding, '&rsce='); |
216
|
|
|
$sas .= $buildOptQueryStr($contentLanguage, '&rscl='); |
217
|
|
|
$sas .= $buildOptQueryStr($contentType, '&rsct='); |
218
|
|
|
} elseif ($type === 't') { |
219
|
|
|
$sas .= '&tn=' . $resourceName; |
220
|
|
|
$sas .= $buildOptQueryStr($startingPartitionKey, '&spk='); |
221
|
|
|
$sas .= $buildOptQueryStr($startingRowKey, '&srk='); |
222
|
|
|
$sas .= $buildOptQueryStr($endingPartitionKey, '&epk='); |
223
|
|
|
$sas .= $buildOptQueryStr($endingRowKey, '&erk='); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
$sas .= $buildOptQueryStr($signedStart, '&st='); |
227
|
|
|
$sas .= '&se=' . $signedExpiry; |
228
|
|
|
$sas .= '&sp=' . $signedPermissions; |
229
|
|
|
$sas .= $buildOptQueryStr($signedIP, '&sip='); |
230
|
|
|
$sas .= $buildOptQueryStr($signedProtocol, '&spr='); |
231
|
|
|
$sas .= $buildOptQueryStr($signedIdentifier, '&si='); |
232
|
|
|
$sas .= '&sig=' . $sig; |
233
|
|
|
|
234
|
|
|
// return the signature |
235
|
|
|
return $sas; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* Generates Blob service shared access signature. |
240
|
|
|
* |
241
|
|
|
* This only supports version 2015-04-05 and later. |
242
|
|
|
* |
243
|
|
|
* @param string $signedResource Resource name to generate the |
244
|
|
|
* canonicalized resource. |
245
|
|
|
* It can be Resources::RESOURCE_TYPE_BLOB |
246
|
|
|
* or Resources::RESOURCE_TYPE_CONTAINER. |
247
|
|
|
* @param string $resourceName The name of the resource, including |
248
|
|
|
* the path of the resource. It should be |
249
|
|
|
* - {container}/{blob}: for blobs, |
250
|
|
|
* - {container}: for containers, e.g.: |
251
|
|
|
* /mymusic/music.mp3 or |
252
|
|
|
* music.mp3 |
253
|
|
|
* @param string $signedPermissions Signed permissions. |
254
|
|
|
* @param string $signedExpiry Signed expiry date. |
255
|
|
|
* @param string $signedStart Signed start date. |
256
|
|
|
* @param string $signedIP Signed IP address. |
257
|
|
|
* @param string $signedProtocol Signed protocol. |
258
|
|
|
* @param string $signedIdentifier Signed identifier. |
259
|
|
|
* @param string $cacheControl Cache-Control header (rscc). |
260
|
|
|
* @param string $contentDisposition Content-Disposition header (rscd). |
261
|
|
|
* @param string $contentEncoding Content-Encoding header (rsce). |
262
|
|
|
* @param string $contentLanguage Content-Language header (rscl). |
263
|
|
|
* @param string $contentType Content-Type header (rsct). |
264
|
|
|
* |
265
|
|
|
* @see Constructing an service SAS at |
266
|
|
|
* https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas |
267
|
|
|
* @return string |
268
|
|
|
*/ |
269
|
|
View Code Duplication |
public function generateBlobServiceSharedAccessSignatureToken( |
|
|
|
|
270
|
|
|
$signedResource, |
271
|
|
|
$resourceName, |
272
|
|
|
$signedPermissions, |
273
|
|
|
$signedExpiry, |
274
|
|
|
$signedStart = "", |
275
|
|
|
$signedIP = "", |
276
|
|
|
$signedProtocol = "", |
277
|
|
|
$signedIdentifier = "", |
278
|
|
|
$cacheControl = "", |
279
|
|
|
$contentDisposition = "", |
280
|
|
|
$contentEncoding = "", |
281
|
|
|
$contentLanguage = "", |
282
|
|
|
$contentType = "" |
283
|
|
|
) { |
284
|
|
|
// check that the resource name is valid. |
285
|
|
|
Validate::isString($signedResource, 'signedResource'); |
286
|
|
|
Validate::notNullOrEmpty($signedResource, 'signedResource'); |
287
|
|
|
Validate::isTrue( |
288
|
|
|
$signedResource == Resources::RESOURCE_TYPE_BLOB || |
289
|
|
|
$signedResource == Resources::RESOURCE_TYPE_CONTAINER, |
290
|
|
|
\sprintf( |
291
|
|
|
Resources::INVALID_VALUE_MSG, |
292
|
|
|
'$signedResource', |
293
|
|
|
'Can only be \'b\' or \'c\'.' |
294
|
|
|
) |
295
|
|
|
); |
296
|
|
|
|
297
|
|
|
return $this->generateServiceSharedAccessSignatureToken( |
298
|
|
|
Resources::RESOURCE_TYPE_BLOB, |
299
|
|
|
$signedResource, |
300
|
|
|
$resourceName, |
301
|
|
|
$signedPermissions, |
302
|
|
|
$signedExpiry, |
303
|
|
|
$signedStart, |
304
|
|
|
$signedIP, |
305
|
|
|
$signedProtocol, |
306
|
|
|
$signedIdentifier, |
307
|
|
|
$cacheControl, |
308
|
|
|
$contentDisposition, |
309
|
|
|
$contentEncoding, |
310
|
|
|
$contentLanguage, |
311
|
|
|
$contentType, |
312
|
|
|
'', |
313
|
|
|
'', |
314
|
|
|
'', |
315
|
|
|
'' |
316
|
|
|
); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Generates File service shared access signature. |
321
|
|
|
* |
322
|
|
|
* This only supports version 2015-04-05 and later. |
323
|
|
|
* |
324
|
|
|
* @param string $signedResource Resource name to generate the |
325
|
|
|
* canonicalized resource. |
326
|
|
|
* It can be Resources::RESOURCE_TYPE_FILE |
327
|
|
|
* or Resources::RESOURCE_TYPE_SHARE. |
328
|
|
|
* @param string $resourceName The name of the resource, including |
329
|
|
|
* the path of the resource. It should be |
330
|
|
|
* - {share}/{file}: for files, |
331
|
|
|
* - {share}: for shares, e.g.: |
332
|
|
|
* /mymusic/music.mp3 or |
333
|
|
|
* music.mp3 |
334
|
|
|
* @param string $signedPermissions Signed permissions. |
335
|
|
|
* @param string $signedExpiry Signed expiry date. |
336
|
|
|
* @param string $signedStart Signed start date. |
337
|
|
|
* @param string $signedIP Signed IP address. |
338
|
|
|
* @param string $signedProtocol Signed protocol. |
339
|
|
|
* @param string $signedIdentifier Signed identifier. |
340
|
|
|
* @param string $cacheControl Cache-Control header (rscc). |
341
|
|
|
* @param string $contentDisposition Content-Disposition header (rscd). |
342
|
|
|
* @param string $contentEncoding Content-Encoding header (rsce). |
343
|
|
|
* @param string $contentLanguage Content-Language header (rscl). |
344
|
|
|
* @param string $contentType Content-Type header (rsct). |
345
|
|
|
* |
346
|
|
|
* @see Constructing an service SAS at |
347
|
|
|
* https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas |
348
|
|
|
* @return string |
349
|
|
|
*/ |
350
|
|
View Code Duplication |
public function generateFileServiceSharedAccessSignatureToken( |
|
|
|
|
351
|
|
|
$signedResource, |
352
|
|
|
$resourceName, |
353
|
|
|
$signedPermissions, |
354
|
|
|
$signedExpiry, |
355
|
|
|
$signedStart = "", |
356
|
|
|
$signedIP = "", |
357
|
|
|
$signedProtocol = "", |
358
|
|
|
$signedIdentifier = "", |
359
|
|
|
$cacheControl = "", |
360
|
|
|
$contentDisposition = "", |
361
|
|
|
$contentEncoding = "", |
362
|
|
|
$contentLanguage = "", |
363
|
|
|
$contentType = "" |
364
|
|
|
) { |
365
|
|
|
// check that the resource name is valid. |
366
|
|
|
Validate::isString($signedResource, 'signedResource'); |
367
|
|
|
Validate::notNullOrEmpty($signedResource, 'signedResource'); |
368
|
|
|
Validate::isTrue( |
369
|
|
|
$signedResource == Resources::RESOURCE_TYPE_FILE || |
370
|
|
|
$signedResource == Resources::RESOURCE_TYPE_SHARE, |
371
|
|
|
\sprintf( |
372
|
|
|
Resources::INVALID_VALUE_MSG, |
373
|
|
|
'$signedResource', |
374
|
|
|
'Can only be \'f\' or \'s\'.' |
375
|
|
|
) |
376
|
|
|
); |
377
|
|
|
|
378
|
|
|
return $this->generateServiceSharedAccessSignatureToken( |
379
|
|
|
Resources::RESOURCE_TYPE_FILE, |
380
|
|
|
$signedResource, |
381
|
|
|
$resourceName, |
382
|
|
|
$signedPermissions, |
383
|
|
|
$signedExpiry, |
384
|
|
|
$signedStart, |
385
|
|
|
$signedIP, |
386
|
|
|
$signedProtocol, |
387
|
|
|
$signedIdentifier, |
388
|
|
|
$cacheControl, |
389
|
|
|
$contentDisposition, |
390
|
|
|
$contentEncoding, |
391
|
|
|
$contentLanguage, |
392
|
|
|
$contentType, |
393
|
|
|
'', |
394
|
|
|
'', |
395
|
|
|
'', |
396
|
|
|
'' |
397
|
|
|
); |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* Generates Table service shared access signature. |
402
|
|
|
* |
403
|
|
|
* This only supports version 2015-04-05 and later. |
404
|
|
|
* |
405
|
|
|
* @param string $tableName The name of the table. |
406
|
|
|
* @param string $signedPermissions Signed permissions. |
407
|
|
|
* @param string $signedExpiry Signed expiry date. |
408
|
|
|
* @param string $signedStart Signed start date. |
409
|
|
|
* @param string $signedIP Signed IP address. |
410
|
|
|
* @param string $signedProtocol Signed protocol. |
411
|
|
|
* @param string $signedIdentifier Signed identifier. |
412
|
|
|
* @param string $startingPartitionKey Minimum partition key. |
413
|
|
|
* @param string $startingRowKey Minimum row key. |
414
|
|
|
* @param string $endingPartitionKey Maximum partition key. |
415
|
|
|
* @param string $endingRowKey Maximum row key. |
416
|
|
|
* |
417
|
|
|
* @see Constructing an service SAS at |
418
|
|
|
* https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas |
419
|
|
|
* @return string |
420
|
|
|
*/ |
421
|
|
|
public function generateTableServiceSharedAccessSignatureToken( |
422
|
|
|
$tableName, |
423
|
|
|
$signedPermissions, |
424
|
|
|
$signedExpiry, |
425
|
|
|
$signedStart = "", |
426
|
|
|
$signedIP = "", |
427
|
|
|
$signedProtocol = "", |
428
|
|
|
$signedIdentifier = "", |
429
|
|
|
$startingPartitionKey = "", |
430
|
|
|
$startingRowKey = "", |
431
|
|
|
$endingPartitionKey = "", |
432
|
|
|
$endingRowKey = "" |
433
|
|
|
) { |
434
|
|
|
return $this->generateServiceSharedAccessSignatureToken( |
435
|
|
|
Resources::RESOURCE_TYPE_TABLE, |
436
|
|
|
Resources::RESOURCE_TYPE_TABLE, |
437
|
|
|
$tableName, |
438
|
|
|
$signedPermissions, |
439
|
|
|
$signedExpiry, |
440
|
|
|
$signedStart, |
441
|
|
|
$signedIP, |
442
|
|
|
$signedProtocol, |
443
|
|
|
$signedIdentifier, |
444
|
|
|
'', |
445
|
|
|
'', |
446
|
|
|
'', |
447
|
|
|
'', |
448
|
|
|
'', |
449
|
|
|
$startingPartitionKey, |
450
|
|
|
$startingRowKey, |
451
|
|
|
$endingPartitionKey, |
452
|
|
|
$endingRowKey |
453
|
|
|
); |
454
|
|
|
} |
455
|
|
|
|
456
|
|
|
/** |
457
|
|
|
* Generates a queue service shared access signature. |
458
|
|
|
* |
459
|
|
|
* This only supports version 2015-04-05 and later. |
460
|
|
|
* |
461
|
|
|
* @param string $queueName The name of the queue. |
462
|
|
|
* @param string $signedPermissions Signed permissions. |
463
|
|
|
* @param string $signedExpiry Signed expiry date. |
464
|
|
|
* @param string $signedStart Signed start date. |
465
|
|
|
* @param string $signedIdentifier Signed identifier. |
466
|
|
|
* @param string $signedIP Signed IP address. |
467
|
|
|
* @param string $signedProtocol Signed protocol. |
468
|
|
|
* |
469
|
|
|
* @see Constructing an service SAS at |
470
|
|
|
* https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas |
471
|
|
|
* @return string |
472
|
|
|
*/ |
473
|
|
|
public function generateQueueServiceSharedAccessSignatureToken( |
474
|
|
|
$queueName, |
475
|
|
|
$signedPermissions, |
476
|
|
|
$signedExpiry, |
477
|
|
|
$signedStart = "", |
478
|
|
|
$signedIP = "", |
479
|
|
|
$signedProtocol = "", |
480
|
|
|
$signedIdentifier = "" |
481
|
|
|
) { |
482
|
|
|
return $this->generateServiceSharedAccessSignatureToken( |
483
|
|
|
Resources::RESOURCE_TYPE_QUEUE, |
484
|
|
|
Resources::RESOURCE_TYPE_QUEUE, |
485
|
|
|
$queueName, |
486
|
|
|
$signedPermissions, |
487
|
|
|
$signedExpiry, |
488
|
|
|
$signedStart, |
489
|
|
|
$signedIP, |
490
|
|
|
$signedProtocol, |
491
|
|
|
$signedIdentifier, |
492
|
|
|
'', |
493
|
|
|
'', |
494
|
|
|
'', |
495
|
|
|
'', |
496
|
|
|
'', |
497
|
|
|
'', |
498
|
|
|
'', |
499
|
|
|
'', |
500
|
|
|
'' |
501
|
|
|
); |
502
|
|
|
} |
503
|
|
|
|
504
|
|
|
/** |
505
|
|
|
* Generates a shared access signature at the account level. |
506
|
|
|
* |
507
|
|
|
* @param string $signedVersion Specifies the signed version to use. |
508
|
|
|
* @param string $signedPermissions Specifies the signed permissions for |
509
|
|
|
* the account SAS. |
510
|
|
|
* @param string $signedService Specifies the signed services |
511
|
|
|
* accessible with the account SAS. |
512
|
|
|
* @param string $signedResourceType Specifies the signed resource types |
513
|
|
|
* that are accessible with the account |
514
|
|
|
* SAS. |
515
|
|
|
* @param string $signedExpiry The time at which the shared access |
516
|
|
|
* signature becomes invalid, in an ISO |
517
|
|
|
* 8601 format. |
518
|
|
|
* @param string $signedStart The time at which the SAS becomes |
519
|
|
|
* valid, in an ISO 8601 format. |
520
|
|
|
* @param string $signedIP Specifies an IP address or a range |
521
|
|
|
* of IP addresses from which to accept |
522
|
|
|
* requests. |
523
|
|
|
* @param string $signedProtocol Specifies the protocol permitted for |
524
|
|
|
* a request made with the account SAS. |
525
|
|
|
* |
526
|
|
|
* @see Constructing an account SAS at |
527
|
|
|
* https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/constructing-an-account-sas |
528
|
|
|
* |
529
|
|
|
* @return string |
530
|
|
|
*/ |
531
|
|
|
public function generateAccountSharedAccessSignatureToken( |
532
|
|
|
$signedVersion, |
533
|
|
|
$signedPermissions, |
534
|
|
|
$signedService, |
535
|
|
|
$signedResourceType, |
536
|
|
|
$signedExpiry, |
537
|
|
|
$signedStart = "", |
538
|
|
|
$signedIP = "", |
539
|
|
|
$signedProtocol = "" |
540
|
|
|
) { |
541
|
|
|
// check that version is valid |
542
|
|
|
Validate::isString($signedVersion, 'signedVersion'); |
543
|
|
|
Validate::notNullOrEmpty($signedVersion, 'signedVersion'); |
544
|
|
|
Validate::isDateString($signedVersion, 'signedVersion'); |
545
|
|
|
|
546
|
|
|
// validate and sanitize signed service |
547
|
|
|
$signedService = $this->validateAndSanitizeSignedService($signedService); |
548
|
|
|
|
549
|
|
|
// validate and sanitize signed resource type |
550
|
|
|
$signedResourceType = $this->validateAndSanitizeSignedResourceType($signedResourceType); |
551
|
|
|
|
552
|
|
|
// validate and sanitize signed permissions |
553
|
|
|
$signedPermissions = $this->validateAndSanitizeSignedPermissions($signedPermissions); |
554
|
|
|
|
555
|
|
|
// check that expiracy is valid |
556
|
|
|
Validate::isString($signedExpiry, 'signedExpiry'); |
557
|
|
|
Validate::notNullOrEmpty($signedExpiry, 'signedExpiry'); |
558
|
|
|
Validate::isDateString($signedExpiry, 'signedExpiry'); |
559
|
|
|
|
560
|
|
|
// check that signed start is valid |
561
|
|
|
Validate::isString($signedStart, 'signedStart'); |
562
|
|
|
if (strlen($signedStart) > 0) { |
563
|
|
|
Validate::isDateString($signedStart, 'signedStart'); |
564
|
|
|
} |
565
|
|
|
|
566
|
|
|
// check that signed IP is valid |
567
|
|
|
Validate::isString($signedIP, 'signedIP'); |
568
|
|
|
|
569
|
|
|
// validate and sanitize signed protocol |
570
|
|
|
$signedProtocol = $this->validateAndSanitizeSignedProtocol($signedProtocol); |
571
|
|
|
|
572
|
|
|
// construct an array with the parameters to generate the shared access signature at the account level |
573
|
|
|
$parameters = array(); |
574
|
|
|
$parameters[] = $this->accountName; |
575
|
|
|
$parameters[] = urldecode($signedPermissions); |
576
|
|
|
$parameters[] = urldecode($signedService); |
577
|
|
|
$parameters[] = urldecode($signedResourceType); |
578
|
|
|
$parameters[] = urldecode($signedStart); |
579
|
|
|
$parameters[] = urldecode($signedExpiry); |
580
|
|
|
$parameters[] = urldecode($signedIP); |
581
|
|
|
$parameters[] = urldecode($signedProtocol); |
582
|
|
|
$parameters[] = urldecode($signedVersion); |
583
|
|
|
|
584
|
|
|
// implode the parameters into a string |
585
|
|
|
$stringToSign = utf8_encode(implode("\n", $parameters) . "\n"); |
586
|
|
|
|
587
|
|
|
// decode the account key from base64 |
588
|
|
|
$decodedAccountKey = base64_decode($this->accountKey); |
589
|
|
|
|
590
|
|
|
// create the signature with hmac sha256 |
591
|
|
|
$signature = hash_hmac("sha256", $stringToSign, $decodedAccountKey, true); |
592
|
|
|
|
593
|
|
|
// encode the signature as base64 and url encode. |
594
|
|
|
$sig = urlencode(base64_encode($signature)); |
595
|
|
|
|
596
|
|
|
//adding all the components for account SAS together. |
597
|
|
|
$sas = 'sv=' . $signedVersion; |
598
|
|
|
$sas .= '&ss=' . $signedService; |
599
|
|
|
$sas .= '&srt=' . $signedResourceType; |
600
|
|
|
$sas .= '&sp=' . $signedPermissions; |
601
|
|
|
$sas .= '&se=' . $signedExpiry; |
602
|
|
|
$sas .= $signedStart === ''? '' : '&st=' . $signedStart; |
603
|
|
|
$sas .= $signedIP === ''? '' : '&sip=' . $signedIP; |
604
|
|
|
$sas .= '&spr=' . $signedProtocol; |
605
|
|
|
$sas .= '&sig=' . $sig; |
606
|
|
|
|
607
|
|
|
// return the signature |
608
|
|
|
return $sas; |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
/** |
612
|
|
|
* Validates and sanitizes the signed service parameter |
613
|
|
|
* |
614
|
|
|
* @param string $signedService Specifies the signed services accessible |
615
|
|
|
* with the account SAS. |
616
|
|
|
* |
617
|
|
|
* @return string |
618
|
|
|
*/ |
619
|
|
View Code Duplication |
private function validateAndSanitizeSignedService($signedService) |
|
|
|
|
620
|
|
|
{ |
621
|
|
|
// validate signed service is not null or empty |
622
|
|
|
Validate::isString($signedService, 'signedService'); |
623
|
|
|
Validate::notNullOrEmpty($signedService, 'signedService'); |
624
|
|
|
|
625
|
|
|
// The signed service should only be a combination of the letters b(lob) q(ueue) t(able) or f(ile) |
626
|
|
|
$validServices = ['b', 'q', 't', 'f']; |
627
|
|
|
|
628
|
|
|
return $this->validateAndSanitizeStringWithArray( |
629
|
|
|
strtolower($signedService), |
630
|
|
|
$validServices |
631
|
|
|
); |
632
|
|
|
} |
633
|
|
|
|
634
|
|
|
/** |
635
|
|
|
* Validates and sanitizes the signed resource type parameter |
636
|
|
|
* |
637
|
|
|
* @param string $signedResourceType Specifies the signed resource types |
638
|
|
|
* that are accessible with the account |
639
|
|
|
* SAS. |
640
|
|
|
* |
641
|
|
|
* @return string |
642
|
|
|
*/ |
643
|
|
View Code Duplication |
private function validateAndSanitizeSignedResourceType($signedResourceType) |
|
|
|
|
644
|
|
|
{ |
645
|
|
|
// validate signed resource type is not null or empty |
646
|
|
|
Validate::isString($signedResourceType, 'signedResourceType'); |
647
|
|
|
Validate::notNullOrEmpty($signedResourceType, 'signedResourceType'); |
648
|
|
|
|
649
|
|
|
// The signed resource type should only be a combination of the letters s(ervice) c(container) or o(bject) |
650
|
|
|
$validResourceTypes = ['s', 'c', 'o']; |
651
|
|
|
|
652
|
|
|
return $this->validateAndSanitizeStringWithArray( |
653
|
|
|
strtolower($signedResourceType), |
654
|
|
|
$validResourceTypes |
655
|
|
|
); |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
/** |
659
|
|
|
* Validates and sanitizes the signed permissions parameter |
660
|
|
|
* |
661
|
|
|
* @param string $signedPermissions Specifies the signed permissions for the |
662
|
|
|
* account SAS. |
663
|
|
|
* @param string $signedResource Specifies the signed resource for the |
664
|
|
|
* |
665
|
|
|
* @return string |
666
|
|
|
*/ |
667
|
|
|
private function validateAndSanitizeSignedPermissions( |
668
|
|
|
$signedPermissions, |
669
|
|
|
$signedResource = '' |
670
|
|
|
) { |
671
|
|
|
// validate signed permissions are not null or empty |
672
|
|
|
Validate::isString($signedPermissions, 'signedPermissions'); |
673
|
|
|
Validate::notNullOrEmpty($signedPermissions, 'signedPermissions'); |
674
|
|
|
|
675
|
|
|
if ($signedResource == '') { |
676
|
|
|
$validPermissions = ['r', 'w', 'd', 'l', 'a', 'c', 'u', 'p']; |
677
|
|
|
} else { |
678
|
|
|
$validPermissions = |
679
|
|
|
AccessPolicy::getResourceValidPermissions()[$signedResource]; |
680
|
|
|
} |
681
|
|
|
|
682
|
|
|
return $this->validateAndSanitizeStringWithArray( |
683
|
|
|
strtolower($signedPermissions), |
684
|
|
|
$validPermissions |
685
|
|
|
); |
686
|
|
|
} |
687
|
|
|
|
688
|
|
|
/** |
689
|
|
|
* Validates and sanitizes the signed protocol parameter |
690
|
|
|
* |
691
|
|
|
* @param string $signedProtocol Specifies the signed protocol for the |
692
|
|
|
* account SAS. |
693
|
|
|
|
694
|
|
|
* @return string |
695
|
|
|
*/ |
696
|
|
|
private function validateAndSanitizeSignedProtocol($signedProtocol) |
697
|
|
|
{ |
698
|
|
|
Validate::isString($signedProtocol, 'signedProtocol'); |
699
|
|
|
// sanitize string |
700
|
|
|
$sanitizedSignedProtocol = strtolower($signedProtocol); |
701
|
|
|
if (strlen($sanitizedSignedProtocol) > 0) { |
702
|
|
|
if (strcmp($sanitizedSignedProtocol, "https") != 0 && strcmp($sanitizedSignedProtocol, "https,http") != 0) { |
703
|
|
|
throw new \InvalidArgumentException(Resources::SIGNED_PROTOCOL_INVALID_VALIDATION_MSG); |
704
|
|
|
} |
705
|
|
|
} |
706
|
|
|
|
707
|
|
|
return $sanitizedSignedProtocol; |
708
|
|
|
} |
709
|
|
|
|
710
|
|
|
/** |
711
|
|
|
* Checks if a string contains an other string |
712
|
|
|
* |
713
|
|
|
* @param string $input The input to test. |
714
|
|
|
* @param string $toFind The string to find in the input. |
715
|
|
|
|
716
|
|
|
* @return bool |
717
|
|
|
*/ |
718
|
|
|
private function strcontains($input, $toFind) |
|
|
|
|
719
|
|
|
{ |
720
|
|
|
return strpos($input, $toFind) !== false; |
721
|
|
|
} |
722
|
|
|
|
723
|
|
|
/** |
724
|
|
|
* Removes duplicate characters from a string |
725
|
|
|
* |
726
|
|
|
* @param string $input The input string. |
727
|
|
|
|
728
|
|
|
* @return string |
729
|
|
|
*/ |
730
|
|
|
private function validateAndSanitizeStringWithArray($input, array $array) |
731
|
|
|
{ |
732
|
|
|
$result = ''; |
733
|
|
|
foreach ($array as $value) { |
734
|
|
|
if (strpos($input, $value) !== false) { |
735
|
|
|
//append the valid permission to result. |
736
|
|
|
$result .= $value; |
737
|
|
|
//remove all the character that represents the permission. |
738
|
|
|
$input = str_replace( |
739
|
|
|
$value, |
740
|
|
|
'', |
741
|
|
|
$input |
742
|
|
|
); |
743
|
|
|
} |
744
|
|
|
} |
745
|
|
|
|
746
|
|
|
Validate::isTrue( |
747
|
|
|
strlen($input) == '', |
748
|
|
|
sprintf( |
749
|
|
|
Resources::STRING_NOT_WITH_GIVEN_COMBINATION, |
750
|
|
|
implode(', ', $array) |
751
|
|
|
) |
752
|
|
|
); |
753
|
|
|
return $result; |
754
|
|
|
} |
755
|
|
|
|
756
|
|
|
|
757
|
|
|
/** |
758
|
|
|
* Generate the canonical resource using the given account name, service |
759
|
|
|
* type and resource. |
760
|
|
|
* |
761
|
|
|
* @param string $accountName The account name of the service. |
762
|
|
|
* @param string $service The service name of the service. |
763
|
|
|
* @param string $resource The name of the resource. |
764
|
|
|
* |
765
|
|
|
* @return string |
766
|
|
|
*/ |
767
|
|
|
private static function generateCanonicalResource( |
768
|
|
|
$accountName, |
769
|
|
|
$service, |
770
|
|
|
$resource |
771
|
|
|
) { |
772
|
|
|
static $serviceMap = array( |
773
|
|
|
Resources::RESOURCE_TYPE_BLOB => 'blob', |
774
|
|
|
Resources::RESOURCE_TYPE_FILE => 'file', |
775
|
|
|
Resources::RESOURCE_TYPE_QUEUE => 'queue', |
776
|
|
|
Resources::RESOURCE_TYPE_TABLE => 'table', |
777
|
|
|
); |
778
|
|
|
$serviceName = $serviceMap[$service]; |
779
|
|
|
if (Utilities::startsWith($resource, '/')) { |
780
|
|
|
$resource = substr(1, strlen($resource) - 1); |
781
|
|
|
} |
782
|
|
|
return sprintf('/%s/%s/%s', $serviceName, $accountName, $resource); |
783
|
|
|
} |
784
|
|
|
} |
785
|
|
|
|
Adding a
@return
annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.Please refer to the PHP core documentation on constructors.