mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-16 06:22:59 +00:00
more hooks for authenticators
Allow authenticators to: - register custom handlers - change login and logout URLs - replace the entire login form This appears to be enough to get oauth working.
This commit is contained in:
@@ -210,7 +210,8 @@ class JupyterHubApp(Application):
|
|||||||
def _cookie_secret_default(self):
|
def _cookie_secret_default(self):
|
||||||
return os.environ.get('JPY_COOKIE_SECRET', random_hex(64))
|
return os.environ.get('JPY_COOKIE_SECRET', random_hex(64))
|
||||||
|
|
||||||
authenticator_class = Type("jupyterhub.auth.PAMAuthenticator", config=True,
|
authenticator_class = Type(PAMAuthenticator, Authenticator,
|
||||||
|
config=True,
|
||||||
help="""Class for authenticating users.
|
help="""Class for authenticating users.
|
||||||
|
|
||||||
This should be a class with the following form:
|
This should be a class with the following form:
|
||||||
@@ -224,12 +225,14 @@ class JupyterHubApp(Application):
|
|||||||
and `data` is the POST form data from the login page.
|
and `data` is the POST form data from the login page.
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
authenticator = Instance(Authenticator)
|
authenticator = Instance(Authenticator)
|
||||||
def _authenticator_default(self):
|
def _authenticator_default(self):
|
||||||
return self.authenticator_class(config=self.config)
|
return self.authenticator_class(config=self.config)
|
||||||
|
|
||||||
# class for spawning single-user servers
|
# class for spawning single-user servers
|
||||||
spawner_class = Type("jupyterhub.spawner.LocalProcessSpawner", config=True,
|
spawner_class = Type(LocalProcessSpawner, Spawner,
|
||||||
|
config=True,
|
||||||
help="""The class to use for spawning single-user servers.
|
help="""The class to use for spawning single-user servers.
|
||||||
|
|
||||||
Should be a subclass of Spawner.
|
Should be a subclass of Spawner.
|
||||||
@@ -323,6 +326,8 @@ class JupyterHubApp(Application):
|
|||||||
h = []
|
h = []
|
||||||
h.extend(handlers.default_handlers)
|
h.extend(handlers.default_handlers)
|
||||||
h.extend(apihandlers.default_handlers)
|
h.extend(apihandlers.default_handlers)
|
||||||
|
# load handlers from the authenticator
|
||||||
|
h.extend(self.authenticator.get_handlers(self))
|
||||||
|
|
||||||
self.handlers = self.add_url_prefix(self.hub_prefix, h)
|
self.handlers = self.add_url_prefix(self.hub_prefix, h)
|
||||||
|
|
||||||
@@ -534,13 +539,16 @@ class JupyterHubApp(Application):
|
|||||||
|
|
||||||
def init_tornado_settings(self):
|
def init_tornado_settings(self):
|
||||||
"""Set up the tornado settings dict."""
|
"""Set up the tornado settings dict."""
|
||||||
base_url = self.base_url
|
base_url = self.hub.server.base_url
|
||||||
template_path = os.path.join(self.data_files_path, 'templates'),
|
template_path = os.path.join(self.data_files_path, 'templates'),
|
||||||
jinja_env = Environment(
|
jinja_env = Environment(
|
||||||
loader=FileSystemLoader(template_path),
|
loader=FileSystemLoader(template_path),
|
||||||
**self.jinja_environment_options
|
**self.jinja_environment_options
|
||||||
)
|
)
|
||||||
|
|
||||||
|
login_url = self.authenticator.login_url(base_url)
|
||||||
|
logout_url = self.authenticator.logout_url(base_url)
|
||||||
|
|
||||||
settings = dict(
|
settings = dict(
|
||||||
config=self.config,
|
config=self.config,
|
||||||
log=self.log,
|
log=self.log,
|
||||||
@@ -550,9 +558,10 @@ class JupyterHubApp(Application):
|
|||||||
admin_users=self.admin_users,
|
admin_users=self.admin_users,
|
||||||
authenticator=self.authenticator,
|
authenticator=self.authenticator,
|
||||||
spawner_class=self.spawner_class,
|
spawner_class=self.spawner_class,
|
||||||
base_url=base_url,
|
base_url=self.base_url,
|
||||||
cookie_secret=self.hub.server.cookie_secret,
|
cookie_secret=self.hub.server.cookie_secret,
|
||||||
login_url=url_path_join(self.hub.server.base_url, 'login'),
|
login_url=login_url,
|
||||||
|
logout_url=logout_url,
|
||||||
static_path=os.path.join(self.data_files_path, 'static'),
|
static_path=os.path.join(self.data_files_path, 'static'),
|
||||||
static_url_prefix=url_path_join(self.hub.server.base_url, 'static/'),
|
static_url_prefix=url_path_join(self.hub.server.base_url, 'static/'),
|
||||||
template_path=template_path,
|
template_path=template_path,
|
||||||
|
@@ -9,6 +9,8 @@ import simplepam
|
|||||||
from IPython.config import LoggingConfigurable
|
from IPython.config import LoggingConfigurable
|
||||||
from IPython.utils.traitlets import Unicode, Set
|
from IPython.utils.traitlets import Unicode, Set
|
||||||
|
|
||||||
|
from .utils import url_path_join
|
||||||
|
|
||||||
class Authenticator(LoggingConfigurable):
|
class Authenticator(LoggingConfigurable):
|
||||||
"""A class for authentication.
|
"""A class for authentication.
|
||||||
|
|
||||||
@@ -22,6 +24,7 @@ class Authenticator(LoggingConfigurable):
|
|||||||
If empty, allow any user to attempt login.
|
If empty, allow any user to attempt login.
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
custom_html = Unicode('')
|
||||||
|
|
||||||
@gen.coroutine
|
@gen.coroutine
|
||||||
def authenticate(self, handler, data):
|
def authenticate(self, handler, data):
|
||||||
@@ -32,6 +35,22 @@ class Authenticator(LoggingConfigurable):
|
|||||||
and return None on failed authentication.
|
and return None on failed authentication.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def login_url(self, base_url):
|
||||||
|
"""Override to register a custom login handler"""
|
||||||
|
return url_path_join(base_url, 'login')
|
||||||
|
|
||||||
|
def logout_url(self, base_url):
|
||||||
|
"""Override to register a custom logout handler"""
|
||||||
|
return url_path_join(base_url, 'logout')
|
||||||
|
|
||||||
|
def get_handlers(self, app):
|
||||||
|
"""Return any custom handlers the authenticator needs to register
|
||||||
|
|
||||||
|
(e.g. for OAuth)
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
class PAMAuthenticator(Authenticator):
|
class PAMAuthenticator(Authenticator):
|
||||||
encoding = Unicode('utf8', config=True,
|
encoding = Unicode('utf8', config=True,
|
||||||
help="""The encoding to use for PAM """
|
help="""The encoding to use for PAM """
|
||||||
|
@@ -206,6 +206,7 @@ class BaseHandler(RequestHandler):
|
|||||||
base_url=self.hub.server.base_url,
|
base_url=self.hub.server.base_url,
|
||||||
user=user,
|
user=user,
|
||||||
login_url=self.settings['login_url'],
|
login_url=self.settings['login_url'],
|
||||||
|
logout_url=self.settings['logout_url'],
|
||||||
static_url=self.static_url,
|
static_url=self.static_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@ class LoginHandler(BaseHandler):
|
|||||||
next=url_escape(self.get_argument('next', default='')),
|
next=url_escape(self.get_argument('next', default='')),
|
||||||
username=username,
|
username=username,
|
||||||
message=message,
|
message=message,
|
||||||
|
custom_html=self.authenticator.custom_html,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
|
@@ -6,6 +6,9 @@
|
|||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
<div id="login-main" class="container">
|
<div id="login-main" class="container">
|
||||||
|
{% if custom_html %}
|
||||||
|
{{custom_html}}
|
||||||
|
{% else %}
|
||||||
<form action="{{login_url}}?next={{next}}" method="post" role="form">
|
<form action="{{login_url}}?next={{next}}" method="post" role="form">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-addon">Username:</span>
|
<span class="input-group-addon">Username:</span>
|
||||||
@@ -24,6 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
<div/>
|
<div/>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -83,9 +83,9 @@
|
|||||||
|
|
||||||
<span id="login_widget">
|
<span id="login_widget">
|
||||||
{% if user %}
|
{% if user %}
|
||||||
<a id="logout" class="btn navbar-btn btn-default pull-right" href="{{base_url}}logout">Logout</a>
|
<a id="logout" class="btn navbar-btn btn-default pull-right" href="{{logout_url}}">Logout</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a id="login" class="btn navbar-btn btn-default pull-right" href="{{base_url}}login">Login</a>
|
<a id="login" class="btn navbar-btn btn-default pull-right" href="{{login_url}}">Login</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user