Authn MFE: Toggle for microfrontend redirect.
VAN-308
This commit is contained in:
@@ -22,7 +22,7 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_
|
||||
from openedx.core.djangoapps.theming.helpers import get_current_site
|
||||
from openedx.core.djangoapps.user_api import accounts as accounts_settings # lint-amnesty, pylint: disable=unused-import
|
||||
from openedx.core.djangoapps.user_api.accounts.utils import is_secondary_email_feature_enabled # lint-amnesty, pylint: disable=unused-import
|
||||
from openedx.core.djangoapps.user_authn.utils import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_authn.toggles import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
|
||||
from common.djangoapps.student.message_types import AccountRecovery as AccountRecoveryMessage
|
||||
from common.djangoapps.student.models import CourseEnrollmentAllowed, email_exists_or_retired # lint-amnesty, pylint: disable=unused-import
|
||||
|
||||
@@ -8,15 +8,17 @@ from django.conf import settings
|
||||
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
from edx_toggles.toggles.testutils import override_waffle_flag
|
||||
from mock import patch
|
||||
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
from openedx.core.djangoapps.user_authn.toggles import REDIRECT_TO_AUTHN_MICROFRONTEND
|
||||
from common.djangoapps.student.models import Registration
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
|
||||
|
||||
FEATURES_WITH_LOGIN_MFE_ENABLED = settings.FEATURES.copy()
|
||||
FEATURES_WITH_LOGIN_MFE_ENABLED['ENABLE_AUTHN_MICROFRONTEND'] = True
|
||||
FEATURES_WITH_AUTHN_MFE_ENABLED = settings.FEATURES.copy()
|
||||
FEATURES_WITH_AUTHN_MFE_ENABLED['ENABLE_AUTHN_MICROFRONTEND'] = True
|
||||
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@@ -151,7 +153,8 @@ class TestActivateAccount(TestCase):
|
||||
self.assertRedirects(response, login_page_url)
|
||||
self.assertContains(response, 'Your account could not be activated')
|
||||
|
||||
@override_settings(FEATURES=FEATURES_WITH_LOGIN_MFE_ENABLED)
|
||||
@override_settings(FEATURES=FEATURES_WITH_AUTHN_MFE_ENABLED)
|
||||
@override_waffle_flag(REDIRECT_TO_AUTHN_MICROFRONTEND, active=True)
|
||||
def test_unauthenticated_user_redirects_to_mfe(self):
|
||||
"""
|
||||
Verify that if Authn MFE is enabled then authenticated user redirects to
|
||||
|
||||
@@ -50,7 +50,7 @@ from openedx.core.djangoapps.programs.models import ProgramsApiConfig
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
from openedx.core.djangoapps.theming import helpers as theming_helpers
|
||||
from openedx.core.djangoapps.user_api.preferences import api as preferences_api
|
||||
from openedx.core.djangoapps.user_authn.utils import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_authn.toggles import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from common.djangoapps.student.email_helpers import generate_activation_email_context
|
||||
from common.djangoapps.student.helpers import DISABLE_UNENROLL_CERT_STATES, cert_info
|
||||
|
||||
@@ -89,7 +89,7 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_
|
||||
from openedx.core.djangoapps.user_api import accounts
|
||||
from openedx.core.djangoapps.user_api.accounts.utils import is_multiple_sso_accounts_association_to_saml_user_enabled
|
||||
from openedx.core.djangoapps.user_authn import cookies as user_authn_cookies
|
||||
from openedx.core.djangoapps.user_authn.utils import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_authn.toggles import should_redirect_to_authn_microfrontend
|
||||
from common.djangoapps.third_party_auth.utils import (
|
||||
get_user_from_email,
|
||||
is_enterprise_customer_user,
|
||||
|
||||
@@ -11,7 +11,7 @@ from django.urls import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from six import text_type
|
||||
|
||||
from openedx.core.djangoapps.user_authn.utils import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_authn.toggles import should_redirect_to_authn_microfrontend
|
||||
%>
|
||||
|
||||
<%
|
||||
|
||||
@@ -5,6 +5,9 @@ Toggles for user_authn
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from edx_toggles.toggles import WaffleFlag
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
|
||||
# .. toggle_name: ENABLE_REQUIRE_THIRD_PARTY_AUTH
|
||||
# .. toggle_implementation: DjangoSetting
|
||||
# .. toggle_default: False
|
||||
@@ -21,3 +24,23 @@ from django.conf import settings
|
||||
def is_require_third_party_auth_enabled():
|
||||
# TODO: Replace function with SettingToggle when it is available.
|
||||
return getattr(settings, "ENABLE_REQUIRE_THIRD_PARTY_AUTH", False)
|
||||
|
||||
# .. toggle_name: user_authn.redirect_to_microfrontend
|
||||
# .. toggle_implementation: WaffleFlag
|
||||
# .. toggle_default: False
|
||||
# .. toggle_description: Supports staged rollout of a new micro-frontend-based implementation of the login and registration pages
|
||||
# .. toggle_use_cases: temporary, open_edx
|
||||
# .. toggle_creation_date: 2021-02-02
|
||||
# .. toggle_target_removal_date: None
|
||||
# .. toggle_warnings: Also set settings.AUTHN_MICROFRONTEND_URL and site's ENABLE_AUTHN_MICROFRONTEND
|
||||
# .. toggle_tickets: VAN-308
|
||||
REDIRECT_TO_AUTHN_MICROFRONTEND = WaffleFlag('user_authn.redirect_to_microfrontend', __name__)
|
||||
|
||||
|
||||
def should_redirect_to_authn_microfrontend():
|
||||
"""
|
||||
Checks if login/registration should be done via MFE.
|
||||
"""
|
||||
return configuration_helpers.get_value(
|
||||
'ENABLE_AUTHN_MICROFRONTEND', settings.FEATURES.get('ENABLE_AUTHN_MICROFRONTEND')
|
||||
) and REDIRECT_TO_AUTHN_MICROFRONTEND.is_enabled()
|
||||
|
||||
@@ -68,12 +68,3 @@ def is_registration_api_v1(request):
|
||||
:return: Bool
|
||||
"""
|
||||
return 'v1' in request.get_full_path() and 'register' not in request.get_full_path()
|
||||
|
||||
|
||||
def should_redirect_to_authn_microfrontend():
|
||||
"""
|
||||
Checks if login/registration should be done via MFE.
|
||||
"""
|
||||
return configuration_helpers.get_value(
|
||||
'ENABLE_AUTHN_MICROFRONTEND', settings.FEATURES.get('ENABLE_AUTHN_MICROFRONTEND')
|
||||
)
|
||||
|
||||
@@ -33,7 +33,7 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_
|
||||
from openedx.core.djangoapps.user_authn.views.login_form import get_login_session_form
|
||||
from openedx.core.djangoapps.user_authn.cookies import get_response_with_refreshed_jwt_cookies, set_logged_in_cookies
|
||||
from openedx.core.djangoapps.user_authn.exceptions import AuthFailedError
|
||||
from openedx.core.djangoapps.user_authn.utils import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_authn.toggles import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.util.user_messages import PageLevelMessages
|
||||
from openedx.core.djangoapps.user_authn.views.password_reset import send_password_reset_email_for_user
|
||||
from openedx.core.djangoapps.user_authn.toggles import is_require_third_party_auth_enabled
|
||||
@@ -125,7 +125,7 @@ def _generate_locked_out_error_message():
|
||||
"""
|
||||
|
||||
locked_out_period_in_sec = settings.MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS
|
||||
if not should_redirect_to_authn_microfrontend: # pylint: disable=no-else-raise
|
||||
if not should_redirect_to_authn_microfrontend(): # pylint: disable=no-else-raise
|
||||
raise AuthFailedError(Text(_('To protect your account, it’s been temporarily '
|
||||
'locked. Try again in {locked_out_period} minutes.'
|
||||
'{li_start}To be on the safe side, you can reset your '
|
||||
@@ -238,7 +238,7 @@ def _handle_failed_authentication(user, authenticated_user):
|
||||
if not LoginFailures.is_user_locked_out(user):
|
||||
max_failures_allowed = settings.MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED
|
||||
remaining_attempts = max_failures_allowed - failure_count
|
||||
if not should_redirect_to_authn_microfrontend: # pylint: disable=no-else-raise
|
||||
if not should_redirect_to_authn_microfrontend(): # pylint: disable=no-else-raise
|
||||
raise AuthFailedError(Text(_('Email or password is incorrect.'
|
||||
'{li_start}You have {remaining_attempts} more sign-in '
|
||||
'attempts before your account is temporarily locked.{li_end}'
|
||||
|
||||
@@ -24,7 +24,7 @@ from openedx.core.djangoapps.user_api.accounts.utils import (
|
||||
)
|
||||
from openedx.core.djangoapps.user_api.helpers import FormDescription
|
||||
from openedx.core.djangoapps.user_authn.cookies import are_logged_in_cookies_set
|
||||
from openedx.core.djangoapps.user_authn.utils import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_authn.toggles import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_authn.views.password_reset import get_password_reset_form
|
||||
from openedx.core.djangoapps.user_authn.views.registration_form import RegistrationFormFactory
|
||||
from openedx.core.djangoapps.user_authn.views.utils import third_party_auth_context
|
||||
|
||||
@@ -35,7 +35,7 @@ from openedx.core.djangoapps.oauth_dispatch.api import destroy_oauth_tokens
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
from openedx.core.djangoapps.theming.helpers import get_current_request, get_current_site
|
||||
from openedx.core.djangoapps.user_api import accounts, errors, helpers
|
||||
from openedx.core.djangoapps.user_authn.utils import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_authn.toggles import should_redirect_to_authn_microfrontend
|
||||
from openedx.core.djangoapps.user_api.accounts.utils import is_secondary_email_feature_enabled
|
||||
from openedx.core.djangoapps.user_api.helpers import FormDescription
|
||||
from openedx.core.djangoapps.user_api.models import UserRetirementRequest
|
||||
|
||||
@@ -18,7 +18,7 @@ from django.http import HttpResponse
|
||||
from django.test.client import Client
|
||||
from django.test.utils import override_settings
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from edx_toggles.toggles.testutils import override_waffle_switch
|
||||
from edx_toggles.toggles.testutils import override_waffle_flag, override_waffle_switch
|
||||
from mock import Mock, patch
|
||||
from common.djangoapps.student.tests.factories import RegistrationFactory, UserFactory, UserProfileFactory
|
||||
|
||||
@@ -29,6 +29,7 @@ from openedx.core.djangoapps.password_policy.compliance import (
|
||||
from openedx.core.djangoapps.user_api.accounts import EMAIL_MIN_LENGTH, EMAIL_MAX_LENGTH
|
||||
from openedx.core.djangoapps.user_authn.cookies import jwt_cookies
|
||||
from openedx.core.djangoapps.user_authn.tests.utils import setup_login_oauth_client
|
||||
from openedx.core.djangoapps.user_authn.toggles import REDIRECT_TO_AUTHN_MICROFRONTEND
|
||||
from openedx.core.djangoapps.user_authn.views.login import (
|
||||
ENABLE_LOGIN_USING_THIRDPARTY_AUTH_ONLY,
|
||||
AllowedAuthUser,
|
||||
@@ -79,8 +80,8 @@ class LoginTest(SiteMixin, CacheIsolationTestCase):
|
||||
self._assert_response(response, success=True)
|
||||
self._assert_audit_log(mock_audit_log, 'info', [u'Login success', self.user_email])
|
||||
|
||||
FEATURES_WITH_LOGIN_MFE_ENABLED = settings.FEATURES.copy()
|
||||
FEATURES_WITH_LOGIN_MFE_ENABLED['ENABLE_AUTHN_MICROFRONTEND'] = True
|
||||
FEATURES_WITH_AUTHN_MFE_ENABLED = settings.FEATURES.copy()
|
||||
FEATURES_WITH_AUTHN_MFE_ENABLED['ENABLE_AUTHN_MICROFRONTEND'] = True
|
||||
|
||||
@patch.dict(settings.FEATURES, {
|
||||
"ENABLE_THIRD_PARTY_AUTH": True
|
||||
@@ -157,7 +158,8 @@ class LoginTest(SiteMixin, CacheIsolationTestCase):
|
||||
)
|
||||
@ddt.unpack
|
||||
@override_settings(LOGIN_REDIRECT_WHITELIST=['openedx.service'])
|
||||
@override_settings(FEATURES=FEATURES_WITH_LOGIN_MFE_ENABLED)
|
||||
@override_settings(FEATURES=FEATURES_WITH_AUTHN_MFE_ENABLED)
|
||||
@override_waffle_flag(REDIRECT_TO_AUTHN_MICROFRONTEND, active=True)
|
||||
@skip_unless_lms
|
||||
def test_login_success_with_redirect(self, next_url, course_id, expected_redirect):
|
||||
post_params = {}
|
||||
|
||||
@@ -19,6 +19,7 @@ from django.test.client import RequestFactory
|
||||
from django.test.utils import override_settings
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from edx_toggles.toggles.testutils import override_waffle_flag
|
||||
from freezegun import freeze_time
|
||||
from pytz import UTC
|
||||
|
||||
@@ -26,6 +27,7 @@ from common.djangoapps.course_modes.models import CourseMode
|
||||
from lms.djangoapps.branding.api import get_privacy_url
|
||||
from openedx.core.djangoapps.site_configuration.tests.mixins import SiteMixin
|
||||
from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme_context
|
||||
from openedx.core.djangoapps.user_authn.toggles import REDIRECT_TO_AUTHN_MICROFRONTEND
|
||||
from openedx.core.djangoapps.user_authn.views.login_form import login_and_registration_form
|
||||
from openedx.core.djangolib.js_utils import dump_js_escaped_json
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
@@ -64,8 +66,8 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
)
|
||||
self.hidden_disabled_provider = self.configure_azure_ad_provider()
|
||||
|
||||
FEATURES_WITH_LOGIN_MFE_ENABLED = settings.FEATURES.copy()
|
||||
FEATURES_WITH_LOGIN_MFE_ENABLED['ENABLE_AUTHN_MICROFRONTEND'] = True
|
||||
FEATURES_WITH_AUTHN_MFE_ENABLED = settings.FEATURES.copy()
|
||||
FEATURES_WITH_AUTHN_MFE_ENABLED['ENABLE_AUTHN_MICROFRONTEND'] = True
|
||||
|
||||
@ddt.data(
|
||||
("signin_user", "/login"),
|
||||
@@ -73,16 +75,21 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
("password_assistance", "/reset"),
|
||||
)
|
||||
@ddt.unpack
|
||||
@override_settings(FEATURES=FEATURES_WITH_LOGIN_MFE_ENABLED)
|
||||
@override_settings(FEATURES=FEATURES_WITH_AUTHN_MFE_ENABLED)
|
||||
def test_logistration_mfe_redirects(self, url_name, path):
|
||||
"""
|
||||
Test that if Logistration MFE is enabled, then we redirect to
|
||||
the correct URL.
|
||||
"""
|
||||
response = self.client.get(reverse(url_name))
|
||||
|
||||
self.assertEqual(response.url, settings.AUTHN_MICROFRONTEND_URL + path)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
# Test with setting enabled and waffle flag in-active, does not redirect
|
||||
response = self.client.get(reverse(url_name))
|
||||
self.assertContains(response, 'Sign in or Register')
|
||||
|
||||
# Test with setting enabled and waffle flag active, redirects to microfrontend
|
||||
with override_waffle_flag(REDIRECT_TO_AUTHN_MICROFRONTEND, active=True):
|
||||
response = self.client.get(reverse(url_name))
|
||||
self.assertRedirects(response, settings.AUTHN_MICROFRONTEND_URL + path, fetch_redirect_response=False)
|
||||
|
||||
@ddt.data(
|
||||
(
|
||||
@@ -97,7 +104,8 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
)
|
||||
)
|
||||
@ddt.unpack
|
||||
@override_settings(FEATURES=FEATURES_WITH_LOGIN_MFE_ENABLED)
|
||||
@override_settings(FEATURES=FEATURES_WITH_AUTHN_MFE_ENABLED)
|
||||
@override_waffle_flag(REDIRECT_TO_AUTHN_MICROFRONTEND, active=True)
|
||||
def test_logistration_redirect_params(self, url_name, path, query_params):
|
||||
"""
|
||||
Test that if request is redirected to logistration MFE,
|
||||
@@ -106,7 +114,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
|
||||
expected_url = settings.AUTHN_MICROFRONTEND_URL + path + '?' + urlencode(query_params)
|
||||
response = self.client.get(reverse(url_name), query_params)
|
||||
|
||||
self.assertRedirects(response, expected_url, target_status_code=302)
|
||||
self.assertRedirects(response, expected_url, fetch_redirect_response=False)
|
||||
|
||||
@ddt.data(
|
||||
("signin_user", "login"),
|
||||
|
||||
@@ -22,6 +22,7 @@ from django.test.client import RequestFactory
|
||||
from django.test.utils import override_settings
|
||||
from django.urls import reverse
|
||||
from django.utils.http import int_to_base36
|
||||
from edx_toggles.toggles.testutils import override_waffle_flag
|
||||
from freezegun import freeze_time
|
||||
from mock import Mock, patch
|
||||
from oauth2_provider import models as dot_models
|
||||
@@ -36,6 +37,7 @@ from openedx.core.djangoapps.user_api.accounts import EMAIL_MAX_LENGTH, EMAIL_MI
|
||||
from openedx.core.djangoapps.user_authn.views.password_reset import (
|
||||
SETTING_CHANGE_INITIATED, password_reset, LogistrationPasswordResetView,
|
||||
PasswordResetConfirmWrapper)
|
||||
from openedx.core.djangoapps.user_authn.toggles import REDIRECT_TO_AUTHN_MICROFRONTEND
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
|
||||
from common.djangoapps.student.tests.factories import TEST_PASSWORD, UserFactory
|
||||
from common.djangoapps.student.tests.test_configuration_overrides import fake_get_value
|
||||
@@ -331,6 +333,7 @@ class ResetPasswordTests(EventTestMixin, CacheIsolationTestCase):
|
||||
)
|
||||
|
||||
@override_settings(FEATURES=ENABLE_AUTHN_MICROFRONTEND)
|
||||
@override_waffle_flag(REDIRECT_TO_AUTHN_MICROFRONTEND, active=True)
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', "Test only valid in LMS")
|
||||
@ddt.data(('Crazy Awesome Site', 'Crazy Awesome Site'), ('edX', 'edX'))
|
||||
@ddt.unpack
|
||||
|
||||
Reference in New Issue
Block a user