Permalink
Browse files

Authenticate all notebook requests (except websockets)

* BaseHandler renamed AuthenticatedHandler
* also clears cookies if invalid, to prevent repeated 'Invalid cookie signature' warning messages.
  • Loading branch information...
1 parent f97967f commit 4d5cfe6c945b73211b425b610a3a40bd12565fe9 @minrk minrk committed Aug 30, 2011
Showing with 43 additions and 27 deletions.
  1. +33 −25 IPython/frontend/html/notebook/handlers.py
  2. +10 −2 IPython/frontend/html/notebook/templates/login.html
@@ -35,48 +35,46 @@
# Top-level handlers
#-----------------------------------------------------------------------------
-class BaseHandler(web.RequestHandler):
+class AuthenticatedHandler(web.RequestHandler):
+ """A RequestHandler with an authenticated user."""
def get_current_user(self):
- user_id = self.get_secure_cookie("user")
- if user_id is None:
- self.clear_cookie('user')
- self.clear_cookie('password')
password = self.get_secure_cookie("password")
+ if password is None:
+ # cookie doesn't exist, or is invalid. Clear to prevent repeated
+ # 'Invalid cookie signature' warnings.
+ self.clear_cookie('password')
+ self.clear_cookie("user_id")
if self.application.password and self.application.password != password:
return None
- if not user_id:
- user_id = 'anonymous'
- return user_id
+ return self.get_secure_cookie("user") or 'anonymous'
-class NBBrowserHandler(BaseHandler):
+class NBBrowserHandler(AuthenticatedHandler):
@web.authenticated
def get(self):
nbm = self.application.notebook_manager
project = nbm.notebook_dir
self.render('nbbrowser.html', project=project)
-class LoginHandler(BaseHandler):
+class LoginHandler(AuthenticatedHandler):
def get(self):
- user_id = self.get_secure_cookie("user")
- if user_id is None:
- self.clear_cookie('user')
- self.clear_cookie('password')
- user_id = ''
-
+ user_id = self.get_secure_cookie("user") or ''
self.render('login.html', user_id=user_id)
def post(self):
self.set_secure_cookie("user", self.get_argument("name", default=u''))
self.set_secure_cookie("password", self.get_argument("password", default=u''))
- self.redirect("/")
+ url = self.get_argument("next", default="/")
+ self.redirect(url)
-class NewHandler(web.RequestHandler):
+class NewHandler(AuthenticatedHandler):
+ @web.authenticated
def get(self):
notebook_id = self.application.notebook_manager.new_notebook()
self.render('notebook.html', notebook_id=notebook_id)
-class NamedNotebookHandler(web.RequestHandler):
+class NamedNotebookHandler(AuthenticatedHandler):
+ @web.authenticated
def get(self, notebook_id):
nbm = self.application.notebook_manager
if not nbm.notebook_exists(notebook_id):
@@ -89,12 +87,14 @@ def get(self, notebook_id):
#-----------------------------------------------------------------------------
-class MainKernelHandler(web.RequestHandler):
+class MainKernelHandler(AuthenticatedHandler):
+ @web.authenticated
def get(self):
km = self.application.kernel_manager
self.finish(jsonapi.dumps(km.kernel_ids))
+ @web.authenticated
def post(self):
km = self.application.kernel_manager
notebook_id = self.get_argument('notebook', default=None)
@@ -105,19 +105,21 @@ def post(self):
self.finish(jsonapi.dumps(data))
-class KernelHandler(web.RequestHandler):
+class KernelHandler(AuthenticatedHandler):
SUPPORTED_METHODS = ('DELETE')
+ @web.authenticated
def delete(self, kernel_id):
km = self.application.kernel_manager
km.kill_kernel(kernel_id)
self.set_status(204)
self.finish()
-class KernelActionHandler(web.RequestHandler):
+class KernelActionHandler(AuthenticatedHandler):
+ @web.authenticated
def post(self, kernel_id, action):
km = self.application.kernel_manager
if action == 'interrupt':
@@ -278,13 +280,15 @@ def on_close(self):
# Notebook web service handlers
#-----------------------------------------------------------------------------
-class NotebookRootHandler(web.RequestHandler):
+class NotebookRootHandler(AuthenticatedHandler):
+ @web.authenticated
def get(self):
nbm = self.application.notebook_manager
files = nbm.list_notebooks()
self.finish(jsonapi.dumps(files))
+ @web.authenticated
def post(self):
nbm = self.application.notebook_manager
body = self.request.body.strip()
@@ -298,10 +302,11 @@ def post(self):
self.finish(jsonapi.dumps(notebook_id))
-class NotebookHandler(web.RequestHandler):
+class NotebookHandler(AuthenticatedHandler):
SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
+ @web.authenticated
def get(self, notebook_id):
nbm = self.application.notebook_manager
format = self.get_argument('format', default='json')
@@ -315,6 +320,7 @@ def get(self, notebook_id):
self.set_header('Last-Modified', last_mod)
self.finish(data)
+ @web.authenticated
def put(self, notebook_id):
nbm = self.application.notebook_manager
format = self.get_argument('format', default='json')
@@ -323,6 +329,7 @@ def put(self, notebook_id):
self.set_status(204)
self.finish()
+ @web.authenticated
def delete(self, notebook_id):
nbm = self.application.notebook_manager
nbm.delete_notebook(notebook_id)
@@ -334,8 +341,9 @@ def delete(self, notebook_id):
#-----------------------------------------------------------------------------
-class RSTHandler(web.RequestHandler):
+class RSTHandler(AuthenticatedHandler):
+ @web.authenticated
def post(self):
if publish_string is None:
raise web.HTTPError(503, u'docutils not available')
@@ -13,10 +13,18 @@
<link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
<link rel="stylesheet" href="static/css/layout.css" type="text/css" />
<link rel="stylesheet" href="static/css/base.css" type="text/css" />
-
+<script type="text/javascript" charset="utf-8">
+function add_next_to_action(){
+ // add 'next' argument to action url, to preserve redirect
+ var query = location.search.substring(1);
+ var form = document.forms[0];
+ var action = form.getAttribute("action");
+ form.setAttribute("action", action + '?' + query);
+}
+</script>
</head>
-<body>
+<body onload="add_next_to_action()">
<div id="header">
<span id="ipython_notebook"><h1>IPython Notebook</h1></span>

0 comments on commit 4d5cfe6

Please sign in to comment.