diff options
| author | Anthony Young <sleepsonthefloor@gmail.com> | 2011-03-29 12:54:35 -0700 |
|---|---|---|
| committer | Anthony Young <sleepsonthefloor@gmail.com> | 2011-03-29 12:54:35 -0700 |
| commit | 3e9b5977137c430d218ec8c00e286b691ea8367d (patch) | |
| tree | 77bd941de12a767d692110eb04694cfac8e8d906 | |
| parent | 94092e3d896732fa1a97627f0fa504c3af70b3c5 (diff) | |
| download | nova-3e9b5977137c430d218ec8c00e286b691ea8367d.tar.gz nova-3e9b5977137c430d218ec8c00e286b691ea8367d.tar.xz nova-3e9b5977137c430d218ec8c00e286b691ea8367d.zip | |
use manager pattern for auth token proxy
| -rwxr-xr-x | bin/nova-vncproxy (renamed from bin/nova-vnc-proxy) | 31 | ||||
| -rw-r--r-- | doc/source/runnova/vncconsole.rst | 6 | ||||
| -rw-r--r-- | nova/flags.py | 2 | ||||
| -rw-r--r-- | nova/vnc/auth.py | 103 | ||||
| -rw-r--r-- | nova/vnc/proxy.py | 3 |
5 files changed, 85 insertions, 60 deletions
diff --git a/bin/nova-vnc-proxy b/bin/nova-vncproxy index e26bc6d8c..0fad8397d 100755 --- a/bin/nova-vnc-proxy +++ b/bin/nova-vncproxy @@ -1,8 +1,7 @@ #!/usr/bin/env python # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. +# Copyright (c) 2010 Openstack, LLC. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,6 +33,7 @@ gettext.install('nova', unicode=1) from nova import flags from nova import log as logging +from nova import service from nova import utils from nova import wsgi from nova import version @@ -45,16 +45,19 @@ LOG = logging.getLogger('nova.vnc-proxy') FLAGS = flags.FLAGS -flags.DEFINE_string('vnc_proxy_wwwroot', '/var/lib/nova/noVNC/', +flags.DEFINE_string('vncproxy_wwwroot', '/var/lib/nova/noVNC/', 'Full path to noVNC directory') flags.DEFINE_boolean('vnc_debug', False, 'Enable debugging features, like token bypassing') -flags.DEFINE_integer('vnc_proxy_port', 6080, +flags.DEFINE_integer('vncproxy_port', 6080, 'Port that the VNC proxy should bind to') -flags.DEFINE_string('vnc_proxy_host', '0.0.0.0', +flags.DEFINE_string('vncproxy_host', '0.0.0.0', 'Address that the VNC proxy should bind to') flags.DEFINE_integer('vnc_token_ttl', 300, 'How many seconds before deleting tokens') +flags.DEFINE_string('vncproxy_manager', 'nova.vnc.auth.VNCProxyAuthManager', + 'Manager for vncproxy auth') + flags.DEFINE_flag(flags.HelpFlag()) flags.DEFINE_flag(flags.HelpshortFlag()) flags.DEFINE_flag(flags.HelpXMLFlag()) @@ -68,18 +71,20 @@ if __name__ == "__main__": LOG.audit(_("Starting nova-vnc-proxy node (version %s)"), version.version_string_with_vcs()) - if not (os.path.exists(FLAGS.vnc_proxy_wwwroot) and - os.path.exists(FLAGS.vnc_proxy_wwwroot + '/vnc_auto.html')): - LOG.info(_("Missing vnc_proxy_wwwroot (version %s)"), - FLAGS.vnc_proxy_wwwroot) + service.serve() + + if not (os.path.exists(FLAGS.vncproxy_wwwroot) and + os.path.exists(FLAGS.vncproxy_wwwroot + '/vnc_auto.html')): + LOG.info(_("Missing vncproxy_wwwroot (version %s)"), + FLAGS.vncproxy_wwwroot) LOG.info(_("You need a slightly modified version of noVNC " "to work with the nova-vnc-proxy")) LOG.info(_("Check out the most recent nova noVNC code: %s"), "git://github.com/sleepsonthefloor/noVNC.git") - LOG.info(_("And drop it in %s"), FLAGS.vnc_proxy_wwwroot) + LOG.info(_("And drop it in %s"), FLAGS.vncproxy_wwwroot) exit(1) - app = proxy.WebsocketVNCProxy(FLAGS.vnc_proxy_wwwroot) + app = proxy.WebsocketVNCProxy(FLAGS.vncproxy_wwwroot) LOG.audit(_("Allowing access to the following files: %s"), app.get_whitelist()) @@ -89,8 +94,8 @@ if __name__ == "__main__": if FLAGS.vnc_debug: with_auth = proxy.DebugMiddleware(with_logging) else: - with_auth = auth.NovaAuthMiddleware(with_logging) + with_auth = auth.VNCNovaAuthMiddleware(with_logging) server = wsgi.Server() - server.start(with_auth, FLAGS.vnc_proxy_port, host=FLAGS.vnc_proxy_host) + server.start(with_auth, FLAGS.vncproxy_port, host=FLAGS.vncproxy_host) server.wait() diff --git a/doc/source/runnova/vncconsole.rst b/doc/source/runnova/vncconsole.rst index 69f147613..6d93bad93 100644 --- a/doc/source/runnova/vncconsole.rst +++ b/doc/source/runnova/vncconsole.rst @@ -40,14 +40,14 @@ you can at find git://github.com/sleepsonthefloor/noVNC.git. .. todo:: add instruction for installing from package -noVNC must be in the location specified by --vnc_proxy_wwwroot, which defaults +noVNC must be in the location specified by --vncproxy_wwwroot, which defaults to /var/lib/nova/noVNC. nova-vnc-proxy will fail to launch until this code is properly installed. By default, nova-vnc-proxy binds 0.0.0.0:6080. This can be configured with: -* --vnc_proxy_port=[port] -* --vnc_proxy_host=[host] +* --vncproxy_port=[port] +* --vncproxy_host=[host] Enabling VNC Consoles in Nova diff --git a/nova/flags.py b/nova/flags.py index ba543f46d..b5c0cd380 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -281,7 +281,7 @@ DEFINE_string('ajax_console_proxy_url', in the form "http://127.0.0.1:8000"') DEFINE_string('ajax_console_proxy_port', 8000, 'port that ajax_console_proxy binds') -DEFINE_string('vnc_console_proxy_topic', 'vnc_proxy', +DEFINE_string('vnc_console_proxy_topic', 'vncproxy', 'the topic vnc proxy nodes listen on') DEFINE_string('vnc_console_proxy_url', 'http://127.0.0.1:6080', diff --git a/nova/vnc/auth.py b/nova/vnc/auth.py index dff9b376f..105b68fe2 100644 --- a/nova/vnc/auth.py +++ b/nova/vnc/auth.py @@ -1,9 +1,7 @@ #!/usr/bin/env python -# pylint: disable-msg=C0103 # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. +# Copyright (c) 2010 Openstack, LLC. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,8 +24,10 @@ import webob from webob import Request +from nova import context from nova import flags from nova import log as logging +from nova import manager from nova import rpc from nova import utils from nova import wsgi @@ -38,12 +38,24 @@ LOG = logging.getLogger('nova.vnc-proxy') FLAGS = flags.FLAGS -class NovaAuthMiddleware(object): +class VNCNovaAuthMiddleware(object): """Implementation of Middleware to Handle Nova Auth.""" def __init__(self, app): self.app = app - self.register_listeners() + self.token_cache = {} + utils.LoopingCall(self._delete_expired_tokens).start(1) + + def get_token_info(self, token): + if token in self.token_cache: + return self.token_cache[token] + + rval = rpc.call(context.get_admin_context(), + FLAGS.vnc_console_proxy_topic, + {"method": "check_token", "args": {'token': token}}) + if rval: + self.token_cache[token] = rval + return rval @webob.dec.wsgify def __call__(self, req): @@ -55,49 +67,27 @@ class NovaAuthMiddleware(object): if 'token' in auth_params: token = auth_params['token'][0] - if not token in self.tokens: + connection_info = self.get_token_info(token) + if not connection_info: LOG.audit(_("Unauthorized Access: (%s)"), req.environ) return webob.exc.HTTPForbidden(detail='Unauthorized') if req.path == vnc.proxy.WS_ENDPOINT: - req.environ['vnc_host'] = self.tokens[token]['args']['host'] - req.environ['vnc_port'] = int(self.tokens[token]['args']['port']) + req.environ['vnc_host'] = connection_info['host'] + req.environ['vnc_port'] = int(connection_info['port']) return req.get_response(self.app) - def register_listeners(self): - middleware = self - middleware.tokens = {} - - class TopicProxy(): - @staticmethod - def authorize_vnc_console(context, **kwargs): - data = kwargs - token = kwargs['token'] - LOG.audit(_("Received Token: %s)"), token) - middleware.tokens[token] = \ - {'args': kwargs, 'last_activity_at': time.time()} - - def delete_expired_tokens(): - now = time.time() - to_delete = [] - for k, v in middleware.tokens.items(): - if now - v['last_activity_at'] > FLAGS.vnc_token_ttl: - to_delete.append(k) - - for k in to_delete: - LOG.audit(_("Deleting Token: %s)"), k) - del middleware.tokens[k] - - conn = rpc.Connection.instance(new=True) - consumer = rpc.TopicAdapterConsumer( - connection=conn, - proxy=TopicProxy, - topic=FLAGS.vnc_console_proxy_topic) - - utils.LoopingCall(consumer.fetch, - enable_callbacks=True).start(0.1) - utils.LoopingCall(delete_expired_tokens).start(1) + def _delete_expired_tokens(self): + now = time.time() + to_delete = [] + for k, v in self.token_cache.items(): + if now - v['last_activity_at'] > FLAGS.vnc_token_ttl: + to_delete.append(k) + + for k in to_delete: + del self.token_cache[k] + class LoggingMiddleware(object): @@ -112,3 +102,34 @@ class LoggingMiddleware(object): LOG.info(_("Received Request: %s"), req.url) return req.get_response(self.app) + + +class VNCProxyAuthManager(manager.Manager): + """Manages token based authentication.""" + + def __init__(self, scheduler_driver=None, *args, **kwargs): + super(VNCProxyAuthManager, self).__init__(*args, **kwargs) + self.tokens = {} + utils.LoopingCall(self._delete_expired_tokens).start(1) + + def authorize_vnc_console(self, context, token, host, port): + self.tokens[token] = {'host': host, + 'port': port, + 'last_activity_at': time.time()} + LOG.audit(_("Received Token: %s, %s)"), token, self.tokens[token]) + + def check_token(self, context, token): + LOG.audit(_("Checking Token: %s, %s)"), token, (token in self.tokens)) + if token in self.tokens: + return self.tokens[token] + + def _delete_expired_tokens(self): + now = time.time() + to_delete = [] + for k, v in self.tokens.items(): + if now - v['last_activity_at'] > FLAGS.vnc_token_ttl: + to_delete.append(k) + + for k in to_delete: + LOG.audit(_("Deleting Expired Token: %s)"), k) + del self.tokens[k] diff --git a/nova/vnc/proxy.py b/nova/vnc/proxy.py index 49379d9ae..c6e46396b 100644 --- a/nova/vnc/proxy.py +++ b/nova/vnc/proxy.py @@ -1,8 +1,7 @@ #!/usr/bin/env python # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. +# Copyright (c) 2010 Openstack, LLC. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); |
