Exemple #1
0
    def test_proxy_connect_err(self, check_token, mock_finish, mock_close):
        check_token.return_value = {
            'host': 'node1',
            'port': '10000',
            'console_type': 'novnc',
            'access_url': 'https://example.net:6080'
        }

        ex = exception.SecurityProxyNegotiationFailed("Wibble")
        self.server.security_proxy.connect.side_effect = ex

        self.assertRaises(exception.SecurityProxyNegotiationFailed,
                          self.wh.new_websocket_client)

        self.assertEqual(len(self.wh.do_proxy.calls), 0)
        mock_close.assert_called_with()
        self.assertEqual(len(mock_finish.calls), 0)
Exemple #2
0
    def test_proxy_connect_err(self, mock_finish, mock_close,
                               mock_port_validate, mock_get,
                               mock_token_validate):
        mock_token_validate.return_value = nova.objects.ConsoleAuthToken(
            instance_uuid=uuids.instance, host='node1', port='10000',
            console_type='novnc', access_url_base='https://example.net:6080')
        # The token attribute is set by the validate() method.
        mock_token_validate.return_value.token = '123-456-789'
        mock_token_validate.return_value.id = 1

        ex = exception.SecurityProxyNegotiationFailed("Wibble")
        self.server.security_proxy.connect.side_effect = ex

        self.assertRaises(exception.SecurityProxyNegotiationFailed,
                          self.wh.new_websocket_client)

        self.assertEqual(len(self.wh.do_proxy.calls), 0)
        mock_close.assert_called_with()
        self.assertEqual(len(mock_finish.calls), 0)
Exemple #3
0
    def connect(self, tenant_sock, compute_sock):
        """Initiate the RFB connection process.

        This method performs the initial ProtocolVersion
        and Security messaging, and returns the socket-like
        object to use to communicate with the server securely.
        If an error occurs SecurityProxyNegotiationFailed
        will be raised.
        """
        def recv(sock, num):
            b = sock.recv(num)
            if len(b) != num:
                reason = _("Incorrect read from socket, wanted %(wanted)d "
                           "bytes but got %(got)d. Socket returned "
                           "%(result)r") % {
                               'wanted': num,
                               'got': len(b),
                               'result': b
                           }
                raise exception.RFBAuthHandshakeFailed(reason=reason)
            return b

        # Negotiate version with compute server
        compute_version = recv(compute_sock, auth.VERSION_LENGTH)
        LOG.debug("Got version string '%s' from compute node",
                  compute_version[:-1].decode('utf-8'))

        if self._parse_version(compute_version) != 3.8:
            reason = _("Security proxying requires RFB protocol version 3.8, "
                       "but server sent %s")
            raise exception.SecurityProxyNegotiationFailed(
                reason=reason % compute_version[:-1].decode('utf-8'))
        compute_sock.sendall(compute_version)

        # Negotiate version with tenant
        tenant_sock.sendall(compute_version)
        tenant_version = recv(tenant_sock, auth.VERSION_LENGTH)
        LOG.debug("Got version string '%s' from tenant",
                  tenant_version[:-1].decode('utf-8'))

        if self._parse_version(tenant_version) != 3.8:
            reason = _("Security proxying requires RFB protocol version 3.8, "
                       "but tenant asked for %s")
            raise exception.SecurityProxyNegotiationFailed(
                reason=reason % tenant_version[:-1].decode('utf-8'))

        # Negotiate security with server
        permitted_auth_types_cnt = recv(compute_sock, 1)[0]

        if permitted_auth_types_cnt == 0:
            # Decode the reason why the request failed
            reason_len_raw = recv(compute_sock, 4)
            reason_len = struct.unpack('!I', reason_len_raw)[0]
            reason = recv(compute_sock, reason_len)

            tenant_sock.sendall(auth.AUTH_STATUS_FAIL + reason_len_raw +
                                reason)

            raise exception.SecurityProxyNegotiationFailed(reason=reason)

        f = recv(compute_sock, permitted_auth_types_cnt)
        permitted_auth_types = []
        for auth_type in f:
            if isinstance(auth_type, str):
                auth_type = ord(auth_type)
            permitted_auth_types.append(auth_type)

        LOG.debug(
            "Server sent security types: %s", ", ".join(
                '%d (%s)' % (auth.AuthType(t).value, auth.AuthType(t).name)
                for t in permitted_auth_types))

        # Negotiate security with client before we say "ok" to the server
        # send 1:[None]
        tenant_sock.sendall(auth.AUTH_STATUS_PASS +
                            bytes((auth.AuthType.NONE, )))
        client_auth = recv(tenant_sock, 1)[0]

        if client_auth != auth.AuthType.NONE:
            self._fail(
                tenant_sock, compute_sock,
                _("Only the security type %d (%s) is supported") % (
                    auth.AuthType.NONE.value,
                    auth.AuthType.NONE.name,
                ))

            reason = _("Client requested a security type other than %d (%s): "
                       "%d (%s)") % (
                           auth.AuthType.NONE.value,
                           auth.AuthType.NONE.name,
                           auth.AuthType(client_auth).value,
                           auth.AuthType(client_auth).name,
                       )
            raise exception.SecurityProxyNegotiationFailed(reason=reason)

        try:
            scheme = self.auth_schemes.find_scheme(permitted_auth_types)
        except exception.RFBAuthNoAvailableScheme as e:
            # Intentionally don't tell client what really failed
            # as that's information leakage
            self._fail(tenant_sock, compute_sock,
                       _("Unable to negotiate security with server"))
            raise exception.SecurityProxyNegotiationFailed(
                reason=_("No compute auth available: %s") % str(e))

        compute_sock.sendall(bytes((scheme.security_type(), )))

        LOG.debug(
            "Using security type %d (%s) with server, %d (%s) with client",
            scheme.security_type().value,
            scheme.security_type().name, auth.AuthType.NONE.value,
            auth.AuthType.NONE.name)

        try:
            compute_sock = scheme.security_handshake(compute_sock)
        except exception.RFBAuthHandshakeFailed as e:
            # Intentionally don't tell client what really failed
            # as that's information leakage
            self._fail(tenant_sock, None,
                       _("Unable to negotiate security with server"))
            LOG.debug("Auth failed %s", str(e))
            raise exception.SecurityProxyNegotiationFailed(
                reason=_("Auth handshake failed"))

        LOG.info("Finished security handshake, resuming normal proxy "
                 "mode using secured socket")

        # we can just proxy the security result -- if the server security
        # negotiation fails, we want the client to think it has failed

        return compute_sock