providers.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. # -*- coding: utf-8 -*-
  2. import json
  3. import time
  4. import calendar
  5. import os
  6. try:
  7. from ConfigParser import ConfigParser
  8. except ImportError:
  9. from configparser import ConfigParser
  10. from Tea.vendored import requests
  11. from Tea.core import TeaCore
  12. from Tea.request import TeaRequest
  13. from alibabacloud_credentials.utils import auth_util as au, \
  14. auth_constant as ac, \
  15. parameter_helper as ph
  16. from alibabacloud_credentials.exceptions import CredentialException
  17. from alibabacloud_credentials.models import Config
  18. from alibabacloud_credentials import credentials
  19. class AlibabaCloudCredentialsProvider(object):
  20. """BaseProvider class"""
  21. duration_seconds = 3600
  22. timeout = 2000
  23. region_id = 'cn-hangzhou'
  24. def __init__(self, config=None):
  25. if isinstance(config, Config):
  26. self.type = config.type
  27. self.access_key_id = config.access_key_id
  28. self.access_key_secret = config.access_key_secret
  29. self.role_arn = config.role_arn
  30. self.role_session_name = config.role_session_name
  31. self.public_key_id = config.public_key_id
  32. self.role_name = config.role_name
  33. self.private_key_file = config.private_key_file
  34. self.bearer_token = config.bearer_token
  35. self.security_token = config.security_token
  36. self.host = config.host
  37. self.timeout = config.timeout + config.connect_timeout
  38. self.connect_timeout = config.connect_timeout
  39. self.proxy = config.proxy
  40. def _set_arg(self, key, value):
  41. if value is not None:
  42. setattr(self, key, value)
  43. val = getattr(self, key, None)
  44. if val is None:
  45. setattr(self, key, None)
  46. def _verify_empty_args(self, config=None, *args):
  47. if None in args and config is None:
  48. raise CredentialException(
  49. '"%s" needs to receive a "model.Config" object or other necessary args' % self.__class__
  50. )
  51. def get_credentials(self):
  52. raise NotImplementedError('get_credentials() must be overridden')
  53. class DefaultCredentialsProvider(AlibabaCloudCredentialsProvider):
  54. def __init__(self):
  55. super(DefaultCredentialsProvider, self).__init__()
  56. self.user_configuration_providers = [
  57. EnvironmentVariableCredentialsProvider(),
  58. ProfileCredentialsProvider()
  59. ]
  60. role_name = au.environment_ECSMeta_data
  61. if role_name is not None:
  62. self.user_configuration_providers.append(EcsRamRoleCredentialProvider(role_name))
  63. def get_credentials(self):
  64. for provider in self.user_configuration_providers:
  65. credential = provider.get_credentials()
  66. if credential is not None:
  67. return credential
  68. raise CredentialException("not found credentials")
  69. def add_credentials_provider(self, p):
  70. self.user_configuration_providers.append(p)
  71. def remove_credentials_provider(self, p):
  72. self.user_configuration_providers.remove(p)
  73. def contains_credentials_provider(self, p):
  74. return self.user_configuration_providers.__contains__(p)
  75. def clear_credentials_provider(self):
  76. self.user_configuration_providers = []
  77. class EcsRamRoleCredentialProvider(AlibabaCloudCredentialsProvider):
  78. """EcsRamRoleCredentialProvider"""
  79. def __init__(self, role_name=None, config=None):
  80. self._verify_empty_args(config, role_name)
  81. super(EcsRamRoleCredentialProvider, self).__init__(config)
  82. self.__url_in_ecs_metadata = "/latest/meta-data/ram/security-credentials/"
  83. self.__ecs_metadata_fetch_error_msg = "Failed to get RAM session credentials from ECS metadata service."
  84. self.__metadata_service_host = "100.100.100.200"
  85. self._set_arg('role_name', role_name)
  86. self._set_credential_url()
  87. def _get_role_name(self, url=None):
  88. url = url if url else self.credential_url
  89. response = requests.get(url, timeout=self.timeout / 1000)
  90. if response.status_code != 200:
  91. raise CredentialException(self.__ecs_metadata_fetch_error_msg + " HttpCode=" + str(response.status_code))
  92. response.encoding = 'utf-8'
  93. self.role_name = response.text
  94. def _create_credential(self, url=None):
  95. tea_request = TeaRequest()
  96. tea_request.headers['host'] = url if url else self.credential_url
  97. # request
  98. response = TeaCore.do_action(tea_request)
  99. if response.status_code != 200:
  100. raise CredentialException(self.__ecs_metadata_fetch_error_msg + " HttpCode=" + str(response.status_code))
  101. dic = json.loads(response.body.decode('utf-8'))
  102. content_code = dic.get('Code')
  103. content_access_key_id = dic.get('AccessKeyId')
  104. content_access_key_secret = dic.get('AccessKeySecret')
  105. content_security_token = dic.get('SecurityToken')
  106. content_expiration = dic.get('Expiration')
  107. if content_code != "Success":
  108. raise CredentialException(self.__ecs_metadata_fetch_error_msg)
  109. # 先转换为时间数组
  110. time_array = time.strptime(content_expiration, "%Y-%m-%dT%H:%M:%SZ")
  111. # 转换为时间戳
  112. time_stamp = calendar.timegm(time_array)
  113. return credentials.EcsRamRoleCredential(content_access_key_id, content_access_key_secret,
  114. content_security_token, time_stamp, self)
  115. def get_credentials(self):
  116. if self.role_name == "":
  117. self._get_role_name()
  118. self._set_credential_url()
  119. return self._create_credential()
  120. def _set_credential_url(self):
  121. self.credential_url = "http://" + self.__metadata_service_host + self.__url_in_ecs_metadata + self.role_name
  122. class RamRoleArnCredentialProvider(AlibabaCloudCredentialsProvider):
  123. """RamRoleArnCredentialProvider"""
  124. def __init__(self, access_key_id=None, access_key_secret=None, role_session_name=None, role_arn=None,
  125. region_id=None,
  126. policy=None, config=None):
  127. self._verify_empty_args(config, access_key_id, access_key_secret)
  128. super(RamRoleArnCredentialProvider, self).__init__(config)
  129. self._set_arg('role_arn', role_arn)
  130. self._set_arg('access_key_id', access_key_id)
  131. self._set_arg('access_key_secret', access_key_secret)
  132. self._set_arg('region_id', region_id)
  133. self._set_arg('role_session_name', role_session_name)
  134. self._set_arg('policy', policy)
  135. def get_credentials(self):
  136. return self._create_credentials()
  137. def _create_credentials(self, turl=None):
  138. # 获取credential 先实现签名用工具类
  139. tea_request = TeaRequest()
  140. tea_request.query = {
  141. 'Action': 'AssumeRole',
  142. 'Format': 'JSON',
  143. 'Version': '2015-04-01',
  144. 'DurationSeconds': str(self.duration_seconds),
  145. 'RoleArn': self.role_arn,
  146. 'AccessKeyId': self.access_key_id,
  147. 'RegionId': self.region_id,
  148. 'RoleSessionName': self.role_session_name
  149. }
  150. if self.policy is not None:
  151. tea_request.query["Policy"] = self.policy
  152. string_to_sign = ph.compose_string_to_sign("GET", tea_request.query)
  153. signature = ph.sign_string(string_to_sign, self.access_key_secret + "&")
  154. tea_request.query["Signature"] = signature
  155. tea_request.headers['host'] = turl if turl else 'https://sts.aliyuncs.com'
  156. # request
  157. response = TeaCore.do_action(tea_request)
  158. if response.status_code == 200:
  159. dic = json.loads(response.body.decode('utf-8'))
  160. if "Credentials" in dic:
  161. cre = dic.get("Credentials")
  162. # 先转换为时间数组
  163. time_array = time.strptime(cre.get("Expiration"), "%Y-%m-%dT%H:%M:%SZ")
  164. # 转换为时间戳
  165. expiration = calendar.timegm(time_array)
  166. return credentials.RamRoleArnCredential(cre.get("AccessKeyId"), cre.get("AccessKeySecret"),
  167. cre.get("SecurityToken"), expiration, self)
  168. raise CredentialException(response.body.decode('utf-8'))
  169. class RsaKeyPairCredentialProvider(AlibabaCloudCredentialsProvider):
  170. def __init__(self, access_key_id=None, access_key_secret=None, region_id=None, config=None):
  171. self._verify_empty_args(config, access_key_id, access_key_secret)
  172. super(RsaKeyPairCredentialProvider, self).__init__(config)
  173. self._set_arg('access_key_id', access_key_id)
  174. self._set_arg('access_key_secret', access_key_secret)
  175. self._set_arg('region_id', region_id)
  176. def get_credentials(self):
  177. return self._create_credential()
  178. def _create_credential(self, turl=None):
  179. tea_request = TeaRequest()
  180. tea_request.query = {
  181. 'Action': 'GenerateSessionAccessKey',
  182. 'Format': 'JSON',
  183. 'Version': '2015-04-01',
  184. 'DurationSeconds': str(self.duration_seconds),
  185. 'AccessKeyId': self.access_key_id,
  186. 'RegionId': self.region_id,
  187. }
  188. str_to_sign = ph.compose_string_to_sign('GET', tea_request.query)
  189. signature = ph.sign_string(str_to_sign, self.access_key_id + '&')
  190. tea_request.query['Signature'] = signature
  191. tea_request.headers['host'] = turl if turl else 'https://sts.aliyuncs.com'
  192. # request
  193. response = TeaCore.do_action(tea_request)
  194. if response.status_code == 200:
  195. dic = json.loads(response.body.decode('utf-8'))
  196. if "SessionAccessKey" in dic:
  197. cre = dic.get("SessionAccessKey")
  198. time_array = time.strptime(cre.get("Expiration"), "%Y-%m-%dT%H:%M:%SZ")
  199. expiration = calendar.timegm(time_array)
  200. return credentials.RsaKeyPairCredential(cre.get("SessionAccessKeyId"), cre.get("SessionAccessKeySecret"),
  201. expiration, self)
  202. raise CredentialException(response.body.decode('utf-8'))
  203. class ProfileCredentialsProvider(AlibabaCloudCredentialsProvider):
  204. def __init__(self, path=None):
  205. super(ProfileCredentialsProvider, self).__init__()
  206. self._set_arg('file_path', path)
  207. def get_credentials(self):
  208. file_path = self.file_path if self.file_path else au.environment_credentials_file
  209. if file_path is None:
  210. if not ac.HOME:
  211. return
  212. file_path = os.path.join(ac.HOME, "/.alibabacloud/credentials.ini")
  213. if len(file_path) == 0:
  214. raise CredentialException("The specified credentials file is empty")
  215. # loads ini
  216. conf = ConfigParser()
  217. conf.read(file_path)
  218. ini_map = dict(conf._sections)
  219. for k in dict(conf._sections):
  220. option = dict(ini_map[k])
  221. for key, value in dict(ini_map[k]).items():
  222. if '#' in value:
  223. option[key] = value.split('#')[0].strip()
  224. else:
  225. option[key] = value.strip()
  226. ini_map[k] = option
  227. client_config = ini_map.get(au.client_type)
  228. if client_config is None:
  229. return
  230. return self._create_credential(client_config)
  231. def _create_credential(self, config):
  232. config_type = config.get(ac.INI_TYPE)
  233. if not config_type:
  234. raise CredentialException("The configured client type is empty")
  235. elif ac.INI_TYPE_ARN == config_type:
  236. return self._get_sts_assume_role_session_credentials(config)
  237. elif ac.INI_TYPE_KEY_PAIR == config_type:
  238. return self._get_sts_get_session_access_key_credentials(config)
  239. elif ac.INI_TYPE_RAM == config_type:
  240. return self._get_instance_profile_credentials(config)
  241. access_key_id = config.get(ac.INI_ACCESS_KEY_ID)
  242. access_key_secret = config.get(ac.INI_ACCESS_KEY_IDSECRET)
  243. if not access_key_id or not access_key_secret:
  244. return
  245. return credentials.AccessKeyCredential(access_key_id, access_key_secret)
  246. @staticmethod
  247. def _get_sts_assume_role_session_credentials(config):
  248. access_key_id = config.get(ac.INI_ACCESS_KEY_ID)
  249. access_key_secret = config.get(ac.INI_ACCESS_KEY_IDSECRET)
  250. role_session_name = config.get(ac.INI_ROLE_SESSION_NAME)
  251. role_arn = config.get(ac.INI_ROLE_ARN)
  252. region_id = config.get(ac.DEFAULT_REGION)
  253. policy = config.get(ac.INI_POLICY)
  254. if not access_key_id or not access_key_secret:
  255. raise CredentialException("The configured access_key_id or access_key_secret is empty")
  256. if not role_session_name or not role_arn:
  257. raise CredentialException("The configured role_session_name or role_arn is empty")
  258. provider = RamRoleArnCredentialProvider(
  259. access_key_id, access_key_secret, role_session_name, role_arn, region_id, policy
  260. )
  261. return provider.get_credentials()
  262. @staticmethod
  263. def _get_sts_get_session_access_key_credentials(config):
  264. public_key_id = config.get(ac.INI_PUBLIC_KEY_ID)
  265. private_key_file = config.get(ac.INI_PRIVATE_KEY_FILE)
  266. if not private_key_file:
  267. raise CredentialException("The configured private_key_file is empty")
  268. private_key = au.get_private_key(private_key_file)
  269. if not public_key_id or not private_key:
  270. raise CredentialException("The configured public_key_id or private_key_file content is empty")
  271. provider = RsaKeyPairCredentialProvider(public_key_id, private_key)
  272. return provider.get_credentials()
  273. @staticmethod
  274. def _get_instance_profile_credentials(config):
  275. role_name = config.get(ac.INI_ROLE_NAME)
  276. if not role_name:
  277. raise CredentialException("The configured role_name is empty")
  278. provider = EcsRamRoleCredentialProvider(role_name)
  279. return provider.get_credentials()
  280. class EnvironmentVariableCredentialsProvider(AlibabaCloudCredentialsProvider):
  281. def get_credentials(self):
  282. if 'default' != au.client_type:
  283. return
  284. access_key_id = au.environment_access_key_id
  285. access_key_secret = au.environment_access_key_secret
  286. if access_key_id is None or access_key_secret is None:
  287. return
  288. if len(access_key_id) == 0:
  289. raise CredentialException("Environment variable accessKeyId cannot be empty")
  290. if len(access_key_secret) == 0:
  291. raise CredentialException("Environment variable accessKeySecret cannot be empty")
  292. return credentials.AccessKeyCredential(access_key_id, access_key_secret)