Skip to content

Commit

Permalink
feat(oauth): handle misconfigured session verifier
Browse files Browse the repository at this point in the history
the case when the session verifier has neither Eligibility API nor IDP config
is a system error / configuration error
  • Loading branch information
thekaveman committed Jul 22, 2024
1 parent ce32497 commit 06fdbb8
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 1 deletion.
19 changes: 18 additions & 1 deletion benefits/oauth/middleware.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import logging

from django.shortcuts import redirect
import sentry_sdk

from benefits.core import session
from benefits.core.middleware import VerifierSessionRequired, user_error

from . import analytics
from .redirects import ROUTE_SYSTEM_ERROR


logger = logging.getLogger(__name__)

Expand All @@ -16,8 +22,19 @@ def process_request(self, request):
# from the base middleware class, the session didn't have a verifier
return result

if session.verifier(request).uses_auth_verification:
verifier = session.verifier(request)

if verifier.uses_auth_verification:
# all good, the chosen verifier is configured correctly
return None
elif verifier.api_url is None and verifier.form_class is None:
# the chosen verifier doesn't have Eligibility API config OR auth provider config
# this is likely a misconfiguration on the backend, not a user error
message = f"Verifier with no API or IDP config: {verifier.name} (id={verifier.id})"
analytics.error(request, message=message, operation=request.path)
sentry_sdk.capture_exception(Exception(message))
return redirect(ROUTE_SYSTEM_ERROR)
else:
# the chosen verifier was for Eligibility API
logger.debug("Session not configured with eligibility verifier that uses auth verification")
return user_error(request)
35 changes: 35 additions & 0 deletions tests/pytest/oauth/test_middleware_authverifier_required.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
from django.urls import reverse
from django.utils.decorators import decorator_from_middleware

import pytest

from benefits.core.middleware import TEMPLATE_USER_ERROR
from benefits.oauth.middleware import VerifierUsesAuthVerificationSessionRequired
import benefits.oauth.middleware
from benefits.oauth.redirects import ROUTE_SYSTEM_ERROR


@pytest.fixture
def decorated_view(mocked_view):
return decorator_from_middleware(VerifierUsesAuthVerificationSessionRequired)(mocked_view)


@pytest.fixture
def mocked_analytics_module(mocked_analytics_module):
return mocked_analytics_module(benefits.oauth.middleware)


@pytest.fixture
def mocked_sentry_sdk_module(mocker):
return mocker.patch.object(benefits.oauth.middleware, "sentry_sdk")


@pytest.mark.django_db
def test_authverifier_required_no_verifier(app_request, mocked_view, decorated_view):
response = decorated_view(app_request)
Expand All @@ -30,6 +43,28 @@ def test_authverifier_required_no_authverifier(app_request, mocked_view, decorat
assert response.template_name == TEMPLATE_USER_ERROR


@pytest.mark.django_db
def test_authverifier_required_misconfigured_verifier(
app_request,
mocked_view,
decorated_view,
mocked_session_verifier_does_not_use_auth_verification,
mocked_analytics_module,
mocked_sentry_sdk_module,
):
# fake a misconfigured verifier
mocked_session_verifier_does_not_use_auth_verification.return_value.api_url = None
mocked_session_verifier_does_not_use_auth_verification.return_value.form_class = None

response = decorated_view(app_request)

mocked_view.assert_not_called()
mocked_analytics_module.error.assert_called_once()
mocked_sentry_sdk_module.capture_exception.assert_called_once()
assert response.status_code == 302
assert response.url == reverse(ROUTE_SYSTEM_ERROR)


@pytest.mark.django_db
@pytest.mark.usefixtures("mocked_session_verifier_oauth")
def test_authverifier_required_authverifier(app_request, mocked_view, decorated_view):
Expand Down

0 comments on commit 06fdbb8

Please sign in to comment.