From 366515dcd1090ca2f9f303009c78394b5665ce1f Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Fri, 23 Aug 2019 15:51:34 +0200 Subject: [PATCH] Mask the token used to allow access to consoles Hide the novncproxy token from the logs. When backported this patch needs to be extended to handle the same issue in the consoleauth service. Conflicts: nova/tests/unit/console/test_websocketproxy.py It is due to If1b6e5f20d2ea82d94f5f0550f13189fc9bc16c4 is only implemented in rocky Co-Authored-By:paul-carlton2 Co-Authored-By:Tristan Cacqueray Change-Id: I5b8fa4233d297722c3af08176901d12887bae3de Closes-Bug: #1492140 (cherry picked from commit 26d4047e17eba9bc271f8868f1d0ffeec97b555e) (cherry picked from commit d7826bcd761af035f3f76f67c607dde2a1d04e48) (cherry picked from commit d8fbf04f325f593836f8d44b6bbf42b85bde94e3) (cherry picked from commit 08f1f914cc219cf526adfb08c46b8f40b4e78232) --- nova/console/websocketproxy.py | 6 +++++- nova/consoleauth/manager.py | 9 ++++---- .../tests/unit/console/test_websocketproxy.py | 3 +++ .../unit/consoleauth/test_consoleauth.py | 21 ++++++++++++++++++- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/nova/console/websocketproxy.py b/nova/console/websocketproxy.py index d93d61ac6b69..8d99143f55d6 100644 --- a/nova/console/websocketproxy.py +++ b/nova/console/websocketproxy.py @@ -18,6 +18,7 @@ Websocket proxy that is compatible with OpenStack Nova. Leverages websockify.py by Joel Martin ''' +import copy import socket import sys @@ -183,7 +184,10 @@ class NovaProxyRequestHandlerBase(object): detail = _("Origin header protocol does not match this host.") raise exception.ValidationError(detail=detail) - self.msg(_('connect info: %s'), str(connect_info)) + sanitized_info = copy.copy(connect_info) + sanitized_info['token'] = '***' + self.msg(_('connect info: %s'), sanitized_info) + host = connect_info['host'] port = int(connect_info['port']) diff --git a/nova/consoleauth/manager.py b/nova/consoleauth/manager.py index 1a0ade144f17..70a19b41171a 100644 --- a/nova/consoleauth/manager.py +++ b/nova/consoleauth/manager.py @@ -100,9 +100,8 @@ class ConsoleAuthManager(manager.Manager): self.mc_instance.set(instance_uuid.encode('UTF-8'), jsonutils.dumps(tokens)) - - LOG.info("Received Token: %(token)s, %(token_dict)s", - {'token': token, 'token_dict': token_dict}) + token_dict['token'] = '***' + LOG.info("Received Token: %(token_dict)s", {'token_dict': token_dict}) def _validate_token(self, context, token): instance_uuid = token['instance_uuid'] @@ -130,8 +129,8 @@ class ConsoleAuthManager(manager.Manager): def check_token(self, context, token): token_str = self.mc.get(token.encode('UTF-8')) token_valid = (token_str is not None) - LOG.info("Checking Token: %(token)s, %(token_valid)s", - {'token': token, 'token_valid': token_valid}) + LOG.info("Checking that token is known: %(token_valid)s", + {'token_valid': token_valid}) if token_valid: token = jsonutils.loads(token_str) if self._validate_token(context, token): diff --git a/nova/tests/unit/console/test_websocketproxy.py b/nova/tests/unit/console/test_websocketproxy.py index 154013b4775e..d736bf0a26f6 100644 --- a/nova/tests/unit/console/test_websocketproxy.py +++ b/nova/tests/unit/console/test_websocketproxy.py @@ -109,6 +109,9 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase): check_token.assert_called_with(mock.ANY, token="123-456-789") self.wh.socket.assert_called_with('node1', 10000, connect=True) self.wh.do_proxy.assert_called_with('') + # ensure that token is masked when logged + connection_info = self.wh.msg.mock_calls[0][1][1] + self.assertEqual('***', connection_info['token']) @mock.patch('nova.consoleauth.rpcapi.ConsoleAuthAPI.check_token') def test_new_websocket_client_ipv6_url(self, check_token): diff --git a/nova/tests/unit/consoleauth/test_consoleauth.py b/nova/tests/unit/consoleauth/test_consoleauth.py index 199d9341d5d4..5b6617406f38 100644 --- a/nova/tests/unit/consoleauth/test_consoleauth.py +++ b/nova/tests/unit/consoleauth/test_consoleauth.py @@ -88,6 +88,17 @@ class ConsoleauthTestCase(test.NoDBTestCase): self.stub_out(self.rpcapi + 'validate_console_port', fake_validate_console_port) + @mock.patch('nova.consoleauth.manager.LOG.info') + def test_authorize_does_not_log_token_secrete(self, mock_info): + self.manager_api.authorize_console( + self.context, 'secret', 'novnc', '127.0.0.1', '8080', 'host', + self.instance_uuid) + + mock_info.assert_called_once_with( + 'Received Token: %(token_dict)s', test.MatchType(dict)) + self.assertEqual( + '***', mock_info.mock_calls[0][1][1]['token_dict']['token']) + @mock.patch('nova.objects.instance.Instance.get_by_uuid') def test_multiple_tokens_for_instance(self, mock_get): mock_get.return_value = None @@ -139,8 +150,9 @@ class ConsoleauthTestCase(test.NoDBTestCase): mock_delete.assert_called_once_with( self.instance_uuid.encode('UTF-8')) + @mock.patch('nova.consoleauth.manager.LOG.info') @mock.patch('nova.objects.instance.Instance.get_by_uuid') - def test_wrong_token_has_port(self, mock_get): + def test_wrong_token_has_port(self, mock_get, mock_log): mock_get.return_value = None token = u'mytok' @@ -151,6 +163,13 @@ class ConsoleauthTestCase(test.NoDBTestCase): '127.0.0.1', '8080', 'host', instance_uuid=self.instance_uuid) self.assertIsNone(self.manager_api.check_token(self.context, token)) + mock_log.assert_has_calls([ + mock.call( + 'Received Token: %(token_dict)s', mock.ANY), + mock.call( + 'Checking that token is known: %(token_valid)s', + {'token_valid': True}), + ]) def test_delete_expired_tokens(self): self.useFixture(test.TimeOverride())