Use X-Forwarded-Proto as origin protocol if present
When using a haproxy with SSL termination to provide secure console connections, haproxy will change the Origin header scheme to 'http' and add the 'X-Forwarded-Proto: https' header. This causes a failure in the Nova console proxy code which verifies that the Origin header scheme matches the access_url scheme for the connection, because the Origin header coming from haproxy is 'http' while the access_url scheme is 'https' or 'wss'. This looks for the X-Forwarded-Proto header and uses its scheme for the verification instead, if it is present. Closes-Bug: #1788180 Change-Id: I43401dc8368853654bf443273a0a1b5b9b63e3f0
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 = '<socket>'
|
||||
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('<socket>')
|
||||
|
||||
@mock.patch('nova.console.websocketproxy.NovaProxyRequestHandlerBase.'
|
||||
'_check_console_port')
|
||||
@mock.patch('nova.objects.ConsoleAuthToken.validate')
|
||||
|
||||
Reference in New Issue
Block a user