diff --git a/jupyterhub/auth.py b/jupyterhub/auth.py index bd4270e6..41ad1058 100644 --- a/jupyterhub/auth.py +++ b/jupyterhub/auth.py @@ -1173,3 +1173,22 @@ class DummyAuthenticator(Authenticator): return data['username'] return None return data['username'] + + +class NullAuthenticator(Authenticator): + """Null Authenticator for JupyterHub + + For cases where authentication should be disabled, + e.g. only allowing access via API tokens. + + .. versionadded:: 2.0 + """ + + # auto_login skips 'Login with...' page on Hub 0.8 + auto_login = True + + # for Hub 0.7, show 'login with...' + login_service = 'null' + + def get_handlers(self, app): + return [] diff --git a/jupyterhub/tests/test_auth.py b/jupyterhub/tests/test_auth.py index 58d48456..1f627426 100644 --- a/jupyterhub/tests/test_auth.py +++ b/jupyterhub/tests/test_auth.py @@ -3,6 +3,7 @@ # Distributed under the terms of the Modified BSD License. import logging from unittest import mock +from urllib.parse import urlparse import pytest from requests import HTTPError @@ -12,6 +13,8 @@ from .mocking import MockPAMAuthenticator from .mocking import MockStructGroup from .mocking import MockStructPasswd from .utils import add_user +from .utils import async_requests +from .utils import public_url from jupyterhub import auth from jupyterhub import crypto from jupyterhub import orm @@ -515,3 +518,12 @@ def test_deprecated_methods_subclass(): assert authenticator.check_whitelist("subclass-allowed") assert not authenticator.check_allowed("otheruser") assert not authenticator.check_whitelist("otheruser") + + +async def test_nullauthenticator(app): + with mock.patch.dict( + app.tornado_settings, {"authenticator": auth.NullAuthenticator(parent=app)} + ): + r = await async_requests.get(public_url(app)) + assert urlparse(r.url).path.endswith("/hub/login") + assert r.status_code == 403 diff --git a/setup.py b/setup.py index 2c189fa6..95cc73cd 100755 --- a/setup.py +++ b/setup.py @@ -100,6 +100,7 @@ setup_args = dict( 'default = jupyterhub.auth:PAMAuthenticator', 'pam = jupyterhub.auth:PAMAuthenticator', 'dummy = jupyterhub.auth:DummyAuthenticator', + 'null = jupyterhub.auth:NullAuthenticator', ], 'jupyterhub.proxies': [ 'default = jupyterhub.proxy:ConfigurableHTTPProxy',