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# -------------------------------------------------------------------------- 6from sys import version_info 7 8if version_info < (3,): 9 def _str(value): 10 if isinstance(value, unicode): 11 return value.encode('utf-8') 12 13 return str(value) 14else: 15 _str = str 16 17 18def _to_str(value): 19 return _str(value) if value is not None else None 20 21 22from azure.common import ( 23 AzureHttpError, 24 AzureConflictHttpError, 25 AzureMissingResourceHttpError, 26 AzureException, 27) 28from ._constants import ( 29 _ENCRYPTION_PROTOCOL_V1, 30) 31 32_ERROR_CONFLICT = 'Conflict ({0})' 33_ERROR_NOT_FOUND = 'Not found ({0})' 34_ERROR_UNKNOWN = 'Unknown error ({0})' 35_ERROR_STORAGE_MISSING_INFO = \ 36 'You need to provide an account name and either an account_key or sas_token when creating a storage service.' 37_ERROR_EMULATOR_DOES_NOT_SUPPORT_FILES = \ 38 'The emulator does not support the file service.' 39_ERROR_ACCESS_POLICY = \ 40 'share_access_policy must be either SignedIdentifier or AccessPolicy ' + \ 41 'instance' 42_ERROR_PARALLEL_NOT_SEEKABLE = 'Parallel operations require a seekable stream.' 43_ERROR_VALUE_SHOULD_BE_BYTES = '{0} should be of type bytes.' 44_ERROR_VALUE_SHOULD_BE_BYTES_OR_STREAM = '{0} should be of type bytes or a readable file-like/io.IOBase stream object.' 45_ERROR_VALUE_SHOULD_BE_SEEKABLE_STREAM = '{0} should be a seekable file-like/io.IOBase type stream object.' 46_ERROR_VALUE_SHOULD_BE_STREAM = '{0} should be a file-like/io.IOBase type stream object with a read method.' 47_ERROR_VALUE_NONE = '{0} should not be None.' 48_ERROR_VALUE_NONE_OR_EMPTY = '{0} should not be None or empty.' 49_ERROR_VALUE_NEGATIVE = '{0} should not be negative.' 50_ERROR_START_END_NEEDED_FOR_MD5 = \ 51 'Both end_range and start_range need to be specified ' + \ 52 'for getting content MD5.' 53_ERROR_RANGE_TOO_LARGE_FOR_MD5 = \ 54 'Getting content MD5 for a range greater than 4MB ' + \ 55 'is not supported.' 56_ERROR_MD5_MISMATCH = \ 57 'MD5 mismatch. Expected value is \'{0}\', computed value is \'{1}\'.' 58_ERROR_TOO_MANY_ACCESS_POLICIES = \ 59 'Too many access policies provided. The server does not support setting more than 5 access policies on a single resource.' 60_ERROR_OBJECT_INVALID = \ 61 '{0} does not define a complete interface. Value of {1} is either missing or invalid.' 62_ERROR_UNSUPPORTED_ENCRYPTION_VERSION = \ 63 'Encryption version is not supported.' 64_ERROR_DECRYPTION_FAILURE = \ 65 'Decryption failed' 66_ERROR_ENCRYPTION_REQUIRED = \ 67 'Encryption required but no key was provided.' 68_ERROR_DECRYPTION_REQUIRED = \ 69 'Decryption required but neither key nor resolver was provided.' + \ 70 ' If you do not want to decypt, please do not set the require encryption flag.' 71_ERROR_INVALID_KID = \ 72 'Provided or resolved key-encryption-key does not match the id of key used to encrypt.' 73_ERROR_UNSUPPORTED_ENCRYPTION_ALGORITHM = \ 74 'Specified encryption algorithm is not supported.' 75_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION = 'The require_encryption flag is set, but encryption is not supported' + \ 76 ' for this method.' 77_ERROR_UNKNOWN_KEY_WRAP_ALGORITHM = 'Unknown key wrap algorithm.' 78_ERROR_DATA_NOT_ENCRYPTED = 'Encryption required, but received data does not contain appropriate metatadata.' + \ 79 'Data was either not encrypted or metadata has been lost.' 80 81 82def _dont_fail_on_exist(error): 83 ''' don't throw exception if the resource exists. 84 This is called by create_* APIs with fail_on_exist=False''' 85 if isinstance(error, AzureConflictHttpError): 86 return False 87 else: 88 raise error 89 90 91def _dont_fail_not_exist(error): 92 ''' don't throw exception if the resource doesn't exist. 93 This is called by create_* APIs with fail_on_exist=False''' 94 if isinstance(error, AzureMissingResourceHttpError): 95 return False 96 else: 97 raise error 98 99 100def _http_error_handler(http_error): 101 ''' Simple error handler for azure.''' 102 message = str(http_error) 103 error_code = None 104 105 if 'x-ms-error-code' in http_error.respheader: 106 error_code = http_error.respheader['x-ms-error-code'] 107 message += ' ErrorCode: ' + error_code 108 109 if http_error.respbody is not None: 110 message += '\n' + http_error.respbody.decode('utf-8-sig') 111 112 ex = AzureHttpError(message, http_error.status) 113 ex.error_code = error_code 114 115 raise ex 116 117 118def _validate_type_bytes(param_name, param): 119 if not isinstance(param, bytes): 120 raise TypeError(_ERROR_VALUE_SHOULD_BE_BYTES.format(param_name)) 121 122 123def _validate_type_bytes_or_stream(param_name, param): 124 if not (isinstance(param, bytes) or hasattr(param, 'read')): 125 raise TypeError(_ERROR_VALUE_SHOULD_BE_BYTES_OR_STREAM.format(param_name)) 126 127 128def _validate_not_none(param_name, param): 129 if param is None: 130 raise ValueError(_ERROR_VALUE_NONE.format(param_name)) 131 132 133def _validate_content_match(server_md5, computed_md5): 134 if server_md5 != computed_md5: 135 raise AzureException(_ERROR_MD5_MISMATCH.format(server_md5, computed_md5)) 136 137 138def _validate_access_policies(identifiers): 139 if identifiers and len(identifiers) > 5: 140 raise AzureException(_ERROR_TOO_MANY_ACCESS_POLICIES) 141 142 143def _validate_key_encryption_key_wrap(kek): 144 # Note that None is not callable and so will fail the second clause of each check. 145 if not hasattr(kek, 'wrap_key') or not callable(kek.wrap_key): 146 raise AttributeError(_ERROR_OBJECT_INVALID.format('key encryption key', 'wrap_key')) 147 if not hasattr(kek, 'get_kid') or not callable(kek.get_kid): 148 raise AttributeError(_ERROR_OBJECT_INVALID.format('key encryption key', 'get_kid')) 149 if not hasattr(kek, 'get_key_wrap_algorithm') or not callable(kek.get_key_wrap_algorithm): 150 raise AttributeError(_ERROR_OBJECT_INVALID.format('key encryption key', 'get_key_wrap_algorithm')) 151 152 153def _validate_key_encryption_key_unwrap(kek): 154 if not hasattr(kek, 'get_kid') or not callable(kek.get_kid): 155 raise AttributeError(_ERROR_OBJECT_INVALID.format('key encryption key', 'get_kid')) 156 if not hasattr(kek, 'unwrap_key') or not callable(kek.unwrap_key): 157 raise AttributeError(_ERROR_OBJECT_INVALID.format('key encryption key', 'unwrap_key')) 158 159 160def _validate_encryption_required(require_encryption, kek): 161 if require_encryption and (kek is None): 162 raise ValueError(_ERROR_ENCRYPTION_REQUIRED) 163 164 165def _validate_decryption_required(require_encryption, kek, resolver): 166 if (require_encryption and (kek is None) and 167 (resolver is None)): 168 raise ValueError(_ERROR_DECRYPTION_REQUIRED) 169 170 171def _validate_encryption_protocol_version(encryption_protocol): 172 if not (_ENCRYPTION_PROTOCOL_V1 == encryption_protocol): 173 raise ValueError(_ERROR_UNSUPPORTED_ENCRYPTION_VERSION) 174 175 176def _validate_kek_id(kid, resolved_id): 177 if not (kid == resolved_id): 178 raise ValueError(_ERROR_INVALID_KID) 179 180 181def _validate_encryption_unsupported(require_encryption, key_encryption_key): 182 if require_encryption or (key_encryption_key is not None): 183 raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION) 184 185 186def _validate_user_delegation_key(user_delegation_key): 187 _validate_not_none('user_delegation_key.signed_oid', user_delegation_key.signed_oid) 188 _validate_not_none('user_delegation_key.signed_tid', user_delegation_key.signed_tid) 189 _validate_not_none('user_delegation_key.signed_start', user_delegation_key.signed_start) 190 _validate_not_none('user_delegation_key.signed_expiry', user_delegation_key.signed_expiry) 191 _validate_not_none('user_delegation_key.signed_version', user_delegation_key.signed_version) 192 _validate_not_none('user_delegation_key.signed_service', user_delegation_key.signed_service) 193 _validate_not_none('user_delegation_key.value', user_delegation_key.value) 194 195 196# wraps a given exception with the desired exception type 197def _wrap_exception(ex, desired_type): 198 msg = "" 199 if len(ex.args) > 0: 200 msg = ex.args[0] 201 if version_info >= (3,): 202 # Automatic chaining in Python 3 means we keep the trace 203 return desired_type(msg) 204 else: 205 # There isn't a good solution in 2 for keeping the stack trace 206 # in general, or that will not result in an error in 3 207 # However, we can keep the previous error type and message 208 # TODO: In the future we will log the trace 209 return desired_type('{}: {}'.format(ex.__class__.__name__, msg)) 210 211 212class AzureSigningError(AzureException): 213 """ 214 Represents a fatal error when attempting to sign a request. 215 In general, the cause of this exception is user error. For example, the given account key is not valid. 216 Please visit https://docs.microsoft.com/en-us/azure/storage/common/storage-create-storage-account for more info. 217 """ 218 pass 219