From 3b0f4cf6bea33e6ee1893f6e872d968b0c309f88 Mon Sep 17 00:00:00 2001 From: John Herndon Date: Tue, 19 Feb 2013 22:53:49 +0000 Subject: Flush tokens on instance delete Force console auth service to flush all tokens associated with an instance when it is deleted. This will fix bug 1125378, where the console for the wrong instance can be connected to via the console if the correct circumstances occur. This change also adds a call to validate the token when it is used. This check will ensure that all tokens are valid for their target instances. Tokens can become scrambled when a compute node is restarted, because the virt driver may not assign ports in the same way. Change-Id: I0d83ec6c4dbfef1af912a200ee15f8052f72da96 fixes: bug 1125378 --- nova/tests/compute/test_compute.py | 77 ++++++++++++++++++++++++++++-- nova/tests/compute/test_rpcapi.py | 6 +++ nova/tests/consoleauth/test_consoleauth.py | 64 ++++++++++++++++++++++++- nova/tests/consoleauth/test_rpcapi.py | 8 +++- 4 files changed, 149 insertions(+), 6 deletions(-) (limited to 'nova/tests') diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index e19470db5..02bbaaa62 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -1420,6 +1420,54 @@ class ComputeTestCase(BaseTestCase): self.compute.terminate_instance(self.context, instance=instance) + def test_validate_console_port_vnc(self): + self.flags(vnc_enabled=True) + self.flags(enabled=True, group='spice') + instance = jsonutils.to_primitive(self._create_fake_instance()) + + def fake_driver_get_console(*args, **kwargs): + return {'host': "fake_host", 'port': "5900", + 'internal_access_path': None} + self.stubs.Set(self.compute.driver, "get_vnc_console", + fake_driver_get_console) + + self.assertTrue(self.compute.validate_console_port(self.context, + instance, + "5900", + "novnc")) + + def test_validate_console_port_spice(self): + self.flags(vnc_enabled=True) + self.flags(enabled=True, group='spice') + instance = jsonutils.to_primitive(self._create_fake_instance()) + + def fake_driver_get_console(*args, **kwargs): + return {'host': "fake_host", 'port': "5900", + 'internal_access_path': None} + self.stubs.Set(self.compute.driver, "get_spice_console", + fake_driver_get_console) + + self.assertTrue(self.compute.validate_console_port(self.context, + instance, + "5900", + "spice-html5")) + + def test_validate_console_port_wrong_port(self): + self.flags(vnc_enabled=True) + self.flags(enabled=True, group='spice') + instance = jsonutils.to_primitive(self._create_fake_instance()) + + def fake_driver_get_console(*args, **kwargs): + return {'host': "fake_host", 'port': "5900", + 'internal_access_path': None} + self.stubs.Set(self.compute.driver, "get_vnc_console", + fake_driver_get_console) + + self.assertFalse(self.compute.validate_console_port(self.context, + instance, + "wrongport", + "spice-html5")) + def test_xvpvnc_vnc_console(self): # Make sure we can a vnc console for an instance. self.flags(vnc_enabled=True) @@ -1715,6 +1763,25 @@ class ComputeTestCase(BaseTestCase): instance=jsonutils.to_primitive(instance), bdms={}) + def test_delete_instance_deletes_console_auth_tokens(self): + instance = self._create_fake_instance() + self.flags(vnc_enabled=True) + + self.tokens_deleted = False + + def fake_delete_tokens(*args, **kwargs): + self.tokens_deleted = True + + cauth_rpcapi = self.compute.consoleauth_rpcapi + self.stubs.Set(cauth_rpcapi, 'delete_tokens_for_instance', + fake_delete_tokens) + + self.compute._delete_instance(self.context, + instance=jsonutils.to_primitive(instance), + bdms={}) + + self.assertTrue(self.tokens_deleted) + def test_instance_termination_exception_sets_error(self): """Test that we handle InstanceTerminationFailure which is propagated up from the underlying driver. @@ -5735,7 +5802,8 @@ class ComputeAPITestCase(BaseTestCase): 'console_type': fake_console_type, 'host': 'fake_console_host', 'port': 'fake_console_port', - 'internal_access_path': 'fake_access_path'} + 'internal_access_path': 'fake_access_path', + 'instance_uuid': fake_instance['uuid']} fake_connect_info2 = copy.deepcopy(fake_connect_info) fake_connect_info2['access_url'] = 'fake_console_url' @@ -5747,7 +5815,7 @@ class ComputeAPITestCase(BaseTestCase): 'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION} rpc_msg2 = {'method': 'authorize_console', 'args': fake_connect_info, - 'version': '1.0'} + 'version': '1.2'} rpc.call(self.context, 'compute.%s' % fake_instance['host'], rpc_msg1, None).AndReturn(fake_connect_info2) @@ -5779,7 +5847,8 @@ class ComputeAPITestCase(BaseTestCase): 'console_type': fake_console_type, 'host': 'fake_console_host', 'port': 'fake_console_port', - 'internal_access_path': 'fake_access_path'} + 'internal_access_path': 'fake_access_path', + 'instance_uuid': fake_instance['uuid']} fake_connect_info2 = copy.deepcopy(fake_connect_info) fake_connect_info2['access_url'] = 'fake_console_url' @@ -5791,7 +5860,7 @@ class ComputeAPITestCase(BaseTestCase): 'version': '2.24'} rpc_msg2 = {'method': 'authorize_console', 'args': fake_connect_info, - 'version': '1.0'} + 'version': '1.2'} rpc.call(self.context, 'compute.%s' % fake_instance['host'], rpc_msg1, None).AndReturn(fake_connect_info2) diff --git a/nova/tests/compute/test_rpcapi.py b/nova/tests/compute/test_rpcapi.py index a78a13883..6c40a95e2 100644 --- a/nova/tests/compute/test_rpcapi.py +++ b/nova/tests/compute/test_rpcapi.py @@ -171,6 +171,12 @@ class ComputeRpcAPITestCase(test.TestCase): instance=self.fake_instance, console_type='type', version='2.24') + def test_validate_console_port(self): + self._test_compute_api('validate_console_port', 'call', + instance=self.fake_instance, port="5900", + console_type="novnc", + version="2.26") + def test_host_maintenance_mode(self): self._test_compute_api('host_maintenance_mode', 'call', host_param='param', mode='mode', host='host') diff --git a/nova/tests/consoleauth/test_consoleauth.py b/nova/tests/consoleauth/test_consoleauth.py index 15397a400..54e3d2261 100644 --- a/nova/tests/consoleauth/test_consoleauth.py +++ b/nova/tests/consoleauth/test_consoleauth.py @@ -42,12 +42,74 @@ class ConsoleauthTestCase(test.TestCase): self.useFixture(test.TimeOverride()) token = 'mytok' self.flags(console_token_ttl=1) + + def fake_validate_console_port(*args, **kwargs): + return True + self.stubs.Set(self.manager.compute_rpcapi, + "validate_console_port", + fake_validate_console_port) + self.manager.authorize_console(self.context, token, 'novnc', - '127.0.0.1', 'host', '') + '127.0.0.1', '8080', 'host', + 'instance') self.assertTrue(self.manager.check_token(self.context, token)) timeutils.advance_time_seconds(1) self.assertFalse(self.manager.check_token(self.context, token)) + def test_multiple_tokens_for_instance(self): + tokens = ["token" + str(i) for i in xrange(10)] + instance = "12345" + + def fake_validate_console_port(*args, **kwargs): + return True + + self.stubs.Set(self.manager.compute_rpcapi, + "validate_console_port", + fake_validate_console_port) + for token in tokens: + self.manager.authorize_console(self.context, token, 'novnc', + '127.0.0.1', '8080', 'host', + instance) + + for token in tokens: + self.assertTrue(self.manager.check_token(self.context, token)) + + def test_delete_tokens_for_instance(self): + instance = "12345" + tokens = ["token" + str(i) for i in xrange(10)] + for token in tokens: + self.manager.authorize_console(self.context, token, 'novnc', + '127.0.0.1', '8080', 'host', + instance) + self.manager.delete_tokens_for_instance(self.context, instance) + stored_tokens = self.manager._get_tokens_for_instance(instance) + + self.assertEqual(len(stored_tokens), 0) + + for token in tokens: + self.assertFalse(self.manager.check_token(self.context, token)) + + def test_wrong_token_has_port(self): + token = 'mytok' + + def fake_validate_console_port(*args, **kwargs): + return False + + self.stubs.Set(self.manager.compute_rpcapi, + "validate_console_port", + fake_validate_console_port) + + self.manager.authorize_console(self.context, token, 'novnc', + '127.0.0.1', '8080', 'host', + instance_uuid='instance') + self.assertFalse(self.manager.check_token(self.context, token)) + + def test_console_no_instance_uuid(self): + self.manager.authorize_console(self.context, "token", 'novnc', + '127.0.0.1', '8080', 'host', + instance_uuid=None) + self.assertFalse(self.manager.check_token(self.context, "token")) + def test_get_backdoor_port(self): self.manager.backdoor_port = 59697 port = self.manager.get_backdoor_port(self.context) diff --git a/nova/tests/consoleauth/test_rpcapi.py b/nova/tests/consoleauth/test_rpcapi.py index 15af5fdcf..53ca2e5d6 100644 --- a/nova/tests/consoleauth/test_rpcapi.py +++ b/nova/tests/consoleauth/test_rpcapi.py @@ -65,11 +65,17 @@ class ConsoleAuthRpcAPITestCase(test.TestCase): def test_authorize_console(self): self._test_consoleauth_api('authorize_console', token='token', console_type='ctype', host='h', port='p', - internal_access_path='iap') + internal_access_path='iap', instance_uuid="instance", + version="1.2") def test_check_token(self): self._test_consoleauth_api('check_token', token='t') + def test_delete_tokens_for_instnace(self): + self._test_consoleauth_api('delete_tokens_for_instance', + instance_uuid="instance", + version='1.2') + def test_get_backdoor_port(self): self._test_consoleauth_api('get_backdoor_port', host='fake_host', version='1.1') -- cgit