diff --git a/osc_lib/api/auth.py b/osc_lib/api/auth.py index 8e0254d..6535797 100644 --- a/osc_lib/api/auth.py +++ b/osc_lib/api/auth.py @@ -15,6 +15,7 @@ import argparse +from keystoneauth1.identity.v3 import k2k from keystoneauth1.loading import base from osc_lib import exceptions as exc @@ -190,3 +191,25 @@ def build_auth_plugins_option_parser(parser): help=argparse.SUPPRESS, ) return parser + + +def get_keystone2keystone_auth(local_auth, service_provider, + project_id=None, project_name=None, + project_domain_id=None, + project_domain_name=None): + """Return Keystone 2 Keystone authentication for service provider. + + :param local_auth: authentication to use with the local Keystone + :param service_provider: service provider id as registered in Keystone + :param project_id: project id to scope to in the service provider + :param project_name: project name to scope to in the service provider + :param project_domain_id: id of domain in the service provider + :param project_domain_name: name of domain to in the service provider + :return: Keystone2Keystone auth object for service provider + """ + return k2k.Keystone2Keystone(local_auth, + service_provider, + project_id=project_id, + project_name=project_name, + project_domain_id=project_domain_id, + project_domain_name=project_domain_name) diff --git a/osc_lib/clientmanager.py b/osc_lib/clientmanager.py index 949e34e..04bee04 100644 --- a/osc_lib/clientmanager.py +++ b/osc_lib/clientmanager.py @@ -169,6 +169,17 @@ class ClientManager(object): LOG.debug('Using parameters %s', strutils.mask_password(self._cli_options.auth)) self.auth = self._cli_options.get_auth() + + if self._cli_options.service_provider: + self.auth = auth.get_keystone2keystone_auth( + self.auth, + self._cli_options.service_provider, + self._cli_options.remote_project_id, + self._cli_options.remote_project_name, + self._cli_options.remote_project_domain_id, + self._cli_options.remote_project_domain_name + ) + self.session = osc_session.TimingSession( auth=self.auth, verify=self.verify, diff --git a/osc_lib/tests/fakes.py b/osc_lib/tests/fakes.py index aef7bec..7e32fb6 100644 --- a/osc_lib/tests/fakes.py +++ b/osc_lib/tests/fakes.py @@ -25,10 +25,13 @@ AUTH_URL = "http://0.0.0.0" USERNAME = "itchy" PASSWORD = "scratchy" PROJECT_NAME = "poochie" +PROJECT_ID = "30c3da29-61f5-4b7b-8eb2-3d18287428c7" REGION_NAME = "richie" INTERFACE = "catchy" VERSION = "3" +SERVICE_PROVIDER_ID = "bob" + TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN, user_name=USERNAME) _s = TEST_RESPONSE_DICT.add_service('identity', name='keystone') diff --git a/osc_lib/tests/test_clientmanager.py b/osc_lib/tests/test_clientmanager.py index 41b1c8d..7ebe1a6 100644 --- a/osc_lib/tests/test_clientmanager.py +++ b/osc_lib/tests/test_clientmanager.py @@ -19,6 +19,7 @@ import mock from keystoneauth1.access import service_catalog from keystoneauth1 import exceptions as ksa_exceptions from keystoneauth1.identity import generic as generic_plugin +from keystoneauth1.identity.v3 import k2k from keystoneauth1 import loading from os_client_config import cloud_config @@ -32,6 +33,13 @@ AUTH_REF = {'version': 'v2.0'} AUTH_REF.update(fakes.TEST_RESPONSE_DICT['access']) SERVICE_CATALOG = service_catalog.ServiceCatalogV2(AUTH_REF) +AUTH_DICT = { + 'auth_url': fakes.AUTH_URL, + 'username': fakes.USERNAME, + 'password': fakes.PASSWORD, + 'project_name': fakes.PROJECT_NAME +} + # This is deferred in api.auth but we need it here... auth.get_options_list() @@ -257,21 +265,15 @@ class TestClientManager(utils.TestClientManager): @mock.patch('osc_lib.api.auth.check_valid_authentication_options') def test_client_manager_auth_setup_once(self, check_authn_options_func): - auth_dict = { - 'auth_url': fakes.AUTH_URL, - 'username': fakes.USERNAME, - 'password': fakes.PASSWORD, - 'project_name': fakes.PROJECT_NAME, - } loader = loading.get_plugin_loader('password') - auth_plugin = loader.load_from_options(**auth_dict) + auth_plugin = loader.load_from_options(**AUTH_DICT) client_manager = self._clientmanager_class()( cli_options=cloud_config.CloudConfig( name='t1', region='1', config=dict( auth_type='password', - auth=auth_dict, + auth=AUTH_DICT, interface=fakes.INTERFACE, region_name=fakes.REGION_NAME, ), @@ -306,3 +308,34 @@ class TestClientManager(utils.TestClientManager): ) self.assertFalse(client_manager.is_service_available('network')) + + def test_client_manager_k2k_auth_setup(self): + loader = loading.get_plugin_loader('password') + auth_plugin = loader.load_from_options(**AUTH_DICT) + client_manager = self._clientmanager_class()( + cli_options=cloud_config.CloudConfig( + name='t1', + region='1', + config=dict( + auth_type='password', + auth=AUTH_DICT, + interface=fakes.INTERFACE, + region_name=fakes.REGION_NAME, + service_provider=fakes.SERVICE_PROVIDER_ID, + remote_project_id=fakes.PROJECT_ID + ), + auth_plugin=auth_plugin, + ), + api_version={ + 'identity': '3', + }, + ) + + self.assertFalse(client_manager._auth_setup_completed) + client_manager.setup_auth() + # Note(knikolla): Make sure that the auth object is of the correct + # type and that the service_provider is correctly set. + self.assertIsInstance(client_manager.auth, k2k.Keystone2Keystone) + self.assertEqual(client_manager.auth._sp_id, fakes.SERVICE_PROVIDER_ID) + self.assertEqual(client_manager.auth.project_id, fakes.PROJECT_ID) + self.assertTrue(client_manager._auth_setup_completed)