Support unscoped token request
Make scope check optional for the "token issue" command as unscoped token is a valid Keystone V2/V3 API. Change-Id: Ie1cded4dbfdafd3a78c0ebdf89e3f66762509930 Closes-Bug: #1543214
This commit is contained in:
		| @@ -135,8 +135,12 @@ def build_auth_params(auth_plugin_name, cmd_options): | ||||
|     return (auth_plugin_class, auth_params) | ||||
|  | ||||
|  | ||||
| def check_valid_auth_options(options, auth_plugin_name): | ||||
|     """Perform basic option checking, provide helpful error messages""" | ||||
| def check_valid_auth_options(options, auth_plugin_name, required_scope=True): | ||||
|     """Perform basic option checking, provide helpful error messages. | ||||
|  | ||||
|     :param required_scope: indicate whether a scoped token is required | ||||
|  | ||||
|     """ | ||||
|  | ||||
|     msg = '' | ||||
|     if auth_plugin_name.endswith('password'): | ||||
| @@ -146,7 +150,8 @@ def check_valid_auth_options(options, auth_plugin_name): | ||||
|         if not options.auth.get('auth_url', None): | ||||
|             msg += _('Set an authentication URL, with --os-auth-url,' | ||||
|                      ' OS_AUTH_URL or auth.auth_url\n') | ||||
|         if (not options.auth.get('project_id', None) and not | ||||
|         if (required_scope and not | ||||
|                 options.auth.get('project_id', None) and not | ||||
|                 options.auth.get('domain_id', None) and not | ||||
|                 options.auth.get('domain_name', None) and not | ||||
|                 options.auth.get('project_name', None) and not | ||||
|   | ||||
| @@ -113,19 +113,35 @@ class ClientManager(object): | ||||
|         root_logger = logging.getLogger('') | ||||
|         LOG.setLevel(root_logger.getEffectiveLevel()) | ||||
|  | ||||
|     def setup_auth(self): | ||||
|         # NOTE(gyee): use this flag to indicate whether auth setup has already | ||||
|         # been completed. If so, do not perform auth setup again. The reason | ||||
|         # we need this flag is that we want to be able to perform auth setup | ||||
|         # outside of auth_ref as auth_ref itself is a property. We can not | ||||
|         # retrofit auth_ref to optionally skip scope check. Some operations | ||||
|         # do not require a scoped token. In those cases, we call setup_auth | ||||
|         # prior to dereferrencing auth_ref. | ||||
|         self._auth_setup_completed = False | ||||
|  | ||||
|     def setup_auth(self, required_scope=True): | ||||
|         """Set up authentication | ||||
|  | ||||
|         :param required_scope: indicate whether a scoped token is required | ||||
|  | ||||
|         This is deferred until authentication is actually attempted because | ||||
|         it gets in the way of things that do not require auth. | ||||
|         """ | ||||
|  | ||||
|         if self._auth_setup_completed: | ||||
|             return | ||||
|  | ||||
|         # If no auth type is named by the user, select one based on | ||||
|         # the supplied options | ||||
|         self.auth_plugin_name = auth.select_auth_plugin(self._cli_options) | ||||
|  | ||||
|         # Basic option checking to avoid unhelpful error messages | ||||
|         auth.check_valid_auth_options(self._cli_options, self.auth_plugin_name) | ||||
|         auth.check_valid_auth_options(self._cli_options, | ||||
|                                       self.auth_plugin_name, | ||||
|                                       required_scope=required_scope) | ||||
|  | ||||
|         # Horrible hack alert...must handle prompt for null password if | ||||
|         # password auth is requested. | ||||
| @@ -180,6 +196,8 @@ class ClientManager(object): | ||||
|             user_agent=USER_AGENT, | ||||
|         ) | ||||
|  | ||||
|         self._auth_setup_completed = True | ||||
|  | ||||
|         return | ||||
|  | ||||
|     @property | ||||
|   | ||||
| @@ -353,6 +353,9 @@ class OpenStackShell(app.App): | ||||
|             cmd.__class__.__name__, | ||||
|         ) | ||||
|         if cmd.auth_required: | ||||
|             if hasattr(cmd, 'required_scope'): | ||||
|                 # let the command decide whether we need a scoped token | ||||
|                 self.client_manager.setup_auth(cmd.required_scope) | ||||
|             # Trigger the Identity client to initialize | ||||
|             self.client_manager.auth_ref | ||||
|         return | ||||
|   | ||||
| @@ -325,3 +325,28 @@ class TestClientManager(utils.TestCase): | ||||
|             exc.CommandError, | ||||
|             client_manager.setup_auth, | ||||
|         ) | ||||
|  | ||||
|     @mock.patch('openstackclient.api.auth.check_valid_auth_options') | ||||
|     def test_client_manager_auth_setup_once(self, check_auth_options_func): | ||||
|         client_manager = clientmanager.ClientManager( | ||||
|             cli_options=FakeOptions( | ||||
|                 auth=dict( | ||||
|                     auth_url=fakes.AUTH_URL, | ||||
|                     username=fakes.USERNAME, | ||||
|                     password=fakes.PASSWORD, | ||||
|                     project_name=fakes.PROJECT_NAME, | ||||
|                 ), | ||||
|             ), | ||||
|             api_version=API_VERSION, | ||||
|             verify=False, | ||||
|         ) | ||||
|         self.assertFalse(client_manager._auth_setup_completed) | ||||
|         client_manager.setup_auth() | ||||
|         self.assertTrue(check_auth_options_func.called) | ||||
|         self.assertTrue(client_manager._auth_setup_completed) | ||||
|  | ||||
|         # now make sure we don't do auth setup the second time around | ||||
|         # by checking whether check_valid_auth_options() gets called again | ||||
|         check_auth_options_func.reset_mock() | ||||
|         client_manager.auth_ref | ||||
|         check_auth_options_func.assert_not_called() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 guang-yee
					guang-yee