diff --git a/nova/console/websocketproxy.py b/nova/console/websocketproxy.py index 0463b7463886..6b692394942b 100644 --- a/nova/console/websocketproxy.py +++ b/nova/console/websocketproxy.py @@ -231,6 +231,13 @@ class NovaProxyRequestHandlerBase(object): origin = urlparse.urlparse(origin_url) origin_hostname = origin.hostname origin_scheme = origin.scheme + # If the console connection was forwarded by a proxy (example: + # haproxy), the original protocol could be contained in the + # X-Forwarded-Proto header instead of the Origin header. Prefer the + # forwarded protocol if it is present. + forwarded_proto = self.headers.get('X-Forwarded-Proto') + if forwarded_proto is not None: + origin_scheme = forwarded_proto if origin_hostname == '' or origin_scheme == '': detail = _("Origin header not valid.") raise exception.ValidationError(detail=detail) diff --git a/nova/tests/unit/console/test_websocketproxy.py b/nova/tests/unit/console/test_websocketproxy.py index d40e06b78a60..539f5c5f556c 100644 --- a/nova/tests/unit/console/test_websocketproxy.py +++ b/nova/tests/unit/console/test_websocketproxy.py @@ -628,6 +628,38 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase): self.assertRaises(exception.ValidationError, self.wh.new_websocket_client) + @mock.patch('nova.console.websocketproxy.NovaProxyRequestHandlerBase.' + '_check_console_port') + @mock.patch('nova.objects.ConsoleAuthToken.validate') + def test_new_websocket_client_http_forwarded_proto_https(self, validate, + check_port): + params = { + 'id': 1, + 'token': '123-456-789', + 'instance_uuid': uuids.instance, + 'host': 'node1', + 'port': '10000', + 'console_type': 'serial', + 'access_url_base': 'wss://example.net:6080' + } + validate.return_value = objects.ConsoleAuthToken(**params) + + header = { + 'cookie': 'token="123-456-789"', + 'Origin': 'http://example.net:6080', + 'Host': 'example.net:6080', + 'X-Forwarded-Proto': 'https' + } + self.wh.socket.return_value = '' + self.wh.path = "https://127.0.0.1/" + self.wh.headers = header + + self.wh.new_websocket_client() + + validate.assert_called_with(mock.ANY, "123-456-789") + self.wh.socket.assert_called_with('node1', 10000, connect=True) + self.wh.do_proxy.assert_called_with('') + @mock.patch('nova.console.websocketproxy.NovaProxyRequestHandlerBase.' '_check_console_port') @mock.patch('nova.objects.ConsoleAuthToken.validate')