Skip to content

Commit

Permalink
feat(oauth): handle load_server_metadata errors
Browse files Browse the repository at this point in the history
  • Loading branch information
thekaveman committed Jul 17, 2024
1 parent 918aabf commit 6550a10
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 9 deletions.
11 changes: 10 additions & 1 deletion benefits/oauth/redirects.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from django.shortcuts import redirect
from django.utils.http import urlencode

import sentry_sdk

ROUTE_SYSTEM_ERROR = "oauth:system-error"


def deauthorize_redirect(oauth_client, token, redirect_uri):
"""Helper implements OIDC signout via the `end_session_endpoint`."""
Expand All @@ -9,7 +13,12 @@ def deauthorize_redirect(oauth_client, token, redirect_uri):
# See https://github.com/lepture/authlib/issues/331#issuecomment-827295954 for more
#
# The implementation here was adapted from the same ticket: https://github.com/lepture/authlib/issues/331#issue-838728145
metadata = oauth_client.load_server_metadata()
try:
metadata = oauth_client.load_server_metadata()
except Exception as ex:
sentry_sdk.capture_exception(ex)
return redirect(ROUTE_SYSTEM_ERROR)

end_session_endpoint = metadata.get("end_session_endpoint")

params = dict(id_token_hint=token, post_logout_redirect_uri=redirect_uri)
Expand Down
11 changes: 5 additions & 6 deletions benefits/oauth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
ROUTE_CONFIRM = "eligibility:confirm"
ROUTE_UNVERIFIED = "eligibility:unverified"
ROUTE_POST_LOGOUT = "oauth:post_logout"
ROUTE_SYSTEM_ERROR = "oauth:system-error"

TEMPLATE_SYSTEM_ERROR = "oauth/system_error.html"

Expand All @@ -44,7 +43,7 @@ def _oauth_client_or_error_redirect(auth_provider):

if exception:
sentry_sdk.capture_exception(exception)
return redirect(ROUTE_SYSTEM_ERROR)
return redirect(redirects.ROUTE_SYSTEM_ERROR)

return oauth_client

Expand Down Expand Up @@ -74,11 +73,11 @@ def login(request):
result = oauth_client.authorize_redirect(request, redirect_uri)
except Exception as ex:
sentry_sdk.capture_exception(ex)
result = redirect(ROUTE_SYSTEM_ERROR)
result = redirect(redirects.ROUTE_SYSTEM_ERROR)

if result.status_code >= 400:
sentry_sdk.capture_message(f"authorize_redirect error response [{result.status_code}]: {result.content.decode()}")
result = redirect(ROUTE_SYSTEM_ERROR)
result = redirect(redirects.ROUTE_SYSTEM_ERROR)

return result

Expand All @@ -104,12 +103,12 @@ def authorize(request):
token = oauth_client.authorize_access_token(request)
except Exception as ex:
sentry_sdk.capture_exception(ex)
return redirect(ROUTE_SYSTEM_ERROR)
return redirect(redirects.ROUTE_SYSTEM_ERROR)

if token is None:
logger.warning("Could not authorize OAuth access token")
sentry_sdk.capture_message("oauth_client.authorize_access_token returned None")
return redirect(ROUTE_SYSTEM_ERROR)
return redirect(redirects.ROUTE_SYSTEM_ERROR)

logger.debug("OAuth access token authorized")

Expand Down
23 changes: 22 additions & 1 deletion tests/pytest/oauth/test_redirects.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
from benefits.oauth.redirects import deauthorize_redirect, generate_redirect_uri
from django.urls import reverse


from benefits.oauth.redirects import ROUTE_SYSTEM_ERROR, deauthorize_redirect, generate_redirect_uri
import benefits.oauth.redirects

import pytest


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


def test_deauthorize_redirect(mocked_oauth_client):
Expand All @@ -14,6 +25,16 @@ def test_deauthorize_redirect(mocked_oauth_client):
)


def test_deauthorize_redirect_load_server_metadata_error(mocked_oauth_client, mocked_sentry_sdk_module):
mocked_oauth_client.load_server_metadata.side_effect = Exception("Side effect")

result = deauthorize_redirect(mocked_oauth_client, "token", "https://localhost/redirect_uri")

assert result.status_code == 302
assert result.url == reverse(ROUTE_SYSTEM_ERROR)
mocked_sentry_sdk_module.capture_exception.assert_called_once()


def test_generate_redirect_uri_default(rf):
request = rf.get("/oauth/login")
path = "/test"
Expand Down
2 changes: 1 addition & 1 deletion tests/pytest/oauth/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

from benefits.eligibility.views import ROUTE_START

from benefits.oauth.redirects import ROUTE_SYSTEM_ERROR
from benefits.oauth.views import (
ROUTE_CONFIRM,
ROUTE_SYSTEM_ERROR,
ROUTE_UNVERIFIED,
TEMPLATE_SYSTEM_ERROR,
_oauth_client_or_error_redirect,
Expand Down

0 comments on commit 6550a10

Please sign in to comment.