Skip to content

Commit eeb2f3b

Browse files
[Storage] Add missing SAS permissions to Storage packages (Azure#23179)
1 parent 038b35f commit eeb2f3b

File tree

8 files changed

+145
-33
lines changed

8 files changed

+145
-33
lines changed

sdk/storage/azure-storage-blob/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ This version and all future versions will require Python 3.6+. Python 2.7 is no
1717
- Added support for `find_blobs_by_tags()` on a container.
1818
- Added support for `Find (f)` container SAS permission.
1919

20+
### Bugs Fixed
21+
- Added all missing Service SAS permissions.
22+
- Fixed a bug that prevented `upload_blob()` from working with an OS pipe
23+
reader stream on Linux. (#23131)
24+
2025
## 12.10.0b4 (2022-02-24)
2126

2227
### Features Added

sdk/storage/azure-storage-blob/azure/storage/blob/_models.py

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -917,33 +917,50 @@ class ContainerSasPermissions(object):
917917
List blobs in the container.
918918
:param bool tag:
919919
Set or get tags on the blobs in the container.
920+
:keyword bool add:
921+
Add a block to an append blob.
922+
:keyword bool create:
923+
Write a new blob, snapshot a blob, or copy a blob to a new blob.
920924
:keyword bool permanent_delete:
921925
To enable permanent delete on the blob is permitted.
922926
:keyword bool find:
923-
To enable finding blobs by tags
927+
To enable finding blobs by tags.
928+
:keyword bool move:
929+
Move a blob or a directory and its contents to a new location.
930+
:keyword bool execute:
931+
Get the system properties and, if the hierarchical namespace is enabled for the storage account,
932+
get the POSIX ACL of a blob.
924933
:keyword bool set_immutability_policy:
925934
To enable operations related to set/delete immutability policy.
926935
To get immutability policy, you just need read permission.
927936
"""
928937
def __init__(self, read=False, write=False, delete=False,
929938
list=False, delete_previous_version=False, tag=False, **kwargs): # pylint: disable=redefined-builtin
930939
self.read = read
940+
self.add = kwargs.pop('add', False)
941+
self.create = kwargs.pop('create', False)
931942
self.write = write
932943
self.delete = delete
933944
self.delete_previous_version = delete_previous_version
934945
self.permanent_delete = kwargs.pop('permanent_delete', False)
935946
self.list = list
936947
self.tag = tag
937948
self.find = kwargs.pop('find', False)
949+
self.move = kwargs.pop('move', False)
950+
self.execute = kwargs.pop('execute', False)
938951
self.set_immutability_policy = kwargs.pop('set_immutability_policy', False)
939952
self._str = (('r' if self.read else '') +
953+
('a' if self.add else '') +
954+
('c' if self.create else '') +
940955
('w' if self.write else '') +
941956
('d' if self.delete else '') +
942957
('x' if self.delete_previous_version else '') +
943958
('y' if self.permanent_delete else '') +
944959
('l' if self.list else '') +
945960
('t' if self.tag else '') +
946961
('f' if self.find else '') +
962+
('m' if self.move else '') +
963+
('e' if self.execute else '') +
947964
('i' if self.set_immutability_policy else ''))
948965

949966
def __str__(self):
@@ -963,17 +980,22 @@ def from_string(cls, permission):
963980
:rtype: ~azure.storage.blob.ContainerSasPermissions
964981
"""
965982
p_read = 'r' in permission
983+
p_add = 'a' in permission
984+
p_create = 'c' in permission
966985
p_write = 'w' in permission
967986
p_delete = 'd' in permission
968987
p_delete_previous_version = 'x' in permission
969988
p_permanent_delete = 'y' in permission
970989
p_list = 'l' in permission
971990
p_tag = 't' in permission
972991
p_find = 'f' in permission
992+
p_move = 'm' in permission
993+
p_execute = 'e' in permission
973994
p_set_immutability_policy = 'i' in permission
974995
parsed = cls(read=p_read, write=p_write, delete=p_delete, list=p_list,
975-
delete_previous_version=p_delete_previous_version, tag=p_tag, find=p_find,
976-
set_immutability_policy=p_set_immutability_policy, permanent_delete=p_permanent_delete)
996+
delete_previous_version=p_delete_previous_version, tag=p_tag, add=p_add,
997+
create=p_create, permanent_delete=p_permanent_delete, find=p_find, move=p_move,
998+
execute=p_execute, set_immutability_policy=p_set_immutability_policy)
977999

9781000
return parsed
9791001

@@ -999,11 +1021,16 @@ class BlobSasPermissions(object):
9991021
Delete the previous blob version for the versioning enabled storage account.
10001022
:param bool tag:
10011023
Set or get tags on the blob.
1024+
:keyword bool permanent_delete:
1025+
To enable permanent delete on the blob is permitted.
1026+
:keyword bool move:
1027+
Move a blob or a directory and its contents to a new location.
1028+
:keyword bool execute:
1029+
Get the system properties and, if the hierarchical namespace is enabled for the storage account,
1030+
get the POSIX ACL of a blob.
10021031
:keyword bool set_immutability_policy:
10031032
To enable operations related to set/delete immutability policy.
10041033
To get immutability policy, you just need read permission.
1005-
:keyword bool permanent_delete:
1006-
To enable permanent delete on the blob is permitted.
10071034
"""
10081035
def __init__(self, read=False, add=False, create=False, write=False,
10091036
delete=False, delete_previous_version=False, tag=True, **kwargs):
@@ -1015,6 +1042,8 @@ def __init__(self, read=False, add=False, create=False, write=False,
10151042
self.delete_previous_version = delete_previous_version
10161043
self.permanent_delete = kwargs.pop('permanent_delete', False)
10171044
self.tag = tag
1045+
self.move = kwargs.pop('move', False)
1046+
self.execute = kwargs.pop('execute', False)
10181047
self.set_immutability_policy = kwargs.pop('set_immutability_policy', False)
10191048
self._str = (('r' if self.read else '') +
10201049
('a' if self.add else '') +
@@ -1024,6 +1053,8 @@ def __init__(self, read=False, add=False, create=False, write=False,
10241053
('x' if self.delete_previous_version else '') +
10251054
('y' if self.permanent_delete else '') +
10261055
('t' if self.tag else '') +
1056+
('m' if self.move else '') +
1057+
('e' if self.execute else '') +
10271058
('i' if self.set_immutability_policy else ''))
10281059

10291060
def __str__(self):
@@ -1050,11 +1081,13 @@ def from_string(cls, permission):
10501081
p_delete_previous_version = 'x' in permission
10511082
p_permanent_delete = 'y' in permission
10521083
p_tag = 't' in permission
1084+
p_move = 'm' in permission
1085+
p_execute = 'e' in permission
10531086
p_set_immutability_policy = 'i' in permission
10541087

10551088
parsed = cls(read=p_read, add=p_add, create=p_create, write=p_write, delete=p_delete,
1056-
delete_previous_version=p_delete_previous_version, tag=p_tag,
1057-
set_immutability_policy=p_set_immutability_policy, permanent_delete=p_permanent_delete)
1089+
delete_previous_version=p_delete_previous_version, tag=p_tag, permanent_delete=p_permanent_delete,
1090+
move=p_move, execute=p_execute, set_immutability_policy=p_set_immutability_policy)
10581091

10591092
return parsed
10601093

sdk/storage/azure-storage-blob/azure/storage/blob/_shared_access_signature.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,14 @@ def generate_blob(self, container_name, blob_name, snapshot=None, version_id=Non
6666
:param str snapshot:
6767
The snapshot parameter is an opaque DateTime value that,
6868
when present, specifies the blob snapshot to grant permission.
69-
:param BlobSasPermissions permission:
69+
:param permission:
7070
The permissions associated with the shared access signature. The
7171
user is restricted to operations allowed by the permissions.
72-
Permissions must be ordered read, write, delete, list.
72+
Permissions must be ordered racwdxytmei.
7373
Required unless an id is given referencing a stored access policy
7474
which contains this field. This field must be omitted if it has been
7575
specified in an associated stored access policy.
76+
:type permission: str or BlobSasPermissions
7677
:param expiry:
7778
The time at which the shared access signature becomes invalid.
7879
Required unless an id is given referencing a stored access policy
@@ -150,14 +151,14 @@ def generate_container(self, container_name, permission=None, expiry=None,
150151
151152
:param str container_name:
152153
Name of container.
153-
:param ContainerSasPermissions permission:
154+
:param permission:
154155
The permissions associated with the shared access signature. The
155156
user is restricted to operations allowed by the permissions.
156-
Permissions must be ordered read, write, delete, delete version, permanent delete, list, tag, find,
157-
set immutability policy.
157+
Permissions must be ordered racwdxyltfmei.
158158
Required unless an id is given referencing a stored access policy
159159
which contains this field. This field must be omitted if it has been
160160
specified in an associated stored access policy.
161+
:type permission: str or ContainerSasPermissions
161162
:param expiry:
162163
The time at which the shared access signature becomes invalid.
163164
Required unless an id is given referencing a stored access policy
@@ -407,8 +408,7 @@ def generate_container_sas(
407408
:param permission:
408409
The permissions associated with the shared access signature. The
409410
user is restricted to operations allowed by the permissions.
410-
Permissions must be ordered read, write, delete, delete version, permanent delete, list, tag, find,
411-
set immutability policy.
411+
Permissions must be ordered racwdxyltfmei.
412412
Required unless an id is given referencing a stored access policy
413413
which contains this field. This field must be omitted if it has been
414414
specified in an associated stored access policy.
@@ -527,7 +527,7 @@ def generate_blob_sas(
527527
:param permission:
528528
The permissions associated with the shared access signature. The
529529
user is restricted to operations allowed by the permissions.
530-
Permissions must be ordered read, write, delete, list.
530+
Permissions must be ordered racwdxytmei.
531531
Required unless an id is given referencing a stored access policy
532532
which contains this field. This field must be omitted if it has been
533533
specified in an associated stored access policy.

sdk/storage/azure-storage-blob/tests/test_common_blob.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,6 +1822,53 @@ def test_account_sas(self, storage_account_name, storage_account_key):
18221822
self.assertEqual(self.byte_data, blob_response.content)
18231823
self.assertTrue(container_response.ok)
18241824

1825+
@pytest.mark.live_test_only
1826+
@BlobPreparer()
1827+
def test_blob_service_sas(self, storage_account_name, storage_account_key):
1828+
# SAS URL is calculated from storage key, so this test runs live only
1829+
1830+
self._setup(storage_account_name, storage_account_key)
1831+
container = self.bsc.get_container_client(self.container_name)
1832+
blob_name = self._create_block_blob(overwrite=True)
1833+
blob = self.bsc.get_blob_client(self.container_name, blob_name)
1834+
1835+
# Generate SAS with all available permissions
1836+
container_sas = generate_container_sas(
1837+
container.account_name,
1838+
container.container_name,
1839+
account_key=container.credential.account_key,
1840+
permission=ContainerSasPermissions(
1841+
read=True, write=True, delete=True, list=True, delete_previous_version=True,
1842+
tag=True, add=True, create=True, permanent_delete=True, find=True, move=True,
1843+
execute=True, set_immutability_policy=True
1844+
),
1845+
expiry=datetime.utcnow() + timedelta(hours=1),
1846+
)
1847+
1848+
blob_sas = generate_blob_sas(
1849+
blob.account_name,
1850+
blob.container_name,
1851+
blob.blob_name,
1852+
snapshot=blob.snapshot,
1853+
account_key=blob.credential.account_key,
1854+
permission=BlobSasPermissions(
1855+
read=True, add=True, create=True, write=True, delete=True, delete_previous_version=True,
1856+
permanent_delete=True, tag=True, find=True, move=True, execute=True, set_immutability_policy=True
1857+
),
1858+
expiry=datetime.utcnow() + timedelta(hours=1),
1859+
)
1860+
1861+
# Act
1862+
container_client = ContainerClient.from_container_url(container.url, credential=container_sas)
1863+
blob_list = list(container_client.list_blobs())
1864+
1865+
blob_client = BlobClient.from_blob_url(blob.url, credential=blob_sas)
1866+
blob_props = blob_client.get_blob_properties()
1867+
1868+
# Assert
1869+
self.assertIsNotNone(blob_list)
1870+
self.assertIsNotNone(blob_props)
1871+
18251872
@pytest.mark.live_test_only
18261873
@BlobPreparer()
18271874
def test_set_immutability_policy_using_sas(self, versioned_storage_account_name, versioned_storage_account_key, storage_resource_group_name):

sdk/storage/azure-storage-file-datalake/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This version and all future versions will require Python 3.6+. Python 2.7 is no
1414

1515
### Bugs Fixed
1616
- Update `azure-core` dependency to avoid inconsistent dependencies from being installed.
17+
- Added all missing Service SAS permissions.
1718

1819
## 12.6.0b2 (2021-12-13)
1920

sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_models.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ class FileSystemSasPermissions(object):
315315
Delete the file system.
316316
:param bool list:
317317
List paths in the file system.
318+
:keyword bool add:
319+
Append data to a file in the directory.
320+
:keyword bool create:
321+
Write a new file, snapshot a file, or copy a file to a new file.
318322
:keyword bool move:
319323
Move any file in the directory to a new location.
320324
Note the move operation can optionally be restricted to the child file or directory owner or
@@ -333,6 +337,8 @@ class FileSystemSasPermissions(object):
333337
def __init__(self, read=False, write=False, delete=False, list=False, # pylint: disable=redefined-builtin
334338
**kwargs):
335339
self.read = read
340+
self.add = kwargs.pop('add', None)
341+
self.create = kwargs.pop('create', None)
336342
self.write = write
337343
self.delete = delete
338344
self.list = list
@@ -341,6 +347,8 @@ def __init__(self, read=False, write=False, delete=False, list=False, # pylint:
341347
self.manage_ownership = kwargs.pop('manage_ownership', None)
342348
self.manage_access_control = kwargs.pop('manage_access_control', None)
343349
self._str = (('r' if self.read else '') +
350+
('a' if self.add else '') +
351+
('c' if self.create else '') +
344352
('w' if self.write else '') +
345353
('d' if self.delete else '') +
346354
('l' if self.list else '') +
@@ -366,6 +374,8 @@ def from_string(cls, permission):
366374
:rtype: ~azure.storage.fildatalake.FileSystemSasPermissions
367375
"""
368376
p_read = 'r' in permission
377+
p_add = 'a' in permission
378+
p_create = 'c' in permission
369379
p_write = 'w' in permission
370380
p_delete = 'd' in permission
371381
p_list = 'l' in permission
@@ -375,7 +385,8 @@ def from_string(cls, permission):
375385
p_manage_access_control = 'p' in permission
376386

377387
parsed = cls(read=p_read, write=p_write, delete=p_delete,
378-
list=p_list, move=p_move, execute=p_execute, manage_ownership=p_manage_ownership,
388+
list=p_list, add=p_add, create=p_create, move=p_move,
389+
execute=p_execute, manage_ownership=p_manage_ownership,
379390
manage_access_control=p_manage_access_control)
380391
return parsed
381392

@@ -392,6 +403,8 @@ class DirectorySasPermissions(object):
392403
Create or write content, properties, metadata. Lease the directory.
393404
:param bool delete:
394405
Delete the directory.
406+
:keyword bool add:
407+
Append data to a file in the directory.
395408
:keyword bool list:
396409
List any files in the directory. Implies Execute.
397410
:keyword bool move:
@@ -412,6 +425,7 @@ class DirectorySasPermissions(object):
412425
def __init__(self, read=False, create=False, write=False,
413426
delete=False, **kwargs):
414427
self.read = read
428+
self.add = kwargs.pop('add', None)
415429
self.create = create
416430
self.write = write
417431
self.delete = delete
@@ -421,6 +435,7 @@ def __init__(self, read=False, create=False, write=False,
421435
self.manage_ownership = kwargs.pop('manage_ownership', None)
422436
self.manage_access_control = kwargs.pop('manage_access_control', None)
423437
self._str = (('r' if self.read else '') +
438+
('a' if self.add else '') +
424439
('c' if self.create else '') +
425440
('w' if self.write else '') +
426441
('d' if self.delete else '') +
@@ -447,6 +462,7 @@ def from_string(cls, permission):
447462
:rtype: ~azure.storage.filedatalake.DirectorySasPermissions
448463
"""
449464
p_read = 'r' in permission
465+
p_add = 'a' in permission
450466
p_create = 'c' in permission
451467
p_write = 'w' in permission
452468
p_delete = 'd' in permission
@@ -456,7 +472,7 @@ def from_string(cls, permission):
456472
p_manage_ownership = 'o' in permission
457473
p_manage_access_control = 'p' in permission
458474

459-
parsed = cls(read=p_read, create=p_create, write=p_write, delete=p_delete,
475+
parsed = cls(read=p_read, create=p_create, write=p_write, delete=p_delete, add=p_add,
460476
list=p_list, move=p_move, execute=p_execute, manage_ownership=p_manage_ownership,
461477
manage_access_control=p_manage_access_control)
462478
return parsed
@@ -470,11 +486,13 @@ class FileSasPermissions(object):
470486
Read the content, properties, metadata etc. Use the file as
471487
the source of a read operation.
472488
:param bool create:
473-
Write a new file
489+
Write a new file.
474490
:param bool write:
475491
Create or write content, properties, metadata. Lease the file.
476492
:param bool delete:
477493
Delete the file.
494+
:keyword bool add:
495+
Append data to the file.
478496
:keyword bool move:
479497
Move any file in the directory to a new location.
480498
Note the move operation can optionally be restricted to the child file or directory owner or
@@ -492,15 +510,16 @@ class FileSasPermissions(object):
492510

493511
def __init__(self, read=False, create=False, write=False, delete=False, **kwargs):
494512
self.read = read
513+
self.add = kwargs.pop('add', None)
495514
self.create = create
496515
self.write = write
497516
self.delete = delete
498-
self.list = list
499517
self.move = kwargs.pop('move', None)
500518
self.execute = kwargs.pop('execute', None)
501519
self.manage_ownership = kwargs.pop('manage_ownership', None)
502520
self.manage_access_control = kwargs.pop('manage_access_control', None)
503521
self._str = (('r' if self.read else '') +
522+
('a' if self.add else '') +
504523
('c' if self.create else '') +
505524
('w' if self.write else '') +
506525
('d' if self.delete else '') +
@@ -526,6 +545,7 @@ def from_string(cls, permission):
526545
:rtype: ~azure.storage.fildatalake.FileSasPermissions
527546
"""
528547
p_read = 'r' in permission
548+
p_add = 'a' in permission
529549
p_create = 'c' in permission
530550
p_write = 'w' in permission
531551
p_delete = 'd' in permission
@@ -534,7 +554,7 @@ def from_string(cls, permission):
534554
p_manage_ownership = 'o' in permission
535555
p_manage_access_control = 'p' in permission
536556

537-
parsed = cls(read=p_read, create=p_create, write=p_write, delete=p_delete,
557+
parsed = cls(read=p_read, create=p_create, write=p_write, delete=p_delete, add=p_add,
538558
move=p_move, execute=p_execute, manage_ownership=p_manage_ownership,
539559
manage_access_control=p_manage_access_control)
540560
return parsed

0 commit comments

Comments
 (0)