console: introduce the VeNCrypt RFB authentication scheme
Provide an implementation for the VeNCrypt RFB authentication scheme, which uses TLS and x509 certificates to provide both encryption and mutual authentication / authorization. Based on earlier work by Solly Ross <sross@redhat.com> Change-Id: I6a63d2535e86faf369ed1c0eeba6cb5a52252b80 Co-authored-by: Stephen Finucane <sfinucan@redhat.com> Implements: bp websocket-proxy-to-host-security
This commit is contained in:
		@@ -217,7 +217,7 @@ Related options:
 | 
			
		||||
    cfg.ListOpt(
 | 
			
		||||
        'auth_schemes',
 | 
			
		||||
        item_type=types.String(
 | 
			
		||||
            choices=['none']
 | 
			
		||||
            choices=['none', 'vencrypt']
 | 
			
		||||
        ),
 | 
			
		||||
        default=['none'],
 | 
			
		||||
        help="""
 | 
			
		||||
@@ -231,6 +231,41 @@ first.
 | 
			
		||||
Possible values:
 | 
			
		||||
 | 
			
		||||
* "none": allow connection without authentication
 | 
			
		||||
"""),
 | 
			
		||||
    cfg.StrOpt(
 | 
			
		||||
        'vencrypt_client_key',
 | 
			
		||||
        help="""The path to the client certificate PEM file (for x509)
 | 
			
		||||
 | 
			
		||||
The fully qualified path to a PEM file containing the private key which the VNC
 | 
			
		||||
proxy server presents to the compute node during VNC authentication.
 | 
			
		||||
 | 
			
		||||
Related options:
 | 
			
		||||
 | 
			
		||||
* ``vnc.auth_schemes``: must include "vencrypt"
 | 
			
		||||
* ``vnc.vencrypt_client_cert```: must also be set
 | 
			
		||||
"""),
 | 
			
		||||
    cfg.StrOpt(
 | 
			
		||||
        'vencrypt_client_cert',
 | 
			
		||||
        help="""The path to the client key file (for x509)
 | 
			
		||||
 | 
			
		||||
The fully qualified path to a PEM file containing the x509 certificate which
 | 
			
		||||
the VNC proxy server presents to the compute node during VNC authentication.
 | 
			
		||||
 | 
			
		||||
Realted options:
 | 
			
		||||
 | 
			
		||||
* ``vnc.auth_schemes``: must include "vencrypt"
 | 
			
		||||
* ``vnc.vencrypt_client_key```: must also be set
 | 
			
		||||
"""),
 | 
			
		||||
    cfg.StrOpt(
 | 
			
		||||
        'vencrypt_ca_certs',
 | 
			
		||||
        help="""The path to the CA certificate PEM file
 | 
			
		||||
 | 
			
		||||
The fully qualified path to a PEM file containing one or more x509 certificates
 | 
			
		||||
for the certificate authorities used by the compute node VNC server.
 | 
			
		||||
 | 
			
		||||
Related options:
 | 
			
		||||
 | 
			
		||||
* ``vnc.auth_schemes``: must include "vencrypt"
 | 
			
		||||
"""),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ import enum
 | 
			
		||||
import six
 | 
			
		||||
 | 
			
		||||
VERSION_LENGTH = 12
 | 
			
		||||
SUBTYPE_LENGTH = 4
 | 
			
		||||
 | 
			
		||||
AUTH_STATUS_FAIL = b"\x00"
 | 
			
		||||
AUTH_STATUS_PASS = b"\x01"
 | 
			
		||||
@@ -39,6 +40,19 @@ class AuthType(enum.IntEnum):
 | 
			
		||||
    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)
 | 
			
		||||
class RFBAuthScheme(object):
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@
 | 
			
		||||
from oslo_config import cfg
 | 
			
		||||
 | 
			
		||||
from nova.console.rfb import authnone
 | 
			
		||||
from nova.console.rfb import authvencrypt
 | 
			
		||||
from nova import exception
 | 
			
		||||
 | 
			
		||||
CONF = cfg.CONF
 | 
			
		||||
@@ -24,6 +25,7 @@ class RFBAuthSchemeList(object):
 | 
			
		||||
 | 
			
		||||
    AUTH_SCHEME_MAP = {
 | 
			
		||||
        "none": authnone.RFBAuthSchemeNone,
 | 
			
		||||
        "vencrypt": authvencrypt.RFBAuthSchemeVeNCrypt,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										128
									
								
								nova/console/rfb/authvencrypt.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								nova/console/rfb/authvencrypt.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
# Copyright (c) 2014-2016 Red Hat, Inc
 | 
			
		||||
#
 | 
			
		||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
# not use this file except in compliance with the License. You may obtain
 | 
			
		||||
# a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
# Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
# License for the specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
import ssl
 | 
			
		||||
import struct
 | 
			
		||||
 | 
			
		||||
from oslo_config import cfg
 | 
			
		||||
from oslo_log import log as logging
 | 
			
		||||
 | 
			
		||||
from nova.console.rfb import auth
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova.i18n import _, _LI
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
CONF = cfg.CONF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RFBAuthSchemeVeNCrypt(auth.RFBAuthScheme):
 | 
			
		||||
    """A security proxy helper which uses VeNCrypt.
 | 
			
		||||
 | 
			
		||||
    This security proxy helper uses the VeNCrypt security
 | 
			
		||||
    type to achieve SSL/TLS-secured VNC.  It supports both
 | 
			
		||||
    standard SSL/TLS encryption and SSL/TLS encryption with
 | 
			
		||||
    x509 authentication.
 | 
			
		||||
 | 
			
		||||
    Refer to https://www.berrange.com/~dan/vencrypt.txt for
 | 
			
		||||
    a brief overview of the protocol.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def security_type(self):
 | 
			
		||||
        return auth.AuthType.VENCRYPT
 | 
			
		||||
 | 
			
		||||
    def security_handshake(self, compute_sock):
 | 
			
		||||
        def recv(num):
 | 
			
		||||
            b = compute_sock.recv(num)
 | 
			
		||||
            if len(b) != num:
 | 
			
		||||
                reason = _("Short read from compute socket, wanted "
 | 
			
		||||
                           "%(wanted)d bytes but got %(got)d") % {
 | 
			
		||||
                               'wanted': num, 'got': len(b)}
 | 
			
		||||
                raise exception.RFBAuthHandshakeFailed(reason=reason)
 | 
			
		||||
            return b
 | 
			
		||||
 | 
			
		||||
        # get the VeNCrypt version from the server
 | 
			
		||||
        maj_ver = ord(recv(1))
 | 
			
		||||
        min_ver = ord(recv(1))
 | 
			
		||||
 | 
			
		||||
        LOG.debug("Server sent VeNCrypt version "
 | 
			
		||||
                  "%(maj)s.%(min)s", {'maj': maj_ver, 'min': min_ver})
 | 
			
		||||
 | 
			
		||||
        if maj_ver != 0 or min_ver != 2:
 | 
			
		||||
            reason = _("Only VeNCrypt version 0.2 is supported by this "
 | 
			
		||||
                       "proxy, but the server wanted to use version "
 | 
			
		||||
                       "%(maj)s.%(min)s") % {'maj': maj_ver, 'min': min_ver}
 | 
			
		||||
            raise exception.RFBAuthHandshakeFailed(reason=reason)
 | 
			
		||||
 | 
			
		||||
        # use version 0.2
 | 
			
		||||
        compute_sock.sendall(b"\x00\x02")
 | 
			
		||||
 | 
			
		||||
        can_use_version = ord(recv(1))
 | 
			
		||||
 | 
			
		||||
        if can_use_version > 0:
 | 
			
		||||
            reason = _("Server could not use VeNCrypt version 0.2")
 | 
			
		||||
            raise exception.RFBAuthHandshakeFailed(reason=reason)
 | 
			
		||||
 | 
			
		||||
        # get the supported sub-auth types
 | 
			
		||||
        sub_types_cnt = ord(recv(1))
 | 
			
		||||
        sub_types_raw = recv(sub_types_cnt * auth.SUBTYPE_LENGTH)
 | 
			
		||||
        sub_types = struct.unpack('!' + str(sub_types_cnt) + 'I',
 | 
			
		||||
                                  sub_types_raw)
 | 
			
		||||
 | 
			
		||||
        LOG.debug("Server supports VeNCrypt sub-types %s", sub_types)
 | 
			
		||||
 | 
			
		||||
        if auth.AuthVeNCryptSubtype.X509NONE not in sub_types:
 | 
			
		||||
            reason = _("Server does not support the x509None (%s) VeNCrypt"
 | 
			
		||||
                       " sub-auth type") % \
 | 
			
		||||
                       auth.AuthVeNCryptSubtype.X509NONE
 | 
			
		||||
            raise exception.RFBAuthHandshakeFailed(reason=reason)
 | 
			
		||||
 | 
			
		||||
        LOG.debug("Attempting to use the x509None (%s) auth sub-type",
 | 
			
		||||
                  auth.AuthVeNCryptSubtype.X509NONE)
 | 
			
		||||
 | 
			
		||||
        compute_sock.sendall(struct.pack(
 | 
			
		||||
            '!I', auth.AuthVeNCryptSubtype.X509NONE))
 | 
			
		||||
 | 
			
		||||
        # NB(sross): the spec is missing a U8 here that's used in
 | 
			
		||||
        # multiple implementations (e.g. QEMU, GTK-VNC).  1 means
 | 
			
		||||
        # acceptance, 0 means failure (unlike the rest of RFB)
 | 
			
		||||
        auth_accepted = ord(recv(1))
 | 
			
		||||
        if auth_accepted == 0:
 | 
			
		||||
            reason = _("Server didn't accept the requested auth sub-type")
 | 
			
		||||
            raise exception.RFBAuthHandshakeFailed(reason=reason)
 | 
			
		||||
 | 
			
		||||
        LOG.debug("Server accepted the requested sub-auth type")
 | 
			
		||||
 | 
			
		||||
        if (CONF.vnc.vencrypt_client_key and
 | 
			
		||||
                CONF.vnc.vencrypt_client_cert):
 | 
			
		||||
            client_key = CONF.vnc.vencrypt_client_key
 | 
			
		||||
            client_cert = CONF.vnc.vencrypt_client_cert
 | 
			
		||||
        else:
 | 
			
		||||
            client_key = None
 | 
			
		||||
            client_cert = None
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            wrapped_sock = ssl.wrap_socket(
 | 
			
		||||
                compute_sock,
 | 
			
		||||
                keyfile=client_key,
 | 
			
		||||
                certfile=client_cert,
 | 
			
		||||
                server_side=False,
 | 
			
		||||
                cert_reqs=ssl.CERT_REQUIRED,
 | 
			
		||||
                ca_certs=CONF.vnc.vencrypt_ca_certs)
 | 
			
		||||
 | 
			
		||||
            LOG.info(_LI("VeNCrypt security handshake accepted"))
 | 
			
		||||
            return wrapped_sock
 | 
			
		||||
 | 
			
		||||
        except ssl.SSLError as e:
 | 
			
		||||
            reason = _("Error establishing TLS connection to server: %s") % e
 | 
			
		||||
            raise exception.RFBAuthHandshakeFailed(reason=reason)
 | 
			
		||||
@@ -26,13 +26,14 @@ class RFBAuthSchemeListTestCase(test.NoDBTestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(RFBAuthSchemeListTestCase, self).setUp()
 | 
			
		||||
 | 
			
		||||
        self.flags(auth_schemes=["none"], group="vnc")
 | 
			
		||||
        self.flags(auth_schemes=["none", "vencrypt"], group="vnc")
 | 
			
		||||
 | 
			
		||||
    def test_load_ok(self):
 | 
			
		||||
        schemelist = auths.RFBAuthSchemeList()
 | 
			
		||||
 | 
			
		||||
        security_types = sorted(schemelist.schemes.keys())
 | 
			
		||||
        self.assertEqual(security_types, [auth.AuthType.NONE])
 | 
			
		||||
        self.assertEqual(security_types, [auth.AuthType.NONE,
 | 
			
		||||
                                          auth.AuthType.VENCRYPT])
 | 
			
		||||
 | 
			
		||||
    def test_load_unknown(self):
 | 
			
		||||
        """Ensure invalid auth schemes are not supported.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										203
									
								
								nova/tests/unit/console/rfb/test_authvencrypt.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								nova/tests/unit/console/rfb/test_authvencrypt.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
			
		||||
# Copyright (c) 2016 Red Hat, Inc
 | 
			
		||||
#
 | 
			
		||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
# not use this file except in compliance with the License. You may obtain
 | 
			
		||||
# a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
# Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
# License for the specific language governing permissions and limitations
 | 
			
		||||
# under the License.
 | 
			
		||||
 | 
			
		||||
import ssl
 | 
			
		||||
import struct
 | 
			
		||||
 | 
			
		||||
import mock
 | 
			
		||||
 | 
			
		||||
from nova.console.rfb import auth
 | 
			
		||||
from nova.console.rfb import authvencrypt
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova import test
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RFBAuthSchemeVeNCryptTestCase(test.NoDBTestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(RFBAuthSchemeVeNCryptTestCase, self).setUp()
 | 
			
		||||
 | 
			
		||||
        self.scheme = authvencrypt.RFBAuthSchemeVeNCrypt()
 | 
			
		||||
        self.compute_sock = mock.MagicMock()
 | 
			
		||||
 | 
			
		||||
        self.compute_sock.recv.side_effect = []
 | 
			
		||||
 | 
			
		||||
        self.expected_calls = []
 | 
			
		||||
 | 
			
		||||
        self.flags(vencrypt_ca_certs="/certs/ca.pem", group="vnc")
 | 
			
		||||
 | 
			
		||||
    def _expect_send(self, val):
 | 
			
		||||
        self.expected_calls.append(mock.call.sendall(val))
 | 
			
		||||
 | 
			
		||||
    def _expect_recv(self, amt, ret_val):
 | 
			
		||||
        self.expected_calls.append(mock.call.recv(amt))
 | 
			
		||||
        self.compute_sock.recv.side_effect = (
 | 
			
		||||
            list(self.compute_sock.recv.side_effect) + [ret_val])
 | 
			
		||||
 | 
			
		||||
    @mock.patch.object(ssl, "wrap_socket", return_value="wrapped")
 | 
			
		||||
    def test_security_handshake_with_x509(self, mock_socket):
 | 
			
		||||
        self.flags(vencrypt_client_key='/certs/keyfile',
 | 
			
		||||
                   vencrypt_client_cert='/certs/cert.pem',
 | 
			
		||||
                   group="vnc")
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
 | 
			
		||||
        self._expect_send(b"\x00\x02")
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
        subtypes_raw = [auth.AuthVeNCryptSubtype.X509NONE,
 | 
			
		||||
                        auth.AuthVeNCryptSubtype.X509VNC]
 | 
			
		||||
        subtypes = struct.pack('!2I', *subtypes_raw)
 | 
			
		||||
        self._expect_recv(8, subtypes)
 | 
			
		||||
 | 
			
		||||
        self._expect_send(struct.pack('!I', subtypes_raw[0]))
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x01")
 | 
			
		||||
 | 
			
		||||
        self.assertEqual("wrapped", self.scheme.security_handshake(
 | 
			
		||||
            self.compute_sock))
 | 
			
		||||
 | 
			
		||||
        mock_socket.assert_called_once_with(
 | 
			
		||||
            self.compute_sock,
 | 
			
		||||
            keyfile='/certs/keyfile',
 | 
			
		||||
            certfile='/certs/cert.pem',
 | 
			
		||||
            server_side=False,
 | 
			
		||||
            cert_reqs=ssl.CERT_REQUIRED,
 | 
			
		||||
            ca_certs='/certs/ca.pem')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(self.expected_calls, self.compute_sock.mock_calls)
 | 
			
		||||
 | 
			
		||||
    @mock.patch.object(ssl, "wrap_socket", return_value="wrapped")
 | 
			
		||||
    def test_security_handshake_without_x509(self, mock_socket):
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
 | 
			
		||||
        self._expect_send(b"\x00\x02")
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
        subtypes_raw = [auth.AuthVeNCryptSubtype.X509NONE,
 | 
			
		||||
                        auth.AuthVeNCryptSubtype.X509VNC]
 | 
			
		||||
        subtypes = struct.pack('!2I', *subtypes_raw)
 | 
			
		||||
        self._expect_recv(8, subtypes)
 | 
			
		||||
 | 
			
		||||
        self._expect_send(struct.pack('!I', subtypes_raw[0]))
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x01")
 | 
			
		||||
 | 
			
		||||
        self.assertEqual("wrapped", self.scheme.security_handshake(
 | 
			
		||||
            self.compute_sock))
 | 
			
		||||
        mock_socket.assert_called_once_with(
 | 
			
		||||
            self.compute_sock,
 | 
			
		||||
            keyfile=None,
 | 
			
		||||
            certfile=None,
 | 
			
		||||
            server_side=False,
 | 
			
		||||
            cert_reqs=ssl.CERT_REQUIRED,
 | 
			
		||||
            ca_certs='/certs/ca.pem'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(self.expected_calls, self.compute_sock.mock_calls)
 | 
			
		||||
 | 
			
		||||
    def _test_security_handshake_fails(self):
 | 
			
		||||
        self.assertRaises(exception.RFBAuthHandshakeFailed,
 | 
			
		||||
                          self.scheme.security_handshake,
 | 
			
		||||
                          self.compute_sock)
 | 
			
		||||
        self.assertEqual(self.expected_calls, self.compute_sock.mock_calls)
 | 
			
		||||
 | 
			
		||||
    def test_security_handshake_fails_on_low_version(self):
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
        self._expect_recv(1, "\x01")
 | 
			
		||||
 | 
			
		||||
        self._test_security_handshake_fails()
 | 
			
		||||
 | 
			
		||||
    def test_security_handshake_fails_on_cant_use_version(self):
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
 | 
			
		||||
        self._expect_send(b"\x00\x02")
 | 
			
		||||
        self._expect_recv(1, "\x01")
 | 
			
		||||
 | 
			
		||||
        self._test_security_handshake_fails()
 | 
			
		||||
 | 
			
		||||
    def test_security_handshake_fails_on_missing_subauth(self):
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
 | 
			
		||||
        self._expect_send(b"\x00\x02")
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x01")
 | 
			
		||||
        subtypes_raw = [auth.AuthVeNCryptSubtype.X509VNC]
 | 
			
		||||
        subtypes = struct.pack('!I', *subtypes_raw)
 | 
			
		||||
        self._expect_recv(4, subtypes)
 | 
			
		||||
 | 
			
		||||
        self._test_security_handshake_fails()
 | 
			
		||||
 | 
			
		||||
    def test_security_handshake_fails_on_auth_not_accepted(self):
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
 | 
			
		||||
        self._expect_send(b"\x00\x02")
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
        subtypes_raw = [auth.AuthVeNCryptSubtype.X509NONE,
 | 
			
		||||
                        auth.AuthVeNCryptSubtype.X509VNC]
 | 
			
		||||
        subtypes = struct.pack('!2I', *subtypes_raw)
 | 
			
		||||
        self._expect_recv(8, subtypes)
 | 
			
		||||
 | 
			
		||||
        self._expect_send(struct.pack('!I', subtypes_raw[0]))
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
 | 
			
		||||
        self._test_security_handshake_fails()
 | 
			
		||||
 | 
			
		||||
    @mock.patch.object(ssl, "wrap_socket")
 | 
			
		||||
    def test_security_handshake_fails_on_ssl_failure(self, mock_socket):
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
 | 
			
		||||
        self._expect_send(b"\x00\x02")
 | 
			
		||||
        self._expect_recv(1, "\x00")
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x02")
 | 
			
		||||
        subtypes_raw = [auth.AuthVeNCryptSubtype.X509NONE,
 | 
			
		||||
                        auth.AuthVeNCryptSubtype.X509VNC]
 | 
			
		||||
        subtypes = struct.pack('!2I', *subtypes_raw)
 | 
			
		||||
        self._expect_recv(8, subtypes)
 | 
			
		||||
 | 
			
		||||
        self._expect_send(struct.pack('!I', subtypes_raw[0]))
 | 
			
		||||
 | 
			
		||||
        self._expect_recv(1, "\x01")
 | 
			
		||||
 | 
			
		||||
        mock_socket.side_effect = ssl.SSLError("cheese")
 | 
			
		||||
 | 
			
		||||
        self._test_security_handshake_fails()
 | 
			
		||||
 | 
			
		||||
        mock_socket.assert_called_once_with(
 | 
			
		||||
            self.compute_sock,
 | 
			
		||||
            keyfile=None,
 | 
			
		||||
            certfile=None,
 | 
			
		||||
            server_side=False,
 | 
			
		||||
            cert_reqs=ssl.CERT_REQUIRED,
 | 
			
		||||
            ca_certs='/certs/ca.pem'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def test_types(self):
 | 
			
		||||
        scheme = authvencrypt.RFBAuthSchemeVeNCrypt()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(auth.AuthType.VENCRYPT,
 | 
			
		||||
                         scheme.security_type())
 | 
			
		||||
@@ -6,3 +6,6 @@ features:
 | 
			
		||||
    *nova-novncproxy* server and the compute node VNC server.
 | 
			
		||||
 | 
			
		||||
    - ``auth_schemes``
 | 
			
		||||
    - ``vencrypt_client_key``
 | 
			
		||||
    - ``vencrypt_client_cert``
 | 
			
		||||
    - ``vencrypt_ca_certs``
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user