Add Authenticator.auto_login

Simplifies login URL, handler login

- all login redirects go to `settings['login_url']`
- `login_url` is unconditionally `/hub/login`
- `/hub/login` renders form page or 'login with...' button
- enabling auto_login redirects from /hub/login to Authenticator.login_url()
This commit is contained in:
Min RK
2017-04-07 14:49:18 +02:00
parent 5f498ffaf3
commit 6b22f80ead
6 changed files with 47 additions and 10 deletions

View File

@@ -1173,10 +1173,12 @@ class JupyterHub(Application):
db.commit() db.commit()
def init_oauth(self): def init_oauth(self):
base_url = self.hub.server.base_url
self.oauth_provider = make_provider( self.oauth_provider = make_provider(
self.session_factory, self.session_factory,
url_prefix=url_path_join(self.hub.server.base_url, 'api/oauth2'), url_prefix=url_path_join(base_url, 'api/oauth2'),
login_url=self.authenticator.login_url(self.hub.server.base_url), login_url=url_path_join(base_url, 'login')
,
) )
def init_proxy(self): def init_proxy(self):
@@ -1307,7 +1309,7 @@ class JupyterHub(Application):
**jinja_options **jinja_options
) )
login_url = self.authenticator.login_url(base_url) login_url = url_path_join(base_url, 'login')
logout_url = self.authenticator.logout_url(base_url) logout_url = self.authenticator.logout_url(base_url)
# if running from git, disable caching of require.js # if running from git, disable caching of require.js

View File

@@ -31,7 +31,7 @@ class Authenticator(LoggingConfigurable):
help=""" help="""
Set of users that will have admin rights on this JupyterHub. Set of users that will have admin rights on this JupyterHub.
Admin users have extra privilages: Admin users have extra privileges:
- Use the admin panel to see list of users logged in - Use the admin panel to see list of users logged in
- Add / remove users in some authenticators - Add / remove users in some authenticators
- Restart / halt the hub - Restart / halt the hub
@@ -250,10 +250,23 @@ class Authenticator(LoggingConfigurable):
""" """
self.whitelist.discard(user.name) self.whitelist.discard(user.name)
auto_login = Bool(False, config=True,
help="""Automatically begin the login process
rather than starting with a "Login with..." link at `/hub/login`
To work, `.login_url()` must give a URL other than the default `/hub/login`,
such as an oauth handler or another automatic login handler,
registered with `.get_handlers()`.
.. versionadded:: 0.8
"""
)
def login_url(self, base_url): def login_url(self, base_url):
"""Override this when registering a custom login handler """Override this when registering a custom login handler
Generally used by authenticators that do not use simple form based authentication. Generally used by authenticators that do not use simple form-based authentication.
The subclass overriding this is responsible for making sure there is a handler The subclass overriding this is responsible for making sure there is a handler
available to handle the URL returned from this method, using the `get_handlers` available to handle the URL returned from this method, using the `get_handlers`

View File

@@ -7,8 +7,8 @@ from urllib.parse import urlparse
from tornado.escape import url_escape from tornado.escape import url_escape
from tornado import gen from tornado import gen
from tornado.httputil import url_concat
from ..utils import url_path_join
from .base import BaseHandler from .base import BaseHandler
@@ -23,8 +23,10 @@ class LogoutHandler(BaseHandler):
self.clear_login_cookie(name) self.clear_login_cookie(name)
user.other_user_cookies = set([]) user.other_user_cookies = set([])
self.statsd.incr('logout') self.statsd.incr('logout')
if self.authenticator.auto_login:
self.redirect(url_path_join(self.hub.server.base_url, 'login'), permanent=False) self.render('logout.html')
else:
self.redirect(self.settings['login_url'], permanent=False)
class LoginHandler(BaseHandler): class LoginHandler(BaseHandler):
@@ -37,6 +39,7 @@ class LoginHandler(BaseHandler):
login_error=login_error, login_error=login_error,
custom_html=self.authenticator.custom_html, custom_html=self.authenticator.custom_html,
login_url=self.settings['login_url'], login_url=self.settings['login_url'],
authenticator_login_url=self.authenticator.login_url(self.hub.server.base_url),
) )
def get(self): def get(self):
@@ -60,6 +63,16 @@ class LoginHandler(BaseHandler):
self.set_login_cookie(self.get_current_user()) self.set_login_cookie(self.get_current_user())
self.redirect(next_url, permanent=False) self.redirect(next_url, permanent=False)
else: 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='') username = self.get_argument('username', default='')
self.finish(self._render(username=username)) self.finish(self._render(username=username))

View File

@@ -53,7 +53,7 @@ class RootHandler(BaseHandler):
url = url_path_join(self.hub.server.base_url, 'home') url = url_path_join(self.hub.server.base_url, 'home')
self.log.debug("User is not running: %s", url) self.log.debug("User is not running: %s", url)
else: else:
url = url_path_join(self.hub.server.base_url, 'login') url = self.settings['login_url']
self.redirect(url) self.redirect(url)

View File

@@ -11,7 +11,7 @@
{{ custom_html }} {{ custom_html }}
{% elif login_service %} {% elif login_service %}
<div class="service-login"> <div class="service-login">
<a class='btn btn-jupyter btn-lg' href='{{login_url}}'> <a class='btn btn-jupyter btn-lg' href='{{authenticator_login_url}}'>
Sign in with {{login_service}} Sign in with {{login_service}}
</a> </a>
</div> </div>

View File

@@ -0,0 +1,9 @@
{% extends "page.html" %}
{% block main %}
<div id="logout-main" class="container">
<p>
Successfully logged out.
</p>
</div>
{% endblock %}