1# -------------------------------------------------------------------------
2# Copyright (c) Microsoft Corporation. All rights reserved.
3# Licensed under the MIT License. See License.txt in the project root for
4# license information.
5# --------------------------------------------------------------------------
6
7from typing import (  # pylint: disable=unused-import
8    Union, Optional, Any, List, TYPE_CHECKING
9)
10
11from ._shared import sign_string
12from ._shared.constants import X_MS_VERSION
13from ._shared.models import Services
14from ._shared.shared_access_signature import SharedAccessSignature, _SharedAccessHelper, QueryStringConstants
15from ._shared.parser import _str
16
17if TYPE_CHECKING:
18    from datetime import datetime
19    from .import (
20        ResourceTypes,
21        AccountSasPermissions,
22        ShareSasPermissions,
23        FileSasPermissions
24    )
25
26class FileSharedAccessSignature(SharedAccessSignature):
27    '''
28    Provides a factory for creating file and share access
29    signature tokens with a common account name and account key.  Users can either
30    use the factory or can construct the appropriate service and use the
31    generate_*_shared_access_signature method directly.
32    '''
33
34    def __init__(self, account_name, account_key):
35        '''
36        :param str account_name:
37            The storage account name used to generate the shared access signatures.
38        :param str account_key:
39            The access key to generate the shares access signatures.
40        '''
41        super(FileSharedAccessSignature, self).__init__(account_name, account_key, x_ms_version=X_MS_VERSION)
42
43    def generate_file(self, share_name, directory_name=None, file_name=None,
44                      permission=None, expiry=None, start=None, policy_id=None,
45                      ip=None, protocol=None, cache_control=None,
46                      content_disposition=None, content_encoding=None,
47                      content_language=None, content_type=None):
48        '''
49        Generates a shared access signature for the file.
50        Use the returned signature with the sas_token parameter of FileService.
51
52        :param str share_name:
53            Name of share.
54        :param str directory_name:
55            Name of directory. SAS tokens cannot be created for directories, so
56            this parameter should only be present if file_name is provided.
57        :param str file_name:
58            Name of file.
59        :param ~azure.storage.fileshare.FileSasPermissions permission:
60            The permissions associated with the shared access signature. The
61            user is restricted to operations allowed by the permissions.
62            Permissions must be ordered read, create, write, delete, list.
63            Required unless an id is given referencing a stored access policy
64            which contains this field. This field must be omitted if it has been
65            specified in an associated stored access policy.
66        :param expiry:
67            The time at which the shared access signature becomes invalid.
68            Required unless an id is given referencing a stored access policy
69            which contains this field. This field must be omitted if it has
70            been specified in an associated stored access policy. Azure will always
71            convert values to UTC. If a date is passed in without timezone info, it
72            is assumed to be UTC.
73        :type expiry: datetime or str
74        :param start:
75            The time at which the shared access signature becomes valid. If
76            omitted, start time for this call is assumed to be the time when the
77            storage service receives the request. Azure will always convert values
78            to UTC. If a date is passed in without timezone info, it is assumed to
79            be UTC.
80        :type start: datetime or str
81        :param str policy_id:
82            A unique value up to 64 characters in length that correlates to a
83            stored access policy. To create a stored access policy, use
84            set_file_service_properties.
85        :param str ip:
86            Specifies an IP address or a range of IP addresses from which to accept requests.
87            If the IP address from which the request originates does not match the IP address
88            or address range specified on the SAS token, the request is not authenticated.
89            For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
90            restricts the request to those IP addresses.
91        :param str protocol:
92            Specifies the protocol permitted for a request made. The default value
93            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
94        :param str cache_control:
95            Response header value for Cache-Control when resource is accessed
96            using this shared access signature.
97        :param str content_disposition:
98            Response header value for Content-Disposition when resource is accessed
99            using this shared access signature.
100        :param str content_encoding:
101            Response header value for Content-Encoding when resource is accessed
102            using this shared access signature.
103        :param str content_language:
104            Response header value for Content-Language when resource is accessed
105            using this shared access signature.
106        :param str content_type:
107            Response header value for Content-Type when resource is accessed
108            using this shared access signature.
109        '''
110        resource_path = share_name
111        if directory_name is not None:
112            resource_path += '/' + _str(directory_name) if directory_name is not None else None
113        resource_path += '/' + _str(file_name) if file_name is not None else None
114
115        sas = _FileSharedAccessHelper()
116        sas.add_base(permission, expiry, start, ip, protocol, self.x_ms_version)
117        sas.add_id(policy_id)
118        sas.add_resource('f')
119        sas.add_override_response_headers(cache_control, content_disposition,
120                                          content_encoding, content_language,
121                                          content_type)
122        sas.add_resource_signature(self.account_name, self.account_key, resource_path)
123
124        return sas.get_token()
125
126    def generate_share(self, share_name, permission=None, expiry=None,
127                       start=None, policy_id=None, ip=None, protocol=None,
128                       cache_control=None, content_disposition=None,
129                       content_encoding=None, content_language=None,
130                       content_type=None):
131        '''
132        Generates a shared access signature for the share.
133        Use the returned signature with the sas_token parameter of FileService.
134
135        :param str share_name:
136            Name of share.
137        :param ShareSasPermissions permission:
138            The permissions associated with the shared access signature. The
139            user is restricted to operations allowed by the permissions.
140            Permissions must be ordered read, create, write, delete, list.
141            Required unless an id is given referencing a stored access policy
142            which contains this field. This field must be omitted if it has been
143            specified in an associated stored access policy.
144        :param expiry:
145            The time at which the shared access signature becomes invalid.
146            Required unless an id is given referencing a stored access policy
147            which contains this field. This field must be omitted if it has
148            been specified in an associated stored access policy. Azure will always
149            convert values to UTC. If a date is passed in without timezone info, it
150            is assumed to be UTC.
151        :type expiry: datetime or str
152        :param start:
153            The time at which the shared access signature becomes valid. If
154            omitted, start time for this call is assumed to be the time when the
155            storage service receives the request. Azure will always convert values
156            to UTC. If a date is passed in without timezone info, it is assumed to
157            be UTC.
158        :type start: datetime or str
159        :param str policy_id:
160            A unique value up to 64 characters in length that correlates to a
161            stored access policy. To create a stored access policy, use
162            set_file_service_properties.
163        :param str ip:
164            Specifies an IP address or a range of IP addresses from which to accept requests.
165            If the IP address from which the request originates does not match the IP address
166            or address range specified on the SAS token, the request is not authenticated.
167            For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
168            restricts the request to those IP addresses.
169        :param str protocol:
170            Specifies the protocol permitted for a request made. The default value
171            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
172        :param str cache_control:
173            Response header value for Cache-Control when resource is accessed
174            using this shared access signature.
175        :param str content_disposition:
176            Response header value for Content-Disposition when resource is accessed
177            using this shared access signature.
178        :param str content_encoding:
179            Response header value for Content-Encoding when resource is accessed
180            using this shared access signature.
181        :param str content_language:
182            Response header value for Content-Language when resource is accessed
183            using this shared access signature.
184        :param str content_type:
185            Response header value for Content-Type when resource is accessed
186            using this shared access signature.
187        '''
188        sas = _FileSharedAccessHelper()
189        sas.add_base(permission, expiry, start, ip, protocol, self.x_ms_version)
190        sas.add_id(policy_id)
191        sas.add_resource('s')
192        sas.add_override_response_headers(cache_control, content_disposition,
193                                          content_encoding, content_language,
194                                          content_type)
195        sas.add_resource_signature(self.account_name, self.account_key, share_name)
196
197        return sas.get_token()
198
199
200class _FileSharedAccessHelper(_SharedAccessHelper):
201
202    def add_resource_signature(self, account_name, account_key, path):
203        def get_value_to_append(query):
204            return_value = self.query_dict.get(query) or ''
205            return return_value + '\n'
206
207        if path[0] != '/':
208            path = '/' + path
209
210        canonicalized_resource = '/file/' + account_name + path + '\n'
211
212        # Form the string to sign from shared_access_policy and canonicalized
213        # resource. The order of values is important.
214        string_to_sign = \
215            (get_value_to_append(QueryStringConstants.SIGNED_PERMISSION) +
216             get_value_to_append(QueryStringConstants.SIGNED_START) +
217             get_value_to_append(QueryStringConstants.SIGNED_EXPIRY) +
218             canonicalized_resource +
219             get_value_to_append(QueryStringConstants.SIGNED_IDENTIFIER) +
220             get_value_to_append(QueryStringConstants.SIGNED_IP) +
221             get_value_to_append(QueryStringConstants.SIGNED_PROTOCOL) +
222             get_value_to_append(QueryStringConstants.SIGNED_VERSION) +
223             get_value_to_append(QueryStringConstants.SIGNED_CACHE_CONTROL) +
224             get_value_to_append(QueryStringConstants.SIGNED_CONTENT_DISPOSITION) +
225             get_value_to_append(QueryStringConstants.SIGNED_CONTENT_ENCODING) +
226             get_value_to_append(QueryStringConstants.SIGNED_CONTENT_LANGUAGE) +
227             get_value_to_append(QueryStringConstants.SIGNED_CONTENT_TYPE))
228
229        # remove the trailing newline
230        if string_to_sign[-1] == '\n':
231            string_to_sign = string_to_sign[:-1]
232
233        self._add_query(QueryStringConstants.SIGNED_SIGNATURE,
234                        sign_string(account_key, string_to_sign))
235
236
237def generate_account_sas(
238        account_name,  # type: str
239        account_key,  # type: str
240        resource_types,  # type: Union[ResourceTypes, str]
241        permission,  # type: Union[AccountSasPermissions, str]
242        expiry,  # type: Optional[Union[datetime, str]]
243        start=None,  # type: Optional[Union[datetime, str]]
244        ip=None,  # type: Optional[str]
245        **kwargs  # type: Any
246    ):
247    # type: (...) -> str
248    """Generates a shared access signature for the file service.
249
250    Use the returned signature with the credential parameter of any ShareServiceClient,
251    ShareClient, ShareDirectoryClient, or ShareFileClient.
252
253    :param str account_name:
254        The storage account name used to generate the shared access signature.
255    :param str account_key:
256        The account key, also called shared key or access key, to generate the shared access signature.
257    :param ~azure.storage.fileshare.ResourceTypes resource_types:
258        Specifies the resource types that are accessible with the account SAS.
259    :param ~azure.storage.fileshare.AccountSasPermissions permission:
260        The permissions associated with the shared access signature. The
261        user is restricted to operations allowed by the permissions.
262        Required unless an id is given referencing a stored access policy
263        which contains this field. This field must be omitted if it has been
264        specified in an associated stored access policy.
265    :param expiry:
266        The time at which the shared access signature becomes invalid.
267        Required unless an id is given referencing a stored access policy
268        which contains this field. This field must be omitted if it has
269        been specified in an associated stored access policy. Azure will always
270        convert values to UTC. If a date is passed in without timezone info, it
271        is assumed to be UTC.
272    :type expiry: ~datetime.datetime or str
273    :param start:
274        The time at which the shared access signature becomes valid. If
275        omitted, start time for this call is assumed to be the time when the
276        storage service receives the request. Azure will always convert values
277        to UTC. If a date is passed in without timezone info, it is assumed to
278        be UTC.
279    :type start: ~datetime.datetime or str
280    :param str ip:
281        Specifies an IP address or a range of IP addresses from which to accept requests.
282        If the IP address from which the request originates does not match the IP address
283        or address range specified on the SAS token, the request is not authenticated.
284        For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
285        restricts the request to those IP addresses.
286    :keyword str protocol:
287        Specifies the protocol permitted for a request made. The default value is https.
288    :return: A Shared Access Signature (sas) token.
289    :rtype: str
290
291    .. admonition:: Example:
292
293        .. literalinclude:: ../samples/file_samples_authentication.py
294            :start-after: [START generate_sas_token]
295            :end-before: [END generate_sas_token]
296            :language: python
297            :dedent: 8
298            :caption: Generate a sas token.
299    """
300    sas = SharedAccessSignature(account_name, account_key)
301    return sas.generate_account(
302        services=Services(fileshare=True),
303        resource_types=resource_types,
304        permission=permission,
305        expiry=expiry,
306        start=start,
307        ip=ip,
308        **kwargs
309    ) # type: ignore
310
311
312def generate_share_sas(
313        account_name,  # type: str
314        share_name,  # type: str
315        account_key,  # type: str
316        permission=None,  # type: Optional[Union[ShareSasPermissions, str]]
317        expiry=None,  # type: Optional[Union[datetime, str]]
318        start=None,  # type: Optional[Union[datetime, str]]
319        policy_id=None,  # type: Optional[str]
320        ip=None,  # type: Optional[str]
321        **kwargs # type: Any
322    ):  # type: (...) -> str
323    """Generates a shared access signature for a share.
324
325    Use the returned signature with the credential parameter of any ShareServiceClient,
326    ShareClient, ShareDirectoryClient, or ShareFileClient.
327
328    :param str account_name:
329        The storage account name used to generate the shared access signature.
330    :param str share_name:
331        The name of the share.
332    :param str account_key:
333        The account key, also called shared key or access key, to generate the shared access signature.
334    :param ~azure.storage.fileshare.ShareSasPermissions permission:
335        The permissions associated with the shared access signature. The
336        user is restricted to operations allowed by the permissions.
337        Permissions must be ordered read, create, write, delete, list.
338        Required unless an id is given referencing a stored access policy
339        which contains this field. This field must be omitted if it has been
340        specified in an associated stored access policy.
341    :param expiry:
342        The time at which the shared access signature becomes invalid.
343        Required unless an id is given referencing a stored access policy
344        which contains this field. This field must be omitted if it has
345        been specified in an associated stored access policy. Azure will always
346        convert values to UTC. If a date is passed in without timezone info, it
347        is assumed to be UTC.
348    :type expiry: ~datetime.datetime or str
349    :param start:
350        The time at which the shared access signature becomes valid. If
351        omitted, start time for this call is assumed to be the time when the
352        storage service receives the request. Azure will always convert values
353        to UTC. If a date is passed in without timezone info, it is assumed to
354        be UTC.
355    :type start: ~datetime.datetime or str
356    :param str policy_id:
357        A unique value up to 64 characters in length that correlates to a
358        stored access policy. To create a stored access policy, use
359        :func:`~azure.storage.fileshare.ShareClient.set_share_access_policy`.
360    :param str ip:
361        Specifies an IP address or a range of IP addresses from which to accept requests.
362        If the IP address from which the request originates does not match the IP address
363        or address range specified on the SAS token, the request is not authenticated.
364        For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
365        restricts the request to those IP addresses.
366    :keyword str cache_control:
367        Response header value for Cache-Control when resource is accessed
368        using this shared access signature.
369    :keyword str content_disposition:
370        Response header value for Content-Disposition when resource is accessed
371        using this shared access signature.
372    :keyword str content_encoding:
373        Response header value for Content-Encoding when resource is accessed
374        using this shared access signature.
375    :keyword str content_language:
376        Response header value for Content-Language when resource is accessed
377        using this shared access signature.
378    :keyword str content_type:
379        Response header value for Content-Type when resource is accessed
380        using this shared access signature.
381    :keyword str protocol:
382        Specifies the protocol permitted for a request made. The default value is https.
383    :return: A Shared Access Signature (sas) token.
384    :rtype: str
385    """
386    sas = FileSharedAccessSignature(account_name, account_key)
387    return sas.generate_share(
388        share_name=share_name,
389        permission=permission,
390        expiry=expiry,
391        start=start,
392        policy_id=policy_id,
393        ip=ip,
394        **kwargs
395    )
396
397
398def generate_file_sas(
399        account_name,  # type: str
400        share_name,  # type: str
401        file_path,  # type: List[str]
402        account_key,  # type: str
403        permission=None,  # type: Optional[Union[FileSasPermissions, str]]
404        expiry=None,  # type: Optional[Union[datetime, str]]
405        start=None,  # type: Optional[Union[datetime, str]]
406        policy_id=None,  # type: Optional[str]
407        ip=None,  # type: Optional[str]
408        **kwargs # type: Any
409    ):
410    # type: (...) -> str
411    """Generates a shared access signature for a file.
412
413    Use the returned signature with the credential parameter of any ShareServiceClient,
414    ShareClient, ShareDirectoryClient, or ShareFileClient.
415
416    :param str account_name:
417        The storage account name used to generate the shared access signature.
418    :param str share_name:
419        The name of the share.
420    :param file_path:
421        The file path represented as a list of path segments, including the file name.
422    :type file_path: List[str]
423    :param str account_key:
424        The account key, also called shared key or access key, to generate the shared access signature.
425    :param ~azure.storage.fileshare.FileSasPermissions permission:
426        The permissions associated with the shared access signature. The
427        user is restricted to operations allowed by the permissions.
428        Permissions must be ordered read, write, delete, list.
429        Required unless an id is given referencing a stored access policy
430        which contains this field. This field must be omitted if it has been
431        specified in an associated stored access policy.
432    :param expiry:
433        The time at which the shared access signature becomes invalid.
434        Required unless an id is given referencing a stored access policy
435        which contains this field. This field must be omitted if it has
436        been specified in an associated stored access policy. Azure will always
437        convert values to UTC. If a date is passed in without timezone info, it
438        is assumed to be UTC.
439    :type expiry: ~datetime.datetime or str
440    :param start:
441        The time at which the shared access signature becomes valid. If
442        omitted, start time for this call is assumed to be the time when the
443        storage service receives the request. Azure will always convert values
444        to UTC. If a date is passed in without timezone info, it is assumed to
445        be UTC.
446    :type start: ~datetime.datetime or str
447    :param str policy_id:
448        A unique value up to 64 characters in length that correlates to a
449        stored access policy.
450    :param str ip:
451        Specifies an IP address or a range of IP addresses from which to accept requests.
452        If the IP address from which the request originates does not match the IP address
453        or address range specified on the SAS token, the request is not authenticated.
454        For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
455        restricts the request to those IP addresses.
456    :keyword str cache_control:
457        Response header value for Cache-Control when resource is accessed
458        using this shared access signature.
459    :keyword str content_disposition:
460        Response header value for Content-Disposition when resource is accessed
461        using this shared access signature.
462    :keyword str content_encoding:
463        Response header value for Content-Encoding when resource is accessed
464        using this shared access signature.
465    :keyword str content_language:
466        Response header value for Content-Language when resource is accessed
467        using this shared access signature.
468    :keyword str content_type:
469        Response header value for Content-Type when resource is accessed
470        using this shared access signature.
471    :keyword str protocol:
472        Specifies the protocol permitted for a request made. The default value is https.
473    :return: A Shared Access Signature (sas) token.
474    :rtype: str
475    """
476    sas = FileSharedAccessSignature(account_name, account_key)
477    if len(file_path) > 1:
478        dir_path = '/'.join(file_path[:-1])
479    else:
480        dir_path = None # type: ignore
481    return sas.generate_file( # type: ignore
482        share_name=share_name,
483        directory_name=dir_path,
484        file_name=file_path[-1],
485        permission=permission,
486        expiry=expiry,
487        start=start,
488        policy_id=policy_id,
489        ip=ip,
490        **kwargs
491    )
492