示例#1
0
    def _test_consoleauth_api(self, method, **kwargs):
        ctxt = context.RequestContext('fake_user', 'fake_project')
        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        expected_retval = 'foo'
        expected_msg = rpcapi.make_msg(method, **kwargs)
        expected_msg['version'] = rpcapi.RPC_API_VERSION

        self.call_ctxt = None
        self.call_topic = None
        self.call_msg = None
        self.call_timeout = None

        def _fake_call(_ctxt, _topic, _msg, _timeout):
            self.call_ctxt = _ctxt
            self.call_topic = _topic
            self.call_msg = _msg
            self.call_timeout = _timeout
            return expected_retval

        self.stubs.Set(rpc, 'call', _fake_call)

        retval = getattr(rpcapi, method)(ctxt, **kwargs)

        self.assertEqual(retval, expected_retval)
        self.assertEqual(self.call_ctxt, ctxt)
        self.assertEqual(self.call_topic, FLAGS.consoleauth_topic)
        self.assertEqual(self.call_msg, expected_msg)
        self.assertEqual(self.call_timeout, None)
示例#2
0
    def _test_consoleauth_api(self, method, **kwargs):
        ctxt = context.RequestContext('fake_user', 'fake_project')
        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        expected_retval = 'foo'
        expected_version = kwargs.pop('version', rpcapi.BASE_RPC_API_VERSION)
        expected_msg = rpcapi.make_msg(method, **kwargs)
        expected_msg['version'] = expected_version

        if method == 'get_backdoor_port':
            del expected_msg['args']['host']

        self.call_ctxt = None
        self.call_topic = None
        self.call_msg = None
        self.call_timeout = None

        def _fake_call(_ctxt, _topic, _msg, _timeout):
            self.call_ctxt = _ctxt
            self.call_topic = _topic
            self.call_msg = _msg
            self.call_timeout = _timeout
            return expected_retval

        self.stubs.Set(rpc, 'call', _fake_call)

        retval = getattr(rpcapi, method)(ctxt, **kwargs)

        self.assertEqual(retval, expected_retval)
        self.assertEqual(self.call_ctxt, ctxt)
        self.assertEqual(self.call_topic, CONF.consoleauth_topic)
        self.assertEqual(self.call_msg, expected_msg)
        self.assertEqual(self.call_timeout, None)
    def _test_consoleauth_api(self, method, **kwargs):
        do_cast = kwargs.pop('_do_cast', False)

        ctxt = context.RequestContext('fake_user', 'fake_project')

        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        self.assertIsNotNone(rpcapi.client)
        self.assertEqual(rpcapi.client.target.topic, CONF.consoleauth_topic)

        orig_prepare = rpcapi.client.prepare
        expected_version = kwargs.pop('version', rpcapi.client.target.version)

        with contextlib.nested(
                mock.patch.object(rpcapi.client,
                                  'cast' if do_cast else 'call'),
                mock.patch.object(rpcapi.client, 'prepare'),
                mock.patch.object(rpcapi.client, 'can_send_version'),
        ) as (rpc_mock, prepare_mock, csv_mock):
            prepare_mock.return_value = rpcapi.client
            rpc_mock.return_value = None if do_cast else 'foo'
            csv_mock.side_effect = (
                lambda v: orig_prepare(version=v).can_send_version())

            retval = getattr(rpcapi, method)(ctxt, **kwargs)
            self.assertEqual(retval, rpc_mock.return_value)

            prepare_mock.assert_called_once_with(version=expected_version)
            rpc_mock.assert_called_once_with(ctxt, method, **kwargs)
示例#4
0
    def _test_consoleauth_api(self, method, **kwargs):
        do_cast = kwargs.pop('_do_cast', False)
        ctxt = context.RequestContext('fake_user', 'fake_project')
        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        expected_retval = 'foo'
        expected_version = kwargs.pop('version', rpcapi.BASE_RPC_API_VERSION)
        expected_msg = rpcapi.make_msg(method, **kwargs)
        expected_msg['version'] = expected_version

        self.call_ctxt = None
        self.call_topic = None
        self.call_msg = None
        self.call_timeout = None

        def _fake_call(_ctxt, _topic, _msg, _timeout=None):
            self.call_ctxt = _ctxt
            self.call_topic = _topic
            self.call_msg = _msg
            self.call_timeout = _timeout
            return expected_retval

        if do_cast:
            self.stubs.Set(rpc, 'cast', _fake_call)
        else:
            self.stubs.Set(rpc, 'call', _fake_call)

        retval = getattr(rpcapi, method)(ctxt, **kwargs)

        if not do_cast:
            self.assertEqual(retval, expected_retval)
        self.assertEqual(self.call_ctxt, ctxt)
        self.assertEqual(self.call_topic, CONF.consoleauth_topic)
        self.assertEqual(self.call_msg, expected_msg)
        self.assertIsNone(self.call_timeout)
示例#5
0
    def new_client(self):
        """Called after a new WebSocket connection has been established."""
        # Reopen the eventlet hub to make sure we don't share an epoll
        # fd with parent and/or siblings, which would be bad
        from eventlet import hubs
        hubs.use_hub()

        cookie = Cookie.SimpleCookie()
        cookie.load(self.headers.getheader('cookie'))
        token = cookie['token'].value
        ctxt = context.get_admin_context()
        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        connect_info = rpcapi.check_token(ctxt, token=token)

        if not connect_info:
            LOG.audit(_("Invalid Token: %s"), token)
            raise Exception(_("Invalid Token"))

        host = connect_info['host']
        port = int(connect_info['port'])

        # Connect to the target
        self.msg("connecting to: %s:%s" % (host, port))
        LOG.audit(_("connecting to: %(host)s:%(port)s"), {
            'host': host,
            'port': port
        })
        tsock = self.socket(host, port, connect=True)

        # Handshake as necessary
        if connect_info.get('internal_access_path'):
            tsock.send("CONNECT %s HTTP/1.1\r\n\r\n" %
                       connect_info['internal_access_path'])
            while True:
                data = tsock.recv(4096, socket.MSG_PEEK)
                if data.find("\r\n\r\n") != -1:
                    if not data.split("\r\n")[0].find("200"):
                        LOG.audit(_("Invalid Connection Info %s"), token)
                        raise Exception(_("Invalid Connection Info"))
                    tsock.recv(len(data))
                    break

        # Start proxying
        try:
            self.do_proxy(tsock)
        except Exception:
            if tsock:
                tsock.shutdown(socket.SHUT_RDWR)
                tsock.close()
                self.vmsg("%s:%s: Target closed" % (host, port))
                LOG.audit(_("%(host)s:%(port)s: Target closed"), {
                    'host': host,
                    'port': port
                })
            raise
示例#6
0
 def __init__(self):
     self.data_path = tempfile.mkdtemp(prefix='nova-coverage_')
     data_out = os.path.join(self.data_path, '.nova-coverage')
     self.coverInst = coverage.coverage(data_file=data_out)
     self.compute_api = compute_api.API()
     self.network_api = network_api.API()
     self.conductor_api = conductor_api.API()
     self.consoleauth_api = consoleauth_api.ConsoleAuthAPI()
     self.console_api = console_api.API()
     self.scheduler_api = scheduler_api.SchedulerAPI()
     self.cert_api = cert_api.CertAPI()
     self.services = []
     self.combine = False
     super(CoverageController, self).__init__()
示例#7
0
 def __init__(self):
     self.data_path = tempfile.mkdtemp(prefix='nova-coverage_')
     self.compute_api = compute_api.API()
     self.network_api = network_api.API()
     self.conductor_api = conductor_api.API()
     self.consoleauth_api = consoleauth_api.ConsoleAuthAPI()
     self.console_api = console_api.API()
     self.scheduler_api = scheduler_api.SchedulerAPI()
     self.cert_api = cert_api.CertAPI()
     self.services = []
     self.combine = False
     self._cover_inst = None
     self.host = CONF.host
     super(CoverageController, self).__init__()
示例#8
0
    def new_client(self):
        """
        Called after a new WebSocket connection has been established.
        """
        cookie = Cookie.SimpleCookie()
        cookie.load(self.headers.getheader('cookie'))
        token = cookie['token'].value
        ctxt = context.get_admin_context()
        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        connect_info = rpcapi.check_token(ctxt, token=token)

        if not connect_info:
            LOG.audit("Invalid Token: %s", token)
            raise Exception(_("Invalid Token"))

        host = connect_info['host']
        port = int(connect_info['port'])

        # Connect to the target
        self.msg("connecting to: %s:%s" % (host, port))
        LOG.audit("connecting to: %s:%s" % (host, port))
        tsock = self.socket(host, port, connect=True)

        # Handshake as necessary
        if connect_info.get('internal_access_path'):
            tsock.send("CONNECT %s HTTP/1.1\r\n\r\n" %
                       connect_info['internal_access_path'])
            while True:
                data = tsock.recv(4096, socket.MSG_PEEK)
                if data.find("\r\n\r\n") != -1:
                    if not data.split("\r\n")[0].find("200"):
                        LOG.audit("Invalid Connection Info %s", token)
                        raise Exception(_("Invalid Connection Info"))
                    tsock.recv(len(data))
                    break

        if self.verbose and not self.daemon:
            print(self.traffic_legend)

        # Start proxying
        try:
            self.do_proxy(tsock)
        except Exception:
            if tsock:
                tsock.shutdown(socket.SHUT_RDWR)
                tsock.close()
                self.vmsg("%s:%s: Target closed" % (host, port))
                LOG.audit("%s:%s: Target closed" % (host, port))
            raise
    def _test_consoleauth_api(self, method, **kwargs):
        do_cast = kwargs.pop('_do_cast', False)

        ctxt = context.RequestContext('fake_user', 'fake_project')

        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        self.assertIsNotNone(rpcapi.client)
        self.assertEqual(rpcapi.client.target.topic,
                         consoleauth_rpcapi.RPC_TOPIC)

        orig_prepare = rpcapi.client.prepare

        version = kwargs.pop('version', None)
        rpc_kwargs = {
            k: v
            for k, v in kwargs.items() if v is not self.DROPPED_ARG
        }

        with test.nested(
                mock.patch.object(rpcapi.client,
                                  'cast' if do_cast else 'call'),
                mock.patch.object(rpcapi.client, 'prepare'),
                mock.patch.object(rpcapi.client, 'can_send_version'),
        ) as (rpc_mock, prepare_mock, csv_mock):
            prepare_mock.return_value = rpcapi.client
            rpc_mock.return_value = None if do_cast else 'foo'

            def fake_csv(v):
                if version:
                    return orig_prepare(version_cap=version).can_send_version(
                        version=v)
                else:
                    return orig_prepare().can_send_version()

            csv_mock.side_effect = fake_csv

            retval = getattr(rpcapi, method)(ctxt, **kwargs)
            self.assertEqual(retval, rpc_mock.return_value)

            if version:
                prepare_mock.assert_called_once_with(version=version)
            else:
                prepare_mock.assert_called_once_with()
            rpc_mock.assert_called_once_with(ctxt, method, **rpc_kwargs)
    def __call__(self, environ, start_response):
        try:
            req = webob.Request(environ)
            LOG.info(_LI("Request: %s"), req)
            token = req.params.get('token')
            if not token:
                LOG.info(_LI("Request made with missing token: %s"), req)
                start_response('400 Invalid Request',
                               [('content-type', 'text/html')])
                return "Invalid Request"

            ctxt = context.get_admin_context()
            api = consoleauth_rpcapi.ConsoleAuthAPI()
            connect_info = api.check_token(ctxt, token)

            if not connect_info:
                LOG.info(_LI("Request made with invalid token: %s"), req)
                start_response('401 Not Authorized',
                               [('content-type', 'text/html')])
                return "Not Authorized"

            return self.proxy_connection(req, connect_info, start_response)
        except Exception as e:
            LOG.info(_LI("Unexpected error: %s"), e)
示例#11
0
    def new_websocket_client(self):
        """Called after a new WebSocket connection has been established."""
        # Reopen the eventlet hub to make sure we don't share an epoll
        # fd with parent and/or siblings, which would be bad
        from eventlet import hubs
        hubs.use_hub()

        # The nova expected behavior is to have token
        # passed to the method GET of the request
        parse = urlparse.urlparse(self.path)
        if parse.scheme not in ('http', 'https'):
            # From a bug in urlparse in Python < 2.7.4 we cannot support
            # special schemes (cf: http://bugs.python.org/issue9374)
            if sys.version_info < (2, 7, 4):
                raise exception.NovaException(
                    _("We do not support scheme '%s' under Python < 2.7.4, "
                      "please use http or https") % parse.scheme)

        query = parse.query
        token = urlparse.parse_qs(query).get("token", [""]).pop()
        if not token:
            # NoVNC uses it's own convention that forward token
            # from the request to a cookie header, we should check
            # also for this behavior
            hcookie = self.headers.getheader('cookie')
            if hcookie:
                cookie = Cookie.SimpleCookie()
                for hcookie_part in hcookie.split(';'):
                    hcookie_part = hcookie_part.lstrip()
                    try:
                        cookie.load(hcookie_part)
                    except Cookie.CookieError:
                        # NOTE(stgleb): Do not print out cookie content
                        # for security reasons.
                        LOG.warning(_LW('Found malformed cookie'))
                    else:
                        if 'token' in cookie:
                            token = cookie['token'].value

        ctxt = context.get_admin_context()
        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        connect_info = rpcapi.check_token(ctxt, token=token)

        if not connect_info:
            raise exception.InvalidToken(token=token)

        # Verify Origin
        expected_origin_hostname = self.headers.getheader('Host')
        if ':' in expected_origin_hostname:
            e = expected_origin_hostname
            if '[' in e and ']' in e:
                expected_origin_hostname = e.split(']')[0][1:]
            else:
                expected_origin_hostname = e.split(':')[0]
        expected_origin_hostnames = CONF.console.allowed_origins
        expected_origin_hostnames.append(expected_origin_hostname)
        origin_url = self.headers.getheader('Origin')
        # missing origin header indicates non-browser client which is OK
        if origin_url is not None:
            origin = urlparse.urlparse(origin_url)
            origin_hostname = origin.hostname
            origin_scheme = origin.scheme
            if origin_hostname == '' or origin_scheme == '':
                detail = _("Origin header not valid.")
                raise exception.ValidationError(detail=detail)
            if origin_hostname not in expected_origin_hostnames:
                detail = _("Origin header does not match this host.")
                raise exception.ValidationError(detail=detail)
            if not self.verify_origin_proto(connect_info, origin_scheme):
                detail = _("Origin header protocol does not match this host.")
                raise exception.ValidationError(detail=detail)

        self.msg(_('connect info: %s'), str(connect_info))
        host = connect_info['host']
        port = int(connect_info['port'])

        # Connect to the target
        self.msg(
            _("connecting to: %(host)s:%(port)s") % {
                'host': host,
                'port': port
            })
        tsock = self.socket(host, port, connect=True)

        # Handshake as necessary
        if connect_info.get('internal_access_path'):
            tsock.send("CONNECT %s HTTP/1.1\r\n\r\n" %
                       connect_info['internal_access_path'])
            while True:
                data = tsock.recv(4096, socket.MSG_PEEK)
                if data.find("\r\n\r\n") != -1:
                    if data.split("\r\n")[0].find("200") == -1:
                        raise exception.InvalidConnectionInfo()
                    tsock.recv(len(data))
                    break

        # Start proxying
        try:
            self.do_proxy(tsock)
        except Exception:
            if tsock:
                tsock.shutdown(socket.SHUT_RDWR)
                tsock.close()
                self.vmsg(
                    _("%(host)s:%(port)s: "
                      "Websocket client or target closed") % {
                          'host': host,
                          'port': port
                      })
            raise
示例#12
0
 def _get_connect_info_consoleauth(self, ctxt, token):
     # NOTE(PaulMurray) consoleauth check_token() validates the token
     # and does an rpc to compute manager to check the console port
     # is correct.
     rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
     return rpcapi.check_token(ctxt, token=token)
示例#13
0
 def __init__(self, *args, **kwargs):
     self._consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
     super(ConsoleAuthTokensController, self).__init__(*args, **kwargs)
示例#14
0
 def __init__(self):
     super(ConsoleAuthTokensController, self).__init__()
     self._consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
示例#15
0
    def new_websocket_client(self):
        """Called after a new WebSocket connection has been established."""
        # Reopen the eventlet hub to make sure we don't share an epoll
        # fd with parent and/or siblings, which would be bad
        from eventlet import hubs
        hubs.use_hub()

        # The nova expected behavior is to have token
        # passed to the method GET of the request
        query = urlparse.urlparse(self.path).query
        token = urlparse.parse_qs(query).get("token", [""]).pop()
        if not token:
            # NoVNC uses it's own convention that forward token
            # from the request to a cookie header, we should check
            # also for this behavior
            hcookie = self.headers.getheader('cookie')
            if hcookie:
                cookie = Cookie.SimpleCookie()
                cookie.load(hcookie)
                if 'token' in cookie:
                    token = cookie['token'].value

        ctxt = context.get_admin_context()
        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        connect_info = rpcapi.check_token(ctxt, token=token)

        if not connect_info:
            raise Exception(_("Invalid Token"))

        # Verify Origin
        expected_origin_hostname = self.headers.getheader('Host')
        if ':' in expected_origin_hostname:
            e = expected_origin_hostname
            expected_origin_hostname = e.split(':')[0]
        origin_url = self.headers.getheader('Origin')
        # missing origin header indicates non-browser client which is OK
        if origin_url is not None:
            origin = urlparse.urlparse(origin_url)
            origin_hostname = origin.hostname
            origin_scheme = origin.scheme
            if origin_hostname == '' or origin_scheme == '':
                detail = _("Origin header not valid.")
                raise exception.ValidationError(detail=detail)
            if expected_origin_hostname != origin_hostname:
                detail = _("Origin header does not match this host.")
                raise exception.ValidationError(detail=detail)
            if not self.verify_origin_proto(connect_info['console_type'],
                                            origin.scheme):
                detail = _("Origin header protocol does not match this host.")
                raise exception.ValidationError(detail=detail)

        self.msg(_('connect info: %s'), str(connect_info))
        host = connect_info['host']
        port = int(connect_info['port'])

        # Connect to the target
        self.msg(
            _("connecting to: %(host)s:%(port)s") % {
                'host': host,
                'port': port
            })
        tsock = self.socket(host, port, connect=True)

        # Handshake as necessary
        if connect_info.get('internal_access_path'):
            tsock.send("CONNECT %s HTTP/1.1\r\n\r\n" %
                       connect_info['internal_access_path'])
            while True:
                data = tsock.recv(4096, socket.MSG_PEEK)
                if data.find("\r\n\r\n") != -1:
                    if not data.split("\r\n")[0].find("200"):
                        raise Exception(_("Invalid Connection Info"))
                    tsock.recv(len(data))
                    break

        instance_id = connect_info.get('instance_uuid', 'None')
        # Start proxying
        try:
            operationlog.info(
                "VNC: host:%s, port:%s, is connecting to vm %s, at %s" %
                (host, port, instance_id, timeutils.utcnow()),
                extra={"type": "operate"})
            self.do_proxy(tsock)
        except Exception:
            if tsock:
                tsock.shutdown(socket.SHUT_RDWR)
                tsock.close()
                operationlog.info(
                    "VNC: host:%s, port:%s, lost connection with vm %s, at %s"
                    % (host, port, instance_id, timeutils.utcnow()),
                    extra={"type": "operate"})
                self.vmsg(
                    _("%(host)s:%(port)s: Target closed") % {
                        'host': host,
                        'port': port
                    })
                LOG.audit("%s:%s: Target closed" % (host, port))
            raise
示例#16
0
    def new_websocket_client(self):
        """Called after a new WebSocket connection has been established."""
        # Reopen the eventlet hub to make sure we don't share an epoll
        # fd with parent and/or siblings, which would be bad
        from eventlet import hubs
        hubs.use_hub()

        # The nova expected behavior is to have token
        # passed to the method GET of the request
        parse = urlparse.urlparse(self.path)
        if parse.scheme not in ('http', 'https'):
            # From a bug in urlparse in Python < 2.7.4 we cannot support
            # special schemes (cf: http://bugs.python.org/issue9374)
            if sys.version_info < (2, 7, 4):
                raise exception.NovaException(
                    _("We do not support scheme '%s' under Python < 2.7.4, "
                      "please use http or https") % parse.scheme)

        query = parse.query
        token = urlparse.parse_qs(query).get("token", [""]).pop()
        if not token:
            # NoVNC uses it's own convention that forward token
            # from the request to a cookie header, we should check
            # also for this behavior
            hcookie = self.headers.getheader('cookie')
            if hcookie:
                cookie = Cookie.SimpleCookie()
                cookie.load(hcookie)
                if 'token' in cookie:
                    token = cookie['token'].value

        ctxt = context.get_admin_context()
        rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
        connect_info = rpcapi.check_token(ctxt, token=token)

        if not connect_info:
            raise exception.InvalidToken(token=token)

        self.msg(_('connect info: %s'), str(connect_info))
        host = connect_info['host']
        port = int(connect_info['port'])

        # Connect to the target
        self.msg(
            _("connecting to: %(host)s:%(port)s") % {
                'host': host,
                'port': port
            })
        tsock = self.socket(host, port, connect=True)

        # Handshake as necessary
        if connect_info.get('internal_access_path'):
            tsock.send("CONNECT %s HTTP/1.1\r\n\r\n" %
                       connect_info['internal_access_path'])
            while True:
                data = tsock.recv(4096, socket.MSG_PEEK)
                if data.find("\r\n\r\n") != -1:
                    if data.split("\r\n")[0].find("200") == -1:
                        raise exception.InvalidConnectionInfo()
                    tsock.recv(len(data))
                    break

        # Start proxying
        try:
            self.do_proxy(tsock)
        except Exception:
            if tsock:
                tsock.shutdown(socket.SHUT_RDWR)
                tsock.close()
                self.vmsg(
                    _("%(host)s:%(port)s: Target closed") % {
                        'host': host,
                        'port': port
                    })
            raise
 def __init__(self):
     self._consoleauth = rpcapi.ConsoleAuthAPI()
     self._tokens = {}