def test_callback_requests_sso_profile_valid_non_staff_user( get_sso_user_profile, get_access_token, flags, caplog, ): """ Test that if SSO user has a matching SSO email user ID, but Data Hub user has `is_staff` or `is_active` flag not set, then the access is forbidden. """ AdviserFactory(sso_email_user_id='some-123@email', **flags) get_access_token.return_value = {'access_token': 'access-token'} get_sso_user_profile.return_value = {'email_user_id': 'some-123@email'} request = get_request_with_session('/oauth/callback/?state=original&code=code') request.session['oauth.state'] = 'original' response = callback(request) response.render() assert response.status_code == status.HTTP_403_FORBIDDEN assert 'Forbidden.' in str(response.content) assert not request.user.is_authenticated assert len(caplog.records) == 1 assert 'Django Admin OAuth2 authentication failed: User not found.' in caplog.text
def test_get_access_token(requests_mock): """Test that access token is being requested.""" token_data = {'access_token': 'example-token'} requests_mock.post( settings.ADMIN_OAUTH2_TOKEN_FETCH_PATH, status_code=status.HTTP_200_OK, json=token_data, ) request = get_request_with_session(reverse('admin:index')) access_token_data = get_access_token( '1234', request.build_absolute_uri(reverse('admin_oauth_callback')), ) oauth_params = { 'code': '1234', 'grant_type': 'authorization_code', 'client_id': settings.ADMIN_OAUTH2_CLIENT_ID, 'client_secret': settings.ADMIN_OAUTH2_CLIENT_SECRET, 'redirect_uri': request.build_absolute_uri(reverse('admin_oauth_callback')), } assert requests_mock.call_count == 1 expected_url = f'{settings.ADMIN_OAUTH2_TOKEN_FETCH_PATH}?{urlencode(oauth_params)}' assert requests_mock.request_history[-1].url == expected_url assert access_token_data == token_data
def test_callback_without_state(): """Test that a callback without provided state will restart login process.""" request = get_request_with_session('/oauth/callback') response = callback(request) assert response.status_code == status.HTTP_302_FOUND assert response.url == request.build_absolute_uri(reverse('admin:login'))
def test_login_view_validates_next_url(dangerous_redirect): """Tests that login view checks redirect URLs for safety.""" login_url = reverse('admin:login') request = get_request_with_session( f'{login_url}?next={dangerous_redirect}', ) response = login(request) assert response.status_code == status.HTTP_302_FOUND assert extract_next_url_from_redirect_url(response.url) is None
def test_login_view_redirects_with_next_url(): """Tests that login view redirects to Staff SSO with next URL.""" login_url = reverse('admin:login') request = get_request_with_session(f'{login_url}?next=/protected-area') response = login(request) assert response.status_code == status.HTTP_302_FOUND next_url = extract_next_url_from_redirect_url(response.url) assert next_url == '/protected-area'
def test_callback_without_state_includes_next_url(): """ Test that a callback without provided state will restart login process including next URL. """ request = get_request_with_session('/oauth/callback/?next=/protected-area') response = callback(request) assert response.status_code == status.HTTP_302_FOUND next_url = extract_next_url_from_url(response.url) assert next_url == '/protected-area'
def test_callback_without_access_code(): """Test that a callback without a code will return an error page.""" fake_state_id = token_urlsafe(settings.ADMIN_OAUTH2_TOKEN_BYTE_LENGTH) request = get_request_with_session(f'/oauth/callback/?state={fake_state_id}') request.session['oauth.state'] = fake_state_id response = callback(request) assert response.status_code == status.HTTP_403_FORBIDDEN response.render() response_content = str(response.content) assert 'Forbidden.' in response_content assert not request.user.is_authenticated
def test_logout(): """Test that logout view clears session data and redirects to SSO Logout URL.""" request = get_request_with_session(reverse('admin:logout')) fake_state_id = token_urlsafe(settings.ADMIN_OAUTH2_TOKEN_BYTE_LENGTH) request.session['oauth.state'] = fake_state_id response = logout(request) assert response.status_code == status.HTTP_302_FOUND expected_path = urljoin(settings.ADMIN_OAUTH2_BASE_URL, settings.ADMIN_OAUTH2_LOGOUT_PATH) assert response.url == expected_path assert 'oauth.state' not in request.session assert not request.user.is_authenticated
def test_callback_validates_next_url(get_sso_user_profile, get_access_token, dangerous_redirect): """Test that successful login redirects user to `next_url`.""" fake_state_id = token_urlsafe(settings.ADMIN_OAUTH2_TOKEN_BYTE_LENGTH) AdviserFactory(sso_email_user_id='some-123@email', is_staff=True, is_active=True) get_access_token.return_value = {'access_token': 'access-token', 'expires_in': 3600} get_sso_user_profile.return_value = {'email_user_id': 'some-123@email'} request = get_request_with_session( f'/oauth/callback/?next={dangerous_redirect}&state={fake_state_id}&code=code', ) request.session['oauth.state'] = fake_state_id response = callback(request) assert response.status_code == status.HTTP_302_FOUND assert response.url == reverse('admin:index')
def test_callback_requests_sso_profile_no_user(get_sso_user_profile, get_access_token): """Test that if SSO user is not found then no access is granted.""" get_access_token.return_value = {'access_token': 'access-token', 'expires_in': 3600} get_sso_user_profile.return_value = {'email_user_id': 'some-123@email'} fake_state_id = token_urlsafe(settings.ADMIN_OAUTH2_TOKEN_BYTE_LENGTH) request = get_request_with_session(f'/oauth/callback/?state={fake_state_id}&code=code') request.session['oauth.state'] = fake_state_id response = callback(request) assert response.status_code == status.HTTP_403_FORBIDDEN response.render() response_content = str(response.content) assert 'Forbidden.' in response_content assert not request.user.is_authenticated
def test_get_access_token_missing(requests_mock): """Test that AuthenticationFailed is raised on missing token.""" requests_mock.post( settings.ADMIN_OAUTH2_TOKEN_FETCH_PATH, status_code=status.HTTP_200_OK, json={}, ) request = get_request_with_session(reverse('admin:index')) with pytest.raises(AuthenticationFailed) as excinfo: get_access_token( '1234', request.build_absolute_uri(reverse('admin_oauth_callback')), ) assert excinfo.value.detail == 'No access token.'
def test_user_is_not_logged_out_when_oauth2_session_is_not_expired(): """ Tests that user is not logged out if OAuth2 session is not expired. """ adviser = AdviserFactory() admin_url = reverse('admin:index') request = get_request_with_session(admin_url) request.session['oauth.expires_on'] = int(FROZEN_TIME.timestamp()) + 1 django_login(request, adviser) assert request.user.is_authenticated oauth_session_middleware = OAuthSessionMiddleware(_get_response) oauth_session_middleware(request) assert request.user.is_authenticated
def test_user_is_logged_out_from_admin_when_oauth2_session_has_expired(): """Tests that user is logged out if OAuth2 session is expired.""" adviser = AdviserFactory() admin_url = reverse('admin:index') request = get_request_with_session(admin_url) request.session['oauth.expires_on'] = int(FROZEN_TIME.timestamp()) - 1 django_login(request, adviser) assert request.user.is_authenticated oauth_session_middleware = OAuthSessionMiddleware(_get_response) response = oauth_session_middleware(request) assert not request.user.is_authenticated assert response.status_code == status.HTTP_302_FOUND assert response.url == reverse_with_query_string('admin:login', {'next': request.path}) assert 'oauth.state' not in request.session
def test_login_view_redirects_to_sso_auth_url(_token_urlsafe): """Tests that login view redirects to Staff SSO Auth URL.""" _token_urlsafe.return_value = 'aZFsiJfbDLF9bwve8f2HTBeC1rCnhFUn4K6c_iq-wLo' request = get_request_with_session(reverse('admin:login')) response = login(request) oauth_url_params = { 'response_type': 'code', 'client_id': settings.ADMIN_OAUTH2_CLIENT_ID, 'redirect_uri': request.build_absolute_uri(reverse('admin_oauth_callback')), 'state': _token_urlsafe.return_value, 'idp': 'cirrus', } redirect_url = urljoin(settings.ADMIN_OAUTH2_BASE_URL, settings.ADMIN_OAUTH2_AUTH_PATH) expected_url = f'{redirect_url}?{urlencode(oauth_url_params)}' assert response.status_code == status.HTTP_302_FOUND assert response.url == expected_url assert request.session['oauth.state'] == _token_urlsafe.return_value
def test_callback_requests_valid_sso_profile(get_sso_user_profile, get_access_token): """ Test that if SSO user has a matching SSO email user id (and relevant flags), then the access is granted. """ fake_state_id = token_urlsafe(settings.ADMIN_OAUTH2_TOKEN_BYTE_LENGTH) adviser = AdviserFactory(sso_email_user_id='some-123@email', is_staff=True, is_active=True) get_access_token.return_value = {'access_token': 'access-token', 'expires_in': 3600} get_sso_user_profile.return_value = {'email_user_id': 'some-123@email'} request = get_request_with_session(f'/oauth/callback/?state={fake_state_id}&code=code') request.session['oauth.state'] = fake_state_id response = callback(request) assert response.status_code == status.HTTP_302_FOUND assert response.url == reverse('admin:index') assert request.user.is_authenticated assert request.user == adviser