Skip to content

Commit 25e222c

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add 'path' query parameter to console access url" into stable/stein
2 parents 5a63174 + 186aff9 commit 25e222c

17 files changed

+53
-36
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"console": {
33
"type": "rdp-html5",
4-
"url": "http://127.0.0.1:6083/?token=191996c3-7b0f-42f3-95a7-f1839f2da6ed"
4+
"url": "http://127.0.0.1:6083/?path=%3Ftoken%3D21efbb20-b84c-4d1f-807d-4e14f6884b7f"
55
}
6-
}
6+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"console": {
33
"type": "serial",
4-
"url":"ws://127.0.0.1:6083/?token=f9906a48-b71e-4f18-baca-c987da3ebdb3"
4+
"url": "ws://127.0.0.1:6083/?path=%3Ftoken%3D6ac46b4c-2705-4d8b-baa3-1b6f1b0c7dd3"
55
}
6-
}
6+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"console": {
33
"type": "spice-html5",
4-
"url": "http://127.0.0.1:6082/spice_auto.html?token=a30e5d08-6a20-4043-958f-0852440c6af4"
4+
"url": "http://127.0.0.1:6082/spice_auto.html?path=%3Ftoken%3Da7bd9607-421c-44b9-8689-18e87ada2f78"
55
}
66
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"console": {
33
"type": "novnc",
4-
"url": "http://127.0.0.1:6080/vnc_auto.html?token=191996c3-7b0f-42f3-95a7-f1839f2da6ed"
4+
"url": "http://127.0.0.1:6080/vnc_auto.html?path=%3Ftoken%3Ddaae261f-474d-4cae-8f6a-1865278ed8c9"
55
}
66
}

doc/api_samples/os-remote-consoles/v2.6/create-vnc-console-resp.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"remote_console": {
33
"protocol": "vnc",
44
"type": "novnc",
5-
"url": "http://example.com:6080/vnc_auto.html?token=b60bcfc3-5fd4-4d21-986c-e83379107819"
5+
"url": "http://example.com:6080/vnc_auto.html?path=%3Ftoken%3Db60bcfc3-5fd4-4d21-986c-e83379107819"
66
}
77
}

doc/source/admin/figures/SCH_5009_V00_NUAC-VNC_OpenStack.svg

Lines changed: 2 additions & 2 deletions
Loading

doc/source/admin/remote-console-access.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ nova provides services to handle this proxying. Consider a noVNC-based VNC
3030
console connection for example:
3131

3232
#. A user connects to the API and gets an ``access_url`` such as,
33-
``http://ip:port/?token=xyz``.
33+
``http://ip:port/?path=%3Ftoken%3Dxyz``.
3434

3535
#. The user pastes the URL in a browser or uses it as a client parameter.
3636

nova/api/openstack/compute/rest_api_version_history.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Example response::
8484
"remote_console": {
8585
"protocol": "vnc",
8686
"type": "novnc",
87-
"url": "http://example.com:6080/vnc_auto.html?token=XYZ"
87+
"url": "http://example.com:6080/vnc_auto.html?path=%3Ftoken%3DXYZ"
8888
}
8989
}
9090

nova/objects/console_auth_token.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from oslo_utils import strutils
1919
from oslo_utils import timeutils
2020
from oslo_utils import uuidutils
21+
import six.moves.urllib.parse as urlparse
2122

2223
from nova.db import api as db
2324
from nova import exception
@@ -60,7 +61,9 @@ def access_url(self):
6061
specific to this authorization.
6162
"""
6263
if self.obj_attr_is_set('id'):
63-
return '%s?token=%s' % (self.access_url_base, self.token)
64+
qparams = {'path': '?token=%s' % self.token}
65+
return '%s?%s' % (self.access_url_base,
66+
urlparse.urlencode(qparams))
6467

6568
@staticmethod
6669
def _from_db_object(context, obj, db_obj):
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"console": {
33
"type": "rdp-html5",
4-
"url": "http://127.0.0.1:6083/?token=%(uuid)s"
4+
"url": "http://127.0.0.1:6083/?path=%%3Ftoken%%3D%(uuid)s"
55
}
66
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"console": {
33
"type": "serial",
4-
"url": "ws://127.0.0.1:6083/?token=%(uuid)s"
4+
"url": "ws://127.0.0.1:6083/?path=%%3Ftoken%%3D%(uuid)s"
55
}
66
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"console": {
33
"type": "spice-html5",
4-
"url": "http://127.0.0.1:6082/spice_auto.html?token=%(uuid)s"
4+
"url": "http://127.0.0.1:6082/spice_auto.html?path=%%3Ftoken%%3D%(uuid)s"
55
}
66
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"console": {
33
"type": "novnc",
4-
"url": "http://127.0.0.1:6080/vnc_auto.html?token=%(uuid)s"
4+
"url": "http://127.0.0.1:6080/vnc_auto.html?path=%%3Ftoken%%3D%(uuid)s"
55
}
66
}

nova/tests/functional/api_sample_tests/test_console_auth_tokens.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import re
1616

1717
from oslo_serialization import jsonutils
18+
import six.moves.urllib.parse as urlparse
1819

1920
from nova.tests.functional.api_sample_tests import test_servers
2021

@@ -32,7 +33,8 @@ def _get_console_token(self, uuid):
3233
{'action': 'os-getRDPConsole'})
3334

3435
url = self._get_console_url(response.content)
35-
return re.match('.+?token=([^&]+)', url).groups()[0]
36+
path = urlparse.urlencode({'path': '?token='})
37+
return re.match('.+?%s([^&]+)' % path, url).groups()[0]
3638

3739
def test_get_console_connect_info(self):
3840
self.flags(enabled=True, group='rdp')

nova/tests/unit/console/test_websocketproxy.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import mock
2121
from oslo_utils.fixture import uuidsentinel as uuids
22+
import six.moves.urllib.parse as urlparse
2223

2324
import nova.conf
2425
from nova.console.securityproxy import base
@@ -47,6 +48,7 @@ def setUp(self):
4748
self.wh.msg = mock.MagicMock()
4849
self.wh.do_proxy = mock.MagicMock()
4950
self.wh.headers = mock.MagicMock()
51+
self.path = urlparse.urlencode({'path': '?token=123-456-789'})
5052

5153
def _fake_console_db(self, **updates):
5254
console_db = copy.deepcopy(fake_ca.fake_token_dict)
@@ -96,7 +98,7 @@ def test_new_websocket_client_db(
9698
tsock.recv.return_value = "HTTP/1.1 200 OK\r\n\r\n"
9799
self.wh.socket.return_value = tsock
98100

99-
self.wh.path = "http://127.0.0.1/?token=123-456-789"
101+
self.wh.path = "http://127.0.0.1/?%s" % self.path
100102
self.wh.headers = self.fake_header
101103

102104
if instance_not_found:
@@ -143,6 +145,8 @@ def setUp(self):
143145
self.wh.msg = mock.MagicMock()
144146
self.wh.do_proxy = mock.MagicMock()
145147
self.wh.headers = mock.MagicMock()
148+
self.path = urlparse.urlencode({'path': '?token=123-456-789'})
149+
self.path_invalid = urlparse.urlencode({'path': '?token=XXX'})
146150

147151
fake_header = {
148152
'cookie': 'token="123-456-789"',
@@ -228,7 +232,7 @@ def test_new_websocket_client_enable_consoleauth(self, check_token):
228232
'access_url': 'https://example.net:6080'
229233
}
230234
self.wh.socket.return_value = '<socket>'
231-
self.wh.path = "http://127.0.0.1/?token=123-456-789"
235+
self.wh.path = "http://127.0.0.1/?%s" % self.path
232236
self.wh.headers = self.fake_header
233237

234238
self.wh.new_websocket_client()
@@ -261,7 +265,7 @@ def test_new_websocket_client_enable_consoleauth_fallback(self, validate,
261265
validate.return_value = objects.ConsoleAuthToken(**params)
262266

263267
self.wh.socket.return_value = '<socket>'
264-
self.wh.path = "http://127.0.0.1/?token=123-456-789"
268+
self.wh.path = "http://127.0.0.1/?%s" % self.path
265269
self.wh.headers = self.fake_header
266270

267271
self.wh.new_websocket_client()
@@ -287,7 +291,7 @@ def test_new_websocket_client(self, validate, check_port):
287291
validate.return_value = objects.ConsoleAuthToken(**params)
288292

289293
self.wh.socket.return_value = '<socket>'
290-
self.wh.path = "http://127.0.0.1/?token=123-456-789"
294+
self.wh.path = "http://127.0.0.1/?%s" % self.path
291295
self.wh.headers = self.fake_header
292296

293297
self.wh.new_websocket_client()
@@ -312,7 +316,7 @@ def test_new_websocket_client_ipv6_url(self, validate, check_port):
312316
validate.return_value = objects.ConsoleAuthToken(**params)
313317

314318
self.wh.socket.return_value = '<socket>'
315-
self.wh.path = "http://[2001:db8::1]/?token=123-456-789"
319+
self.wh.path = "http://[2001:db8::1]/?%s" % self.path
316320
self.wh.headers = self.fake_header_ipv6
317321

318322
self.wh.new_websocket_client()
@@ -325,7 +329,7 @@ def test_new_websocket_client_ipv6_url(self, validate, check_port):
325329
def test_new_websocket_client_token_invalid(self, validate):
326330
validate.side_effect = exception.InvalidToken(token='XXX')
327331

328-
self.wh.path = "http://127.0.0.1/?token=XXX"
332+
self.wh.path = "http://127.0.0.1/?%s" % self.path_invalid
329333
self.wh.headers = self.fake_header_bad_token
330334

331335
self.assertRaises(exception.InvalidToken,
@@ -353,7 +357,7 @@ def test_new_websocket_client_internal_access_path(self, validate,
353357
tsock.recv.return_value = "HTTP/1.1 200 OK\r\n\r\n"
354358

355359
self.wh.socket.return_value = tsock
356-
self.wh.path = "http://127.0.0.1/?token=123-456-789"
360+
self.wh.path = "http://127.0.0.1/?%s" % self.path
357361
self.wh.headers = self.fake_header
358362

359363
self.wh.new_websocket_client()
@@ -386,7 +390,7 @@ def test_new_websocket_client_internal_access_path_err(self, validate,
386390
tsock.recv.return_value = "HTTP/1.1 500 Internal Server Error\r\n\r\n"
387391

388392
self.wh.socket.return_value = tsock
389-
self.wh.path = "http://127.0.0.1/?token=123-456-789"
393+
self.wh.path = "http://127.0.0.1/?%s" % self.path
390394
self.wh.headers = self.fake_header
391395

392396
self.assertRaises(exception.InvalidConnectionInfo,
@@ -418,7 +422,7 @@ def test_new_websocket_client_internal_access_path_rfb(self, validate,
418422
HTTP_RESP]
419423

420424
self.wh.socket.return_value = tsock
421-
self.wh.path = "http://127.0.0.1/?token=123-456-789"
425+
self.wh.path = "http://127.0.0.1/?%s" % self.path
422426
self.wh.headers = self.fake_header
423427

424428
self.wh.new_websocket_client()
@@ -448,7 +452,7 @@ def test_new_websocket_client_py273_good_scheme(
448452
validate.return_value = objects.ConsoleAuthToken(**params)
449453

450454
self.wh.socket.return_value = '<socket>'
451-
self.wh.path = "http://127.0.0.1/?token=123-456-789"
455+
self.wh.path = "http://127.0.0.1/?%s" % self.path
452456
self.wh.headers = self.fake_header
453457

454458
self.wh.new_websocket_client()
@@ -468,7 +472,7 @@ def test_new_websocket_client_py273_special_scheme(
468472
'console_type': 'novnc'
469473
}
470474
self.wh.socket.return_value = '<socket>'
471-
self.wh.path = "ws://127.0.0.1/?token=123-456-789"
475+
self.wh.path = "ws://127.0.0.1/?%s" % self.path
472476
self.wh.headers = self.fake_header
473477

474478
self.assertRaises(exception.NovaException,
@@ -477,10 +481,9 @@ def test_new_websocket_client_py273_special_scheme(
477481
@mock.patch('socket.getfqdn')
478482
def test_address_string_doesnt_do_reverse_dns_lookup(self, getfqdn):
479483
request_mock = mock.MagicMock()
480-
request_mock.makefile().readline.side_effect = [
481-
b'GET /vnc.html?token=123-456-789 HTTP/1.1\r\n',
482-
b''
483-
]
484+
msg = 'GET /vnc.html?%s HTTP/1.1\r\n' % self.path
485+
request_mock.makefile().readline.side_effect = [msg.encode('utf-8'),
486+
b'']
484487
server_mock = mock.MagicMock()
485488
client_address = ('8.8.8.8', 54321)
486489

@@ -734,7 +737,8 @@ def setUp(self):
734737
with mock.patch('websockify.ProxyRequestHandler'):
735738
self.wh = websocketproxy.NovaProxyRequestHandler()
736739
self.wh.server = self.server
737-
self.wh.path = "http://127.0.0.1/?token=123-456-789"
740+
path = urlparse.urlencode({'path': '?token=123-456-789'})
741+
self.wh.path = "http://127.0.0.1/?%s" % path
738742
self.wh.socket = mock.MagicMock()
739743
self.wh.msg = mock.MagicMock()
740744
self.wh.do_proxy = mock.MagicMock()

nova/tests/unit/objects/test_console_auth_token.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from oslo_db.exception import DBDuplicateEntry
2020
from oslo_utils.fixture import uuidsentinel
2121
from oslo_utils import timeutils
22+
import six.moves.urllib.parse as urlparse
2223

2324
from nova import exception
2425
from nova.objects import console_auth_token as token_obj
@@ -70,9 +71,9 @@ def test_authorize(self, mock_create):
7071
self.compare_obj(obj, expected)
7172

7273
url = obj.access_url
73-
expected_url = '%s?token=%s' % (
74-
fakes.fake_token_dict['access_url_base'],
75-
fakes.fake_token)
74+
path = urlparse.urlencode({'path': '?token=%s' % fakes.fake_token})
75+
expected_url = '%s?%s' % (
76+
fakes.fake_token_dict['access_url_base'], path)
7677
self.assertEqual(expected_url, url)
7778

7879
@mock.patch('nova.db.api.console_auth_token_create')
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
fixes:
3+
- |
4+
Add support for noVNC >= v1.1.0 for VNC consoles. Prior to this fix, VNC
5+
console token validation always failed regardless of actual token validity
6+
with noVNC >= v1.1.0. See
7+
https://bugs.launchpad.net/nova/+bug/1822676 for more details.

0 commit comments

Comments
 (0)