mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-11 03:52:59 +00:00

for easier re-use of login in custom handlers Further, enable auto_login + no custom login handler to mean that auth info is already present in requests (e.g. REMOTE_USER)
109 lines
3.9 KiB
Python
109 lines
3.9 KiB
Python
"""HTTP Handlers for the hub server"""
|
|
|
|
# Copyright (c) Jupyter Development Team.
|
|
# Distributed under the terms of the Modified BSD License.
|
|
|
|
from tornado.escape import url_escape
|
|
from tornado import gen
|
|
from tornado.httputil import url_concat
|
|
from tornado import web
|
|
|
|
from .base import BaseHandler
|
|
|
|
|
|
class LogoutHandler(BaseHandler):
|
|
"""Log a user out by clearing their login cookie."""
|
|
def get(self):
|
|
user = self.get_current_user()
|
|
if user:
|
|
self.log.info("User logged out: %s", user.name)
|
|
self.clear_login_cookie()
|
|
self.statsd.incr('logout')
|
|
if self.authenticator.auto_login:
|
|
self.render('logout.html')
|
|
else:
|
|
self.redirect(self.settings['login_url'], permanent=False)
|
|
|
|
|
|
class LoginHandler(BaseHandler):
|
|
"""Render the login page."""
|
|
|
|
def _render(self, login_error=None, username=None):
|
|
return self.render_template('login.html',
|
|
next=url_escape(self.get_argument('next', default='')),
|
|
username=username,
|
|
login_error=login_error,
|
|
custom_html=self.authenticator.custom_html,
|
|
login_url=self.settings['login_url'],
|
|
authenticator_login_url=url_concat(
|
|
self.authenticator.login_url(self.hub.base_url),
|
|
{'next': self.get_argument('next', '')},
|
|
),
|
|
)
|
|
|
|
@gen.coroutine
|
|
def get(self):
|
|
self.statsd.incr('login.request')
|
|
user = self.get_current_user()
|
|
if user:
|
|
# set new login cookie
|
|
# because single-user cookie may have been cleared or incorrect
|
|
self.set_login_cookie(self.get_current_user())
|
|
self.redirect(self.get_next_url(user), permanent=False)
|
|
else:
|
|
if self.authenticator.auto_login:
|
|
auto_login_url = self.authenticator.login_url(self.hub.base_url)
|
|
if auto_login_url == self.settings['login_url']:
|
|
# auto_login without a custom login handler
|
|
# means that auth info is already in the request
|
|
# (e.g. REMOTE_USER header)
|
|
user = yield self.login_user()
|
|
if user is None:
|
|
# auto_login failed, just 403
|
|
raise web.HTTPError(403)
|
|
else:
|
|
self.redirect(self.get_next_url(user))
|
|
else:
|
|
if self.get_argument('next', default=False):
|
|
auto_login_url = url_concat(auto_login_url, {'next': self.get_next_url()})
|
|
self.redirect(auto_login_url)
|
|
return
|
|
username = self.get_argument('username', default='')
|
|
self.finish(self._render(username=username))
|
|
|
|
@gen.coroutine
|
|
def post(self):
|
|
# parse the arguments dict
|
|
data = {}
|
|
for arg in self.request.arguments:
|
|
data[arg] = self.get_argument(arg, strip=False)
|
|
|
|
auth_timer = self.statsd.timer('login.authenticate').start()
|
|
user = yield self.login_user(data)
|
|
auth_timer.stop(send=False)
|
|
|
|
if user:
|
|
already_running = False
|
|
if user.spawner:
|
|
status = yield user.spawner.poll()
|
|
already_running = (status is None)
|
|
if not already_running and not user.spawner.options_form:
|
|
# logging in triggers spawn
|
|
yield self.spawn_single_user(user)
|
|
self.redirect(self.get_next_url())
|
|
else:
|
|
html = self._render(
|
|
login_error='Invalid username or password',
|
|
username=data['username'],
|
|
)
|
|
self.finish(html)
|
|
|
|
|
|
# /login renders the login page or the "Login with..." link,
|
|
# so it should always be registered.
|
|
# /logout clears cookies.
|
|
default_handlers = [
|
|
(r"/login", LoginHandler),
|
|
(r"/logout", LogoutHandler),
|
|
]
|