Merge "Reduce scope of 'path' query parameter to noVNC consoles"
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"console": {
|
"console": {
|
||||||
"type": "rdp-html5",
|
"type": "rdp-html5",
|
||||||
"url": "http://127.0.0.1:6083/?path=%3Ftoken%3D21efbb20-b84c-4d1f-807d-4e14f6884b7f"
|
"url": "http://127.0.0.1:6083/?token=191996c3-7b0f-42f3-95a7-f1839f2da6ed"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"console": {
|
"console": {
|
||||||
"type": "serial",
|
"type": "serial",
|
||||||
"url": "ws://127.0.0.1:6083/?path=%3Ftoken%3D6ac46b4c-2705-4d8b-baa3-1b6f1b0c7dd3"
|
"url":"ws://127.0.0.1:6083/?token=f9906a48-b71e-4f18-baca-c987da3ebdb3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"console": {
|
"console": {
|
||||||
"type": "spice-html5",
|
"type": "spice-html5",
|
||||||
"url": "http://127.0.0.1:6082/spice_auto.html?path=%3Ftoken%3Da7bd9607-421c-44b9-8689-18e87ada2f78"
|
"url": "http://127.0.0.1:6082/spice_auto.html?token=a30e5d08-6a20-4043-958f-0852440c6af4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,9 +64,17 @@ class ConsoleAuthToken(base.NovaTimestampObject, base.NovaObject):
|
|||||||
specific to this authorization.
|
specific to this authorization.
|
||||||
"""
|
"""
|
||||||
if self.obj_attr_is_set('id'):
|
if self.obj_attr_is_set('id'):
|
||||||
|
if self.console_type == 'novnc':
|
||||||
|
# NOTE(melwitt): As of noVNC v1.1.0, we must use the 'path'
|
||||||
|
# query parameter to pass the auth token within, as the
|
||||||
|
# top-level 'token' query parameter was removed. The 'path'
|
||||||
|
# parameter is supported in older noVNC versions, so it is
|
||||||
|
# backward compatible.
|
||||||
qparams = {'path': '?token=%s' % self.token}
|
qparams = {'path': '?token=%s' % self.token}
|
||||||
return '%s?%s' % (self.access_url_base,
|
return '%s?%s' % (self.access_url_base,
|
||||||
urlparse.urlencode(qparams))
|
urlparse.urlencode(qparams))
|
||||||
|
else:
|
||||||
|
return '%s?token=%s' % (self.access_url_base, self.token)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _from_db_object(context, obj, db_obj):
|
def _from_db_object(context, obj, db_obj):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"console": {
|
"console": {
|
||||||
"type": "rdp-html5",
|
"type": "rdp-html5",
|
||||||
"url": "http://127.0.0.1:6083/?path=%%3Ftoken%%3D%(uuid)s"
|
"url": "http://127.0.0.1:6083/?token=%(uuid)s"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"console": {
|
"console": {
|
||||||
"type": "serial",
|
"type": "serial",
|
||||||
"url": "ws://127.0.0.1:6083/?path=%%3Ftoken%%3D%(uuid)s"
|
"url": "ws://127.0.0.1:6083/?token=%(uuid)s"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"console": {
|
"console": {
|
||||||
"type": "spice-html5",
|
"type": "spice-html5",
|
||||||
"url": "http://127.0.0.1:6082/spice_auto.html?path=%%3Ftoken%%3D%(uuid)s"
|
"url": "http://127.0.0.1:6082/spice_auto.html?token=%(uuid)s"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
import six.moves.urllib.parse as urlparse
|
|
||||||
|
|
||||||
from nova.tests.functional.api_sample_tests import test_servers
|
from nova.tests.functional.api_sample_tests import test_servers
|
||||||
|
|
||||||
@@ -33,8 +32,7 @@ class ConsoleAuthTokensSampleJsonTests(test_servers.ServersSampleBase):
|
|||||||
{'action': 'os-getRDPConsole'})
|
{'action': 'os-getRDPConsole'})
|
||||||
|
|
||||||
url = self._get_console_url(response.content)
|
url = self._get_console_url(response.content)
|
||||||
path = urlparse.urlencode({'path': '?token='})
|
return re.match('.+?token=([^&]+)', url).groups()[0]
|
||||||
return re.match('.+?%s([^&]+)' % path, url).groups()[0]
|
|
||||||
|
|
||||||
def test_get_console_connect_info(self):
|
def test_get_console_connect_info(self):
|
||||||
self.flags(enabled=True, group='rdp')
|
self.flags(enabled=True, group='rdp')
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import socket
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo_utils.fixture import uuidsentinel as uuids
|
from oslo_utils.fixture import uuidsentinel as uuids
|
||||||
import six.moves.urllib.parse as urlparse
|
|
||||||
|
|
||||||
import nova.conf
|
import nova.conf
|
||||||
from nova.console.securityproxy import base
|
from nova.console.securityproxy import base
|
||||||
@@ -48,7 +47,6 @@ class NovaProxyRequestHandlerDBTestCase(test.TestCase):
|
|||||||
self.wh.msg = mock.MagicMock()
|
self.wh.msg = mock.MagicMock()
|
||||||
self.wh.do_proxy = mock.MagicMock()
|
self.wh.do_proxy = mock.MagicMock()
|
||||||
self.wh.headers = mock.MagicMock()
|
self.wh.headers = mock.MagicMock()
|
||||||
self.path = urlparse.urlencode({'path': '?token=123-456-789'})
|
|
||||||
|
|
||||||
def _fake_console_db(self, **updates):
|
def _fake_console_db(self, **updates):
|
||||||
console_db = copy.deepcopy(fake_ca.fake_token_dict)
|
console_db = copy.deepcopy(fake_ca.fake_token_dict)
|
||||||
@@ -97,7 +95,7 @@ class NovaProxyRequestHandlerDBTestCase(test.TestCase):
|
|||||||
tsock.recv.return_value = "HTTP/1.1 200 OK\r\n\r\n"
|
tsock.recv.return_value = "HTTP/1.1 200 OK\r\n\r\n"
|
||||||
self.wh.socket.return_value = tsock
|
self.wh.socket.return_value = tsock
|
||||||
|
|
||||||
self.wh.path = "http://127.0.0.1/?%s" % self.path
|
self.wh.path = "http://127.0.0.1/?token=123-456-789"
|
||||||
self.wh.headers = self.fake_header
|
self.wh.headers = self.fake_header
|
||||||
|
|
||||||
if instance_not_found:
|
if instance_not_found:
|
||||||
@@ -143,8 +141,6 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
|
|||||||
self.wh.msg = mock.MagicMock()
|
self.wh.msg = mock.MagicMock()
|
||||||
self.wh.do_proxy = mock.MagicMock()
|
self.wh.do_proxy = mock.MagicMock()
|
||||||
self.wh.headers = mock.MagicMock()
|
self.wh.headers = mock.MagicMock()
|
||||||
self.path = urlparse.urlencode({'path': '?token=123-456-789'})
|
|
||||||
self.path_invalid = urlparse.urlencode({'path': '?token=XXX'})
|
|
||||||
|
|
||||||
fake_header = {
|
fake_header = {
|
||||||
'cookie': 'token="123-456-789"',
|
'cookie': 'token="123-456-789"',
|
||||||
@@ -215,7 +211,7 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
|
|||||||
validate.return_value = objects.ConsoleAuthToken(**params)
|
validate.return_value = objects.ConsoleAuthToken(**params)
|
||||||
|
|
||||||
self.wh.socket.return_value = '<socket>'
|
self.wh.socket.return_value = '<socket>'
|
||||||
self.wh.path = "http://127.0.0.1/?%s" % self.path
|
self.wh.path = "http://127.0.0.1/?token=123-456-789"
|
||||||
self.wh.headers = self.fake_header
|
self.wh.headers = self.fake_header
|
||||||
|
|
||||||
self.wh.new_websocket_client()
|
self.wh.new_websocket_client()
|
||||||
@@ -240,7 +236,7 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
|
|||||||
validate.return_value = objects.ConsoleAuthToken(**params)
|
validate.return_value = objects.ConsoleAuthToken(**params)
|
||||||
|
|
||||||
self.wh.socket.return_value = '<socket>'
|
self.wh.socket.return_value = '<socket>'
|
||||||
self.wh.path = "http://[2001:db8::1]/?%s" % self.path
|
self.wh.path = "http://[2001:db8::1]/?token=123-456-789"
|
||||||
self.wh.headers = self.fake_header_ipv6
|
self.wh.headers = self.fake_header_ipv6
|
||||||
|
|
||||||
self.wh.new_websocket_client()
|
self.wh.new_websocket_client()
|
||||||
@@ -253,7 +249,7 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
|
|||||||
def test_new_websocket_client_token_invalid(self, validate):
|
def test_new_websocket_client_token_invalid(self, validate):
|
||||||
validate.side_effect = exception.InvalidToken(token='XXX')
|
validate.side_effect = exception.InvalidToken(token='XXX')
|
||||||
|
|
||||||
self.wh.path = "http://127.0.0.1/?%s" % self.path_invalid
|
self.wh.path = "http://127.0.0.1/?token=XXX"
|
||||||
self.wh.headers = self.fake_header_bad_token
|
self.wh.headers = self.fake_header_bad_token
|
||||||
|
|
||||||
self.assertRaises(exception.InvalidToken,
|
self.assertRaises(exception.InvalidToken,
|
||||||
@@ -281,7 +277,7 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
|
|||||||
tsock.recv.return_value = "HTTP/1.1 200 OK\r\n\r\n"
|
tsock.recv.return_value = "HTTP/1.1 200 OK\r\n\r\n"
|
||||||
|
|
||||||
self.wh.socket.return_value = tsock
|
self.wh.socket.return_value = tsock
|
||||||
self.wh.path = "http://127.0.0.1/?%s" % self.path
|
self.wh.path = "http://127.0.0.1/?token=123-456-789"
|
||||||
self.wh.headers = self.fake_header
|
self.wh.headers = self.fake_header
|
||||||
|
|
||||||
self.wh.new_websocket_client()
|
self.wh.new_websocket_client()
|
||||||
@@ -314,7 +310,7 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
|
|||||||
tsock.recv.return_value = "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
tsock.recv.return_value = "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
||||||
|
|
||||||
self.wh.socket.return_value = tsock
|
self.wh.socket.return_value = tsock
|
||||||
self.wh.path = "http://127.0.0.1/?%s" % self.path
|
self.wh.path = "http://127.0.0.1/?token=123-456-789"
|
||||||
self.wh.headers = self.fake_header
|
self.wh.headers = self.fake_header
|
||||||
|
|
||||||
self.assertRaises(exception.InvalidConnectionInfo,
|
self.assertRaises(exception.InvalidConnectionInfo,
|
||||||
@@ -346,7 +342,7 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
|
|||||||
HTTP_RESP]
|
HTTP_RESP]
|
||||||
|
|
||||||
self.wh.socket.return_value = tsock
|
self.wh.socket.return_value = tsock
|
||||||
self.wh.path = "http://127.0.0.1/?%s" % self.path
|
self.wh.path = "http://127.0.0.1/?token=123-456-789"
|
||||||
self.wh.headers = self.fake_header
|
self.wh.headers = self.fake_header
|
||||||
|
|
||||||
self.wh.new_websocket_client()
|
self.wh.new_websocket_client()
|
||||||
@@ -376,7 +372,7 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
|
|||||||
validate.return_value = objects.ConsoleAuthToken(**params)
|
validate.return_value = objects.ConsoleAuthToken(**params)
|
||||||
|
|
||||||
self.wh.socket.return_value = '<socket>'
|
self.wh.socket.return_value = '<socket>'
|
||||||
self.wh.path = "http://127.0.0.1/?%s" % self.path
|
self.wh.path = "http://127.0.0.1/?token=123-456-789"
|
||||||
self.wh.headers = self.fake_header
|
self.wh.headers = self.fake_header
|
||||||
|
|
||||||
self.wh.new_websocket_client()
|
self.wh.new_websocket_client()
|
||||||
@@ -388,9 +384,10 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
|
|||||||
@mock.patch('socket.getfqdn')
|
@mock.patch('socket.getfqdn')
|
||||||
def test_address_string_doesnt_do_reverse_dns_lookup(self, getfqdn):
|
def test_address_string_doesnt_do_reverse_dns_lookup(self, getfqdn):
|
||||||
request_mock = mock.MagicMock()
|
request_mock = mock.MagicMock()
|
||||||
msg = 'GET /vnc.html?%s HTTP/1.1\r\n' % self.path
|
request_mock.makefile().readline.side_effect = [
|
||||||
request_mock.makefile().readline.side_effect = [msg.encode('utf-8'),
|
b'GET /vnc.html?token=123-456-789 HTTP/1.1\r\n',
|
||||||
b'']
|
b''
|
||||||
|
]
|
||||||
server_mock = mock.MagicMock()
|
server_mock = mock.MagicMock()
|
||||||
client_address = ('8.8.8.8', 54321)
|
client_address = ('8.8.8.8', 54321)
|
||||||
|
|
||||||
@@ -644,8 +641,7 @@ class NovaWebsocketSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
with mock.patch('websockify.ProxyRequestHandler'):
|
with mock.patch('websockify.ProxyRequestHandler'):
|
||||||
self.wh = websocketproxy.NovaProxyRequestHandler()
|
self.wh = websocketproxy.NovaProxyRequestHandler()
|
||||||
self.wh.server = self.server
|
self.wh.server = self.server
|
||||||
path = urlparse.urlencode({'path': '?token=123-456-789'})
|
self.wh.path = "http://127.0.0.1/?token=123-456-789"
|
||||||
self.wh.path = "http://127.0.0.1/?%s" % path
|
|
||||||
self.wh.socket = mock.MagicMock()
|
self.wh.socket = mock.MagicMock()
|
||||||
self.wh.msg = mock.MagicMock()
|
self.wh.msg = mock.MagicMock()
|
||||||
self.wh.do_proxy = mock.MagicMock()
|
self.wh.do_proxy = mock.MagicMock()
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ from nova.tests.unit.objects import test_objects
|
|||||||
class _TestConsoleAuthToken(object):
|
class _TestConsoleAuthToken(object):
|
||||||
|
|
||||||
@mock.patch('nova.db.api.console_auth_token_create')
|
@mock.patch('nova.db.api.console_auth_token_create')
|
||||||
def test_authorize(self, mock_create):
|
def _test_authorize(self, console_type, mock_create):
|
||||||
# the expires time is calculated from the current time and
|
# the expires time is calculated from the current time and
|
||||||
# a ttl value in the object. Fix the current time so we can
|
# a ttl value in the object. Fix the current time so we can
|
||||||
# test expires is calculated correctly as expected
|
# test expires is calculated correctly as expected
|
||||||
@@ -41,10 +41,12 @@ class _TestConsoleAuthToken(object):
|
|||||||
|
|
||||||
db_dict = copy.deepcopy(fakes.fake_token_dict)
|
db_dict = copy.deepcopy(fakes.fake_token_dict)
|
||||||
db_dict['expires'] = expires
|
db_dict['expires'] = expires
|
||||||
|
db_dict['console_type'] = console_type
|
||||||
mock_create.return_value = db_dict
|
mock_create.return_value = db_dict
|
||||||
|
|
||||||
create_dict = copy.deepcopy(fakes.fake_token_dict)
|
create_dict = copy.deepcopy(fakes.fake_token_dict)
|
||||||
create_dict['expires'] = expires
|
create_dict['expires'] = expires
|
||||||
|
create_dict['console_type'] = console_type
|
||||||
del create_dict['id']
|
del create_dict['id']
|
||||||
del create_dict['created_at']
|
del create_dict['created_at']
|
||||||
del create_dict['updated_at']
|
del create_dict['updated_at']
|
||||||
@@ -53,10 +55,11 @@ class _TestConsoleAuthToken(object):
|
|||||||
del expected['token_hash']
|
del expected['token_hash']
|
||||||
del expected['expires']
|
del expected['expires']
|
||||||
expected['token'] = fakes.fake_token
|
expected['token'] = fakes.fake_token
|
||||||
|
expected['console_type'] = console_type
|
||||||
|
|
||||||
obj = token_obj.ConsoleAuthToken(
|
obj = token_obj.ConsoleAuthToken(
|
||||||
context=self.context,
|
context=self.context,
|
||||||
console_type=fakes.fake_token_dict['console_type'],
|
console_type=console_type,
|
||||||
host=fakes.fake_token_dict['host'],
|
host=fakes.fake_token_dict['host'],
|
||||||
port=fakes.fake_token_dict['port'],
|
port=fakes.fake_token_dict['port'],
|
||||||
internal_access_path=fakes.fake_token_dict['internal_access_path'],
|
internal_access_path=fakes.fake_token_dict['internal_access_path'],
|
||||||
@@ -71,11 +74,23 @@ class _TestConsoleAuthToken(object):
|
|||||||
self.compare_obj(obj, expected)
|
self.compare_obj(obj, expected)
|
||||||
|
|
||||||
url = obj.access_url
|
url = obj.access_url
|
||||||
|
if console_type != 'novnc':
|
||||||
|
expected_url = '%s?token=%s' % (
|
||||||
|
fakes.fake_token_dict['access_url_base'],
|
||||||
|
fakes.fake_token)
|
||||||
|
else:
|
||||||
path = urlparse.urlencode({'path': '?token=%s' % fakes.fake_token})
|
path = urlparse.urlencode({'path': '?token=%s' % fakes.fake_token})
|
||||||
expected_url = '%s?%s' % (
|
expected_url = '%s?%s' % (
|
||||||
fakes.fake_token_dict['access_url_base'], path)
|
fakes.fake_token_dict['access_url_base'],
|
||||||
|
path)
|
||||||
self.assertEqual(expected_url, url)
|
self.assertEqual(expected_url, url)
|
||||||
|
|
||||||
|
def test_authorize(self):
|
||||||
|
self._test_authorize(fakes.fake_token_dict['console_type'])
|
||||||
|
|
||||||
|
def test_authorize_novnc(self):
|
||||||
|
self._test_authorize('novnc')
|
||||||
|
|
||||||
@mock.patch('nova.db.api.console_auth_token_create')
|
@mock.patch('nova.db.api.console_auth_token_create')
|
||||||
def test_authorize_duplicate_token(self, mock_create):
|
def test_authorize_duplicate_token(self, mock_create):
|
||||||
mock_create.side_effect = DBDuplicateEntry()
|
mock_create.side_effect = DBDuplicateEntry()
|
||||||
|
|||||||
Reference in New Issue
Block a user