|
8 | 8 | """ |
9 | 9 | import logging |
10 | 10 | import re |
| 11 | +from urllib.parse import urlparse |
11 | 12 |
|
12 | 13 | import six |
13 | 14 | from django.conf import settings |
14 | 15 | from django.contrib.auth import REDIRECT_FIELD_NAME |
15 | 16 | from django.contrib.auth.views import redirect_to_login |
| 17 | +from django.db import IntegrityError |
16 | 18 | from django.db.models.signals import post_save |
17 | 19 | from django.dispatch import receiver |
18 | 20 | from django.http import Http404, HttpResponseRedirect |
| 21 | +from django.urls import reverse |
19 | 22 | from django.utils.deprecation import MiddlewareMixin |
| 23 | +from requests.exceptions import HTTPError |
20 | 24 |
|
21 | 25 | from eox_core.edxapp_wrapper.configuration_helpers import get_configuration_helper |
| 26 | +from eox_core.edxapp_wrapper.third_party_auth import get_tpa_exception_middleware |
22 | 27 | from eox_core.models import Redirection |
23 | 28 | from eox_core.utils import cache, fasthash |
24 | 29 |
|
| 30 | +try: |
| 31 | + from social_core.exceptions import AuthUnreachableProvider, AuthAlreadyAssociated, AuthFailed |
| 32 | +except ImportError: |
| 33 | + AuthUnreachableProvider = Exception |
| 34 | + AuthAlreadyAssociated = Exception |
| 35 | + AuthFailed = Exception |
| 36 | + |
| 37 | +try: |
| 38 | + from eox_tenant.pipeline import EoxTenantAuthException |
| 39 | +except ImportError: |
| 40 | + |
| 41 | + class EoxTenantAuthException: |
| 42 | + """Dummy eox-tenant Exception.""" |
| 43 | + |
| 44 | + |
25 | 45 | configuration_helper = get_configuration_helper() # pylint: disable=invalid-name |
| 46 | +ExceptionMiddleware = get_tpa_exception_middleware() |
26 | 47 |
|
27 | 48 | LOG = logging.getLogger(__name__) |
28 | 49 |
|
@@ -229,3 +250,45 @@ def clear_cache(sender, instance, **kwargs): # pylint: disable=unused-argument |
229 | 250 | """ |
230 | 251 | cache_key = "redirect_cache." + fasthash(instance.domain) |
231 | 252 | cache.delete(cache_key) # pylint: disable=maybe-no-member |
| 253 | + |
| 254 | + |
| 255 | +class TPAExceptionMiddleware(ExceptionMiddleware): |
| 256 | + """Middleware to handle exceptions not catched by Social Django""" |
| 257 | + |
| 258 | + def process_exception(self, request, exception): |
| 259 | + """ |
| 260 | + Handle exceptions raised during the authentication process. |
| 261 | + """ |
| 262 | + referer_url = request.META.get('HTTP_REFERER', '') |
| 263 | + referer_url = urlparse(referer_url).path |
| 264 | + |
| 265 | + if referer_url != reverse('signin_user') and request.view_name not in ['auth', 'complete']: |
| 266 | + return super().process_exception(request, exception) |
| 267 | + |
| 268 | + if isinstance(exception, EoxTenantAuthException): |
| 269 | + new_exception = AuthFailed( |
| 270 | + exception.backend, |
| 271 | + str(exception), |
| 272 | + ) |
| 273 | + LOG.error("%s", exception) |
| 274 | + return super().process_exception(request, new_exception) |
| 275 | + |
| 276 | + if isinstance(exception, IntegrityError): |
| 277 | + backend = getattr(request, 'backend', None) |
| 278 | + new_exception = AuthAlreadyAssociated( |
| 279 | + backend, |
| 280 | + "The given email address is associated with another account", |
| 281 | + ) |
| 282 | + LOG.error("%s", exception) |
| 283 | + return super().process_exception(request, new_exception) |
| 284 | + |
| 285 | + if isinstance(exception, HTTPError): |
| 286 | + backend = getattr(request, 'backend', None) |
| 287 | + new_exception = AuthUnreachableProvider( |
| 288 | + backend, |
| 289 | + "Unable to connect with the external provider", |
| 290 | + ) |
| 291 | + LOG.error("%s", exception) |
| 292 | + return super().process_exception(request, new_exception) |
| 293 | + |
| 294 | + return super().process_exception(request, exception) |
0 commit comments