diff --git a/.gitignore b/.gitignore index 1216e7a..4942864 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ dist/ # IDE files .idea/ + +# Poetry files +poetry.lock diff --git a/crc_jupyter_auth/remote_user_auth.py b/crc_jupyter_auth/remote_user_auth.py index 6329ce8..d4831ad 100644 --- a/crc_jupyter_auth/remote_user_auth.py +++ b/crc_jupyter_auth/remote_user_auth.py @@ -6,8 +6,6 @@ --------------- """ -import os - from jupyterhub.auth import Authenticator, LocalAuthenticator from jupyterhub.handlers import BaseHandler from jupyterhub.utils import url_path_join @@ -51,7 +49,7 @@ def get(self): # Facilitate user authentication user = self.user_from_username(remote_user) self.set_login_cookie(user) - self.redirect(url_path_join(self.hub.server.base_url, 'home')) + self.redirect_or_raise(url_path_join(self.hub.server.base_url, 'home')) def redirect_or_raise(self, url, raise_status=404): """Redirect to the given url diff --git a/tests/test_request_routing.py b/tests/test_request_routing.py index dbc10c8..38b7e82 100644 --- a/tests/test_request_routing.py +++ b/tests/test_request_routing.py @@ -1,11 +1,14 @@ """Test HTTP request routing by the ``RemoteUserLoginHandler`` class.""" +from datetime import datetime from typing import Type from unittest import TestCase from unittest.mock import MagicMock, patch from jupyterhub.auth import Authenticator -from jupyterhub.objects import Server +from jupyterhub.objects import Hub +from jupyterhub.orm import User +from jupyterhub.utils import new_token, url_path_join from tornado import web from tornado.httputil import HTTPConnection, HTTPHeaders, HTTPServerRequest from tornado.web import Application @@ -14,6 +17,16 @@ from crc_jupyter_auth.remote_user_auth import AuthenticatorSettings, RemoteUserLoginHandler +def mock_user() -> User: + """Create a jupyterhub user object with mock/dummy data + + Returns: + A partially instantiated User instance + """ + + return User(id=1, name='mock_user', admin=False, created=datetime.now(), cookie_id=new_token()) + + class TestUtils: """Base class for general testing/setup utilities""" @@ -37,7 +50,7 @@ def create_http_request_handler( """ # Create a tornado application running a jupyterhub server - application = Application(hub=Server(), authenticator=authenticator_type()) + application = Application(hub=Hub(), authenticator=authenticator_type(), cookie_secret='secret') # HTTP connections are used by the application to write HTTP responses # The `set_close_callback` method is required to exist by JupyterHub @@ -51,7 +64,7 @@ def create_http_request_handler( class RoutingByUsername(TestUtils, TestCase): - """Test missing or invalid username information results in a HTTP 401 error""" + """Test missing or invalid username information results in an HTTP 401 error""" def test_missing_username_401(self) -> None: """Test for a 401 error when the username is missing from the HTTP header""" @@ -143,3 +156,19 @@ def test_incorrect_role_redirect(self, mock_redirect_call: MagicMock) -> None: request_handler.get() mock_redirect_call.assert_called_once_with(request_handler.authenticator.missing_role_redirect) + + +class SuccessfulLoginRouting(TestUtils, TestCase): + """Test the routing of users after a successful login""" + + @patch.object(RemoteUserLoginHandler, 'redirect', return_value=None) + @patch.object(RemoteUserLoginHandler, 'user_from_username', return_value=mock_user()) + def test_user_is_redirected(self, mock_user: User, mock_redirect_call: MagicMock) -> None: + """Test the user is redirected to the jupyterhub server""" + + request_data = {AuthenticatorSettings().username_header: 'username'} + request_handler = self.create_http_request_handler(request_data) + request_handler.get() + + expected_url = url_path_join(request_handler.hub.server.base_url, 'home') + mock_redirect_call.assert_called_once_with(expected_url)