Fix accumulated nits
Fix nits from the following reviews: - https://review.openstack.org/#/c/345397/35 - https://review.openstack.org/#/c/345398/36 - https://review.openstack.org/#/c/345399/42 Change-Id: Iafa5b4432a85353a216da4d55e46e1eda30842e3 Blueprint: websocket-proxy-to-host-security
This commit is contained in:
@@ -230,7 +230,12 @@ first.
|
|||||||
|
|
||||||
Possible values:
|
Possible values:
|
||||||
|
|
||||||
* "none": allow connection without authentication
|
* ``none``: allow connection without authentication
|
||||||
|
* ``vencrypt``: use VeNCrypt authentication scheme
|
||||||
|
|
||||||
|
Related options:
|
||||||
|
|
||||||
|
* ``[vnc]vencrypt_client_key``, ``[vnc]vencrypt_client_cert``: must also be set
|
||||||
"""),
|
"""),
|
||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
'vencrypt_client_key',
|
'vencrypt_client_key',
|
||||||
@@ -241,8 +246,8 @@ proxy server presents to the compute node during VNC authentication.
|
|||||||
|
|
||||||
Related options:
|
Related options:
|
||||||
|
|
||||||
* ``vnc.auth_schemes``: must include "vencrypt"
|
* ``vnc.auth_schemes``: must include ``vencrypt``
|
||||||
* ``vnc.vencrypt_client_cert```: must also be set
|
* ``vnc.vencrypt_client_cert``: must also be set
|
||||||
"""),
|
"""),
|
||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
'vencrypt_client_cert',
|
'vencrypt_client_cert',
|
||||||
@@ -253,8 +258,8 @@ the VNC proxy server presents to the compute node during VNC authentication.
|
|||||||
|
|
||||||
Realted options:
|
Realted options:
|
||||||
|
|
||||||
* ``vnc.auth_schemes``: must include "vencrypt"
|
* ``vnc.auth_schemes``: must include ``vencrypt``
|
||||||
* ``vnc.vencrypt_client_key```: must also be set
|
* ``vnc.vencrypt_client_key``: must also be set
|
||||||
"""),
|
"""),
|
||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
'vencrypt_ca_certs',
|
'vencrypt_ca_certs',
|
||||||
@@ -265,7 +270,7 @@ for the certificate authorities used by the compute node VNC server.
|
|||||||
|
|
||||||
Related options:
|
Related options:
|
||||||
|
|
||||||
* ``vnc.auth_schemes``: must include "vencrypt"
|
* ``vnc.auth_schemes``: must include ``vencrypt``
|
||||||
"""),
|
"""),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@@ -40,19 +40,6 @@ class AuthType(enum.IntEnum):
|
|||||||
MSLOGON = 0xfffffffa # Used by UltraVNC
|
MSLOGON = 0xfffffffa # Used by UltraVNC
|
||||||
|
|
||||||
|
|
||||||
class AuthVeNCryptSubtype(enum.IntEnum):
|
|
||||||
|
|
||||||
PLAIN = 256
|
|
||||||
TLSNONE = 257
|
|
||||||
TLSVNC = 258
|
|
||||||
TLSPLAIN = 259
|
|
||||||
X509NONE = 260
|
|
||||||
X509VNC = 261
|
|
||||||
X509PLAIN = 262
|
|
||||||
X509SASL = 263
|
|
||||||
TLSSASL = 264
|
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class RFBAuthScheme(object):
|
class RFBAuthScheme(object):
|
||||||
|
|
||||||
@@ -74,5 +61,7 @@ class RFBAuthScheme(object):
|
|||||||
|
|
||||||
Should raise exception.RFBAuthHandshakeFailed if
|
Should raise exception.RFBAuthHandshakeFailed if
|
||||||
an error occurs
|
an error occurs
|
||||||
|
|
||||||
|
:param compute_sock: socket connected to the compute node instance
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
@@ -37,6 +37,13 @@ class RFBAuthSchemeList(object):
|
|||||||
self.schemes[scheme.security_type()] = scheme
|
self.schemes[scheme.security_type()] = scheme
|
||||||
|
|
||||||
def find_scheme(self, desired_types):
|
def find_scheme(self, desired_types):
|
||||||
|
"""Find a suitable authentication scheme to use with compute node.
|
||||||
|
|
||||||
|
Identify which of the ``desired_types`` we can accept.
|
||||||
|
|
||||||
|
:param desired_types: A list of ints corresponding to the various
|
||||||
|
authentication types supported.
|
||||||
|
"""
|
||||||
for security_type in desired_types:
|
for security_type in desired_types:
|
||||||
if security_type in self.schemes:
|
if security_type in self.schemes:
|
||||||
return self.schemes[security_type]
|
return self.schemes[security_type]
|
||||||
|
@@ -12,20 +12,39 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import enum
|
||||||
import ssl
|
import ssl
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
import six
|
||||||
|
|
||||||
from nova.console.rfb import auth
|
from nova.console.rfb import auth
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.i18n import _, _LI
|
from nova.i18n import _
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class AuthVeNCryptSubtype(enum.IntEnum):
|
||||||
|
"""Possible VeNCrypt subtypes.
|
||||||
|
|
||||||
|
From https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst
|
||||||
|
"""
|
||||||
|
|
||||||
|
PLAIN = 256
|
||||||
|
TLSNONE = 257
|
||||||
|
TLSVNC = 258
|
||||||
|
TLSPLAIN = 259
|
||||||
|
X509NONE = 260
|
||||||
|
X509VNC = 261
|
||||||
|
X509PLAIN = 262
|
||||||
|
X509SASL = 263
|
||||||
|
TLSSASL = 264
|
||||||
|
|
||||||
|
|
||||||
class RFBAuthSchemeVeNCrypt(auth.RFBAuthScheme):
|
class RFBAuthSchemeVeNCrypt(auth.RFBAuthScheme):
|
||||||
"""A security proxy helper which uses VeNCrypt.
|
"""A security proxy helper which uses VeNCrypt.
|
||||||
|
|
||||||
@@ -81,17 +100,20 @@ class RFBAuthSchemeVeNCrypt(auth.RFBAuthScheme):
|
|||||||
|
|
||||||
LOG.debug("Server supports VeNCrypt sub-types %s", sub_types)
|
LOG.debug("Server supports VeNCrypt sub-types %s", sub_types)
|
||||||
|
|
||||||
if auth.AuthVeNCryptSubtype.X509NONE not in sub_types:
|
# We use X509None as we're only seeking to encrypt the channel (ruling
|
||||||
|
# out PLAIN) and prevent MITM (ruling out TLS*, which uses trivially
|
||||||
|
# MITM'd Anonymous Diffie Hellmann (DH) cyphers)
|
||||||
|
if AuthVeNCryptSubtype.X509NONE not in sub_types:
|
||||||
reason = _("Server does not support the x509None (%s) VeNCrypt"
|
reason = _("Server does not support the x509None (%s) VeNCrypt"
|
||||||
" sub-auth type") % \
|
" sub-auth type") % \
|
||||||
auth.AuthVeNCryptSubtype.X509NONE
|
AuthVeNCryptSubtype.X509NONE
|
||||||
raise exception.RFBAuthHandshakeFailed(reason=reason)
|
raise exception.RFBAuthHandshakeFailed(reason=reason)
|
||||||
|
|
||||||
LOG.debug("Attempting to use the x509None (%s) auth sub-type",
|
LOG.debug("Attempting to use the x509None (%s) auth sub-type",
|
||||||
auth.AuthVeNCryptSubtype.X509NONE)
|
AuthVeNCryptSubtype.X509NONE)
|
||||||
|
|
||||||
compute_sock.sendall(struct.pack(
|
compute_sock.sendall(struct.pack(
|
||||||
'!I', auth.AuthVeNCryptSubtype.X509NONE))
|
'!I', AuthVeNCryptSubtype.X509NONE))
|
||||||
|
|
||||||
# NB(sross): the spec is missing a U8 here that's used in
|
# NB(sross): the spec is missing a U8 here that's used in
|
||||||
# multiple implementations (e.g. QEMU, GTK-VNC). 1 means
|
# multiple implementations (e.g. QEMU, GTK-VNC). 1 means
|
||||||
@@ -120,9 +142,10 @@ class RFBAuthSchemeVeNCrypt(auth.RFBAuthScheme):
|
|||||||
cert_reqs=ssl.CERT_REQUIRED,
|
cert_reqs=ssl.CERT_REQUIRED,
|
||||||
ca_certs=CONF.vnc.vencrypt_ca_certs)
|
ca_certs=CONF.vnc.vencrypt_ca_certs)
|
||||||
|
|
||||||
LOG.info(_LI("VeNCrypt security handshake accepted"))
|
LOG.info("VeNCrypt security handshake accepted")
|
||||||
return wrapped_sock
|
return wrapped_sock
|
||||||
|
|
||||||
except ssl.SSLError as e:
|
except ssl.SSLError as e:
|
||||||
reason = _("Error establishing TLS connection to server: %s") % e
|
reason = _("Error establishing TLS connection to server: %s") % (
|
||||||
|
six.text_type(e))
|
||||||
raise exception.RFBAuthHandshakeFailed(reason=reason)
|
raise exception.RFBAuthHandshakeFailed(reason=reason)
|
||||||
|
@@ -23,7 +23,7 @@ from nova.console.rfb import auth
|
|||||||
from nova.console.rfb import auths
|
from nova.console.rfb import auths
|
||||||
from nova.console.securityproxy import base
|
from nova.console.securityproxy import base
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.i18n import _, _LI
|
from nova.i18n import _
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -46,6 +46,10 @@ class RFBSecurityProxy(base.SecurityProxy):
|
|||||||
See the general RFB specification at:
|
See the general RFB specification at:
|
||||||
|
|
||||||
https://tools.ietf.org/html/rfc6143
|
https://tools.ietf.org/html/rfc6143
|
||||||
|
|
||||||
|
See an updated, maintained RDB specification at:
|
||||||
|
|
||||||
|
https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -67,7 +71,13 @@ class RFBSecurityProxy(base.SecurityProxy):
|
|||||||
# by sending the "Invalid" security type
|
# by sending the "Invalid" security type
|
||||||
compute_sock.sendall(auth.AUTH_STATUS_FAIL)
|
compute_sock.sendall(auth.AUTH_STATUS_FAIL)
|
||||||
|
|
||||||
def _parse_version(self, version_str):
|
@staticmethod
|
||||||
|
def _parse_version(version_str):
|
||||||
|
r"""Convert a version string to a float.
|
||||||
|
|
||||||
|
>>> RFBSecurityProxy._parse_version('RFB 003.008\n')
|
||||||
|
0.2
|
||||||
|
"""
|
||||||
maj_str = version_str[4:7]
|
maj_str = version_str[4:7]
|
||||||
min_str = version_str[8:11]
|
min_str = version_str[8:11]
|
||||||
|
|
||||||
@@ -119,6 +129,7 @@ class RFBSecurityProxy(base.SecurityProxy):
|
|||||||
permitted_auth_types_cnt = six.byte2int(recv(compute_sock, 1))
|
permitted_auth_types_cnt = six.byte2int(recv(compute_sock, 1))
|
||||||
|
|
||||||
if permitted_auth_types_cnt == 0:
|
if permitted_auth_types_cnt == 0:
|
||||||
|
# Decode the reason why the request failed
|
||||||
reason_len_raw = recv(compute_sock, 4)
|
reason_len_raw = recv(compute_sock, 4)
|
||||||
reason_len = struct.unpack('!I', reason_len_raw)[0]
|
reason_len = struct.unpack('!I', reason_len_raw)[0]
|
||||||
reason = recv(compute_sock, reason_len)
|
reason = recv(compute_sock, reason_len)
|
||||||
@@ -148,9 +159,8 @@ class RFBSecurityProxy(base.SecurityProxy):
|
|||||||
_("Only the security type None (%d) is supported") %
|
_("Only the security type None (%d) is supported") %
|
||||||
auth.AuthType.NONE)
|
auth.AuthType.NONE)
|
||||||
|
|
||||||
reason = _("Client requested a security type other than "
|
reason = _("Client requested a security type other than None "
|
||||||
" None (%(none_code)d): "
|
"(%(none_code)d): %(auth_type)s") % {
|
||||||
"%(auth_type)s") % {
|
|
||||||
'auth_type': client_auth,
|
'auth_type': client_auth,
|
||||||
'none_code': auth.AuthType.NONE}
|
'none_code': auth.AuthType.NONE}
|
||||||
raise exception.SecurityProxyNegotiationFailed(reason=reason)
|
raise exception.SecurityProxyNegotiationFailed(reason=reason)
|
||||||
@@ -179,10 +189,10 @@ class RFBSecurityProxy(base.SecurityProxy):
|
|||||||
_("Unable to negotiate security with server"))
|
_("Unable to negotiate security with server"))
|
||||||
LOG.debug("Auth failed %s", six.text_type(e))
|
LOG.debug("Auth failed %s", six.text_type(e))
|
||||||
raise exception.SecurityProxyNegotiationFailed(
|
raise exception.SecurityProxyNegotiationFailed(
|
||||||
reason="Auth handshake failed")
|
reason=_("Auth handshake failed"))
|
||||||
|
|
||||||
LOG.info(_LI("Finished security handshake, resuming normal proxy "
|
LOG.info("Finished security handshake, resuming normal proxy "
|
||||||
"mode using secured socket"))
|
"mode using secured socket")
|
||||||
|
|
||||||
# we can just proxy the security result -- if the server security
|
# we can just proxy the security result -- if the server security
|
||||||
# negotiation fails, we want the client to think it has failed
|
# negotiation fails, we want the client to think it has failed
|
||||||
|
@@ -32,8 +32,8 @@ class RFBAuthSchemeListTestCase(test.NoDBTestCase):
|
|||||||
schemelist = auths.RFBAuthSchemeList()
|
schemelist = auths.RFBAuthSchemeList()
|
||||||
|
|
||||||
security_types = sorted(schemelist.schemes.keys())
|
security_types = sorted(schemelist.schemes.keys())
|
||||||
self.assertEqual(security_types, [auth.AuthType.NONE,
|
self.assertEqual([auth.AuthType.NONE, auth.AuthType.VENCRYPT],
|
||||||
auth.AuthType.VENCRYPT])
|
security_types)
|
||||||
|
|
||||||
def test_load_unknown(self):
|
def test_load_unknown(self):
|
||||||
"""Ensure invalid auth schemes are not supported.
|
"""Ensure invalid auth schemes are not supported.
|
||||||
|
@@ -58,8 +58,8 @@ class RFBAuthSchemeVeNCryptTestCase(test.NoDBTestCase):
|
|||||||
self._expect_recv(1, "\x00")
|
self._expect_recv(1, "\x00")
|
||||||
|
|
||||||
self._expect_recv(1, "\x02")
|
self._expect_recv(1, "\x02")
|
||||||
subtypes_raw = [auth.AuthVeNCryptSubtype.X509NONE,
|
subtypes_raw = [authvencrypt.AuthVeNCryptSubtype.X509NONE,
|
||||||
auth.AuthVeNCryptSubtype.X509VNC]
|
authvencrypt.AuthVeNCryptSubtype.X509VNC]
|
||||||
subtypes = struct.pack('!2I', *subtypes_raw)
|
subtypes = struct.pack('!2I', *subtypes_raw)
|
||||||
self._expect_recv(8, subtypes)
|
self._expect_recv(8, subtypes)
|
||||||
|
|
||||||
@@ -89,8 +89,8 @@ class RFBAuthSchemeVeNCryptTestCase(test.NoDBTestCase):
|
|||||||
self._expect_recv(1, "\x00")
|
self._expect_recv(1, "\x00")
|
||||||
|
|
||||||
self._expect_recv(1, "\x02")
|
self._expect_recv(1, "\x02")
|
||||||
subtypes_raw = [auth.AuthVeNCryptSubtype.X509NONE,
|
subtypes_raw = [authvencrypt.AuthVeNCryptSubtype.X509NONE,
|
||||||
auth.AuthVeNCryptSubtype.X509VNC]
|
authvencrypt.AuthVeNCryptSubtype.X509VNC]
|
||||||
subtypes = struct.pack('!2I', *subtypes_raw)
|
subtypes = struct.pack('!2I', *subtypes_raw)
|
||||||
self._expect_recv(8, subtypes)
|
self._expect_recv(8, subtypes)
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ class RFBAuthSchemeVeNCryptTestCase(test.NoDBTestCase):
|
|||||||
self._expect_recv(1, "\x00")
|
self._expect_recv(1, "\x00")
|
||||||
|
|
||||||
self._expect_recv(1, "\x01")
|
self._expect_recv(1, "\x01")
|
||||||
subtypes_raw = [auth.AuthVeNCryptSubtype.X509VNC]
|
subtypes_raw = [authvencrypt.AuthVeNCryptSubtype.X509VNC]
|
||||||
subtypes = struct.pack('!I', *subtypes_raw)
|
subtypes = struct.pack('!I', *subtypes_raw)
|
||||||
self._expect_recv(4, subtypes)
|
self._expect_recv(4, subtypes)
|
||||||
|
|
||||||
@@ -154,8 +154,8 @@ class RFBAuthSchemeVeNCryptTestCase(test.NoDBTestCase):
|
|||||||
self._expect_recv(1, "\x00")
|
self._expect_recv(1, "\x00")
|
||||||
|
|
||||||
self._expect_recv(1, "\x02")
|
self._expect_recv(1, "\x02")
|
||||||
subtypes_raw = [auth.AuthVeNCryptSubtype.X509NONE,
|
subtypes_raw = [authvencrypt.AuthVeNCryptSubtype.X509NONE,
|
||||||
auth.AuthVeNCryptSubtype.X509VNC]
|
authvencrypt.AuthVeNCryptSubtype.X509VNC]
|
||||||
subtypes = struct.pack('!2I', *subtypes_raw)
|
subtypes = struct.pack('!2I', *subtypes_raw)
|
||||||
self._expect_recv(8, subtypes)
|
self._expect_recv(8, subtypes)
|
||||||
|
|
||||||
@@ -174,8 +174,8 @@ class RFBAuthSchemeVeNCryptTestCase(test.NoDBTestCase):
|
|||||||
self._expect_recv(1, "\x00")
|
self._expect_recv(1, "\x00")
|
||||||
|
|
||||||
self._expect_recv(1, "\x02")
|
self._expect_recv(1, "\x02")
|
||||||
subtypes_raw = [auth.AuthVeNCryptSubtype.X509NONE,
|
subtypes_raw = [authvencrypt.AuthVeNCryptSubtype.X509NONE,
|
||||||
auth.AuthVeNCryptSubtype.X509VNC]
|
authvencrypt.AuthVeNCryptSubtype.X509VNC]
|
||||||
subtypes = struct.pack('!2I', *subtypes_raw)
|
subtypes = struct.pack('!2I', *subtypes_raw)
|
||||||
self._expect_recv(8, subtypes)
|
self._expect_recv(8, subtypes)
|
||||||
|
|
||||||
|
@@ -62,7 +62,7 @@ class RFBSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
self._expect_tenant_recv(auth.VERSION_LENGTH, full_version_str)
|
self._expect_tenant_recv(auth.VERSION_LENGTH, full_version_str)
|
||||||
|
|
||||||
def _to_binary(self, val):
|
def _to_binary(self, val):
|
||||||
if type(val) != six.binary_type:
|
if not isinstance(val, six.binary_type):
|
||||||
val = six.binary_type(val, 'utf-8')
|
val = six.binary_type(val, 'utf-8')
|
||||||
return val
|
return val
|
||||||
|
|
||||||
@@ -87,6 +87,11 @@ class RFBSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
list(self.compute_sock.recv.side_effect) + [ret_val])
|
list(self.compute_sock.recv.side_effect) + [ret_val])
|
||||||
|
|
||||||
def test_fail(self):
|
def test_fail(self):
|
||||||
|
"""Validate behavior for invalid initial message from tenant.
|
||||||
|
|
||||||
|
The spec defines the sequence that should be used in the handshaking
|
||||||
|
process. Anything outside of this is invalid.
|
||||||
|
"""
|
||||||
self._expect_tenant_send("\x00\x00\x00\x01\x00\x00\x00\x04blah")
|
self._expect_tenant_send("\x00\x00\x00\x01\x00\x00\x00\x04blah")
|
||||||
|
|
||||||
self.proxy._fail(self.tenant_sock, None, 'blah')
|
self.proxy._fail(self.tenant_sock, None, 'blah')
|
||||||
@@ -94,6 +99,11 @@ class RFBSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
self._assert_expected_calls()
|
self._assert_expected_calls()
|
||||||
|
|
||||||
def test_fail_server_message(self):
|
def test_fail_server_message(self):
|
||||||
|
"""Validate behavior for invalid initial message from server.
|
||||||
|
|
||||||
|
The spec defines the sequence that should be used in the handshaking
|
||||||
|
process. Anything outside of this is invalid.
|
||||||
|
"""
|
||||||
self._expect_tenant_send("\x00\x00\x00\x01\x00\x00\x00\x04blah")
|
self._expect_tenant_send("\x00\x00\x00\x01\x00\x00\x00\x04blah")
|
||||||
self._expect_compute_send("\x00")
|
self._expect_compute_send("\x00")
|
||||||
|
|
||||||
@@ -102,20 +112,30 @@ class RFBSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
self._assert_expected_calls()
|
self._assert_expected_calls()
|
||||||
|
|
||||||
def test_parse_version(self):
|
def test_parse_version(self):
|
||||||
|
"""Validate behavior of version parser."""
|
||||||
res = self.proxy._parse_version("RFB 012.034\n")
|
res = self.proxy._parse_version("RFB 012.034\n")
|
||||||
self.assertEqual(12.34, res)
|
self.assertEqual(12.34, res)
|
||||||
|
|
||||||
def test_fails_on_compute_version(self):
|
def test_fails_on_compute_version(self):
|
||||||
|
"""Validate behavior for unsupported compute RFB version.
|
||||||
|
|
||||||
|
We only support RFB protocol version 3.8.
|
||||||
|
"""
|
||||||
for full_version_str in ["RFB 003.007\n", "RFB 003.009\n"]:
|
for full_version_str in ["RFB 003.007\n", "RFB 003.009\n"]:
|
||||||
self._expect_compute_recv(auth.VERSION_LENGTH, full_version_str)
|
self._expect_compute_recv(auth.VERSION_LENGTH, full_version_str)
|
||||||
|
|
||||||
self.assertRaises(exception.SecurityProxyNegotiationFailed,
|
ex = self.assertRaises(exception.SecurityProxyNegotiationFailed,
|
||||||
self.proxy.connect,
|
self.proxy.connect,
|
||||||
self.tenant_sock,
|
self.tenant_sock,
|
||||||
self.compute_sock)
|
self.compute_sock)
|
||||||
|
self.assertIn('version 3.8, but server', six.text_type(ex))
|
||||||
self._assert_expected_calls()
|
self._assert_expected_calls()
|
||||||
|
|
||||||
def test_fails_on_tenant_version(self):
|
def test_fails_on_tenant_version(self):
|
||||||
|
"""Validate behavior for unsupported tenant RFB version.
|
||||||
|
|
||||||
|
We only support RFB protocol version 3.8.
|
||||||
|
"""
|
||||||
full_version_str = "RFB 003.008\n"
|
full_version_str = "RFB 003.008\n"
|
||||||
|
|
||||||
for full_version_str_invalid in ["RFB 003.007\n", "RFB 003.009\n"]:
|
for full_version_str_invalid in ["RFB 003.007\n", "RFB 003.009\n"]:
|
||||||
@@ -126,13 +146,19 @@ class RFBSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
self._expect_tenant_recv(auth.VERSION_LENGTH,
|
self._expect_tenant_recv(auth.VERSION_LENGTH,
|
||||||
full_version_str_invalid)
|
full_version_str_invalid)
|
||||||
|
|
||||||
self.assertRaises(exception.SecurityProxyNegotiationFailed,
|
ex = self.assertRaises(exception.SecurityProxyNegotiationFailed,
|
||||||
self.proxy.connect,
|
self.proxy.connect,
|
||||||
self.tenant_sock,
|
self.tenant_sock,
|
||||||
self.compute_sock)
|
self.compute_sock)
|
||||||
|
self.assertIn('version 3.8, but tenant', six.text_type(ex))
|
||||||
self._assert_expected_calls()
|
self._assert_expected_calls()
|
||||||
|
|
||||||
def test_fails_on_sec_type_cnt_zero(self):
|
def test_fails_on_sec_type_cnt_zero(self):
|
||||||
|
"""Validate behavior if a server returns 0 supported security types.
|
||||||
|
|
||||||
|
This indicates a random issue and the cause of that issues should be
|
||||||
|
decoded and reported in the exception.
|
||||||
|
"""
|
||||||
self.proxy._fail = mock.Mock()
|
self.proxy._fail = mock.Mock()
|
||||||
|
|
||||||
self._version_handshake()
|
self._version_handshake()
|
||||||
@@ -142,15 +168,17 @@ class RFBSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
self._expect_compute_recv(6, "cheese")
|
self._expect_compute_recv(6, "cheese")
|
||||||
self._expect_tenant_send("\x00\x00\x00\x00\x06cheese")
|
self._expect_tenant_send("\x00\x00\x00\x00\x06cheese")
|
||||||
|
|
||||||
self.assertRaises(exception.SecurityProxyNegotiationFailed,
|
ex = self.assertRaises(exception.SecurityProxyNegotiationFailed,
|
||||||
self.proxy.connect,
|
self.proxy.connect,
|
||||||
self.tenant_sock,
|
self.tenant_sock,
|
||||||
self.compute_sock)
|
self.compute_sock)
|
||||||
|
self.assertIn('cheese', six.text_type(ex))
|
||||||
|
|
||||||
self._assert_expected_calls()
|
self._assert_expected_calls()
|
||||||
|
|
||||||
@mock.patch.object(authnone.RFBAuthSchemeNone, "security_handshake")
|
@mock.patch.object(authnone.RFBAuthSchemeNone, "security_handshake")
|
||||||
def test_full_run(self, mock_handshake):
|
def test_full_run(self, mock_handshake):
|
||||||
|
"""Validate correct behavior."""
|
||||||
new_sock = mock.MagicMock()
|
new_sock = mock.MagicMock()
|
||||||
mock_handshake.return_value = new_sock
|
mock_handshake.return_value = new_sock
|
||||||
|
|
||||||
@@ -171,6 +199,7 @@ class RFBSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
self._assert_expected_calls()
|
self._assert_expected_calls()
|
||||||
|
|
||||||
def test_client_auth_invalid_fails(self):
|
def test_client_auth_invalid_fails(self):
|
||||||
|
"""Validate behavior if no security types are supported."""
|
||||||
self.proxy._fail = self.manager.proxy._fail
|
self.proxy._fail = self.manager.proxy._fail
|
||||||
self.proxy.security_handshake = self.manager.proxy.security_handshake
|
self.proxy.security_handshake = self.manager.proxy.security_handshake
|
||||||
|
|
||||||
@@ -195,6 +224,7 @@ class RFBSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
self._assert_expected_calls()
|
self._assert_expected_calls()
|
||||||
|
|
||||||
def test_exception_in_choose_security_type_fails(self):
|
def test_exception_in_choose_security_type_fails(self):
|
||||||
|
"""Validate behavior if a given security type isn't supported."""
|
||||||
self.proxy._fail = self.manager.proxy._fail
|
self.proxy._fail = self.manager.proxy._fail
|
||||||
self.proxy.security_handshake = self.manager.proxy.security_handshake
|
self.proxy.security_handshake = self.manager.proxy.security_handshake
|
||||||
|
|
||||||
@@ -220,6 +250,7 @@ class RFBSecurityProxyTestCase(test.NoDBTestCase):
|
|||||||
|
|
||||||
@mock.patch.object(authnone.RFBAuthSchemeNone, "security_handshake")
|
@mock.patch.object(authnone.RFBAuthSchemeNone, "security_handshake")
|
||||||
def test_exception_security_handshake_fails(self, mock_auth):
|
def test_exception_security_handshake_fails(self, mock_auth):
|
||||||
|
"""Validate behavior if the security handshake fails for any reason."""
|
||||||
self.proxy._fail = self.manager.proxy._fail
|
self.proxy._fail = self.manager.proxy._fail
|
||||||
|
|
||||||
self._version_handshake()
|
self._version_handshake()
|
||||||
|
@@ -17,8 +17,7 @@ features:
|
|||||||
ensure it is connecting to a valid compute node. The proxy can also send
|
ensure it is connecting to a valid compute node. The proxy can also send
|
||||||
its own x509 cert to allow the compute node to validate that the connection
|
its own x509 cert to allow the compute node to validate that the connection
|
||||||
comes from the official proxy server.
|
comes from the official proxy server.
|
||||||
upgrade:
|
|
||||||
- |
|
|
||||||
To make use of VeNCrypt, configuration steps are required for both the
|
To make use of VeNCrypt, configuration steps are required for both the
|
||||||
`nova-novncproxy` service and libvirt on all the compute nodes. The
|
`nova-novncproxy` service and libvirt on all the compute nodes. The
|
||||||
``/etc/libvirt/qemu.conf`` file should be modified to set the ``vnc_tls``
|
``/etc/libvirt/qemu.conf`` file should be modified to set the ``vnc_tls``
|
||||||
|
Reference in New Issue
Block a user