Skip to content

Commit

Permalink
feat(TPA): Add middleware to handle TPA exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
MoisesGSalas committed Aug 18, 2021
1 parent 8e8c8a6 commit 6eb9427
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Change Log
.. There should always be an "Unreleased" section for changes pending release.
Unreleased
----------
* Add new middleware to catch unhandled exceptions during the third
party authentication.

[4.15.1] - 2021-08-13
---------------------
Expand Down
10 changes: 10 additions & 0 deletions eox_core/edxapp_wrapper/backends/third_party_auth_j_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Backend for the third party authentication exception middleware."""


def get_tpa_exception_middleware():
"""Get the ExceptionMiddleware class."""
try:
from third_party_auth.middleware import ExceptionMiddleware # pylint: disable=import-outside-toplevel
except ImportError:
from django.utils.deprecation import MiddlewareMixin as ExceptionMiddleware # pylint: disable=import-outside-toplevel
return ExceptionMiddleware
14 changes: 14 additions & 0 deletions eox_core/edxapp_wrapper/third_party_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""
Third Party Auth Exception Middleware definitions.
"""

from importlib import import_module

from django.conf import settings


def get_tpa_exception_middleware():
"""Get the ExceptionMiddleware class."""
backend_function = settings.EOX_CORE_THIRD_PARTY_AUTH_BACKEND
backend = import_module(backend_function)
return backend.get_tpa_exception_middleware()
63 changes: 63 additions & 0 deletions eox_core/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,42 @@
"""
import logging
import re
from urllib.parse import urlparse

import six
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.views import redirect_to_login
from django.db import IntegrityError
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.http import Http404, HttpResponseRedirect
from django.urls import reverse
from django.utils.deprecation import MiddlewareMixin
from requests.exceptions import HTTPError

from eox_core.edxapp_wrapper.configuration_helpers import get_configuration_helper
from eox_core.edxapp_wrapper.third_party_auth import get_tpa_exception_middleware
from eox_core.models import Redirection
from eox_core.utils import cache, fasthash

try:
from social_core.exceptions import AuthUnreachableProvider, AuthAlreadyAssociated, AuthFailed
except ImportError:
AuthUnreachableProvider = Exception
AuthAlreadyAssociated = Exception
AuthFailed = Exception

try:
from eox_tenant.pipeline import EoxTenantAuthException
except ImportError:

class EoxTenantAuthException:
"""Dummy eox-tenant Exception."""


configuration_helper = get_configuration_helper() # pylint: disable=invalid-name
ExceptionMiddleware = get_tpa_exception_middleware()

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -229,3 +250,45 @@ def clear_cache(sender, instance, **kwargs): # pylint: disable=unused-argument
"""
cache_key = "redirect_cache." + fasthash(instance.domain)
cache.delete(cache_key) # pylint: disable=maybe-no-member


class TPAExceptionMiddleware(ExceptionMiddleware):
"""Middleware to handle exceptions not catched by Social Django"""

def process_exception(self, request, exception):
"""
Handle exceptions raised during the authentication process.
"""
referer_url = request.META.get('HTTP_REFERER', '')
referer_url = urlparse(referer_url).path

if referer_url != reverse('signin_user') and request.view_name not in ['auth', 'complete']:
return super().process_exception(request, exception)

if isinstance(exception, EoxTenantAuthException):
new_exception = AuthFailed(
exception.backend,
str(exception),
)
LOG.error("%s", exception)
return super().process_exception(request, new_exception)

if isinstance(exception, IntegrityError):
backend = getattr(request, 'backend', None)
new_exception = AuthAlreadyAssociated(
backend,
"The given email address is associated with another account",
)
LOG.error("%s", exception)
return super().process_exception(request, new_exception)

if isinstance(exception, HTTPError):
backend = getattr(request, 'backend', None)
new_exception = AuthUnreachableProvider(
backend,
"Unable to connect with the external provider",
)
LOG.error("%s", exception)
return super().process_exception(request, new_exception)

return super().process_exception(request, exception)
1 change: 1 addition & 0 deletions eox_core/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def plugin_settings(settings):
settings.EOX_CORE_USER_UPDATE_SAFE_FIELDS = ["is_active", "password", "fullname", "mailing_address", "year_of_birth", "gender", "level_of_education", "city", "country", "goals", "bio", "phone_number"]
settings.EOX_CORE_BEARER_AUTHENTICATION = 'eox_core.edxapp_wrapper.backends.bearer_authentication_j_v1'
settings.EOX_CORE_ASYNC_TASKS = []
settings.EOX_CORE_THIRD_PARTY_AUTH_BACKEND = 'eox_core.edxapp_wrapper.backends.third_party_auth_j_v1'

if settings.EOX_CORE_USER_ENABLE_MULTI_TENANCY:
settings.EOX_CORE_USER_ORIGIN_SITE_SOURCES = [
Expand Down
8 changes: 6 additions & 2 deletions eox_core/settings/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ def plugin_settings(settings): # pylint: disable=function-redefined
'EOX_CORE_COURSE_MANAGEMENT_REQUEST_TIMEOUT',
settings.EOX_CORE_COURSE_MANAGEMENT_REQUEST_TIMEOUT
)

settings.EOX_CORE_THIRD_PARTY_AUTH_BACKEND = getattr(settings, 'ENV_TOKENS', {}).get(
'EOX_CORE_THIRD_PARTY_AUTH_BACKEND',
settings.EOX_CORE_THIRD_PARTY_AUTH_BACKEND
)
settings.EOX_CORE_USER_ENABLE_MULTI_TENANCY = getattr(settings, 'ENV_TOKENS', {}).get(
'EOX_CORE_USER_ENABLE_MULTI_TENANCY',
settings.EOX_CORE_USER_ENABLE_MULTI_TENANCY
Expand All @@ -119,7 +122,8 @@ def plugin_settings(settings): # pylint: disable=function-redefined
if settings.EOX_CORE_APPEND_LMS_MIDDLEWARE_CLASSES:
settings.MIDDLEWARE += [
'eox_core.middleware.PathRedirectionMiddleware',
'eox_core.middleware.RedirectionsMiddleware'
'eox_core.middleware.RedirectionsMiddleware',
'eox_core.middleware.TPAExceptionMiddleware'
]

# Sentry Integration
Expand Down
1 change: 1 addition & 0 deletions eox_core/settings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def plugin_settings(settings): # pylint: disable=function-redefined
settings.EOX_CORE_ENABLE_UPDATE_USERS = True
settings.EOX_CORE_USER_UPDATE_SAFE_FIELDS = ["is_active", "password", "fullname"]
settings.EOX_CORE_BEARER_AUTHENTICATION = 'eox_core.edxapp_wrapper.backends.bearer_authentication_j_v1_test'
settings.EOX_CORE_THIRD_PARTY_AUTH_BACKEND = 'eox_core.edxapp_wrapper.backends.third_party_auth_j_v1'


SETTINGS = SettingsClass()
Expand Down

0 comments on commit 6eb9427

Please sign in to comment.