diff --git a/common/djangoapps/third_party_auth/middleware.py b/common/djangoapps/third_party_auth/middleware.py index 81e4d3de786e4edc83cc2bca99e75a1bf5fc3afc..19993ad64dda9024d941d8e22d33449fded2748a 100644 --- a/common/djangoapps/third_party_auth/middleware.py +++ b/common/djangoapps/third_party_auth/middleware.py @@ -1,7 +1,16 @@ """Middleware classes for third_party_auth.""" +import urlparse + +from django.contrib import messages +from django.shortcuts import redirect +from django.urls import reverse +from django.utils.translation import ugettext as _ +from requests import HTTPError from social_django.middleware import SocialAuthExceptionMiddleware +from student.helpers import get_next_url_for_login_page + from . import pipeline @@ -23,3 +32,19 @@ class ExceptionMiddleware(SocialAuthExceptionMiddleware): redirect_uri = pipeline.AUTH_DISPATCH_URLS[auth_entry] return redirect_uri + + def process_exception(self, request, exception): + """Handles specific exception raised by Python Social Auth eg HTTPError.""" + + referer_url = request.META.get('HTTP_REFERER', '') + if (referer_url and isinstance(exception, HTTPError) and + exception.response.status_code == 502): + referer_url = urlparse.urlparse(referer_url).path + if referer_url == reverse('signin_user'): + messages.error(request, _('Unable to connect with the external provider, please try again'), + extra_tags='social-auth') + + redirect_url = get_next_url_for_login_page(request) + return redirect('/login?next=' + redirect_url) + + return super(ExceptionMiddleware, self).process_exception(request, exception) diff --git a/common/djangoapps/third_party_auth/tests/test_middleware.py b/common/djangoapps/third_party_auth/tests/test_middleware.py new file mode 100644 index 0000000000000000000000000000000000000000..88757b264af68572729be78f21351c7bef1854ad --- /dev/null +++ b/common/djangoapps/third_party_auth/tests/test_middleware.py @@ -0,0 +1,42 @@ +""" +Tests for third party auth middleware +""" +import mock +from django.contrib.messages.middleware import MessageMiddleware +from django.http import HttpResponse +from django.test.client import RequestFactory +from requests.exceptions import HTTPError + +from openedx.core.djangolib.testing.utils import skip_unless_lms +from third_party_auth.middleware import ExceptionMiddleware +from third_party_auth.tests.testutil import TestCase +from student.helpers import get_next_url_for_login_page + + +class ThirdPartyAuthMiddlewareTestCase(TestCase): + """Tests that ExceptionMiddleware is correctly redirected""" + + @skip_unless_lms + @mock.patch('django.conf.settings.MESSAGE_STORAGE', 'django.contrib.messages.storage.cookie.CookieStorage') + def test_http_exception_redirection(self): + """ + Test ExceptionMiddleware is correctly redirected to login page + when PSA raises HttpError exception. + """ + + request = RequestFactory().get("dummy_url") + next_url = get_next_url_for_login_page(request) + login_url = '/login?next=' + next_url + request.META['HTTP_REFERER'] = 'http://example.com:8000/login' + exception = HTTPError() + exception.response = HttpResponse(status=502) + + # Add error message for error in auth pipeline + MessageMiddleware().process_request(request) + response = ExceptionMiddleware().process_exception( + request, exception + ) + target_url = response.url + + self.assertEqual(response.status_code, 302) + self.assertTrue(target_url.endswith(login_url))