Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion openedx/core/djangoapps/user_authn/config/waffle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Waffle flags and switches for user authn.
"""

from edx_toggles.toggles import WaffleSwitch
from edx_toggles.toggles import WaffleFlag, WaffleSwitch

_WAFFLE_NAMESPACE = 'user_authn'

Expand Down Expand Up @@ -31,3 +31,19 @@
ENABLE_PWNED_PASSWORD_API = WaffleSwitch(
f'{_WAFFLE_NAMESPACE}.enable_pwned_password_api', __name__
)

# .. toggle_name: user_authn.enable_enterprise_redirect_to_authn
# .. toggle_implementation: WaffleFlag
# .. toggle_default: False
# .. toggle_description: When enabled, allows Enterprise/B2B customers to be redirected to the AuthN MFE instead of
# the legacy Django login templates. This flag provides an incremental rollout mechanism for migrating Enterprise
# customers to the modern authentication experience. The flag has no effect on users with external authentication
# providers (SAML/TPA), who always remain on the legacy flow. B2C users are redirected to the MFE by default
# regardless of this flag.
# .. toggle_use_cases: opt_in
# .. toggle_creation_date: 2026-02-18
# .. toggle_warning: This flag only affects Enterprise customers without external auth providers (SAML/TPA).
# Enabling this flag for an Enterprise customer with complex SSO requirements may break authentication flows.
ENABLE_ENTERPRISE_REDIRECT_TO_AUTHN = WaffleFlag(
f'{_WAFFLE_NAMESPACE}.enable_enterprise_redirect_to_authn', __name__
)
26 changes: 19 additions & 7 deletions openedx/core/djangoapps/user_authn/views/login_form.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,41 @@
""" Login related views """


import json
import logging
import urllib

from django.conf import settings
from django.contrib import messages
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import gettext as _
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.decorators.http import require_http_methods
from django_ratelimit.decorators import ratelimit

from common.djangoapps import third_party_auth
from common.djangoapps.edxmako.shortcuts import render_to_response
from common.djangoapps.student.helpers import get_next_url_for_login_page
from common.djangoapps.third_party_auth import pipeline
from common.djangoapps.third_party_auth.decorators import xframe_allow_whitelisted
from common.djangoapps.util.password_policy_validators import DEFAULT_MAX_PASSWORD_LENGTH
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.user_api import accounts
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_authn.cookies import set_logged_in_cookies
from openedx.core.djangoapps.user_authn.toggles import (
is_require_third_party_auth_enabled,
should_redirect_to_authn_microfrontend,
)
from openedx.core.djangoapps.user_authn.config.waffle import ENABLE_ENTERPRISE_REDIRECT_TO_AUTHN
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
from openedx.features.enterprise_support.api import enterprise_customer_for_request, enterprise_enabled
from openedx.features.enterprise_support.utils import (
get_enterprise_slug_login_url,
handle_enterprise_cookies_for_logistration,
update_logistration_context_for_enterprise,
)

Check failure on line 38 in openedx/core/djangoapps/user_authn/views/login_form.py

View workflow job for this annotation

GitHub Actions / Quality Others (ubuntu-24.04, 3.12, 20)

ruff (I001)

openedx/core/djangoapps/user_authn/views/login_form.py:4:1: I001 Import block is un-sorted or un-formatted help: Organize imports

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -202,10 +200,24 @@

enterprise_customer = enterprise_customer_for_request(request)

# Check for external providers (SAML/TPA) which must NEVER redirect to MFE
has_external_provider = bool(tpa_hint_provider or saml_provider)

# Determine eligibility based on segment
if enterprise_customer:
# Enterprise/B2B: Requires the specific rollout waffle flag
is_segment_eligible = ENABLE_ENTERPRISE_REDIRECT_TO_AUTHN.is_enabled()
else:
# B2C: Eligible by default
is_segment_eligible = True

# Redirect to authn MFE if all conditions are met:
# 1. MFE is globally enabled (should_redirect_to_authn_microfrontend)
# 2. User segment is eligible (B2C by default, or Enterprise with flag enabled)
# 3. No external auth provider is present (SAML/TPA must use legacy flow)
if should_redirect_to_authn_microfrontend() and \
not enterprise_customer and \
not tpa_hint_provider and \
not saml_provider:
is_segment_eligible and \
not has_external_provider:

# This is to handle a case where a logged-in cookie is not present but the user is authenticated.
# Note: If we don't handle this learner is redirected to authn MFE and then back to dashboard
Expand Down Expand Up @@ -262,7 +274,7 @@
'is_account_recovery_feature_enabled': is_secondary_email_feature_enabled(),
'enterprise_slug_login_url': get_enterprise_slug_login_url(),
'is_enterprise_enable': enterprise_enabled(),
'is_require_third_party_auth_enabled': is_require_third_party_auth_enabled(),

Check failure on line 277 in openedx/core/djangoapps/user_authn/views/login_form.py

View workflow job for this annotation

GitHub Actions / Quality Others (ubuntu-24.04, 3.12, 20)

ruff (F821)

openedx/core/djangoapps/user_authn/views/login_form.py:277:52: F821 Undefined name `is_require_third_party_auth_enabled`
'enable_coppa_compliance': settings.ENABLE_COPPA_COMPLIANCE,
'edx_user_info_cookie_name': settings.EDXMKTG_USER_INFO_COOKIE_NAME,
},
Expand Down
Loading