OpenStack Identity (Keystone) Client
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

v2.py 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  2. # not use this file except in compliance with the License. You may obtain
  3. # a copy of the License at
  4. #
  5. # http://www.apache.org/licenses/LICENSE-2.0
  6. #
  7. # Unless required by applicable law or agreed to in writing, software
  8. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  9. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  10. # License for the specific language governing permissions and limitations
  11. # under the License.
  12. import abc
  13. import logging
  14. from oslo_config import cfg
  15. import six
  16. from keystoneclient import access
  17. from keystoneclient.auth.identity import base
  18. from keystoneclient import exceptions
  19. from keystoneclient import utils
  20. _logger = logging.getLogger(__name__)
  21. @six.add_metaclass(abc.ABCMeta)
  22. class Auth(base.BaseIdentityPlugin):
  23. """Identity V2 Authentication Plugin.
  24. :param string auth_url: Identity service endpoint for authorization.
  25. :param string trust_id: Trust ID for trust scoping.
  26. :param string tenant_id: Tenant ID for project scoping.
  27. :param string tenant_name: Tenant name for project scoping.
  28. :param bool reauthenticate: Allow fetching a new token if the current one
  29. is going to expire. (optional) default True
  30. """
  31. @classmethod
  32. def get_options(cls):
  33. options = super(Auth, cls).get_options()
  34. options.extend([
  35. cfg.StrOpt('tenant-id', help='Tenant ID'),
  36. cfg.StrOpt('tenant-name', help='Tenant Name'),
  37. cfg.StrOpt('trust-id', help='Trust ID'),
  38. ])
  39. return options
  40. def __init__(self, auth_url,
  41. trust_id=None,
  42. tenant_id=None,
  43. tenant_name=None,
  44. reauthenticate=True):
  45. super(Auth, self).__init__(auth_url=auth_url,
  46. reauthenticate=reauthenticate)
  47. self._trust_id = trust_id
  48. self.tenant_id = tenant_id
  49. self.tenant_name = tenant_name
  50. @property
  51. def trust_id(self):
  52. # Override to remove deprecation.
  53. return self._trust_id
  54. @trust_id.setter
  55. def trust_id(self, value):
  56. # Override to remove deprecation.
  57. self._trust_id = value
  58. def get_auth_ref(self, session, **kwargs):
  59. headers = {'Accept': 'application/json'}
  60. url = self.auth_url.rstrip('/') + '/tokens'
  61. params = {'auth': self.get_auth_data(headers)}
  62. if self.tenant_id:
  63. params['auth']['tenantId'] = self.tenant_id
  64. elif self.tenant_name:
  65. params['auth']['tenantName'] = self.tenant_name
  66. if self.trust_id:
  67. params['auth']['trust_id'] = self.trust_id
  68. _logger.debug('Making authentication request to %s', url)
  69. resp = session.post(url, json=params, headers=headers,
  70. authenticated=False, log=False)
  71. try:
  72. resp_data = resp.json()['access']
  73. except (KeyError, ValueError):
  74. raise exceptions.InvalidResponse(response=resp)
  75. return access.AccessInfoV2(**resp_data)
  76. @abc.abstractmethod
  77. def get_auth_data(self, headers=None):
  78. """Return the authentication section of an auth plugin.
  79. :param dict headers: The headers that will be sent with the auth
  80. request if a plugin needs to add to them.
  81. :return: A dict of authentication data for the auth type.
  82. :rtype: dict
  83. """
  84. pass # pragma: no cover
  85. _NOT_PASSED = object()
  86. class Password(Auth):
  87. """A plugin for authenticating with a username and password.
  88. A username or user_id must be provided.
  89. :param string auth_url: Identity service endpoint for authorization.
  90. :param string username: Username for authentication.
  91. :param string password: Password for authentication.
  92. :param string user_id: User ID for authentication.
  93. :param string trust_id: Trust ID for trust scoping.
  94. :param string tenant_id: Tenant ID for tenant scoping.
  95. :param string tenant_name: Tenant name for tenant scoping.
  96. :param bool reauthenticate: Allow fetching a new token if the current one
  97. is going to expire. (optional) default True
  98. :raises TypeError: if a user_id or username is not provided.
  99. """
  100. def __init__(self, auth_url, username=_NOT_PASSED, password=None,
  101. user_id=_NOT_PASSED, **kwargs):
  102. super(Password, self).__init__(auth_url, **kwargs)
  103. if username is _NOT_PASSED and user_id is _NOT_PASSED:
  104. msg = 'You need to specify either a username or user_id'
  105. raise TypeError(msg)
  106. if username is _NOT_PASSED:
  107. username = None
  108. if user_id is _NOT_PASSED:
  109. user_id = None
  110. self.user_id = user_id
  111. self._username = username
  112. self._password = password
  113. @property
  114. def username(self):
  115. # Override to remove deprecation.
  116. return self._username
  117. @username.setter
  118. def username(self, value):
  119. # Override to remove deprecation.
  120. self._username = value
  121. @property
  122. def password(self):
  123. # Override to remove deprecation.
  124. return self._password
  125. @password.setter
  126. def password(self, value):
  127. # Override to remove deprecation.
  128. self._password = value
  129. def get_auth_data(self, headers=None):
  130. auth = {'password': self.password}
  131. if self.username:
  132. auth['username'] = self.username
  133. elif self.user_id:
  134. auth['userId'] = self.user_id
  135. return {'passwordCredentials': auth}
  136. @classmethod
  137. def load_from_argparse_arguments(cls, namespace, **kwargs):
  138. if not (kwargs.get('password') or namespace.os_password):
  139. kwargs['password'] = utils.prompt_user_password()
  140. return super(Password, cls).load_from_argparse_arguments(namespace,
  141. **kwargs)
  142. @classmethod
  143. def get_options(cls):
  144. options = super(Password, cls).get_options()
  145. options.extend([
  146. cfg.StrOpt('username',
  147. dest='username',
  148. deprecated_name='user-name',
  149. help='Username to login with'),
  150. cfg.StrOpt('user-id', help='User ID to login with'),
  151. cfg.StrOpt('password', secret=True, help='Password to use'),
  152. ])
  153. return options
  154. class Token(Auth):
  155. """A plugin for authenticating with an existing token.
  156. :param string auth_url: Identity service endpoint for authorization.
  157. :param string token: Existing token for authentication.
  158. :param string tenant_id: Tenant ID for tenant scoping.
  159. :param string tenant_name: Tenant name for tenant scoping.
  160. :param string trust_id: Trust ID for trust scoping.
  161. :param bool reauthenticate: Allow fetching a new token if the current one
  162. is going to expire. (optional) default True
  163. """
  164. def __init__(self, auth_url, token, **kwargs):
  165. super(Token, self).__init__(auth_url, **kwargs)
  166. self._token = token
  167. @property
  168. def token(self):
  169. # Override to remove deprecation.
  170. return self._token
  171. @token.setter
  172. def token(self, value):
  173. # Override to remove deprecation.
  174. self._token = value
  175. def get_auth_data(self, headers=None):
  176. if headers is not None:
  177. headers['X-Auth-Token'] = self.token
  178. return {'token': {'id': self.token}}
  179. @classmethod
  180. def get_options(cls):
  181. options = super(Token, cls).get_options()
  182. options.extend([
  183. cfg.StrOpt('token', secret=True, help='Token'),
  184. ])
  185. return options