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)
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)
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)
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
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__()
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__()
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)
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
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)
def __init__(self, *args, **kwargs): self._consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI() super(ConsoleAuthTokensController, self).__init__(*args, **kwargs)
def __init__(self): super(ConsoleAuthTokensController, self).__init__() self._consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
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
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 = {}