mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-12 20:43:02 +00:00
122 lines
4.6 KiB
Python
122 lines
4.6 KiB
Python
"""HTTP Handlers for the hub server"""
|
|
|
|
# Copyright (c) Jupyter Development Team.
|
|
# Distributed under the terms of the Modified BSD License.
|
|
|
|
from urllib.parse import urlparse
|
|
|
|
from tornado.escape import url_escape
|
|
from tornado import gen
|
|
from tornado.httputil import url_concat
|
|
|
|
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=self.authenticator.login_url(self.hub.server.base_url),
|
|
)
|
|
|
|
def get(self):
|
|
self.statsd.incr('login.request')
|
|
next_url = self.get_argument('next', '')
|
|
if (next_url + '/').startswith('%s://%s/' % (self.request.protocol, self.request.host)):
|
|
# treat absolute URLs for our host as absolute paths:
|
|
next_url = urlparse(next_url).path
|
|
elif not next_url.startswith('/'):
|
|
# disallow non-absolute next URLs (e.g. full URLs to other hosts)
|
|
next_url = ''
|
|
user = self.get_current_user()
|
|
if user:
|
|
if not next_url:
|
|
if user.running:
|
|
next_url = user.url
|
|
else:
|
|
next_url = self.hub.server.base_url
|
|
# set new login cookie
|
|
# because single-user cookie may have been cleared or incorrect
|
|
self.set_login_cookie(self.get_current_user())
|
|
self.redirect(next_url, permanent=False)
|
|
else:
|
|
if self.authenticator.auto_login:
|
|
auto_login_url = self.authenticator.login_url(self.hub.server.base_url)
|
|
if auto_login_url == self.settings['login_url']:
|
|
self.authenticator.auto_login = False
|
|
self.log.warning("Authenticator.auto_login cannot be used without a custom login_url")
|
|
else:
|
|
if next_url:
|
|
auto_login_url = url_concat(auto_login_url, {'next': 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)
|
|
|
|
auth_timer = self.statsd.timer('login.authenticate').start()
|
|
username = yield self.authenticate(data)
|
|
auth_timer.stop(send=False)
|
|
|
|
if username:
|
|
self.statsd.incr('login.success')
|
|
self.statsd.timing('login.authenticate.success', auth_timer.ms)
|
|
user = self.user_from_username(username)
|
|
already_running = False
|
|
if user.spawner:
|
|
status = yield user.spawner.poll()
|
|
already_running = (status == None)
|
|
if not already_running and not user.spawner.options_form:
|
|
yield self.spawn_single_user(user)
|
|
self.set_login_cookie(user)
|
|
next_url = self.get_argument('next', default='')
|
|
if not next_url.startswith('/'):
|
|
next_url = ''
|
|
next_url = next_url or self.hub.server.base_url
|
|
self.redirect(next_url)
|
|
self.log.info("User logged in: %s", username)
|
|
else:
|
|
self.statsd.incr('login.failure')
|
|
self.statsd.timing('login.authenticate.failure', auth_timer.ms)
|
|
self.log.debug("Failed login for %s", data.get('username', 'unknown user'))
|
|
html = self._render(
|
|
login_error='Invalid username or password',
|
|
username=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),
|
|
]
|