summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony Young <sleepsonthefloor@gmail.com>2011-03-23 15:53:46 -0700
committerAnthony Young <sleepsonthefloor@gmail.com>2011-03-23 15:53:46 -0700
commite0289dd26821545a6ef2ca91eb2dba7c11c2cc9f (patch)
treee39d0a18e3410c516d24e098cc93cd667cd03be6
parent5cdf8f63fb2dbccea0152d17f00bf80352f8fa1a (diff)
general cleanup, use whitelist for webserver security
-rwxr-xr-xbin/nova-vnc-proxy22
-rw-r--r--nova/flags.py2
-rw-r--r--nova/virt/libvirt.xml.template2
-rw-r--r--nova/virt/libvirt_conn.py2
-rw-r--r--nova/vnc/auth.py34
-rw-r--r--nova/vnc/proxy.py28
6 files changed, 68 insertions, 22 deletions
diff --git a/bin/nova-vnc-proxy b/bin/nova-vnc-proxy
index 838c871d0..4cd1e9082 100755
--- a/bin/nova-vnc-proxy
+++ b/bin/nova-vnc-proxy
@@ -44,14 +44,16 @@ from nova.vnc import proxy
LOG = logging.getLogger('nova.vnc-proxy')
FLAGS = flags.FLAGS
-flags.DEFINE_string('vnc_proxy_wwwroot', '/code/noVNC/vnclet/noVNC',
+flags.DEFINE_string('vnc_proxy_wwwroot', '/code/noVNC/',
'Full path to noVNC directory')
flags.DEFINE_boolean('vnc_debug', False,
'Enable debugging features, like token bypassing')
-flags.DEFINE_integer('vnc_proxy_port', 7000,
+flags.DEFINE_integer('vnc_proxy_port', 6080,
'Port that the VNC proxy should bind to')
-flags.DEFINE_string('vnc_proxy_host', '0.0.0.0',
+flags.DEFINE_string('vnc_proxy_iface', '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_flag(flags.HelpFlag())
flags.DEFINE_flag(flags.HelpshortFlag())
flags.DEFINE_flag(flags.HelpXMLFlag())
@@ -64,8 +66,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):
+ LOG.info(_("Missing vnc_proxy_wwwroot (version %s)"),
+ FLAGS.vnc_proxy_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 here: %s"),
+ "git://github.com/sleepsonthefloor/noVNC.git")
+ exit(1)
+
app = proxy.WebsocketVNCProxy(FLAGS.vnc_proxy_wwwroot)
+ LOG.audit(_("Allowing access to the following files: %s"),
+ app.get_whitelist())
+
with_logging = auth.LoggingMiddleware(app)
if FLAGS.vnc_debug:
@@ -74,5 +88,5 @@ if __name__ == "__main__":
with_auth = auth.NovaAuthMiddleware(with_logging)
server = wsgi.Server()
- server.start(with_auth, FLAGS.vnc_proxy_port, host=FLAGS.vnc_proxy_host)
+ server.start(with_auth, FLAGS.vnc_proxy_port, host=FLAGS.vnc_proxy_iface)
server.wait()
diff --git a/nova/flags.py b/nova/flags.py
index 0360b1e3a..a0ea10795 100644
--- a/nova/flags.py
+++ b/nova/flags.py
@@ -287,7 +287,7 @@ DEFINE_string('vnc_console_proxy_url',
'http://127.0.0.1:6080',
'location of vnc console proxy, \
in the form "http://127.0.0.1:6080"')
-DEFINE_string('vnc_host_iface', '0.0.0.0',
+DEFINE_string('vnc_compute_host_iface', '0.0.0.0',
'the compute host interface on which vnc server should listen')
DEFINE_bool('vnc_enabled', True,
'enable vnc related features')
diff --git a/nova/virt/libvirt.xml.template b/nova/virt/libvirt.xml.template
index 037cd0902..bcc6b3aed 100644
--- a/nova/virt/libvirt.xml.template
+++ b/nova/virt/libvirt.xml.template
@@ -101,7 +101,7 @@
<target port='0'/>
</serial>
-#if $getVar('vnc_host_iface', False)
+#if $getVar('vnc_compute_host_iface', False)
<graphics type='vnc' port='-1' autoport='yes' keymap='en-us' listen='${vnc_host_iface}'/>
#end if
</devices>
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 51f263ce9..c3529f512 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -735,7 +735,7 @@ class LibvirtConnection(object):
'driver_type': driver_type}
if FLAGS.vnc_enabled:
- xml_info['vnc_host_iface'] = FLAGS.vnc_host_iface
+ xml_info['vnc_compute_host_iface'] = FLAGS.vnc_compute_host_iface
if ra_server:
xml_info['ra_server'] = ra_server + "/128"
if not rescue:
diff --git a/nova/vnc/auth.py b/nova/vnc/auth.py
index 9b30b08b8..676cb2360 100644
--- a/nova/vnc/auth.py
+++ b/nova/vnc/auth.py
@@ -21,13 +21,16 @@
"""Auth Components for VNC Console"""
import time
+import urlparse
+import webob
from webob import Request
+
from nova import flags
from nova import log as logging
from nova import rpc
from nova import utils
from nova import wsgi
-import webob
+from nova import vnc
LOG = logging.getLogger('nova.vnc-proxy')
FLAGS = flags.FLAGS
@@ -42,13 +45,19 @@ class NovaAuthMiddleware(object):
@webob.dec.wsgify
def __call__(self, req):
- if req.path == '/data':
- token = req.params.get('token')
- if not token in self.tokens:
- start_response('403 Forbidden',
- [('content-type', 'text/html')])
- return 'Not Authorized'
+ token = req.params.get('token')
+
+ if not token:
+ referrer = req.environ.get('HTTP_REFERER')
+ auth_params = urlparse.parse_qs(urlparse.urlparse(referrer).query)
+ if 'token' in auth_params:
+ token = auth_params['token'][0]
+
+ if not token in self.tokens:
+ 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'])
@@ -62,7 +71,7 @@ class NovaAuthMiddleware(object):
def __call__(self, data, message):
if data['method'] == 'authorize_vnc_console':
token = data['args']['token']
- LOG.info(_("Received Token: %s)"), token)
+ LOG.audit(_("Received Token: %s)"), token)
middleware.tokens[token] = \
{'args': data['args'], 'last_activity_at': time.time()}
@@ -70,10 +79,11 @@ class NovaAuthMiddleware(object):
now = time.time()
to_delete = []
for k, v in middleware.tokens.items():
- if now - v['last_activity_at'] > 600:
+ 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)
@@ -94,9 +104,9 @@ class LoggingMiddleware(object):
@webob.dec.wsgify
def __call__(self, req):
- if req.path == '/data':
- LOG.info(_("Received Websocket Request: %s)"), req.url)
+ if req.path == vnc.proxy.WS_ENDPOINT:
+ LOG.info(_("Received Websocket Request: %s"), req.url)
else:
- LOG.info(_("Received Request: %s)"), req.url)
+ LOG.info(_("Received Request: %s"), req.url)
return req.get_response(self.app)
diff --git a/nova/vnc/proxy.py b/nova/vnc/proxy.py
index 354c2405f..70ebd022a 100644
--- a/nova/vnc/proxy.py
+++ b/nova/vnc/proxy.py
@@ -28,12 +28,30 @@ import os
from webob import Request
import webob
+WS_ENDPOINT = '/data'
+
class WebsocketVNCProxy(object):
"""Class to proxy from websocket to vnc server"""
def __init__(self, wwwroot):
self.wwwroot = wwwroot
+ self.whitelist = {}
+ for root, dirs, files in os.walk(wwwroot):
+ hidden_dirs = []
+ for d in dirs:
+ if d.startswith('.'):
+ hidden_dirs.append(d)
+ for d in hidden_dirs:
+ dirs.remove(d)
+ for name in files:
+ if not str(name).startswith('.'):
+ filename = os.path.join(root, name)
+ self.whitelist[filename] = True
+
+
+ def get_whitelist(self):
+ return self.whitelist.keys()
def sock2ws(self, source, dest):
try:
@@ -72,7 +90,7 @@ class WebsocketVNCProxy(object):
def __call__(self, environ, start_response):
req = Request(environ)
- if req.path == '/data':
+ if req.path == WS_ENDPOINT:
return self.proxy_connection(environ, start_response)
else:
if req.path == '/':
@@ -80,7 +98,11 @@ class WebsocketVNCProxy(object):
else:
fname = req.path
- fname = self.wwwroot + fname
+ fname = (self.wwwroot + fname).replace('//','/')
+ if not fname in self.whitelist:
+ start_response('404 Not Found',
+ [('content-type', 'text/html')])
+ return "Not Found"
base, ext = os.path.splitext(fname)
if ext == '.js':
@@ -104,7 +126,7 @@ class DebugMiddleware(object):
@webob.dec.wsgify
def __call__(self, req):
- if req.path == '/data':
+ if req.path == WS_ENDPOINT:
req.environ['vnc_host'] = req.params.get('host')
req.environ['vnc_port'] = int(req.params.get('port'))
return req.get_response(self.app)