diff --git a/sdk/storage/azure-storage-blob/HISTORY.md b/sdk/storage/azure-storage-blob/HISTORY.md index fa5e07d3928d..4a5031c7fedd 100644 --- a/sdk/storage/azure-storage-blob/HISTORY.md +++ b/sdk/storage/azure-storage-blob/HISTORY.md @@ -9,6 +9,8 @@ - Removed types that were accidentally exposed from two modules. Only `BlobServiceClient`, `ContainerClient`, `BlobClient` and `LeaseClient` should be imported from azure.storage.blob.aio - `Logging` has been renamed to `BlobAnalyticsLogging`. +- The `generate_shared_access_signature` methods on each of `BlobServiceClient`, `ContainerClient` and `BlobClient` have been replaced by module level functions `generate_account_sas`, `generate_container_sas` and `generate_blob_sas`. + **New features** diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/__init__.py b/sdk/storage/azure-storage-blob/azure/storage/blob/__init__.py index 67f9b3cc4409..c9d6be68f33b 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/__init__.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/__init__.py @@ -13,6 +13,7 @@ from .blob_service_client import BlobServiceClient from .lease import LeaseClient from .download import StorageStreamDownloader +from ._shared_access_signature import generate_account_sas, generate_container_sas, generate_blob_sas from ._shared.policies import ExponentialRetry, LinearRetry from ._shared.models import( LocationMode, @@ -89,7 +90,10 @@ 'AccountSasPermissions', 'StorageStreamDownloader', 'CustomerProvidedEncryptionKey', - 'RehydratePriority' + 'RehydratePriority', + 'generate_account_sas', + 'generate_container_sas', + 'generate_blob_sas' ] diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py index 32f38cbd9b5b..7e416c7e9569 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py @@ -64,7 +64,7 @@ } -class StorageAccountHostsMixin(object): +class StorageAccountHostsMixin(object): # pylint: disable=too-many-instance-attributes def __init__( self, parsed_url, # type: Any @@ -80,11 +80,14 @@ def __init__( if service not in ["blob", "queue", "file"]: raise ValueError("Invalid service: {}".format(service)) account = parsed_url.netloc.split(".{}.core.".format(service)) + self.account_name = account[0] secondary_hostname = None + self.credential = format_shared_key_credential(account, credential) if self.scheme.lower() != "https" and hasattr(self.credential, "get_token"): raise ValueError("Token credential is only supported with HTTPS.") if hasattr(self.credential, "account_name"): + self.account_name = self.credential.account_name secondary_hostname = "{}-secondary.{}.{}".format(self.credential.account_name, service, SERVICE_HOST_BASE) if not self._hosts: diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/models.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/models.py index 80c4d22a6b2f..2c491acdf8e3 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/models.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/models.py @@ -261,8 +261,8 @@ def from_string(cls, string): class AccountSasPermissions(object): """ - :class:`~ResourceTypes` class to be used with generate_shared_access_signature - method and for the AccessPolicies used with set_*_acl. There are two types of + :class:`~ResourceTypes` class to be used with generate_account_sas + function and for the AccessPolicies used with set_*_acl. There are two types of SAS which may be used to grant resource access. One is to grant access to a specific resource (resource-specific). Another is to grant access to the entire service for a specific account and allow certain operations based on diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/request_handlers.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/request_handlers.py index 57e3521fb192..873c67dd8e4f 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/request_handlers.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/request_handlers.py @@ -17,7 +17,6 @@ from azure.core.configuration import Configuration from azure.core.exceptions import raise_with_traceback -from azure.core.pipeline import Pipeline _LOGGER = logging.getLogger(__name__) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/uploads.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/uploads.py index 6ed1f9084df5..032915c06e2d 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/uploads.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/uploads.py @@ -395,7 +395,7 @@ def flush(self): pass def read(self, size=None): - if self.closed: + if self.closed: # pylint: disable=using-constant-test raise ValueError("Stream is closed.") if size is None: diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared_access_signature.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared_access_signature.py index 4c05f380ad78..8ab9411bf67d 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared_access_signature.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared_access_signature.py @@ -6,6 +6,7 @@ from azure.storage.blob._shared import sign_string, url_quote from azure.storage.blob._shared.constants import X_MS_VERSION +from azure.storage.blob._shared.models import Services from azure.storage.blob._shared.shared_access_signature import SharedAccessSignature, _SharedAccessHelper, \ QueryStringConstants @@ -260,3 +261,298 @@ def get_token(self): exclude = [BlobQueryStringConstants.SIGNED_TIMESTAMP] return '&'.join(['{0}={1}'.format(n, url_quote(v)) for n, v in self.query_dict.items() if v is not None and n not in exclude]) + + +def generate_account_sas( + account_name, # type: str + account_key, # type: str + resource_types, # type: Union[ResourceTypes, str] + permission, # type: Union[AccountSasPermissions, str] + expiry, # type: Optional[Union[datetime, str]] + start=None, # type: Optional[Union[datetime, str]] + ip=None, # type: Optional[str] + **kwargs # type: Any + ): # type: (...) -> str + """Generates a shared access signature for the blob service. + + Use the returned signature with the credential parameter of any BlobServiceClient, + ContainerClient or BlobClient. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str account_key: + The access key to generate the shared access signature. + :param resource_types: + Specifies the resource types that are accessible with the account SAS. + :type resource_types: str or ~azure.storage.blob.ResourceTypes + :param permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :type permission: str or ~azure.storage.blob.AccountSasPermissions + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. Azure will always convert values + to UTC. If a date is passed in without timezone info, it is assumed to + be UTC. + :type start: ~datetime.datetime or str + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying ip=168.1.5.65 or ip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :return: A Shared Access Signature (sas) token. + :rtype: str + + .. admonition:: Example: + + .. literalinclude:: ../tests/test_blob_samples_authentication.py + :start-after: [START create_sas_token] + :end-before: [END create_sas_token] + :language: python + :dedent: 8 + :caption: Generating a shared access signature. + """ + sas = SharedAccessSignature(account_name, account_key) + return sas.generate_account( + services=Services(blob=True), + resource_types=resource_types, + permission=permission, + expiry=expiry, + start=start, + ip=ip, + **kwargs + ) # type: ignore + + +def generate_container_sas( + account_name, # type: str + container_name, # type: str + account_key=None, # type: Optional[str] + user_delegation_key=None, # type: Optional[UserDelegationKey] + permission=None, # type: Optional[Union[ContainerSasPermissions, str]] + expiry=None, # type: Optional[Union[datetime, str]] + start=None, # type: Optional[Union[datetime, str]] + policy_id=None, # type: Optional[str] + ip=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> Any + """Generates a shared access signature for a container. + + Use the returned signature with the credential parameter of any BlobServiceClient, + ContainerClient or BlobClient. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str container_name: + The name of the container. + :param str account_key: + The access key to generate the shared access signature. Either `account_key` or + `user_delegation_key` must be specified. + :param ~azure.storage.blob.UserDelegationKey user_delegation_key: + Instead of an account key, the user could pass in a user delegation key. + A user delegation key can be obtained from the service by authenticating with an AAD identity; + this can be accomplished by calling :func:`~azure.storage.blob.BlobServiceClient.get_user_delegation_key`. + When present, the SAS is signed with the user delegation key instead. + :param permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Permissions must be ordered read, write, delete, list. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :type permission: str or ~azure.storage.blob.ContainerSasPermissions + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. Azure will always convert values + to UTC. If a date is passed in without timezone info, it is assumed to + be UTC. + :type start: datetime or str + :param str policy_id: + A unique value up to 64 characters in length that correlates to a + stored access policy. To create a stored access policy, use + :func:`~azure.storage.blob.ContainerClient.set_container_access_policy`. + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying ip=168.1.5.65 or ip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :keyword str cache_control: + Response header value for Cache-Control when resource is accessed + using this shared access signature. + :keyword str content_disposition: + Response header value for Content-Disposition when resource is accessed + using this shared access signature. + :keyword str content_encoding: + Response header value for Content-Encoding when resource is accessed + using this shared access signature. + :keyword str content_language: + Response header value for Content-Language when resource is accessed + using this shared access signature. + :keyword str content_type: + Response header value for Content-Type when resource is accessed + using this shared access signature. + :return: A Shared Access Signature (sas) token. + :rtype: str + + .. admonition:: Example: + + .. literalinclude:: ../tests/test_blob_samples_containers.py + :start-after: [START generate_sas_token] + :end-before: [END generate_sas_token] + :language: python + :dedent: 12 + :caption: Generating a sas token. + """ + if not user_delegation_key and not account_key: + raise ValueError("Either user_delegation_key or account_key must be provided.") + + if user_delegation_key: + sas = BlobSharedAccessSignature(account_name, user_delegation_key=user_delegation_key) + else: + sas = BlobSharedAccessSignature(account_name, account_key=account_key) + return sas.generate_container( + container_name, + permission=permission, + expiry=expiry, + start=start, + policy_id=policy_id, + ip=ip, + **kwargs + ) + + +def generate_blob_sas( + account_name, # type: str + container_name, # type: str + blob_name, # type: str + snapshot=None, # type: Optional[str] + account_key=None, # type: Optional[str] + user_delegation_key=None, # type: Optional[UserDelegationKey] + permission=None, # type: Optional[Union[BlobSasPermissions, str]] + expiry=None, # type: Optional[Union[datetime, str]] + start=None, # type: Optional[Union[datetime, str]] + policy_id=None, # type: Optional[str] + ip=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> Any + """Generates a shared access signature for a blob. + + Use the returned signature with the credential parameter of any BlobServiceClient, + ContainerClient or BlobClient. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str container_name: + The name of the container. + :param str blob_name: + The name of the blob. + :param str snapshot: + An optional blob snapshot ID. + :param str account_key: + The access key to generate the shared access signature. Either `account_key` or + `user_delegation_key` must be specified. + :param ~azure.storage.blob.UserDelegationKey user_delegation_key: + Instead of an account key, the user could pass in a user delegation key. + A user delegation key can be obtained from the service by authenticating with an AAD identity; + this can be accomplished by calling :func:`~azure.storage.blob.BlobServiceClient.get_user_delegation_key`. + When present, the SAS is signed with the user delegation key instead. + :param permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Permissions must be ordered read, write, delete, list. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :type permission: str or ~azure.storage.blob.BlobSasPermissions + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. Azure will always convert values + to UTC. If a date is passed in without timezone info, it is assumed to + be UTC. + :type start: ~datetime.datetime or str + :param str policy_id: + A unique value up to 64 characters in length that correlates to a + stored access policy. To create a stored access policy, use + :func:`~azure.storage.blob.ContainerClient.set_container_access_policy()`. + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying ip=168.1.5.65 or ip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :keyword str cache_control: + Response header value for Cache-Control when resource is accessed + using this shared access signature. + :keyword str content_disposition: + Response header value for Content-Disposition when resource is accessed + using this shared access signature. + :keyword str content_encoding: + Response header value for Content-Encoding when resource is accessed + using this shared access signature. + :keyword str content_language: + Response header value for Content-Language when resource is accessed + using this shared access signature. + :keyword str content_type: + Response header value for Content-Type when resource is accessed + using this shared access signature. + :return: A Shared Access Signature (sas) token. + :rtype: str + """ + if not user_delegation_key and not account_key: + raise ValueError("Either user_delegation_key or account_key must be provided.") + + if user_delegation_key: + sas = BlobSharedAccessSignature(account_name, user_delegation_key=user_delegation_key) + else: + sas = BlobSharedAccessSignature(account_name, account_key=account_key) + return sas.generate_blob( + container_name, + blob_name, + snapshot=snapshot, + permission=permission, + expiry=expiry, + start=start, + policy_id=policy_id, + ip=ip, + **kwargs + ) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py index 958eeb28bdec..d093a6db587c 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py @@ -49,7 +49,6 @@ from .models import BlobType, BlobBlock from .download import StorageStreamDownloader from .lease import LeaseClient, get_access_conditions -from ._shared_access_signature import BlobSharedAccessSignature if TYPE_CHECKING: from datetime import datetime @@ -261,116 +260,6 @@ def from_connection_string( return cls( account_url, container_name=container_name, blob_name=blob_name, snapshot=snapshot, credential=credential, **kwargs - ) - - def generate_shared_access_signature( - self, permission=None, # type: Optional[Union[BlobSasPermissions, str]] - expiry=None, # type: Optional[Union[datetime, str]] - start=None, # type: Optional[Union[datetime, str]] - policy_id=None, # type: Optional[str] - ip=None, # type: Optional[str] - user_delegation_key=None, # type: Optional[UserDelegationKey] - **kwargs # type: Any - ): - # type: (...) -> Any - """ - Generates a shared access signature for the blob. - Use the returned signature with the credential parameter of any BlobServiceClient, - ContainerClient or BlobClient. - - :param permission: - The permissions associated with the shared access signature. The - user is restricted to operations allowed by the permissions. - Permissions must be ordered read, write, delete, list. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has been - specified in an associated stored access policy. - :type permission: str or ~azure.storage.blob.BlobSasPermissions - :param expiry: - The time at which the shared access signature becomes invalid. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has - been specified in an associated stored access policy. Azure will always - convert values to UTC. If a date is passed in without timezone info, it - is assumed to be UTC. - :type expiry: ~datetime.datetime or str - :param start: - The time at which the shared access signature becomes valid. If - omitted, start time for this call is assumed to be the time when the - storage service receives the request. Azure will always convert values - to UTC. If a date is passed in without timezone info, it is assumed to - be UTC. - :type start: ~datetime.datetime or str - :param str policy_id: - A unique value up to 64 characters in length that correlates to a - stored access policy. To create a stored access policy, use - :func:`~ContainerClient.set_container_access_policy()`. - :param str ip: - Specifies an IP address or a range of IP addresses from which to accept requests. - If the IP address from which the request originates does not match the IP address - or address range specified on the SAS token, the request is not authenticated. - For example, specifying ip=168.1.5.65 or ip=168.1.5.60-168.1.5.70 on the SAS - restricts the request to those IP addresses. - :param ~azure.storage.blob.UserDelegationKey user_delegation_key: - Instead of an account key, the user could pass in a user delegation key. - A user delegation key can be obtained from the service by authenticating with an AAD identity; - this can be accomplished by calling get_user_delegation_key. - When present, the SAS is signed with the user delegation key instead. - :keyword str protocol: - Specifies the protocol permitted for a request made. The default value is https. - :keyword str account_name: - Specifies the account_name when using oauth token as credential. If you use oauth token as credential. - :keyword str cache_control: - Response header value for Cache-Control when resource is accessed - using this shared access signature. - :keyword str content_disposition: - Response header value for Content-Disposition when resource is accessed - using this shared access signature. - :keyword str content_encoding: - Response header value for Content-Encoding when resource is accessed - using this shared access signature. - :keyword str content_language: - Response header value for Content-Language when resource is accessed - using this shared access signature. - :keyword str content_type: - Response header value for Content-Type when resource is accessed - using this shared access signature. - :return: A Shared Access Signature (sas) token. - :rtype: str - """ - protocol = kwargs.pop('protocol', None) - account_name = kwargs.pop('account_name', None) - cache_control = kwargs.pop('cache_control', None) - content_disposition = kwargs.pop('content_disposition', None) - content_encoding = kwargs.pop('content_encoding', None) - content_language = kwargs.pop('content_language', None) - content_type = kwargs.pop('content_type', None) - - if user_delegation_key is not None: - if not hasattr(self.credential, 'account_name') and not account_name: - raise ValueError("No account_name available. Please provide account_name parameter.") - - account_name = self.credential.account_name if hasattr(self.credential, 'account_name') else account_name - sas = BlobSharedAccessSignature(account_name, user_delegation_key=user_delegation_key) - else: - if not hasattr(self.credential, 'account_key') or not self.credential.account_key: - raise ValueError("No account SAS key available.") - sas = BlobSharedAccessSignature(self.credential.account_name, self.credential.account_key) - return sas.generate_blob( - self.container_name, - self.blob_name, - snapshot=self.snapshot, - permission=permission, - expiry=expiry, - start=start, - policy_id=policy_id, - ip=ip, - protocol=protocol, - cache_control=cache_control, - content_disposition=content_disposition, - content_encoding=content_encoding, - content_language=content_language, - content_type=content_type, ) @distributed_trace diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/blob_service_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/blob_service_client.py index de298072a45e..57b74da0abc8 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/blob_service_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/blob_service_client.py @@ -18,8 +18,7 @@ from azure.core.paging import ItemPaged from azure.core.tracing.decorator import distributed_trace -from ._shared.shared_access_signature import SharedAccessSignature -from ._shared.models import LocationMode, Services, UserDelegationKey +from ._shared.models import LocationMode from ._shared.base_client import StorageAccountHostsMixin, parse_connection_str, parse_query from ._shared.parser import _to_utc_datetime from ._shared.response_handlers import return_response_headers, process_storage_error, \ @@ -28,16 +27,17 @@ from ._generated.models import StorageErrorException, StorageServiceProperties, KeyInfo from .container_client import ContainerClient from .blob_client import BlobClient -from .models import ContainerProperties, ContainerPropertiesPaged +from .models import ContainerPropertiesPaged if TYPE_CHECKING: from datetime import datetime from azure.core.pipeline.transport import HttpTransport from azure.core.pipeline.policies import HTTPPolicy - from ._shared.models import AccountSasPermissions, ResourceTypes + from ._shared.models import UserDelegationKey from .lease import LeaseClient from .models import ( BlobProperties, + ContainerProperties, BlobAnalyticsLogging, Metrics, RetentionPolicy, @@ -157,79 +157,6 @@ def from_connection_string( kwargs['secondary_hostname'] = secondary return cls(account_url, credential=credential, **kwargs) - def generate_shared_access_signature( - self, resource_types, # type: Union[ResourceTypes, str] - permission, # type: Union[AccountSasPermissions, str] - expiry, # type: Optional[Union[datetime, str]] - start=None, # type: Optional[Union[datetime, str]] - ip=None, # type: Optional[str] - **kwargs # type: Any - ): # type: (...) -> str - """Generates a shared access signature for the blob service. - - Use the returned signature with the credential parameter of any BlobServiceClient, - ContainerClient or BlobClient. - - :param resource_types: - Specifies the resource types that are accessible with the account SAS. - :type resource_types: str or ~azure.storage.blob.ResourceTypes - :param permission: - The permissions associated with the shared access signature. The - user is restricted to operations allowed by the permissions. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has been - specified in an associated stored access policy. - :type permission: str or ~azure.storage.blob.AccountSasPermissions - :param expiry: - The time at which the shared access signature becomes invalid. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has - been specified in an associated stored access policy. Azure will always - convert values to UTC. If a date is passed in without timezone info, it - is assumed to be UTC. - :type expiry: ~datetime.datetime or str - :param start: - The time at which the shared access signature becomes valid. If - omitted, start time for this call is assumed to be the time when the - storage service receives the request. Azure will always convert values - to UTC. If a date is passed in without timezone info, it is assumed to - be UTC. - :type start: ~datetime.datetime or str - :param str ip: - Specifies an IP address or a range of IP addresses from which to accept requests. - If the IP address from which the request originates does not match the IP address - or address range specified on the SAS token, the request is not authenticated. - For example, specifying ip=168.1.5.65 or ip=168.1.5.60-168.1.5.70 on the SAS - restricts the request to those IP addresses. - :keyword str protocol: - Specifies the protocol permitted for a request made. The default value is https. - :return: A Shared Access Signature (sas) token. - :rtype: str - - .. admonition:: Example: - - .. literalinclude:: ../tests/test_blob_samples_authentication.py - :start-after: [START create_sas_token] - :end-before: [END create_sas_token] - :language: python - :dedent: 8 - :caption: Generating a shared access signature. - """ - protocol = kwargs.pop('protocol', None) - if not hasattr(self.credential, 'account_key') and not self.credential.account_key: - raise ValueError("No account SAS key available.") - - sas = SharedAccessSignature(self.credential.account_name, self.credential.account_key) - return sas.generate_account( - services=Services(blob=True), - resource_types=resource_types, - permission=permission, - expiry=expiry, - start=start, - ip=ip, - protocol=protocol - ) # type: ignore - @distributed_trace def get_user_delegation_key(self, key_start_time, # type: datetime key_expiry_time, # type: datetime diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py index 15e9012f9b7c..6df9e9b03b11 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py @@ -43,14 +43,13 @@ BlobPrefix) from .lease import LeaseClient, get_access_conditions from .blob_client import BlobClient -from ._shared_access_signature import BlobSharedAccessSignature if TYPE_CHECKING: from azure.core.pipeline.transport import HttpTransport, HttpResponse # pylint: disable=ungrouped-imports from azure.core.pipeline.policies import HTTPPolicy # pylint: disable=ungrouped-imports - from .models import ContainerSasPermissions, PublicAccess from datetime import datetime from .models import ( # pylint: disable=unused-import + PublicAccess, AccessPolicy, ContentSettings, PremiumPageBlobTier) @@ -212,120 +211,6 @@ def from_connection_string( return cls( account_url, container_name=container_name, credential=credential, **kwargs) - def generate_shared_access_signature( - self, permission=None, # type: Optional[Union[ContainerSasPermissions, str]] - expiry=None, # type: Optional[Union[datetime, str]] - start=None, # type: Optional[Union[datetime, str]] - policy_id=None, # type: Optional[str] - ip=None, # type: Optional[str] - user_delegation_key=None, # type: Optional[Any] - **kwargs # type: Any - ): - # type: (...) -> Any - """Generates a shared access signature for the container. - Use the returned signature with the credential parameter of any BlobServiceClient, - ContainerClient or BlobClient. - - :param permission: - The permissions associated with the shared access signature. The - user is restricted to operations allowed by the permissions. - Permissions must be ordered read, write, delete, list. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has been - specified in an associated stored access policy. - :type permission: str or ~azure.storage.blob.ContainerSasPermissions - :param expiry: - The time at which the shared access signature becomes invalid. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has - been specified in an associated stored access policy. Azure will always - convert values to UTC. If a date is passed in without timezone info, it - is assumed to be UTC. - :type expiry: datetime or str - :param start: - The time at which the shared access signature becomes valid. If - omitted, start time for this call is assumed to be the time when the - storage service receives the request. Azure will always convert values - to UTC. If a date is passed in without timezone info, it is assumed to - be UTC. - :type start: datetime or str - :param str policy_id: - A unique value up to 64 characters in length that correlates to a - stored access policy. To create a stored access policy, use :func:`~set_container_access_policy`. - :param str ip: - Specifies an IP address or a range of IP addresses from which to accept requests. - If the IP address from which the request originates does not match the IP address - or address range specified on the SAS token, the request is not authenticated. - For example, specifying ip=168.1.5.65 or ip=168.1.5.60-168.1.5.70 on the SAS - restricts the request to those IP addresses. - :param ~azure.storage.blob.UserDelegationKey user_delegation_key: - Instead of an account key, the user could pass in a user delegation key. - A user delegation key can be obtained from the service by authenticating with an AAD identity; - this can be accomplished by calling get_user_delegation_key. - When present, the SAS is signed with the user delegation key instead. - :keyword str protocol: - Specifies the protocol permitted for a request made. The default value is https. - :keyword str account_name: - Specifies the account_name when using oauth token as credential. If you use oauth token as credential. - :keyword str cache_control: - Response header value for Cache-Control when resource is accessed - using this shared access signature. - :keyword str content_disposition: - Response header value for Content-Disposition when resource is accessed - using this shared access signature. - :keyword str content_encoding: - Response header value for Content-Encoding when resource is accessed - using this shared access signature. - :keyword str content_language: - Response header value for Content-Language when resource is accessed - using this shared access signature. - :keyword str content_type: - Response header value for Content-Type when resource is accessed - using this shared access signature. - :return: A Shared Access Signature (sas) token. - :rtype: str - - .. admonition:: Example: - - .. literalinclude:: ../tests/test_blob_samples_containers.py - :start-after: [START generate_sas_token] - :end-before: [END generate_sas_token] - :language: python - :dedent: 12 - :caption: Generating a sas token. - """ - protocol = kwargs.pop('protocol', None) - account_name = kwargs.pop('account_name', None) - cache_control = kwargs.pop('cache_control', None) - content_disposition = kwargs.pop('content_disposition', None) - content_encoding = kwargs.pop('content_encoding', None) - content_language = kwargs.pop('content_language', None) - content_type = kwargs.pop('content_type', None) - if user_delegation_key is not None: - if not hasattr(self.credential, 'account_name') and not account_name: - raise ValueError("No account_name available. Please provide account_name parameter.") - - account_name = self.credential.account_name if hasattr(self.credential, 'account_name') else account_name - sas = BlobSharedAccessSignature(account_name, user_delegation_key=user_delegation_key) - else: - if not hasattr(self.credential, 'account_key') and not self.credential.account_key: - raise ValueError("No account SAS key available.") - sas = BlobSharedAccessSignature(self.credential.account_name, self.credential.account_key) - return sas.generate_container( - self.container_name, - permission=permission, - expiry=expiry, - start=start, - policy_id=policy_id, - ip=ip, - protocol=protocol, - cache_control=cache_control, - content_disposition=content_disposition, - content_encoding=content_encoding, - content_language=content_language, - content_type=content_type, - ) - @distributed_trace def create_container(self, metadata=None, public_access=None, **kwargs): # type: (Optional[Dict[str, str]], Optional[Union[PublicAccess, str]], **Any) -> None diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/models.py b/sdk/storage/azure-storage-blob/azure/storage/blob/models.py index 79d477db923b..3d8189802865 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/models.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/models.py @@ -848,8 +848,8 @@ def __init__(self, permission=None, expiry=None, start=None): class ContainerSasPermissions(object): - """ContainerSasPermissions class to be used with - :func:`~azure.storage.blob.ContainerClient.generate_shared_access_signature` API and + """ContainerSasPermissions class to be used with the + :func:`~azure.storage.blob.generate_container_sas` function and for the AccessPolicies used with :func:`~azure.storage.blob.ContainerClient.set_container_access_policy`. @@ -894,8 +894,8 @@ def from_string(cls, permission): class BlobSasPermissions(object): - """BlobSasPermissions class to be used with - :func:`~azure.storage.blob.blob_client.BlobClient.generate_shared_access_signature` API. + """BlobSasPermissions class to be used with the + :func:`~azure.storage.blob.generate_blob_sas` function. :param bool read: Read the content, properties, metadata and block list. Use the blob as diff --git a/sdk/storage/azure-storage-blob/tests/test_append_blob.py b/sdk/storage/azure-storage-blob/tests/test_append_blob.py index c965f80f7e63..7fc9e7e6dbb2 100644 --- a/sdk/storage/azure-storage-blob/tests/test_append_blob.py +++ b/sdk/storage/azure-storage-blob/tests/test_append_blob.py @@ -13,6 +13,7 @@ from azure.core.exceptions import ResourceNotFoundError, ResourceModifiedError, HttpResponseError from azure.storage.blob import ( + generate_blob_sas, BlobServiceClient, ContainerClient, BlobClient, @@ -197,7 +198,12 @@ def test_append_block_from_url(self): # Arrange source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -239,7 +245,12 @@ def test_append_block_from_url_and_validate_content_md5(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) src_md5 = StorageContentValidation.get_content_md5(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -272,7 +283,12 @@ def test_append_block_from_url_with_source_if_modified(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) source_blob_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -310,7 +326,12 @@ def test_append_block_from_url_with_source_if_unmodified(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) source_blob_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -348,7 +369,12 @@ def test_append_block_from_url_with_source_if_match(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) source_blob_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -384,7 +410,12 @@ def test_append_block_from_url_with_source_if_none_match(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) source_blob_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -419,7 +450,12 @@ def test_append_block_from_url_with_if_match(self): # Arrange source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -458,7 +494,12 @@ def test_append_block_from_url_with_if_none_match(self): # Arrange source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -493,7 +534,12 @@ def test_append_block_from_url_with_maxsize_condition(self): # Arrange source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -528,7 +574,12 @@ def test_append_block_from_url_with_appendpos_condition(self): # Arrange source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -564,7 +615,12 @@ def test_append_block_from_url_with_if_modified(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) source_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -601,7 +657,12 @@ def test_append_block_from_url_with_if_unmodified(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data) source_properties = source_blob_client.append_block(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_append_blob_async.py b/sdk/storage/azure-storage-blob/tests/test_append_blob_async.py index 62c634cacf4e..60d621f8f850 100644 --- a/sdk/storage/azure-storage-blob/tests/test_append_blob_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_append_blob_async.py @@ -18,7 +18,7 @@ from azure.core.pipeline.transport import AioHttpTransport from multidict import CIMultiDict, CIMultiDictProxy -from azure.storage.blob import BlobSasPermissions +from azure.storage.blob import BlobSasPermissions, generate_blob_sas from azure.storage.blob._shared.policies import StorageContentValidation from azure.storage.blob import BlobType from azure.storage.blob.aio import ( @@ -254,7 +254,12 @@ async def _test_append_block_from_url(self): await self._setup() source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -301,7 +306,12 @@ async def _test_append_block_from_url_and_validate_content_md5(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) src_md5 = StorageContentValidation.get_content_md5(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -339,7 +349,12 @@ async def _test_append_block_from_url_with_source_if_modified(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) source_blob_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -382,7 +397,12 @@ async def _test_append_block_from_url_with_source_if_unmodified(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) source_blob_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -426,7 +446,12 @@ async def _test_append_block_from_url_with_source_if_match(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -467,7 +492,12 @@ async def _test_append_block_from_url_with_source_if_none_match(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -507,7 +537,12 @@ async def _test_append_block_from_url_with_if_match(self): await self._setup() source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -551,7 +586,12 @@ async def _test_append_block_from_url_with_if_none_match(self): await self._setup() source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -592,7 +632,12 @@ async def _test_append_block_from_url_with_maxsize_condition(self): await self._setup() source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -633,7 +678,12 @@ async def _test_append_block_from_url_with_appendpos_condition(self): await self._setup() source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -675,7 +725,12 @@ async def _test_append_block_from_url_with_if_modified(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -718,7 +773,12 @@ async def _test_append_block_from_url_with_if_unmodified(self): source_blob_data = self.get_random_bytes(LARGE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_blob_client.py b/sdk/storage/azure-storage-blob/tests/test_blob_client.py index a3805ac02c9d..779de264d5b8 100644 --- a/sdk/storage/azure-storage-blob/tests/test_blob_client.py +++ b/sdk/storage/azure-storage-blob/tests/test_blob_client.py @@ -44,6 +44,7 @@ def setUp(self): # --Helpers----------------------------------------------------------------- def validate_standard_account_endpoints(self, service, url_type): self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue('{}.{}.core.windows.net'.format(self.account_name, url_type) in service.url) @@ -71,6 +72,7 @@ def test_create_blob_client_with_complete_blob_url(self): self.assertEqual(service.scheme, 'https') self.assertEqual(service.container_name, 'foo') self.assertEqual(service.blob_name, 'bar') + self.assertEqual(service.account_name, self.account_name) def test_create_service_with_connection_string(self): @@ -93,6 +95,7 @@ def test_create_service_with_sas(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertTrue(service.url.startswith('https://' + self.account_name + '.blob.core.windows.net')) self.assertTrue(service.url.endswith(self.sas_token)) self.assertIsNone(service.credential) @@ -109,6 +112,7 @@ def test_create_service_with_token(self): self.assertEqual(service.credential, self.token_credential) self.assertFalse(hasattr(service.credential, 'account_key')) self.assertTrue(hasattr(service.credential, 'get_token')) + self.assertEqual(service.account_name, self.account_name) def test_create_service_with_token_and_http(self): for service_type in SERVICES: @@ -128,6 +132,7 @@ def test_create_service_china(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith( @@ -158,6 +163,7 @@ def test_create_blob_service_anonymous(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertTrue(service.url.startswith('https://' + self.account_name + '.blob.core.windows.net')) self.assertIsNone(service.credential) @@ -175,6 +181,7 @@ def test_create_blob_service_custom_domain(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -226,6 +233,7 @@ def test_create_service_with_connection_string_sas(self): self.assertTrue(service.url.startswith('https://' + self.account_name + '.blob.core.windows.net')) self.assertTrue(service.url.endswith(self.sas_token)) self.assertIsNone(service.credential) + self.assertEqual(service.account_name, self.account_name) def test_create_service_with_connection_string_endpoint_protocol(self): # Arrange @@ -238,6 +246,7 @@ def test_create_service_with_connection_string_endpoint_protocol(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue( @@ -267,6 +276,7 @@ def test_create_service_with_connection_string_anonymous(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, "www.mydomain.com") self.assertIsNone(service.credential) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) with self.assertRaises(ValueError): @@ -283,6 +293,7 @@ def test_create_service_with_connection_string_custom_domain(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -299,6 +310,7 @@ def test_create_service_with_connection_string_custom_domain_trailing_slash(self # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -317,6 +329,7 @@ def test_create_service_with_connection_string_custom_domain_secondary_override( # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -350,6 +363,7 @@ def test_create_service_with_connection_string_succeeds_if_secondary_with_primar # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) diff --git a/sdk/storage/azure-storage-blob/tests/test_blob_client_async.py b/sdk/storage/azure-storage-blob/tests/test_blob_client_async.py index 95cda6b9f56c..6a05020a6397 100644 --- a/sdk/storage/azure-storage-blob/tests/test_blob_client_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_blob_client_async.py @@ -60,6 +60,7 @@ def setUp(self): # --Helpers----------------------------------------------------------------- def validate_standard_account_endpoints(self, service, url_type): self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue('{}.{}.core.windows.net'.format(self.account_name, url_type) in service.url) @@ -99,6 +100,7 @@ def test_create_service_with_sas_async(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertTrue(service.url.startswith('https://' + self.account_name + '.blob.core.windows.net')) self.assertTrue(service.url.endswith(self.sas_token)) self.assertIsNone(service.credential) @@ -115,6 +117,7 @@ def test_create_service_with_token_async(self): self.assertEqual(service.credential, self.token_credential) self.assertFalse(hasattr(service.credential, 'account_key')) self.assertTrue(hasattr(service.credential, 'get_token')) + self.assertEqual(service.account_name, self.account_name) def test_create_service_with_token_and_http_async(self): for service_type in SERVICES: @@ -134,6 +137,7 @@ def test_create_service_china_async(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith( @@ -166,6 +170,7 @@ def test_create_blob_service_anonymous_async(self): self.assertIsNotNone(service) self.assertTrue(service.url.startswith('https://' + self.account_name + '.blob.core.windows.net')) self.assertIsNone(service.credential) + self.assertEqual(service.account_name, self.account_name) def test_create_blob_service_custom_domain_async(self): # Arrange @@ -181,6 +186,7 @@ def test_create_blob_service_custom_domain_async(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -232,6 +238,7 @@ def test_create_service_with_connection_string_sas_async(self): self.assertTrue(service.url.startswith('https://' + self.account_name + '.blob.core.windows.net')) self.assertTrue(service.url.endswith(self.sas_token)) self.assertIsNone(service.credential) + self.assertEqual(service.account_name, self.account_name) def test_create_blob_client_with_complete_blob_url_async(self): # Arrange @@ -242,6 +249,7 @@ def test_create_blob_client_with_complete_blob_url_async(self): self.assertEqual(service.scheme, 'https') self.assertEqual(service.container_name, 'foo') self.assertEqual(service.blob_name, 'bar') + self.assertEqual(service.account_name, self.account_name) def test_create_service_with_connection_string_endpoint_protocol_async(self): # Arrange @@ -254,6 +262,7 @@ def test_create_service_with_connection_string_endpoint_protocol_async(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue( @@ -283,6 +292,7 @@ def test_create_service_with_connection_string_anonymous_async(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, "www.mydomain.com") self.assertIsNone(service.credential) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) with self.assertRaises(ValueError): @@ -299,6 +309,7 @@ def test_create_service_with_connection_string_custom_domain_async(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -315,6 +326,7 @@ def test_create_service_with_connection_string_custom_domain_trailing_slash_asyn # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -332,6 +344,7 @@ def test_create_service_with_connection_string_custom_domain_secondary_override_ # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -364,6 +377,7 @@ def test_create_service_with_connection_string_succeeds_if_secondary_with_primar # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) diff --git a/sdk/storage/azure-storage-blob/tests/test_blob_samples_authentication.py b/sdk/storage/azure-storage-blob/tests/test_blob_samples_authentication.py index 780c7660823b..20686ed04d9a 100644 --- a/sdk/storage/azure-storage-blob/tests/test_blob_samples_authentication.py +++ b/sdk/storage/azure-storage-blob/tests/test_blob_samples_authentication.py @@ -115,9 +115,11 @@ def test_auth_shared_access_signature(self): # [START create_sas_token] # Create a SAS token to use to authenticate a new client from datetime import datetime, timedelta - from azure.storage.blob import ResourceTypes, AccountSasPermissions + from azure.storage.blob import ResourceTypes, AccountSasPermissions, generate_account_sas - sas_token = blob_service_client.generate_shared_access_signature( + sas_token = generate_account_sas( + blob_service_client.account_name, + account_key=blob_service_client.credential.account_key, resource_types=ResourceTypes(object=True), permission=AccountSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1) diff --git a/sdk/storage/azure-storage-blob/tests/test_blob_samples_authentication_async.py b/sdk/storage/azure-storage-blob/tests/test_blob_samples_authentication_async.py index 817a75882e76..2a11e5578d28 100644 --- a/sdk/storage/azure-storage-blob/tests/test_blob_samples_authentication_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_blob_samples_authentication_async.py @@ -140,9 +140,11 @@ async def _test_auth_shared_access_signature_async(self): # [START create_sas_token] # Create a SAS token to use to authenticate a new client from datetime import datetime, timedelta - from azure.storage.blob import ResourceTypes, AccountSasPermissions + from azure.storage.blob import ResourceTypes, AccountSasPermissions, generate_account_sas - sas_token = blob_service_client.generate_shared_access_signature( + sas_token = generate_account_sas( + blob_service_client.account_name, + account_key=blob_service_client.credential.account_key, resource_types=ResourceTypes(object=True), permission=AccountSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1) diff --git a/sdk/storage/azure-storage-blob/tests/test_blob_samples_containers.py b/sdk/storage/azure-storage-blob/tests/test_blob_samples_containers.py index bd7d3cd6cc22..4f2d960e7b87 100644 --- a/sdk/storage/azure-storage-blob/tests/test_blob_samples_containers.py +++ b/sdk/storage/azure-storage-blob/tests/test_blob_samples_containers.py @@ -166,7 +166,12 @@ def test_container_access_policy(self): # [START generate_sas_token] # Use access policy to generate a sas token - sas_token = container_client.generate_shared_access_signature( + from azure.storage.blob import generate_container_sas + + sas_token = generate_container_sas( + container_client.account_name, + container_client.container_name, + account_key=container_client.credential.account_key, policy_id='my-access-policy-id' ) # [END generate_sas_token] diff --git a/sdk/storage/azure-storage-blob/tests/test_blob_samples_containers_async.py b/sdk/storage/azure-storage-blob/tests/test_blob_samples_containers_async.py index b4feac762ef1..0eccb1041aec 100644 --- a/sdk/storage/azure-storage-blob/tests/test_blob_samples_containers_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_blob_samples_containers_async.py @@ -183,7 +183,12 @@ async def _test_container_access_policy_async(self): # [START generate_sas_token] # Use access policy to generate a sas token - sas_token = container_client.generate_shared_access_signature( + from azure.storage.blob import generate_container_sas + + sas_token = generate_container_sas( + container_client.account_name, + container_client.container_name, + account_key=container_client.credential.account_key, policy_id='my-access-policy-id' ) # [END generate_sas_token] diff --git a/sdk/storage/azure-storage-blob/tests/test_block_blob_sync_copy.py b/sdk/storage/azure-storage-blob/tests/test_block_blob_sync_copy.py index bf443354c5a7..6e600a37f355 100644 --- a/sdk/storage/azure-storage-blob/tests/test_block_blob_sync_copy.py +++ b/sdk/storage/azure-storage-blob/tests/test_block_blob_sync_copy.py @@ -12,7 +12,8 @@ ContainerClient, BlobClient, StorageErrorCode, - BlobSasPermissions + BlobSasPermissions, + generate_blob_sas ) from azure.storage.blob._shared.policies import StorageContentValidation from testcase import ( @@ -54,7 +55,12 @@ def setUp(self): blob.upload_blob(self.source_blob_data) # generate a SAS so that it is accessible with a URL - sas_token = blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_block_blob_sync_copy_async.py b/sdk/storage/azure-storage-blob/tests/test_block_blob_sync_copy_async.py index 4e8ca3b77b55..ce5007719c8a 100644 --- a/sdk/storage/azure-storage-blob/tests/test_block_blob_sync_copy_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_block_blob_sync_copy_async.py @@ -11,7 +11,7 @@ from azure.core.pipeline.transport import AioHttpTransport from multidict import CIMultiDict, CIMultiDictProxy -from azure.storage.blob import StorageErrorCode, BlobSasPermissions +from azure.storage.blob import StorageErrorCode, BlobSasPermissions, generate_blob_sas from azure.storage.blob.aio import ( BlobServiceClient, @@ -68,7 +68,12 @@ def setUp(self): blob = self.bsc.get_blob_client(self.container_name, self.source_blob_name) # generate a SAS so that it is accessible with a URL - sas_token = blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -94,7 +99,12 @@ async def _setup(self): await blob.upload_blob(self.source_blob_data, overwrite=True) # generate a SAS so that it is accessible with a URL - sas_token = blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_common_blob.py b/sdk/storage/azure-storage-blob/tests/test_common_blob.py index 92f66abad986..302f2fb55e01 100644 --- a/sdk/storage/azure-storage-blob/tests/test_common_blob.py +++ b/sdk/storage/azure-storage-blob/tests/test_common_blob.py @@ -20,6 +20,9 @@ from azure.storage.blob import ( upload_blob_to_url, download_blob_from_url, + generate_account_sas, + generate_blob_sas, + generate_container_sas, BlobServiceClient, ContainerClient, BlobClient, @@ -944,7 +947,12 @@ def test_copy_blob_async_private_blob_with_sas(self): data = b'12345678' * 1024 * 1024 self._create_remote_container() source_blob = self._create_remote_block_blob(blob_data=data) - sas_token = source_blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + source_blob.account_name, + source_blob.container_name, + source_blob.blob_name, + snapshot=source_blob.snapshot, + account_key=source_blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1207,7 +1215,12 @@ def test_sas_access_blob(self): blob_name = self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1231,7 +1244,12 @@ def test_sas_access_blob_snapshot(self): blob_snapshot = blob_client.create_snapshot() blob_snapshot_client = self.bsc.get_blob_client(self.container_name, blob_name, snapshot=blob_snapshot) - token = blob_snapshot_client.generate_shared_access_signature( + token = generate_blob_sas( + blob_snapshot_client.account_name, + blob_snapshot_client.container_name, + blob_snapshot_client.blob_name, + snapshot=blob_snapshot_client.snapshot, + account_key=blob_snapshot_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1270,7 +1288,13 @@ def test_sas_signed_identifier(self): resp = container.set_container_access_policy(identifiers) - token = blob.generate_shared_access_signature(policy_id='testid') + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, + policy_id='testid') # Act service = BlobClient.from_blob_url(blob.url, credential=token) @@ -1289,7 +1313,9 @@ def test_account_sas(self): # Arrange blob_name = self._create_block_blob() - token = self.bsc.generate_shared_access_signature( + token = generate_account_sas( + self.bsc.account_name, + self.bsc.credential.account_key, ResourceTypes(container=True, object=True), AccountSasPermissions(read=True), datetime.utcnow() + timedelta(hours=1), @@ -1356,7 +1382,12 @@ def test_user_delegation_sas_for_blob(self): blob_client = container_client.get_blob_client(self.get_resource_name('oauthblob')) blob_client.upload_blob(self.byte_data, length=len(self.byte_data)) - token = blob_client.generate_shared_access_signature( + token = generate_blob_sas( + blob_client.account_name, + blob_client.container_name, + blob_client.blob_name, + snapshot=blob_client.snapshot, + account_key=blob_client.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), user_delegation_key=user_delegation_key, @@ -1402,7 +1433,12 @@ def test_shared_read_access_blob(self): blob_name = self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1426,7 +1462,12 @@ def test_shared_read_access_blob_with_content_query_params(self): blob_name = self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), cache_control='no-cache', @@ -1460,7 +1501,12 @@ def test_shared_write_access_blob(self): blob_name = self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(write=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1486,7 +1532,12 @@ def test_shared_delete_access_blob(self): blob_name = self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1540,7 +1591,10 @@ def test_get_account_information_with_container_sas(self): # Arrange container = self.bsc.get_container_client(self.container_name) - token = container.generate_shared_access_signature( + token = generate_container_sas( + container.account_name, + container.container_name, + account_key=container.credential.account_key, permission=ContainerSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1563,7 +1617,12 @@ def test_get_account_information_with_blob_sas(self): blob_name = self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1584,7 +1643,12 @@ def test_download_to_file_with_sas(self): data = b'12345678' * 1024 * 1024 self._create_remote_container() source_blob = self._create_remote_block_blob(blob_data=data) - sas_token = source_blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + source_blob.account_name, + source_blob.container_name, + source_blob.blob_name, + snapshot=source_blob.snapshot, + account_key=source_blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1698,7 +1762,12 @@ def test_upload_to_url_bytes_with_sas(self): blob_name = self._get_blob_reference() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(write=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_common_blob_async.py b/sdk/storage/azure-storage-blob/tests/test_common_blob_async.py index dd732030b4de..936fa74af6ae 100644 --- a/sdk/storage/azure-storage-blob/tests/test_common_blob_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_common_blob_async.py @@ -32,6 +32,9 @@ from azure.storage.blob import ( upload_blob_to_url, download_blob_from_url, + generate_blob_sas, + generate_account_sas, + generate_container_sas, BlobType, StorageErrorCode, BlobSasPermissions, @@ -1250,7 +1253,12 @@ async def _test_copy_blob_async_private_blob_with_sas(self): data = b'12345678' * 1024 * 1024 await self._create_remote_container() source_blob = await self._create_remote_block_blob(blob_data=data) - sas_token = source_blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + source_blob.account_name, + source_blob.container_name, + source_blob.blob_name, + snapshot=source_blob.snapshot, + account_key=source_blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1601,7 +1609,12 @@ async def _test_sas_access_blob(self): blob_name = await self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1638,7 +1651,13 @@ async def _test_sas_signed_identifier(self): resp = await container.set_container_access_policy(identifiers) - token = blob.generate_shared_access_signature(policy_id='testid') + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, + policy_id='testid') # Act service = BlobClient.from_blob_url(blob.url, credential=token) @@ -1662,7 +1681,9 @@ async def _test_account_sas(self): await self._setup() blob_name = await self._create_block_blob() - token = self.bsc.generate_shared_access_signature( + token = generate_account_sas( + self.bsc.account_name, + self.bsc.credential.account_key, ResourceTypes(container=True, object=True), AccountSasPermissions(read=True), datetime.utcnow() + timedelta(hours=1), @@ -1765,7 +1786,12 @@ async def _test_shared_read_access_blob(self): blob_name = await self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1794,7 +1820,12 @@ async def _test_shared_read_access_blob_with_content_query_params(self): blob_name = await self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), cache_control='no-cache', @@ -1833,7 +1864,12 @@ async def _test_shared_write_access_blob(self): blob_name = await self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(write=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1864,7 +1900,12 @@ async def _test_shared_delete_access_blob(self): blob_name = await self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1938,7 +1979,10 @@ async def _test_get_account_information_with_container_sas(self): # Arrange await self._setup() container = self.bsc.get_container_client(self.container_name) - token = container.generate_shared_access_signature( + token = generate_container_sas( + container.account_name, + container.container_name, + account_key=container.credential.account_key, permission=ContainerSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1966,7 +2010,12 @@ async def _test_get_account_information_with_blob_sas(self): blob_name = await self._create_block_blob() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1992,7 +2041,12 @@ async def _test_download_to_file_with_sas(self): data = b'12345678' * 1024 * 1024 await self._create_remote_container() source_blob = await self._create_remote_block_blob(blob_data=data) - sas_token = source_blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + source_blob.account_name, + source_blob.container_name, + source_blob.blob_name, + snapshot=source_blob.snapshot, + account_key=source_blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -2130,7 +2184,12 @@ async def _test_upload_to_url_bytes_with_sas(self): blob_name = self._get_blob_reference() blob = self.bsc.get_blob_client(self.container_name, blob_name) - token = blob.generate_shared_access_signature( + token = generate_blob_sas( + blob.account_name, + blob.container_name, + blob.blob_name, + snapshot=blob.snapshot, + account_key=blob.credential.account_key, permission=BlobSasPermissions(write=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_container.py b/sdk/storage/azure-storage-blob/tests/test_container.py index 3bd206d347a6..79f4feebd49f 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container.py +++ b/sdk/storage/azure-storage-blob/tests/test_container.py @@ -25,7 +25,8 @@ ContainerSasPermissions, AccessPolicy, StandardBlobTier, - PremiumPageBlobTier + PremiumPageBlobTier, + generate_container_sas, ) from azure.identity import ClientSecretCredential @@ -1210,7 +1211,10 @@ def test_shared_access_container(self): blob = container.get_blob_client(blob_name) blob.upload_blob(data) - token = container.generate_shared_access_signature( + token = generate_container_sas( + container.account_name, + container.container_name, + account_key=container.credential.account_key, expiry=datetime.utcnow() + timedelta(hours=1), permission=ContainerSasPermissions(read=True), ) @@ -1268,7 +1272,10 @@ def test_user_delegation_sas_for_container(self): datetime.utcnow() + timedelta(hours=1)) container_client = service_client.create_container(self.get_resource_name('oauthcontainer')) - token = container_client.generate_shared_access_signature( + token = generate_container_sas( + container_client.account_name, + container_client.container_name, + account_key=container_client.credential.account_key, expiry=datetime.utcnow() + timedelta(hours=1), permission=ContainerSasPermissions(read=True), user_delegation_key=user_delegation_key, diff --git a/sdk/storage/azure-storage-blob/tests/test_container_async.py b/sdk/storage/azure-storage-blob/tests/test_container_async.py index 29487d7141e7..70ca725b5495 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_container_async.py @@ -27,7 +27,8 @@ BlobProperties, ContainerSasPermissions, StandardBlobTier, - PremiumPageBlobTier + PremiumPageBlobTier, + generate_container_sas ) from azure.storage.blob.aio import ( @@ -1477,7 +1478,10 @@ async def _test_shared_access_container(self): blob = container.get_blob_client(blob_name) await blob.upload_blob(data) - token = container.generate_shared_access_signature( + token = generate_container_sas( + container.account_name, + container.container_name, + account_key=container.credential.account_key, expiry=datetime.utcnow() + timedelta(hours=1), permission=ContainerSasPermissions(read=True), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_cpk.py b/sdk/storage/azure-storage-blob/tests/test_cpk.py index 4ddbb845d7f6..c46bfad64397 100644 --- a/sdk/storage/azure-storage-blob/tests/test_cpk.py +++ b/sdk/storage/azure-storage-blob/tests/test_cpk.py @@ -13,6 +13,7 @@ BlobServiceClient, BlobType, BlobBlock, + generate_blob_sas ) from azure.storage.blob.models import CustomerProvidedEncryptionKey, BlobSasPermissions from testcase import ( @@ -218,7 +219,12 @@ def test_put_block_from_url_and_commit_with_cpk(self): source_blob_name = self.get_resource_name("sourceblob") self.config.use_byte_buffer = True # Make sure using chunk upload, then we can record the request source_blob_client, _ = self._create_block_blob(blob_name=source_blob_name, data=self.byte_data) - source_blob_sas = source_blob_client.generate_shared_access_signature( + source_blob_sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1) ) @@ -297,7 +303,12 @@ def test_append_block_from_url(self): source_blob_name = self.get_resource_name("sourceblob") self.config.use_byte_buffer = True # chunk upload source_blob_client, _ = self._create_block_blob(blob_name=source_blob_name, data=self.byte_data) - source_blob_sas = source_blob_client.generate_shared_access_signature( + source_blob_sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1) ) @@ -392,7 +403,12 @@ def test_update_page_from_url(self): source_blob_name = self.get_resource_name("sourceblob") self.config.use_byte_buffer = True # Make sure using chunk upload, then we can record the request source_blob_client, _ = self._create_block_blob(blob_name=source_blob_name, data=self.byte_data) - source_blob_sas = source_blob_client.generate_shared_access_signature( + source_blob_sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1) ) diff --git a/sdk/storage/azure-storage-blob/tests/test_cpk_async.py b/sdk/storage/azure-storage-blob/tests/test_cpk_async.py index d91f12f2348a..a2249c708729 100644 --- a/sdk/storage/azure-storage-blob/tests/test_cpk_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_cpk_async.py @@ -12,7 +12,7 @@ from azure.core.exceptions import HttpResponseError from azure.core.pipeline.transport import AioHttpTransport from multidict import CIMultiDict, CIMultiDictProxy -from azure.storage.blob import BlobType, BlobBlock +from azure.storage.blob import BlobType, BlobBlock, generate_blob_sas from azure.storage.blob.aio import BlobServiceClient from azure.storage.blob.models import CustomerProvidedEncryptionKey, BlobSasPermissions from testcase import ( @@ -250,7 +250,12 @@ async def _test_put_block_from_url_and_commit(self): source_blob_name = self.get_resource_name("sourceblob") self.config.use_byte_buffer = True # Make sure using chunk upload, then we can record the request source_blob_client, _ = await self._create_block_blob(blob_name=source_blob_name, data=self.byte_data) - source_blob_sas = source_blob_client.generate_shared_access_signature( + source_blob_sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1) ) @@ -339,7 +344,12 @@ async def _test_append_block_from_url(self): source_blob_name = self.get_resource_name("sourceblob") self.config.use_byte_buffer = True # chunk upload source_blob_client, _ = await self._create_block_blob(blob_name=source_blob_name, data=self.byte_data) - source_blob_sas = source_blob_client.generate_shared_access_signature( + source_blob_sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1) ) @@ -446,7 +456,12 @@ async def _test_update_page_from_url(self): source_blob_name = self.get_resource_name("sourceblob") self.config.use_byte_buffer = True # Make sure using chunk upload, then we can record the request source_blob_client, _ = await self._create_block_blob(blob_name=source_blob_name, data=self.byte_data) - source_blob_sas = source_blob_client.generate_shared_access_signature( + source_blob_sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1) ) diff --git a/sdk/storage/azure-storage-blob/tests/test_logging.py b/sdk/storage/azure-storage-blob/tests/test_logging.py index dcd41ef319fb..8607e2478c5f 100644 --- a/sdk/storage/azure-storage-blob/tests/test_logging.py +++ b/sdk/storage/azure-storage-blob/tests/test_logging.py @@ -15,7 +15,9 @@ ContainerClient, BlobClient, ContainerSasPermissions, - BlobSasPermissions + BlobSasPermissions, + generate_blob_sas, + generate_container_sas ) from azure.storage.blob._shared.shared_access_signature import QueryStringConstants @@ -55,7 +57,12 @@ def setUp(self): source_blob.upload_blob(self.source_blob_data) # generate a SAS so that it is accessible with a URL - sas_token = source_blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + source_blob.account_name, + source_blob.container_name, + source_blob.blob_name, + snapshot=source_blob.snapshot, + account_key=source_blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -90,7 +97,10 @@ def test_sas_signature_is_scrubbed_off(self): # Arrange container = self.bsc.get_container_client(self.container_name) - token = container.generate_shared_access_signature( + token = generate_container_sas( + container.account_name, + container.container_name, + account_key=container.credential.account_key, permission=ContainerSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_logging_async.py b/sdk/storage/azure-storage-blob/tests/test_logging_async.py index 3436b7480a55..b8614f864fb5 100644 --- a/sdk/storage/azure-storage-blob/tests/test_logging_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_logging_async.py @@ -23,6 +23,8 @@ from azure.storage.blob import ( ContainerSasPermissions, BlobSasPermissions, + generate_container_sas, + generate_blob_sas ) from azure.storage.blob._shared.shared_access_signature import QueryStringConstants @@ -87,7 +89,12 @@ async def _setup(self): await source_blob.upload_blob(self.source_blob_data) # generate a SAS so that it is accessible with a URL - sas_token = source_blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + source_blob.account_name, + source_blob.container_name, + source_blob.blob_name, + snapshot=source_blob.snapshot, + account_key=source_blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -123,7 +130,10 @@ async def _test_sas_signature_is_scrubbed_off(self): await self._setup() # Arrange container = self.bsc.get_container_client(self.container_name) - token = container.generate_shared_access_signature( + token = generate_container_sas( + container.account_name, + container.container_name, + account_key=container.credential.account_key, permission=ContainerSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_page_blob.py b/sdk/storage/azure-storage-blob/tests/test_page_blob.py index 6cb20eb2671a..a674618102a0 100644 --- a/sdk/storage/azure-storage-blob/tests/test_page_blob.py +++ b/sdk/storage/azure-storage-blob/tests/test_page_blob.py @@ -22,7 +22,8 @@ BlobType, PremiumPageBlobTier, SequenceNumberAction, - StorageErrorCode) + StorageErrorCode, + generate_blob_sas) from azure.storage.blob._shared.policies import StorageContentValidation from testcase import ( @@ -377,7 +378,12 @@ def test_upload_pages_from_url(self): # Arrange source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -408,7 +414,12 @@ def test_upload_pages_from_url_and_validate_content_md5(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) src_md5 = StorageContentValidation.get_content_md5(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -444,7 +455,12 @@ def test_upload_pages_from_url_with_source_if_modified(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -482,7 +498,12 @@ def test_upload_pages_from_url_with_source_if_unmodified(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -519,7 +540,12 @@ def test_upload_pages_from_url_with_source_if_match(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -555,7 +581,12 @@ def test_upload_pages_from_url_with_source_if_none_match(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -591,7 +622,12 @@ def test_upload_pages_from_url_with_if_modified(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -628,7 +664,12 @@ def test_upload_pages_from_url_with_if_unmodified(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -665,7 +706,12 @@ def test_upload_pages_from_url_with_if_match(self): # Arrange source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -701,7 +747,12 @@ def test_upload_pages_from_url_with_if_none_match(self): # Arrange source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -738,7 +789,12 @@ def test_upload_pages_from_url_with_sequence_number_lt(self): start_sequence = 10 source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -774,7 +830,12 @@ def test_upload_pages_from_url_with_sequence_number_lte(self): start_sequence = 10 source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -810,7 +871,12 @@ def test_upload_pages_from_url_with_sequence_number_eq(self): start_sequence = 10 source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -1354,7 +1420,12 @@ def test_incremental_copy_blob(self): snapshot_blob = BlobClient.from_blob_url( source_blob.url, credential=source_blob.credential, snapshot=source_snapshot_blob) - sas_token = snapshot_blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + snapshot_blob.account_name, + snapshot_blob.container_name, + snapshot_blob.blob_name, + snapshot=snapshot_blob.snapshot, + account_key=snapshot_blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-blob/tests/test_page_blob_async.py b/sdk/storage/azure-storage-blob/tests/test_page_blob_async.py index 9f123782f9f8..c72f075bb9c0 100644 --- a/sdk/storage/azure-storage-blob/tests/test_page_blob_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_page_blob_async.py @@ -24,7 +24,8 @@ BlobType, PremiumPageBlobTier, SequenceNumberAction, - StorageErrorCode + StorageErrorCode, + generate_blob_sas ) from azure.storage.blob.aio import ( @@ -484,7 +485,12 @@ async def _test_upload_pages_from_url(self): await self._setup() source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -518,7 +524,12 @@ async def _test_upload_pages_from_url_and_validate_content_md5(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) src_md5 = StorageContentValidation.get_content_md5(source_blob_data) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -558,7 +569,12 @@ async def _test_upload_pages_from_url_with_source_if_modified(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -600,7 +616,12 @@ async def _test_upload_pages_from_url_with_source_if_unmodified(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -642,7 +663,12 @@ async def _test_upload_pages_from_url_with_source_if_match(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -681,7 +707,12 @@ async def _test_upload_pages_from_url_with_source_if_none_match(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -720,7 +751,12 @@ async def _test_upload_pages_from_url_with_if_modified(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -762,7 +798,12 @@ async def _test_upload_pages_from_url_with_if_unmodified(self): source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) source_properties = await source_blob_client.get_blob_properties() - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -803,7 +844,12 @@ async def _test_upload_pages_from_url_with_if_match(self): await self._setup() source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -842,7 +888,12 @@ async def _test_upload_pages_from_url_with_if_none_match(self): await self._setup() source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -881,7 +932,12 @@ async def _test_upload_pages_from_url_with_sequence_number_lt(self): start_sequence = 10 source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -920,7 +976,12 @@ async def _test_upload_pages_from_url_with_sequence_number_lte(self): start_sequence = 10 source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -959,7 +1020,12 @@ async def _test_upload_pages_from_url_with_sequence_number_eq(self): start_sequence = 10 source_blob_data = self.get_random_bytes(SOURCE_BLOB_SIZE) source_blob_client = await self._create_source_blob(source_blob_data, 0, SOURCE_BLOB_SIZE) - sas = source_blob_client.generate_shared_access_signature( + sas = generate_blob_sas( + source_blob_client.account_name, + source_blob_client.container_name, + source_blob_client.blob_name, + snapshot=source_blob_client.snapshot, + account_key=source_blob_client.credential.account_key, permission=BlobSasPermissions(read=True, delete=True), expiry=datetime.utcnow() + timedelta(hours=1)) @@ -1627,7 +1693,12 @@ async def _test_incremental_copy_blob(self): snapshot_blob = BlobClient.from_blob_url( source_blob.url, credential=source_blob.credential, snapshot=source_snapshot_blob) - sas_token = snapshot_blob.generate_shared_access_signature( + sas_token = generate_blob_sas( + snapshot_blob.account_name, + snapshot_blob.container_name, + snapshot_blob.blob_name, + snapshot=snapshot_blob.snapshot, + account_key=snapshot_blob.credential.account_key, permission=BlobSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-file/HISTORY.md b/sdk/storage/azure-storage-file/HISTORY.md index 548bb8b80d3d..44020dc630e9 100644 --- a/sdk/storage/azure-storage-file/HISTORY.md +++ b/sdk/storage/azure-storage-file/HISTORY.md @@ -20,6 +20,7 @@ To use a directory_url, the method `from_directory_url` must be used. - `max_concurrency` - `validate_content` - `timeout` etc. +- The `generate_shared_access_signature` methods on each of `FileServiceClient`, `ShareClient` and `FileClient` have been replaced by module level functions `generate_account_sas`, `generate_share_sas` and `generate_file_sas`. - `start_range` and `end_range` params are now renamed to and behave like`offset` and `length` in the following APIs: - download_file diff --git a/sdk/storage/azure-storage-file/azure/storage/file/__init__.py b/sdk/storage/azure-storage-file/azure/storage/file/__init__.py index 83382a9e6486..9099ce806096 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/__init__.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/__init__.py @@ -9,8 +9,9 @@ from .directory_client import DirectoryClient from .share_client import ShareClient from .file_service_client import FileServiceClient +from ._shared_access_signature import generate_account_sas, generate_share_sas, generate_file_sas from ._shared.policies import ExponentialRetry, LinearRetry -from ._shared.models import( +from ._shared.models import ( LocationMode, ResourceTypes, AccountSasPermissions, @@ -58,5 +59,8 @@ 'ContentSettings', 'Handle', 'NTFSAttributes', - 'HandleItem' + 'HandleItem', + 'generate_account_sas', + 'generate_share_sas', + 'generate_file_sas' ] diff --git a/sdk/storage/azure-storage-file/azure/storage/file/_shared/base_client.py b/sdk/storage/azure-storage-file/azure/storage/file/_shared/base_client.py index 85111a60c90a..7e416c7e9569 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/_shared/base_client.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/_shared/base_client.py @@ -64,7 +64,7 @@ } -class StorageAccountHostsMixin(object): +class StorageAccountHostsMixin(object): # pylint: disable=too-many-instance-attributes def __init__( self, parsed_url, # type: Any @@ -80,11 +80,14 @@ def __init__( if service not in ["blob", "queue", "file"]: raise ValueError("Invalid service: {}".format(service)) account = parsed_url.netloc.split(".{}.core.".format(service)) + self.account_name = account[0] secondary_hostname = None + self.credential = format_shared_key_credential(account, credential) if self.scheme.lower() != "https" and hasattr(self.credential, "get_token"): raise ValueError("Token credential is only supported with HTTPS.") if hasattr(self.credential, "account_name"): + self.account_name = self.credential.account_name secondary_hostname = "{}-secondary.{}.{}".format(self.credential.account_name, service, SERVICE_HOST_BASE) if not self._hosts: @@ -189,7 +192,8 @@ def _create_pipeline(self, credential, **kwargs): return config, Pipeline(config.transport, policies=policies) def _batch_send( - self, *reqs # type: HttpRequest + self, *reqs, # type: HttpRequest + **kwargs ): """Given a series of request, do a Storage batch call. """ @@ -209,7 +213,7 @@ def _batch_send( ) pipeline_response = self._pipeline.run( - request, + request, **kwargs ) response = pipeline_response.http_response diff --git a/sdk/storage/azure-storage-file/azure/storage/file/_shared/models.py b/sdk/storage/azure-storage-file/azure/storage/file/_shared/models.py index 943842ced4c2..c14d8cad8b8e 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/_shared/models.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/_shared/models.py @@ -261,8 +261,8 @@ def from_string(cls, string): class AccountSasPermissions(object): """ - :class:`~ResourceTypes` class to be used with generate_shared_access_signature - method and for the AccessPolicies used with set_*_acl. There are two types of + :class:`~ResourceTypes` class to be used with generate_account_sas + function and for the AccessPolicies used with set_*_acl. There are two types of SAS which may be used to grant resource access. One is to grant access to a specific resource (resource-specific). Another is to grant access to the entire service for a specific account and allow certain operations based on diff --git a/sdk/storage/azure-storage-file/azure/storage/file/_shared/request_handlers.py b/sdk/storage/azure-storage-file/azure/storage/file/_shared/request_handlers.py index 57e3521fb192..873c67dd8e4f 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/_shared/request_handlers.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/_shared/request_handlers.py @@ -17,7 +17,6 @@ from azure.core.configuration import Configuration from azure.core.exceptions import raise_with_traceback -from azure.core.pipeline import Pipeline _LOGGER = logging.getLogger(__name__) diff --git a/sdk/storage/azure-storage-file/azure/storage/file/_shared/uploads.py b/sdk/storage/azure-storage-file/azure/storage/file/_shared/uploads.py index 2e6d62edd4ac..9aa0b2aefbb0 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/_shared/uploads.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/_shared/uploads.py @@ -396,7 +396,7 @@ def flush(self): pass def read(self, size=None): - if self.closed: + if self.closed: # pylint: disable=using-constant-test raise ValueError("Stream is closed.") if size is None: diff --git a/sdk/storage/azure-storage-file/azure/storage/file/_shared_access_signature.py b/sdk/storage/azure-storage-file/azure/storage/file/_shared_access_signature.py index 1bfac4a176f0..93d8fd7d2bbd 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/_shared_access_signature.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/_shared_access_signature.py @@ -6,6 +6,7 @@ from ._shared import sign_string from ._shared.constants import X_MS_VERSION +from ._shared.models import Services from ._shared.shared_access_signature import SharedAccessSignature, _SharedAccessHelper, QueryStringConstants from ._shared.parser import _str @@ -219,3 +220,266 @@ def get_value_to_append(query): self._add_query(QueryStringConstants.SIGNED_SIGNATURE, sign_string(account_key, string_to_sign)) + + +def generate_account_sas( + account_name, # type: str + account_key, # type: str + resource_types, # type: Union[ResourceTypes, str] + permission, # type: Union[AccountSasPermissions, str] + expiry, # type: Optional[Union[datetime, str]] + start=None, # type: Optional[Union[datetime, str]] + ip=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> str + """Generates a shared access signature for the file service. + + Use the returned signature with the credential parameter of any FileServiceClient, + ShareClient, DirectoryClient, or FileClient. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str account_key: + The access key to generate the shared access signature. + :param ~azure.storage.file.ResourceTypes resource_types: + Specifies the resource types that are accessible with the account SAS. + :param ~azure.storage.file.AccountSasPermissions permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. Azure will always convert values + to UTC. If a date is passed in without timezone info, it is assumed to + be UTC. + :type start: datetime or str + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :return: A Shared Access Signature (sas) token. + :rtype: str + + .. admonition:: Example: + + .. literalinclude:: ../tests/test_file_samples_authentication.py + :start-after: [START generate_sas_token] + :end-before: [END generate_sas_token] + :language: python + :dedent: 8 + :caption: Generate a sas token. + """ + sas = SharedAccessSignature(account_name, account_key) + return sas.generate_account( + services=Services(file=True), + resource_types=resource_types, + permission=permission, + expiry=expiry, + start=start, + ip=ip, + **kwargs + ) # type: ignore + + +def generate_share_sas( + account_name, # type: str + share_name, # type: str + account_key, # type: str + permission=None, # type: Optional[Union[ShareSasPermissions, str]] + expiry=None, # type: Optional[Union[datetime, str]] + start=None, # type: Optional[Union[datetime, str]] + policy_id=None, # type: Optional[str] + ip=None, # type: Optional[str] + **kwargs # type: Any + ): # type: (...) -> str + """Generates a shared access signature for a share. + + Use the returned signature with the credential parameter of any FileServiceClient, + ShareClient, DirectoryClient, or FileClient. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str share_name: + The name of the share. + :param str account_key: + The access key to generate the shared access signature. + :param ~azure.storage.file.ShareSasPermissions permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Permissions must be ordered read, create, write, delete, list. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. Azure will always convert values + to UTC. If a date is passed in without timezone info, it is assumed to + be UTC. + :type start: ~datetime.datetime or str + :param str policy_id: + A unique value up to 64 characters in length that correlates to a + stored access policy. To create a stored access policy, use + :func:`~azure.storage.file.ShareClient.set_share_access_policy`. + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword str protocol: + Specifies the protocol permitted for a request made. Possible values are + both HTTPS and HTTP (https,http) or HTTPS only (https). The default value + is https,http. Note that HTTP only is not a permitted value. + :keyword str cache_control: + Response header value for Cache-Control when resource is accessed + using this shared access signature. + :keyword str content_disposition: + Response header value for Content-Disposition when resource is accessed + using this shared access signature. + :keyword str content_encoding: + Response header value for Content-Encoding when resource is accessed + using this shared access signature. + :keyword str content_language: + Response header value for Content-Language when resource is accessed + using this shared access signature. + :keyword str content_type: + Response header value for Content-Type when resource is accessed + using this shared access signature. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :return: A Shared Access Signature (sas) token. + :rtype: str + """ + sas = FileSharedAccessSignature(account_name, account_key) + return sas.generate_share( + share_name=share_name, + permission=permission, + expiry=expiry, + start=start, + policy_id=policy_id, + ip=ip, + **kwargs + ) + + +def generate_file_sas( + account_name, # type: str + share_name, # type: str + file_path, # type: List[str] + account_key, # type: str + permission=None, # type: Optional[Union[FileSasPermissions, str]] + expiry=None, # type: Optional[Union[datetime, str]] + start=None, # type: Optional[Union[datetime, str]] + policy_id=None, # type: Optional[str] + ip=None, # type: Optional[str] + **kwargs # type: Any + ): + # type: (...) -> str + """Generates a shared access signature for a file. + + Use the returned signature with the credential parameter of any FileServiceClient, + ShareClient, DirectoryClient, or FileClient. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str share_name: + The name of the share. + :param file_path: + The file path represented as a list of path segments, including the file name. + :type file_path: List[str] + :param str account_key: + The access key to generate the shared access signature. + :param ~azure.storage.file.FileSasPermissions permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Permissions must be ordered read, write, delete, list. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. Azure will always convert values + to UTC. If a date is passed in without timezone info, it is assumed to + be UTC. + :type start: ~datetime.datetime or str + :param str policy_id: + A unique value up to 64 characters in length that correlates to a + stored access policy. + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :keyword str cache_control: + Response header value for Cache-Control when resource is accessed + using this shared access signature. + :keyword str content_disposition: + Response header value for Content-Disposition when resource is accessed + using this shared access signature. + :keyword str content_encoding: + Response header value for Content-Encoding when resource is accessed + using this shared access signature. + :keyword str content_language: + Response header value for Content-Language when resource is accessed + using this shared access signature. + :keyword str content_type: + Response header value for Content-Type when resource is accessed + using this shared access signature. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :return: A Shared Access Signature (sas) token. + :rtype: str + """ + sas = FileSharedAccessSignature(account_name, account_key) + if len(file_path) > 1: + dir_path = '/'.join(file_path[:-1]) + else: + dir_path = None # type: ignore + return sas.generate_file( # type: ignore + share_name=share_name, + directory_name=dir_path, + file_name=file_path[-1], + permission=permission, + expiry=expiry, + start=start, + policy_id=policy_id, + ip=ip, + **kwargs + ) diff --git a/sdk/storage/azure-storage-file/azure/storage/file/file_client.py b/sdk/storage/azure-storage-file/azure/storage/file/file_client.py index 4cac6b3d28ff..a4ee44df4bef 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/file_client.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/file_client.py @@ -34,12 +34,11 @@ from ._deserialize import deserialize_file_properties, deserialize_file_stream from ._polling import CloseHandles from .models import HandlesPaged, NTFSAttributes # pylint: disable=unused-import -from ._shared_access_signature import FileSharedAccessSignature from .download import StorageStreamDownloader if TYPE_CHECKING: from datetime import datetime - from .models import ShareProperties, FileSasPermissions, ContentSettings, FileProperties + from .models import ShareProperties, ContentSettings, FileProperties from ._generated.models import HandleItem @@ -266,103 +265,6 @@ def from_connection_string( return cls( account_url, share_name=share_name, file_path=file_path, snapshot=snapshot, credential=credential, **kwargs) - def generate_shared_access_signature( - self, permission=None, # type: Optional[Union[FileSasPermissions, str]] - expiry=None, # type: Optional[Union[datetime, str]] - start=None, # type: Optional[Union[datetime, str]] - policy_id=None, # type: Optional[str] - ip=None, # type: Optional[str] - **kwargs # type: Any - ): - # type: (...) -> str - """Generates a shared access signature for the file. - - Use the returned signature with the credential parameter of any FileServiceClient, - ShareClient, DirectoryClient, or FileClient. - - :param ~azure.storage.file.FileSasPermissions permission: - The permissions associated with the shared access signature. The - user is restricted to operations allowed by the permissions. - Permissions must be ordered read, write, delete, list. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has been - specified in an associated stored access policy. - :param expiry: - The time at which the shared access signature becomes invalid. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has - been specified in an associated stored access policy. Azure will always - convert values to UTC. If a date is passed in without timezone info, it - is assumed to be UTC. - :type expiry: ~datetime.datetime or str - :param start: - The time at which the shared access signature becomes valid. If - omitted, start time for this call is assumed to be the time when the - storage service receives the request. Azure will always convert values - to UTC. If a date is passed in without timezone info, it is assumed to - be UTC. - :type start: ~datetime.datetime or str - :param str policy_id: - A unique value up to 64 characters in length that correlates to a - stored access policy. - :param str ip: - Specifies an IP address or a range of IP addresses from which to accept requests. - If the IP address from which the request originates does not match the IP address - or address range specified on the SAS token, the request is not authenticated. - For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS - restricts the request to those IP addresses. - :keyword str protocol: - Specifies the protocol permitted for a request made. The default value is https. - :keyword str cache_control: - Response header value for Cache-Control when resource is accessed - using this shared access signature. - :keyword str content_disposition: - Response header value for Content-Disposition when resource is accessed - using this shared access signature. - :keyword str content_encoding: - Response header value for Content-Encoding when resource is accessed - using this shared access signature. - :keyword str content_language: - Response header value for Content-Language when resource is accessed - using this shared access signature. - :keyword str content_type: - Response header value for Content-Type when resource is accessed - using this shared access signature. - :keyword str protocol: - Specifies the protocol permitted for a request made. The default value is https. - :return: A Shared Access Signature (sas) token. - :rtype: str - """ - protocol = kwargs.pop('protocol', None) - cache_control = kwargs.pop('cache_control', None) - content_disposition = kwargs.pop('content_disposition', None) - content_encoding = kwargs.pop('content_encoding', None) - content_language = kwargs.pop('content_language', None) - content_type = kwargs.pop('content_type', None) - - if not hasattr(self.credential, 'account_key') or not self.credential.account_key: - raise ValueError("No account SAS key available.") - sas = FileSharedAccessSignature(self.credential.account_name, self.credential.account_key) - if len(self.file_path) > 1: - file_path = '/'.join(self.file_path[:-1]) - else: - file_path = None # type: ignore - return sas.generate_file( # type: ignore - share_name=self.share_name, - directory_name=file_path, - file_name=self.file_name, - permission=permission, - expiry=expiry, - start=start, - policy_id=policy_id, - ip=ip, - protocol=protocol, - cache_control=cache_control, - content_disposition=content_disposition, - content_encoding=content_encoding, - content_language=content_language, - content_type=content_type) - @distributed_trace def create_file( # type: ignore self, size, # type: int diff --git a/sdk/storage/azure-storage-file/azure/storage/file/file_service_client.py b/sdk/storage/azure-storage-file/azure/storage/file/file_service_client.py index e349527fa0f4..591bfefb2fdd 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/file_service_client.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/file_service_client.py @@ -17,8 +17,6 @@ from azure.core.paging import ItemPaged from azure.core.tracing.decorator import distributed_trace -from ._shared.shared_access_signature import SharedAccessSignature -from ._shared.models import Services from ._shared.base_client import StorageAccountHostsMixin, parse_connection_str, parse_query from ._shared.response_handlers import process_storage_error from ._generated import AzureFileStorage @@ -29,7 +27,6 @@ if TYPE_CHECKING: from datetime import datetime - from ._shared.models import ResourceTypes, AccountSasPermissions from .models import Metrics, CorsRule, ShareProperties @@ -137,77 +134,6 @@ def from_connection_string( kwargs['secondary_hostname'] = secondary return cls(account_url, credential=credential, **kwargs) - def generate_shared_access_signature( - self, resource_types, # type: Union[ResourceTypes, str] - permission, # type: Union[AccountSasPermissions, str] - expiry, # type: Optional[Union[datetime, str]] - start=None, # type: Optional[Union[datetime, str]] - ip=None, # type: Optional[str] - **kwargs # type: Any - ): # type: (...) -> str - """Generates a shared access signature for the file service. - - Use the returned signature with the credential parameter of any FileServiceClient, - ShareClient, DirectoryClient, or FileClient. - - :param ~azure.storage.file.ResourceTypes resource_types: - Specifies the resource types that are accessible with the account SAS. - :param ~azure.storage.file.AccountSasPermissions permission: - The permissions associated with the shared access signature. The - user is restricted to operations allowed by the permissions. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has been - specified in an associated stored access policy. - :param expiry: - The time at which the shared access signature becomes invalid. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has - been specified in an associated stored access policy. Azure will always - convert values to UTC. If a date is passed in without timezone info, it - is assumed to be UTC. - :type expiry: datetime or str - :param start: - The time at which the shared access signature becomes valid. If - omitted, start time for this call is assumed to be the time when the - storage service receives the request. Azure will always convert values - to UTC. If a date is passed in without timezone info, it is assumed to - be UTC. - :type start: datetime or str - :param str ip: - Specifies an IP address or a range of IP addresses from which to accept requests. - If the IP address from which the request originates does not match the IP address - or address range specified on the SAS token, the request is not authenticated. - For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS - restricts the request to those IP addresses. - :keyword str protocol: - Specifies the protocol permitted for a request made. The default value is https. - :return: A Shared Access Signature (sas) token. - :rtype: str - - .. admonition:: Example: - - .. literalinclude:: ../tests/test_file_samples_authentication.py - :start-after: [START generate_sas_token] - :end-before: [END generate_sas_token] - :language: python - :dedent: 8 - :caption: Generate a sas token. - """ - protocol = kwargs.pop('protocol', None) - if not hasattr(self.credential, 'account_key') and not self.credential.account_key: - raise ValueError("No account SAS key available.") - - sas = SharedAccessSignature(self.credential.account_name, self.credential.account_key) - return sas.generate_account( - services=Services(file=True), - resource_types=resource_types, - permission=permission, - expiry=expiry, - start=start, - ip=ip, - protocol=protocol - ) # type: ignore - @distributed_trace def get_service_properties(self, **kwargs): # type: (Any) -> Dict[str, Any] diff --git a/sdk/storage/azure-storage-file/azure/storage/file/share_client.py b/sdk/storage/azure-storage-file/azure/storage/file/share_client.py index 29618ef0cf7a..e41cd1468d4f 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/share_client.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/share_client.py @@ -31,10 +31,9 @@ from ._deserialize import deserialize_share_properties, deserialize_permission_key, deserialize_permission from .directory_client import DirectoryClient from .file_client import FileClient -from ._shared_access_signature import FileSharedAccessSignature if TYPE_CHECKING: - from .models import ShareProperties, AccessPolicy, ShareSasPermissions + from .models import ShareProperties, AccessPolicy class ShareClient(StorageAccountHostsMixin): @@ -196,97 +195,6 @@ def from_connection_string( return cls( account_url, share_name=share_name, snapshot=snapshot, credential=credential, **kwargs) - def generate_shared_access_signature( - self, permission=None, # type: Optional[Union[ShareSasPermissions, str]] - expiry=None, # type: Optional[Union[datetime, str]] - start=None, # type: Optional[Union[datetime, str]] - policy_id=None, # type: Optional[str] - ip=None, # type: Optional[str] - **kwargs # type: Any - ): # type: (...) -> str - """Generates a shared access signature for the share. - Use the returned signature with the credential parameter of any FileServiceClient, - ShareClient, DirectoryClient, or FileClient. - - :param ~azure.storage.file.ShareSasPermissions permission: - The permissions associated with the shared access signature. The - user is restricted to operations allowed by the permissions. - Permissions must be ordered read, create, write, delete, list. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has been - specified in an associated stored access policy. - :param expiry: - The time at which the shared access signature becomes invalid. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has - been specified in an associated stored access policy. Azure will always - convert values to UTC. If a date is passed in without timezone info, it - is assumed to be UTC. - :type expiry: ~datetime.datetime or str - :param start: - The time at which the shared access signature becomes valid. If - omitted, start time for this call is assumed to be the time when the - storage service receives the request. Azure will always convert values - to UTC. If a date is passed in without timezone info, it is assumed to - be UTC. - :type start: ~datetime.datetime or str - :param str policy_id: - A unique value up to 64 characters in length that correlates to a - stored access policy. To create a stored access policy, use :func:`~set_share_access_policy`. - :param str ip: - Specifies an IP address or a range of IP addresses from which to accept requests. - If the IP address from which the request originates does not match the IP address - or address range specified on the SAS token, the request is not authenticated. - For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS - restricts the request to those IP addresses. - :keyword str protocol: - Specifies the protocol permitted for a request made. Possible values are - both HTTPS and HTTP (https,http) or HTTPS only (https). The default value - is https,http. Note that HTTP only is not a permitted value. - :keyword str cache_control: - Response header value for Cache-Control when resource is accessed - using this shared access signature. - :keyword str content_disposition: - Response header value for Content-Disposition when resource is accessed - using this shared access signature. - :keyword str content_encoding: - Response header value for Content-Encoding when resource is accessed - using this shared access signature. - :keyword str content_language: - Response header value for Content-Language when resource is accessed - using this shared access signature. - :keyword str content_type: - Response header value for Content-Type when resource is accessed - using this shared access signature. - :keyword str protocol: - Specifies the protocol permitted for a request made. The default value is https. - :return: A Shared Access Signature (sas) token. - :rtype: str - """ - protocol = kwargs.pop('protocol', None) - cache_control = kwargs.pop('cache_control', None) - content_disposition = kwargs.pop('content_disposition', None) - content_encoding = kwargs.pop('content_encoding', None) - content_language = kwargs.pop('content_language', None) - content_type = kwargs.pop('content_type', None) - if not hasattr(self.credential, 'account_key') or not self.credential.account_key: - raise ValueError("No account SAS key available.") - sas = FileSharedAccessSignature(self.credential.account_name, self.credential.account_key) - return sas.generate_share( - share_name=self.share_name, - permission=permission, - expiry=expiry, - start=start, - policy_id=policy_id, - ip=ip, - protocol=protocol, - cache_control=cache_control, - content_disposition=content_disposition, - content_encoding=content_encoding, - content_language=content_language, - content_type=content_type, - ) - def get_directory_client(self, directory_path=None): # type: (Optional[str]) -> DirectoryClient """Get a client to interact with the specified directory. diff --git a/sdk/storage/azure-storage-file/tests/test_file.py b/sdk/storage/azure-storage-file/tests/test_file.py index 59122131db93..1c9689cb1470 100644 --- a/sdk/storage/azure-storage-file/tests/test_file.py +++ b/sdk/storage/azure-storage-file/tests/test_file.py @@ -16,6 +16,8 @@ from azure.core.exceptions import HttpResponseError, ResourceNotFoundError, ResourceExistsError from azure.storage.file import ( + generate_account_sas, + generate_file_sas, FileClient, FileServiceClient, ContentSettings, @@ -597,8 +599,12 @@ def test_update_range_from_file_url_when_source_file_does_not_have_enough_bytes( destination_file_client = self._create_file(destination_file_name) # generate SAS for the source file - sas_token_for_source_file = \ - source_file_client.generate_shared_access_signature() + sas_token_for_source_file = generate_file_sas( + source_file_client.account_name, + source_file_client.share_name, + source_file_client.file_path, + source_file_client.credential.account_key, + ) source_file_url = source_file_client.url + '?' + sas_token_for_source_file @@ -619,10 +625,13 @@ def test_update_range_from_file_url(self): destination_file_client = self._create_empty_file(file_name=destination_file_name) # generate SAS for the source file - sas_token_for_source_file = \ - source_file_client.generate_shared_access_signature( - FileSasPermissions(read=True), - expiry=datetime.utcnow() + timedelta(hours=1)) + sas_token_for_source_file = generate_file_sas( + source_file_client.account_name, + source_file_client.share_name, + source_file_client.file_path, + source_file_client.credential.account_key, + FileSasPermissions(read=True), + expiry=datetime.utcnow() + timedelta(hours=1)) source_file_url = source_file_client.url + '?' + sas_token_for_source_file # Act @@ -651,10 +660,13 @@ def test_update_big_range_from_file_url(self): destination_file_client = self._create_empty_file(file_name=destination_file_name, file_size=1024 * 1024) # generate SAS for the source file - sas_token_for_source_file = \ - source_file_client.generate_shared_access_signature( - FileSasPermissions(read=True), - expiry=datetime.utcnow() + timedelta(hours=1)) + sas_token_for_source_file = generate_file_sas( + source_file_client.account_name, + source_file_client.share_name, + source_file_client.file_path, + source_file_client.credential.account_key, + FileSasPermissions(read=True), + expiry=datetime.utcnow() + timedelta(hours=1)) source_file_url = source_file_client.url + '?' + sas_token_for_source_file @@ -858,7 +870,11 @@ def test_copy_file_async_private_file_with_sas(self): data = b'12345678' * 1024 * 1024 self._create_remote_share() source_file = self._create_remote_file(file_data=data) - sas_token = source_file.generate_shared_access_signature( + sas_token = generate_file_sas( + source_file.account_name, + source_file.share_name, + source_file.file_path, + source_file.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -886,7 +902,11 @@ def test_abort_copy_file(self): data = b'12345678' * 1024 * 1024 self._create_remote_share() source_file = self._create_remote_file(file_data=data) - sas_token = source_file.generate_shared_access_signature( + sas_token = generate_file_sas( + source_file.account_name, + source_file.share_name, + source_file.file_path, + source_file.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1403,7 +1423,11 @@ def test_sas_access_file(self): # Arrange file_client = self._create_file() - token = file_client.generate_shared_access_signature( + token = generate_file_sas( + file_client.account_name, + file_client.share_name, + file_client.file_path, + file_client.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1436,7 +1460,12 @@ def test_sas_signed_identifier(self): identifiers = {'testid': access_policy} share_client.set_share_access_policy(identifiers) - token = file_client.generate_shared_access_signature(policy_id='testid') + token = generate_file_sas( + file_client.account_name, + file_client.share_name, + file_client.file_path, + file_client.credential.account_key, + policy_id='testid') # Act sas_file = FileClient.from_file_url( @@ -1456,7 +1485,9 @@ def test_account_sas(self): # Arrange file_client = self._create_file() - token = self.fsc.generate_shared_access_signature( + token = generate_account_sas( + self.fsc.account_name, + self.fsc.credential.account_key, ResourceTypes(object=True), AccountSasPermissions(read=True), datetime.utcnow() + timedelta(hours=1), @@ -1483,7 +1514,11 @@ def test_shared_read_access_file(self): # Arrange file_client = self._create_file() - token = file_client.generate_shared_access_signature( + token = generate_file_sas( + file_client.account_name, + file_client.share_name, + file_client.file_path, + file_client.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1508,7 +1543,11 @@ def test_shared_read_access_file_with_content_query_params(self): # Arrange file_client = self._create_file() - token = file_client.generate_shared_access_signature( + token = generate_file_sas( + file_client.account_name, + file_client.share_name, + file_client.file_path, + file_client.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), cache_control='no-cache', @@ -1543,7 +1582,11 @@ def test_shared_write_access_file(self): # Arrange updated_data = b'updated file data' file_client_admin = self._create_file() - token = file_client_admin.generate_shared_access_signature( + token = generate_file_sas( + file_client_admin.account_name, + file_client_admin.share_name, + file_client_admin.file_path, + file_client_admin.credential.account_key, permission=FileSasPermissions(write=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1570,7 +1613,11 @@ def test_shared_delete_access_file(self): # Arrange file_client_admin = self._create_file() - token = file_client_admin.generate_shared_access_signature( + token = generate_file_sas( + file_client_admin.account_name, + file_client_admin.share_name, + file_client_admin.file_path, + file_client_admin.credential.account_key, permission=FileSasPermissions(delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-file/tests/test_file_async.py b/sdk/storage/azure-storage-file/tests/test_file_async.py index 83075ed0c60b..7b8ccf8bfd31 100644 --- a/sdk/storage/azure-storage-file/tests/test_file_async.py +++ b/sdk/storage/azure-storage-file/tests/test_file_async.py @@ -17,6 +17,8 @@ from azure.core.exceptions import HttpResponseError, ResourceNotFoundError, ResourceExistsError from azure.storage.file import ( + generate_account_sas, + generate_file_sas, NTFSAttributes, ContentSettings, FileSasPermissions, @@ -741,8 +743,11 @@ async def _test_update_range_from_file_url_when_source_file_does_not_have_enough destination_file_client = await self._create_file(destination_file_name) # generate SAS for the source file - sas_token_for_source_file = \ - source_file_client.generate_shared_access_signature() + sas_token_for_source_file = generate_file_sas( + source_file_client.account_name, + source_file_client.share_name, + source_file_client.file_path, + source_file_client.credential.account_key) source_file_url = source_file_client.url + '?' + sas_token_for_source_file @@ -767,10 +772,13 @@ async def _test_update_range_from_file_url(self): destination_file_client = await self._create_empty_file(file_name=destination_file_name) # generate SAS for the source file - sas_token_for_source_file = \ - source_file_client.generate_shared_access_signature( - FileSasPermissions(read=True), - expiry=datetime.utcnow() + timedelta(hours=1)) + sas_token_for_source_file = generate_file_sas( + source_file_client.account_name, + source_file_client.share_name, + source_file_client.file_path, + source_file_client.credential.account_key, + FileSasPermissions(read=True), + expiry=datetime.utcnow() + timedelta(hours=1)) source_file_url = source_file_client.url + '?' + sas_token_for_source_file # Act @@ -804,10 +812,13 @@ async def _test_update_big_range_from_file_url(self): destination_file_client = await self._create_empty_file(file_name=destination_file_name, file_size=1024 * 1024) # generate SAS for the source file - sas_token_for_source_file = \ - source_file_client.generate_shared_access_signature( - FileSasPermissions(read=True), - expiry=datetime.utcnow() + timedelta(hours=1)) + sas_token_for_source_file = generate_file_sas( + source_file_client.account_name, + source_file_client.share_name, + source_file_client.file_path, + source_file_client.credential.account_key, + FileSasPermissions(read=True), + expiry=datetime.utcnow() + timedelta(hours=1)) source_file_url = source_file_client.url + '?' + sas_token_for_source_file @@ -1062,7 +1073,11 @@ async def _test_copy_file_async_private_file_with_sas_async(self): data = b'12345678' * 1024 * 1024 await self._create_remote_share() source_file = await self._create_remote_file(file_data=data) - sas_token = source_file.generate_shared_access_signature( + sas_token = generate_file_sas( + source_file.account_name, + source_file.share_name, + source_file.file_path, + source_file.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1097,7 +1112,11 @@ async def _test_abort_copy_file_async(self): data = b'12345678' * 1024 * 1024 await self._create_remote_share() source_file = await self._create_remote_file(file_data=data) - sas_token = source_file.generate_shared_access_signature( + sas_token = generate_file_sas( + source_file.account_name, + source_file.share_name, + source_file.file_path, + source_file.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1734,7 +1753,11 @@ async def _test_sas_access_file_async(self): # Arrange file_client = await self._create_file() - token = file_client.generate_shared_access_signature( + token = generate_file_sas( + file_client.account_name, + file_client.share_name, + file_client.file_path, + file_client.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1772,7 +1795,12 @@ async def _test_sas_signed_identifier_async(self): identifiers = {'testid': access_policy} await share_client.set_share_access_policy(identifiers) - token = file_client.generate_shared_access_signature(policy_id='testid') + token = generate_file_sas( + file_client.account_name, + file_client.share_name, + file_client.file_path, + file_client.credential.account_key, + policy_id='testid') # Act sas_file = FileClient.from_file_url( @@ -1797,7 +1825,9 @@ async def _test_account_sas_async(self): # Arrange file_client = await self._create_file() - token = self.fsc.generate_shared_access_signature( + token = generate_account_sas( + self.fsc.account_name, + self.fsc.credential.account_key, ResourceTypes(object=True), AccountSasPermissions(read=True), datetime.utcnow() + timedelta(hours=1), @@ -1828,7 +1858,11 @@ async def _test_shared_read_access_file_async(self): # Arrange file_client = await self._create_file() - token = file_client.generate_shared_access_signature( + token = generate_file_sas( + file_client.account_name, + file_client.share_name, + file_client.file_path, + file_client.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1857,7 +1891,11 @@ async def _test_shared_read_access_file_with_content_query_params_async(self): # Arrange file_client = await self._create_file() - token = file_client.generate_shared_access_signature( + token = generate_file_sas( + file_client.account_name, + file_client.share_name, + file_client.file_path, + file_client.credential.account_key, permission=FileSasPermissions(read=True), expiry=datetime.utcnow() + timedelta(hours=1), cache_control='no-cache', @@ -1896,7 +1934,11 @@ async def _test_shared_write_access_file_async(self): # Arrange updated_data = b'updated file data' file_client_admin = await self._create_file() - token = file_client_admin.generate_shared_access_signature( + token = generate_file_sas( + file_client_admin.account_name, + file_client_admin.share_name, + file_client_admin.file_path, + file_client_admin.credential.account_key, permission=FileSasPermissions(write=True), expiry=datetime.utcnow() + timedelta(hours=1), ) @@ -1928,7 +1970,11 @@ async def _test_shared_delete_access_file_async(self): # Arrange file_client_admin = await self._create_file() - token = file_client_admin.generate_shared_access_signature( + token = generate_file_sas( + file_client_admin.account_name, + file_client_admin.share_name, + file_client_admin.file_path, + file_client_admin.credential.account_key, permission=FileSasPermissions(delete=True), expiry=datetime.utcnow() + timedelta(hours=1), ) diff --git a/sdk/storage/azure-storage-file/tests/test_file_client.py b/sdk/storage/azure-storage-file/tests/test_file_client.py index b6bf44543fe5..86427c230667 100644 --- a/sdk/storage/azure-storage-file/tests/test_file_client.py +++ b/sdk/storage/azure-storage-file/tests/test_file_client.py @@ -44,6 +44,7 @@ def setUp(self): # --Helpers----------------------------------------------------------------- def validate_standard_account_endpoints(self, service, service_type, protocol='https'): self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('{}://{}.{}.core.windows.net/'.format( @@ -77,6 +78,7 @@ def test_create_service_with_sas(self): # Assert self.assertIsNotNone(service) self.assertIsNone(service.credential) + self.assertEqual(service.account_name, self.account_name) self.assertTrue(service.url.endswith(self.sas_token)) def test_create_service_with_token(self): @@ -98,6 +100,7 @@ def test_create_service_china(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertEqual(service.primary_hostname, '{}.{}.core.chinacloudapi.cn'.format( @@ -175,6 +178,7 @@ def test_create_service_with_connection_string_sas(self): # Assert self.assertIsNotNone(service) self.assertIsNone(service.credential) + self.assertEqual(service.account_name, self.account_name) self.assertTrue(service.url.endswith(self.sas_token)) def test_create_service_with_connection_string_endpoint_protocol(self): @@ -189,6 +193,7 @@ def test_create_service_with_connection_string_endpoint_protocol(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertEqual(service.primary_hostname, '{}.{}.core.chinacloudapi.cn'.format(self.account_name, service_type[1])) @@ -233,6 +238,7 @@ def test_create_service_with_connection_string_succeeds_if_secondary_with_primar # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertEqual(service.primary_hostname, 'www.mydomain.com') diff --git a/sdk/storage/azure-storage-file/tests/test_file_client_async.py b/sdk/storage/azure-storage-file/tests/test_file_client_async.py index a3bd440f570f..4b23104371e6 100644 --- a/sdk/storage/azure-storage-file/tests/test_file_client_async.py +++ b/sdk/storage/azure-storage-file/tests/test_file_client_async.py @@ -57,6 +57,7 @@ def setUp(self): # --Helpers----------------------------------------------------------------- def validate_standard_account_endpoints(self, service, service_type, protocol='https'): self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertTrue(service.primary_endpoint.startswith('{}://{}.{}.core.windows.net/'.format( @@ -92,6 +93,7 @@ def test_create_service_with_sas_async(self): # Assert self.assertIsNotNone(service) self.assertIsNone(service.credential) + self.assertEqual(service.account_name, self.account_name) self.assertTrue(service.url.endswith(self.sas_token)) @record @@ -115,6 +117,7 @@ def test_create_service_china_async(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertEqual(service.primary_hostname, '{}.{}.core.chinacloudapi.cn'.format( @@ -195,6 +198,7 @@ def test_create_service_with_connection_string_sas_async(self): # Assert self.assertIsNotNone(service) self.assertIsNone(service.credential) + self.assertEqual(service.account_name, self.account_name) self.assertTrue(service.url.endswith(self.sas_token)) @record @@ -210,6 +214,7 @@ def test_create_service_with_connection_string_endpoint_protocol_async(self): # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertEqual(service.primary_hostname, '{}.{}.core.chinacloudapi.cn'.format(self.account_name, service_type[1])) @@ -257,6 +262,7 @@ def test_create_service_with_connection_string_succeeds_if_secondary_with_primar # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, self.account_name) self.assertEqual(service.credential.account_name, self.account_name) self.assertEqual(service.credential.account_key, self.account_key) self.assertEqual(service.primary_hostname, 'www.mydomain.com') diff --git a/sdk/storage/azure-storage-file/tests/test_file_samples_authentication.py b/sdk/storage/azure-storage-file/tests/test_file_samples_authentication.py index 746a9b758189..6ef8d950a47c 100644 --- a/sdk/storage/azure-storage-file/tests/test_file_samples_authentication.py +++ b/sdk/storage/azure-storage-file/tests/test_file_samples_authentication.py @@ -64,7 +64,11 @@ def test_auth_shared_access_signature(self): # Create a SAS token to use to authenticate a new client # [START generate_sas_token] - sas_token = file_service_client.generate_shared_access_signature( + from azure.storage.file import generate_account_sas + + sas_token = generate_account_sas( + file_service_client.account_name, + file_service_client.credential.account_key, resource_types="object", permission="read", expiry=datetime.utcnow() + timedelta(hours=1) diff --git a/sdk/storage/azure-storage-file/tests/test_file_samples_authentication_async.py b/sdk/storage/azure-storage-file/tests/test_file_samples_authentication_async.py index ab78f5fad071..93b327fd17b4 100644 --- a/sdk/storage/azure-storage-file/tests/test_file_samples_authentication_async.py +++ b/sdk/storage/azure-storage-file/tests/test_file_samples_authentication_async.py @@ -75,7 +75,11 @@ async def _test_auth_shared_access_signature(self): # Create a SAS token to use to authenticate a new client # [START generate_sas_token] - sas_token = file_service_client.generate_shared_access_signature( + from azure.storage.file import generate_account_sas + + sas_token = generate_account_sas( + file_service_client.account_name, + file_service_client.credential.account_key, resource_types="object", permission="read", expiry=datetime.utcnow() + timedelta(hours=1) diff --git a/sdk/storage/azure-storage-file/tests/test_file_samples_service_async.py b/sdk/storage/azure-storage-file/tests/test_file_samples_service_async.py index 5df46ee76608..86c45dc81f55 100644 --- a/sdk/storage/azure-storage-file/tests/test_file_samples_service_async.py +++ b/sdk/storage/azure-storage-file/tests/test_file_samples_service_async.py @@ -104,7 +104,7 @@ async def _test_get_share_client(self): file_service = FileServiceClient.from_connection_string(self.connection_string) # Get a share client to interact with a specific share - share = await file_service.get_share_client("fileshare") + share = file_service.get_share_client("fileshare") # [END get_share_client] def test_get_share_client(self): diff --git a/sdk/storage/azure-storage-file/tests/test_share.py b/sdk/storage/azure-storage-file/tests/test_share.py index 53f6063e2e13..3824ff9f608b 100644 --- a/sdk/storage/azure-storage-file/tests/test_share.py +++ b/sdk/storage/azure-storage-file/tests/test_share.py @@ -15,11 +15,15 @@ ResourceNotFoundError, ResourceExistsError) -from azure.storage.file.models import AccessPolicy, ShareSasPermissions -from azure.storage.file.file_service_client import FileServiceClient -from azure.storage.file.directory_client import DirectoryClient -from azure.storage.file.file_client import FileClient -from azure.storage.file.share_client import ShareClient +from azure.storage.file import ( + AccessPolicy, + ShareSasPermissions, + FileServiceClient, + DirectoryClient, + FileClient, + ShareClient, + generate_share_sas) + from azure.storage.file._generated.models import DeleteSnapshotsOptionType, ListSharesIncludeType from filetestcase import ( FileTestCase, @@ -725,7 +729,10 @@ def test_shared_access_share(self): dir1 = share.create_directory(dir_name) dir1.upload_file(file_name, data) - token = share.generate_shared_access_signature( + token = generate_share_sas( + share.account_name, + share.share_name, + share.credential.account_key, expiry=datetime.utcnow() + timedelta(hours=1), permission=ShareSasPermissions(read=True), ) diff --git a/sdk/storage/azure-storage-file/tests/test_share_async.py b/sdk/storage/azure-storage-file/tests/test_share_async.py index fe4d3687d017..08e2136e0fef 100644 --- a/sdk/storage/azure-storage-file/tests/test_share_async.py +++ b/sdk/storage/azure-storage-file/tests/test_share_async.py @@ -20,6 +20,7 @@ from azure.storage.file import ( AccessPolicy, ShareSasPermissions, + generate_share_sas, ) from azure.storage.file.aio import ( FileServiceClient, @@ -874,7 +875,10 @@ async def _test_shared_access_share_async(self): dir1 = await share.create_directory(dir_name) await dir1.upload_file(file_name, data) - token = share.generate_shared_access_signature( + token = generate_share_sas( + share.account_name, + share.share_name, + share.credential.account_key, expiry=datetime.utcnow() + timedelta(hours=1), permission=ShareSasPermissions(read=True), ) diff --git a/sdk/storage/azure-storage-queue/HISTORY.md b/sdk/storage/azure-storage-queue/HISTORY.md index bdbd883e6ad0..5ff6703625bb 100644 --- a/sdk/storage/azure-storage-queue/HISTORY.md +++ b/sdk/storage/azure-storage-queue/HISTORY.md @@ -20,6 +20,8 @@ should be imported from azure.storage.queue.aio to `inserted_on`, `next_visible_on`, `expires_on`, respectively. - `Logging` has been renamed to `QueueAnalyticsLogging`. - `enqueue_message` is now called `send_message`. +- The `generate_shared_access_signature` methods on both `QueueServiceClient` and `QueueClient` have been replaced by module level functions `generate_account_sas` and `generate_queue_sas`. + **New features** diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/__init__.py b/sdk/storage/azure-storage-queue/azure/storage/queue/__init__.py index 15bbdf3d4ff1..0ef1b11b7f69 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/__init__.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/__init__.py @@ -7,6 +7,7 @@ from .version import VERSION from .queue_client import QueueClient from .queue_service_client import QueueServiceClient +from ._shared_access_signature import generate_account_sas, generate_queue_sas from ._shared.policies import ExponentialRetry, LinearRetry from ._shared.models import( LocationMode, @@ -58,4 +59,6 @@ 'Metrics', 'CorsRule', 'RetentionPolicy', + 'generate_account_sas', + 'generate_queue_sas' ] diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py index 85111a60c90a..7e416c7e9569 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/base_client.py @@ -64,7 +64,7 @@ } -class StorageAccountHostsMixin(object): +class StorageAccountHostsMixin(object): # pylint: disable=too-many-instance-attributes def __init__( self, parsed_url, # type: Any @@ -80,11 +80,14 @@ def __init__( if service not in ["blob", "queue", "file"]: raise ValueError("Invalid service: {}".format(service)) account = parsed_url.netloc.split(".{}.core.".format(service)) + self.account_name = account[0] secondary_hostname = None + self.credential = format_shared_key_credential(account, credential) if self.scheme.lower() != "https" and hasattr(self.credential, "get_token"): raise ValueError("Token credential is only supported with HTTPS.") if hasattr(self.credential, "account_name"): + self.account_name = self.credential.account_name secondary_hostname = "{}-secondary.{}.{}".format(self.credential.account_name, service, SERVICE_HOST_BASE) if not self._hosts: @@ -189,7 +192,8 @@ def _create_pipeline(self, credential, **kwargs): return config, Pipeline(config.transport, policies=policies) def _batch_send( - self, *reqs # type: HttpRequest + self, *reqs, # type: HttpRequest + **kwargs ): """Given a series of request, do a Storage batch call. """ @@ -209,7 +213,7 @@ def _batch_send( ) pipeline_response = self._pipeline.run( - request, + request, **kwargs ) response = pipeline_response.http_response diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/models.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/models.py index b8078927e0de..6ddfaee28734 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/models.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/models.py @@ -261,8 +261,8 @@ def from_string(cls, string): class AccountSasPermissions(object): """ - :class:`~ResourceTypes` class to be used with generate_shared_access_signature - method and for the AccessPolicies used with set_*_acl. There are two types of + :class:`~ResourceTypes` class to be used with generate_account_sas + function and for the AccessPolicies used with set_*_acl. There are two types of SAS which may be used to grant resource access. One is to grant access to a specific resource (resource-specific). Another is to grant access to the entire service for a specific account and allow certain operations based on diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/request_handlers.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/request_handlers.py index 57e3521fb192..873c67dd8e4f 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/request_handlers.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/request_handlers.py @@ -17,7 +17,6 @@ from azure.core.configuration import Configuration from azure.core.exceptions import raise_with_traceback -from azure.core.pipeline import Pipeline _LOGGER = logging.getLogger(__name__) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/uploads.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/uploads.py index 6ed1f9084df5..032915c06e2d 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/uploads.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/uploads.py @@ -395,7 +395,7 @@ def flush(self): pass def read(self, size=None): - if self.closed: + if self.closed: # pylint: disable=using-constant-test raise ValueError("Stream is closed.") if size is None: diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared_access_signature.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared_access_signature.py index 827d00c77084..29b0e8f2b9c7 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared_access_signature.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared_access_signature.py @@ -6,6 +6,7 @@ from azure.storage.queue._shared import sign_string from azure.storage.queue._shared.constants import X_MS_VERSION +from azure.storage.queue._shared.models import Services from azure.storage.queue._shared.shared_access_signature import SharedAccessSignature, _SharedAccessHelper, \ QueryStringConstants @@ -108,3 +109,142 @@ def get_value_to_append(query): self._add_query(QueryStringConstants.SIGNED_SIGNATURE, sign_string(account_key, string_to_sign)) + + +def generate_account_sas( + account_name, # type: str + account_key, # type: str + resource_types, # type: Union[ResourceTypes, str] + permission, # type: Union[AccountSasPermissions, str] + expiry, # type: Optional[Union[datetime, str]] + start=None, # type: Optional[Union[datetime, str]] + ip=None, # type: Optional[str] + **kwargs # type: Any + ): # type: (...) -> str + """Generates a shared access signature for the queue service. + + Use the returned signature with the credential parameter of any Queue Service. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str account_key: + The access key to generate the shared access signature. + :param ~azure.storage.queue.ResourceTypes resource_types: + Specifies the resource types that are accessible with the account SAS. + :param ~azure.storage.queue.AccountSasPermissions permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. Azure will always convert values + to UTC. If a date is passed in without timezone info, it is assumed to + be UTC. + :type start: ~datetime.datetime or str + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :return: A Shared Access Signature (sas) token. + :rtype: str + """ + sas = SharedAccessSignature(account_name, account_key) + return sas.generate_account( + services=Services(queue=True), + resource_types=resource_types, + permission=permission, + expiry=expiry, + start=start, + ip=ip, + **kwargs + ) # type: ignore + + +def generate_queue_sas( + account_name, # type: str + queue_name, # type: str + account_key, # type: str + permission=None, # type: Optional[Union[QueueSasPermissions, str]] + expiry=None, # type: Optional[Union[datetime, str]] + start=None, # type: Optional[Union[datetime, str]] + policy_id=None, # type: Optional[str] + ip=None, # type: Optional[str] + **kwargs # type: Any + ): # type: (...) -> str + """Generates a shared access signature for a queue. + + Use the returned signature with the credential parameter of any Queue Service. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str queue_name: + The name of the queue. + :param str account_key: + The access key to generate the shared access signature. + :param ~azure.storage.queue.QueueSasPermissions permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Required unless a policy_id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless a policy_id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. Azure will always convert values + to UTC. If a date is passed in without timezone info, it is assumed to + be UTC. + :type start: datetime or str + :param str policy_id: + A unique value up to 64 characters in length that correlates to a + stored access policy. To create a stored access policy, use + :func:`~azure.storage.queue.QueueClient.set_queue_access_policy`. + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip='168.1.5.65' or sip='168.1.5.60-168.1.5.70' on the SAS + restricts the request to those IP addresses. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :return: A Shared Access Signature (sas) token. + :rtype: str + + .. admonition:: Example: + + .. literalinclude:: ../tests/test_queue_samples_message.py + :start-after: [START queue_client_sas_token] + :end-before: [END queue_client_sas_token] + :language: python + :dedent: 12 + :caption: Generate a sas token. + """ + sas = QueueSharedAccessSignature(account_name, account_key) + return sas.generate_queue( + queue_name, + permission=permission, + expiry=expiry, + start=start, + policy_id=policy_id, + ip=ip, + **kwargs + ) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/models.py b/sdk/storage/azure-storage-queue/azure/storage/queue/models.py index d0eef3d745f0..c9effe089491 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/models.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/models.py @@ -332,10 +332,9 @@ def _extract_data_cb(self, get_next_return): class QueueSasPermissions(object): - """QueueSasPermissions class to be used with - :func:`~azure.storage.queue.queue_client.QueueClient.generate_shared_access_signature` - method and for the AccessPolicies used with - :func:`~azure.storage.queue.queue_client.QueueClient.set_queue_access_policy`. + """QueueSasPermissions class to be used with the + :func:`~azure.storage.queue.generate_queue_sas` function and for the AccessPolicies used with + :func:`~azure.storage.queue.QueueClient.set_queue_access_policy`. :param bool read: Read metadata and properties, including message count. Peek at messages. diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/queue_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/queue_client.py index eca9d20e9a90..8fbef4de4fa4 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/queue_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/queue_client.py @@ -30,13 +30,12 @@ from ._generated.models import StorageErrorException, SignedIdentifier from ._generated.models import QueueMessage as GenQueueMessage -from ._shared_access_signature import QueueSharedAccessSignature from .models import QueueMessage, AccessPolicy, MessagesPaged if TYPE_CHECKING: from datetime import datetime from azure.core.pipeline.policies import HTTPPolicy - from .models import QueueSasPermissions, QueueProperties + from .models import QueueProperties class QueueClient(StorageAccountHostsMixin): @@ -192,77 +191,6 @@ def from_connection_string( kwargs['secondary_hostname'] = secondary return cls(account_url, queue_name=queue_name, credential=credential, **kwargs) # type: ignore - def generate_shared_access_signature( - self, permission=None, # type: Optional[Union[QueueSasPermissions, str]] - expiry=None, # type: Optional[Union[datetime, str]] - start=None, # type: Optional[Union[datetime, str]] - policy_id=None, # type: Optional[str] - ip=None, # type: Optional[str] - **kwargs # type: Any - ): # type: (...) -> str - """Generates a shared access signature for the queue. - - Use the returned signature with the credential parameter of any Queue Service. - - :param ~azure.storage.queue.QueueSasPermissions permission: - The permissions associated with the shared access signature. The - user is restricted to operations allowed by the permissions. - Required unless a policy_id is given referencing a stored access policy - which contains this field. This field must be omitted if it has been - specified in an associated stored access policy. - :param expiry: - The time at which the shared access signature becomes invalid. - Required unless a policy_id is given referencing a stored access policy - which contains this field. This field must be omitted if it has - been specified in an associated stored access policy. Azure will always - convert values to UTC. If a date is passed in without timezone info, it - is assumed to be UTC. - :type expiry: datetime or str - :param start: - The time at which the shared access signature becomes valid. If - omitted, start time for this call is assumed to be the time when the - storage service receives the request. Azure will always convert values - to UTC. If a date is passed in without timezone info, it is assumed to - be UTC. - :type start: datetime or str - :param str policy_id: - A unique value up to 64 characters in length that correlates to a - stored access policy. To create a stored access policy, use :func:`~set_queue_access_policy`. - :param str ip: - Specifies an IP address or a range of IP addresses from which to accept requests. - If the IP address from which the request originates does not match the IP address - or address range specified on the SAS token, the request is not authenticated. - For example, specifying sip='168.1.5.65' or sip='168.1.5.60-168.1.5.70' on the SAS - restricts the request to those IP addresses. - :keyword str protocol: - Specifies the protocol permitted for a request made. The default value is https. - :return: A Shared Access Signature (sas) token. - :rtype: str - - .. admonition:: Example: - - .. literalinclude:: ../tests/test_queue_samples_message.py - :start-after: [START queue_client_sas_token] - :end-before: [END queue_client_sas_token] - :language: python - :dedent: 12 - :caption: Generate a sas token. - """ - protocol = kwargs.pop('protocol', None) - if not hasattr(self.credential, 'account_key') and not self.credential.account_key: - raise ValueError("No account SAS key available.") - sas = QueueSharedAccessSignature( - self.credential.account_name, self.credential.account_key) - return sas.generate_queue( - self.queue_name, - permission=permission, - expiry=expiry, - start=start, - policy_id=policy_id, - ip=ip, - protocol=protocol, - ) - @distributed_trace def create_queue(self, **kwargs): # type: (Optional[Any]) -> None diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/queue_service_client.py b/sdk/storage/azure-storage-queue/azure/storage/queue/queue_service_client.py index 16446c471b58..a7eeec5cd657 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/queue_service_client.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/queue_service_client.py @@ -15,8 +15,7 @@ from azure.core.paging import ItemPaged from azure.core.tracing.decorator import distributed_trace -from ._shared.shared_access_signature import SharedAccessSignature -from ._shared.models import LocationMode, Services +from ._shared.models import LocationMode from ._shared.base_client import StorageAccountHostsMixin, parse_connection_str, parse_query from ._shared.response_handlers import process_storage_error from ._generated import AzureQueueStorage @@ -29,7 +28,6 @@ from datetime import datetime from azure.core.configuration import Configuration from azure.core.pipeline.policies import HTTPPolicy - from ._shared.models import AccountSasPermissions, ResourceTypes from .models import ( QueueProperties, QueueAnalyticsLogging, @@ -149,64 +147,6 @@ def from_connection_string( kwargs['secondary_hostname'] = secondary return cls(account_url, credential=credential, **kwargs) - def generate_shared_access_signature( - self, resource_types, # type: Union[ResourceTypes, str] - permission, # type: Union[AccountSasPermissions, str] - expiry, # type: Optional[Union[datetime, str]] - start=None, # type: Optional[Union[datetime, str]] - ip=None, # type: Optional[str] - **kwargs # type: Any - ): # type: (...) -> str - """Generates a shared access signature for the queue service. - - Use the returned signature with the credential parameter of any Queue Service. - - :param ~azure.storage.queue.ResourceTypes resource_types: - Specifies the resource types that are accessible with the account SAS. - :param ~azure.storage.queue.AccountSasPermissions permission: - The permissions associated with the shared access signature. The - user is restricted to operations allowed by the permissions. - :param expiry: - The time at which the shared access signature becomes invalid. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has - been specified in an associated stored access policy. Azure will always - convert values to UTC. If a date is passed in without timezone info, it - is assumed to be UTC. - :type expiry: ~datetime.datetime or str - :param start: - The time at which the shared access signature becomes valid. If - omitted, start time for this call is assumed to be the time when the - storage service receives the request. Azure will always convert values - to UTC. If a date is passed in without timezone info, it is assumed to - be UTC. - :type start: ~datetime.datetime or str - :param str ip: - Specifies an IP address or a range of IP addresses from which to accept requests. - If the IP address from which the request originates does not match the IP address - or address range specified on the SAS token, the request is not authenticated. - For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS - restricts the request to those IP addresses. - :keyword str protocol: - Specifies the protocol permitted for a request made. The default value is https. - :return: A Shared Access Signature (sas) token. - :rtype: str - """ - protocol = kwargs.pop('protocol', None) - if not hasattr(self.credential, 'account_key') and not self.credential.account_key: - raise ValueError("No account SAS key available.") - - sas = SharedAccessSignature(self.credential.account_name, self.credential.account_key) - return sas.generate_account( - services=Services(queue=True), - resource_types=resource_types, - permission=permission, - expiry=expiry, - start=start, - ip=ip, - protocol=protocol - ) # type: ignore - @distributed_trace def get_service_stats(self, **kwargs): # type: ignore # type: (Optional[Any]) -> Dict[str, Any] diff --git a/sdk/storage/azure-storage-queue/tests/test_queue.py b/sdk/storage/azure-storage-queue/tests/test_queue.py index 0525c6f644a2..35f3410b1b55 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue.py @@ -31,6 +31,8 @@ AccessPolicy, ResourceTypes, AccountSasPermissions, + generate_account_sas, + generate_queue_sas ) from queuetestcase import ( @@ -541,7 +543,9 @@ def test_account_sas(self, resource_group, location, storage_account, storage_ac queue_client = self._get_queue_reference(qsc) queue_client.create_queue() queue_client.send_message(u'message1') - token = qsc.generate_shared_access_signature( + token = generate_account_sas( + qsc.account_name, + qsc.credential.account_key, ResourceTypes(object=True), AccountSasPermissions(read=True), datetime.utcnow() + timedelta(hours=1), @@ -599,7 +603,10 @@ def test_sas_read(self, resource_group, location, storage_account, storage_accou queue_client = self._get_queue_reference(qsc) queue_client.create_queue() queue_client.send_message(u'message1') - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, QueueSasPermissions(read=True), datetime.utcnow() + timedelta(hours=1), datetime.utcnow() - timedelta(minutes=5) @@ -631,7 +638,10 @@ def test_sas_add(self, resource_group, location, storage_account, storage_accoun qsc = QueueServiceClient(self._account_url(storage_account.name), storage_account_key) queue_client = self._get_queue_reference(qsc) queue_client.create_queue() - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, QueueSasPermissions(add=True), datetime.utcnow() + timedelta(hours=1), ) @@ -659,7 +669,10 @@ def test_sas_update(self, resource_group, location, storage_account, storage_acc queue_client = self._get_queue_reference(qsc) queue_client.create_queue() queue_client.send_message(u'message1') - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, QueueSasPermissions(update=True), datetime.utcnow() + timedelta(hours=1), ) @@ -694,7 +707,10 @@ def test_sas_process(self, resource_group, location, storage_account, storage_ac queue_client = self._get_queue_reference(qsc) queue_client.create_queue() queue_client.send_message(u'message1') - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, QueueSasPermissions(process=True), datetime.utcnow() + timedelta(hours=1), ) @@ -733,7 +749,10 @@ def test_sas_signed_identifier(self, resource_group, location, storage_account, queue_client.send_message(u'message1') - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, policy_id='testid' ) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_async.py index 3de50da06d05..874dbd59efd4 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_async.py @@ -28,6 +28,8 @@ AccessPolicy, ResourceTypes, AccountSasPermissions, + generate_account_sas, + generate_queue_sas ) from azure.storage.queue.aio import QueueServiceClient, QueueClient @@ -583,7 +585,9 @@ async def test_account_sas(self, resource_group, location, storage_account, stor # Arrange queue_client = await self._create_queue(qsc) await queue_client.send_message(u'message1') - token = qsc.generate_shared_access_signature( + token = generate_account_sas( + qsc.account_name, + qsc.credential.account_key, ResourceTypes(object=True), AccountSasPermissions(read=True), datetime.utcnow() + timedelta(hours=1), @@ -646,7 +650,10 @@ async def test_sas_read(self, resource_group, location, storage_account, storage # Arrange queue_client = await self._create_queue(qsc) await queue_client.send_message(u'message1') - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, QueueSasPermissions(read=True), datetime.utcnow() + timedelta(hours=1), datetime.utcnow() - timedelta(minutes=5) @@ -678,7 +685,10 @@ async def test_sas_add(self, resource_group, location, storage_account, storage_ # Arrange queue_client = await self._create_queue(qsc) - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, QueueSasPermissions(add=True), datetime.utcnow() + timedelta(hours=1), ) @@ -709,7 +719,10 @@ async def test_sas_update(self, resource_group, location, storage_account, stora # Arrange queue_client = await self._create_queue(qsc) await queue_client.send_message(u'message1') - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, QueueSasPermissions(update=True), datetime.utcnow() + timedelta(hours=1), ) @@ -749,7 +762,10 @@ async def test_sas_process(self, resource_group, location, storage_account, stor # Arrange queue_client = await self._create_queue(qsc) await queue_client.send_message(u'message1') - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, QueueSasPermissions(process=True), datetime.utcnow() + timedelta(hours=1), ) @@ -791,7 +807,10 @@ async def test_sas_signed_identifier(self, resource_group, location, storage_acc await queue_client.send_message(u'message1') - token = queue_client.generate_shared_access_signature( + token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, policy_id='testid' ) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_client.py b/sdk/storage/azure-storage-queue/tests/test_queue_client.py index 24f8cd082874..8d1d87e09f70 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_client.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_client.py @@ -35,6 +35,7 @@ def setUp(self): # --Helpers----------------------------------------------------------------- def validate_standard_account_endpoints(self, service, url_type, account_name, account_key): self.assertIsNotNone(service) + self.assertEqual(service.account_name, account_name) self.assertEqual(service.credential.account_name, account_name) self.assertEqual(service.credential.account_key, account_key) self.assertTrue('{}.{}.core.windows.net'.format(account_name, url_type) in service.url) @@ -80,6 +81,7 @@ def test_create_service_with_sas(self, resource_group, location, storage_account # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertTrue(service.url.startswith('https://' + storage_account.name + '.queue.core.windows.net')) self.assertTrue(service.url.endswith(self.sas_token)) self.assertIsNone(service.credential) @@ -94,6 +96,7 @@ def test_create_service_with_token(self, resource_group, location, storage_accou # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertTrue(service.url.startswith('https://' + storage_account.name + '.queue.core.windows.net')) self.assertEqual(service.credential, self.token_credential) self.assertFalse(hasattr(service.credential, 'account_key')) @@ -121,6 +124,7 @@ def test_create_service_china(self, resource_group, location, storage_account, s # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith( @@ -202,6 +206,7 @@ def test_create_service_with_connection_string_sas(self, resource_group, locatio # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertTrue(service.url.startswith('https://' + storage_account.name + '.queue.core.windows.net')) self.assertTrue(service.url.endswith(self.sas_token)) self.assertIsNone(service.credential) @@ -219,6 +224,7 @@ def test_create_service_with_connection_string_endpoint_protocol(self, resource_ # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue( @@ -253,6 +259,7 @@ def test_create_service_with_connection_string_custom_domain(self, resource_grou # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -271,6 +278,7 @@ def test_create_service_with_conn_str_custom_domain_trailing_slash(self, resourc # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -290,6 +298,7 @@ def test_create_service_with_conn_str_custom_domain_sec_override(self, resource_ # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -326,6 +335,7 @@ def test_create_service_with_conn_str_succeeds_if_sec_with_primary(self, resourc # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_client_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_client_async.py index efbe15f3c359..8fd9ae2c9a78 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_client_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_client_async.py @@ -49,6 +49,7 @@ def setUp(self): # --Helpers----------------------------------------------------------------- def validate_standard_account_endpoints(self, service, url_type, storage_account, storage_account_key): self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue('{}.{}.core.windows.net'.format(storage_account.name, url_type) in service.url) @@ -94,6 +95,7 @@ def test_create_service_with_sas(self, resource_group, location, storage_account # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertTrue(service.url.startswith('https://' + storage_account.name + '.queue.core.windows.net')) self.assertTrue(service.url.endswith(self.sas_token)) self.assertIsNone(service.credential) @@ -108,6 +110,7 @@ def test_create_service_with_token(self, resource_group, location, storage_accou # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertTrue(service.url.startswith('https://' + storage_account.name + '.queue.core.windows.net')) self.assertEqual(service.credential, self.token_credential) self.assertFalse(hasattr(service.credential, 'account_key')) @@ -135,6 +138,7 @@ def test_create_service_china(self, resource_group, location, storage_account, s # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith( @@ -216,6 +220,7 @@ def test_create_service_with_connection_string_sas(self, resource_group, locatio # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertTrue(service.url.startswith('https://' + storage_account.name + '.queue.core.windows.net')) self.assertTrue(service.url.endswith(self.sas_token)) self.assertIsNone(service.credential) @@ -233,6 +238,7 @@ def test_create_service_with_conn_str_endpoint_protocol(self, resource_group, lo # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue( @@ -267,6 +273,7 @@ def test_create_service_with_connection_string_custom_domain(self, resource_grou # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -285,6 +292,7 @@ def test_create_serv_with_cs_custom_dmn_trlng_slash(self, resource_group, locati # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -305,6 +313,7 @@ def test_create_service_with_cs_custom_dmn_sec_override(self, resource_group, lo # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) @@ -341,6 +350,7 @@ def test_create_service_with_cs_succeeds_if_sec_with_prim(self, resource_group, # Assert self.assertIsNotNone(service) + self.assertEqual(service.account_name, storage_account.name) self.assertEqual(service.credential.account_name, storage_account.name) self.assertEqual(service.credential.account_key, storage_account_key) self.assertTrue(service.primary_endpoint.startswith('https://www.mydomain.com/')) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_samples_authentication.py b/sdk/storage/azure-storage-queue/tests/test_queue_samples_authentication.py index a24332962c37..92999b0f9dc6 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_samples_authentication.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_samples_authentication.py @@ -91,7 +91,11 @@ def test_auth_shared_access_signature(self, resource_group, location, storage_ac queue_service = QueueServiceClient.from_connection_string(connection_string) # Create a SAS token to use for authentication of a client - sas_token = queue_service.generate_shared_access_signature( + from azure.storage.queue import generate_account_sas + + sas_token = generate_account_sas( + queue_service.account_name, + queue_service.credential.account_key, resource_types="object", permission="read", expiry=datetime.utcnow() + timedelta(hours=1) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_samples_authentication_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_samples_authentication_async.py index ee58bf06fb6e..3ba2722dbcae 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_samples_authentication_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_samples_authentication_async.py @@ -87,7 +87,11 @@ async def test_auth_shared_access_signature(self, resource_group, location, stor queue_service = QueueServiceClient(self._account_url(storage_account.name), storage_account_key) # Create a SAS token to use for authentication of a client - sas_token = queue_service.generate_shared_access_signature( + from azure.storage.queue import generate_account_sas + + sas_token = generate_account_sas( + queue_service.account_name, + queue_service.credential.account_key, resource_types="object", permission="read", expiry=datetime.utcnow() + timedelta(hours=1) diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_samples_message.py b/sdk/storage/azure-storage-queue/tests/test_queue_samples_message.py index fbf77f25bfd5..5f3c50ba0e2b 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_samples_message.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_samples_message.py @@ -52,7 +52,12 @@ def test_set_access_policy(self, resource_group, location, storage_account, stor # Use the access policy to generate a SAS token # [START queue_client_sas_token] - sas_token = queue_client.generate_shared_access_signature( + from azure.storage.queue import generate_queue_sas + + sas_token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, policy_id='my-access-policy-id' ) # [END queue_client_sas_token] diff --git a/sdk/storage/azure-storage-queue/tests/test_queue_samples_message_async.py b/sdk/storage/azure-storage-queue/tests/test_queue_samples_message_async.py index b034a121bb65..f356d700a5ac 100644 --- a/sdk/storage/azure-storage-queue/tests/test_queue_samples_message_async.py +++ b/sdk/storage/azure-storage-queue/tests/test_queue_samples_message_async.py @@ -51,7 +51,12 @@ async def test_set_access_policy(self, resource_group, location, storage_account # [END async_set_access_policy] # Use the access policy to generate a SAS token - sas_token = queue_client.generate_shared_access_signature( + from azure.storage.queue import generate_queue_sas + + sas_token = generate_queue_sas( + queue_client.account_name, + queue_client.queue_name, + queue_client.credential.account_key, policy_id='my-access-policy-id' ) # [END async_set_access_policy]