33"""
44
55import copy
6+ import logging
67import re
78from importlib import import_module
89
1819from eventtracking import tracker
1920
2021from common .djangoapps import third_party_auth
22+ from common .djangoapps .third_party_auth .models import SAMLProviderConfig
2123from common .djangoapps .edxmako .shortcuts import marketing_link
2224from common .djangoapps .student .models import CourseEnrollmentAllowed , UserProfile , email_exists_or_retired
2325from common .djangoapps .util .password_policy_validators import (
3638from openedx .features .enterprise_support .api import enterprise_customer_for_request
3739
3840
41+ log = logging .getLogger (__name__ )
42+
43+
3944class TrueCheckbox (widgets .CheckboxInput ):
4045 """
4146 A checkbox widget that only accepts "true" (case-insensitive) as true.
@@ -410,6 +415,56 @@ def __init__(self):
410415 field_order .extend (sorted (difference ))
411416
412417 self .field_order = field_order
418+ self .request = None # Will be set by get_registration_form
419+
420+ def _get_saml_provider_config (self ):
421+ """
422+ Get the SAML provider config for the current request's running pipeline.
423+
424+ Returns:
425+ SAMLProviderConfig or None: The SAML provider config if found, None otherwise
426+ """
427+ if not self .request or not third_party_auth .is_enabled ():
428+ return None
429+
430+ running_pipeline = third_party_auth .pipeline .get (self .request )
431+ if not running_pipeline :
432+ return None
433+
434+ try :
435+ # idp_name can be in kwargs directly or in kwargs['details']
436+ saml_provider_name = running_pipeline .get ('kwargs' , {}).get ('idp_name' )
437+ if not saml_provider_name :
438+ saml_provider_name = (
439+ running_pipeline .get ('kwargs' , {})
440+ .get ('details' , {})
441+ .get ('idp_name' )
442+ )
443+
444+ if not saml_provider_name :
445+ return None
446+
447+ try :
448+ # Try to find the SAML provider config
449+ # First try with current_set(), then fall back to direct query
450+ try :
451+ return SAMLProviderConfig .objects .current_set ().get (
452+ slug = saml_provider_name
453+ )
454+ except SAMLProviderConfig .DoesNotExist :
455+ # Fallback to direct query without current_set()
456+ return SAMLProviderConfig .objects .get (
457+ slug = saml_provider_name
458+ )
459+ except SAMLProviderConfig .DoesNotExist :
460+ log .debug (
461+ "SAML provider config not found for idp_name: %s" ,
462+ saml_provider_name
463+ )
464+ return None
465+ except Exception as exc : # pylint: disable=broad-except
466+ log .debug ("Error getting SAML provider config: %s" , str (exc ))
467+ return None
413468
414469 def get_registration_form (self , request ):
415470 """Return a description of the registration form.
@@ -426,6 +481,7 @@ def get_registration_form(self, request):
426481 Returns:
427482 HttpResponse
428483 """
484+ self .request = request
429485 form_desc = FormDescription ("post" , self ._get_registration_submit_url (request ))
430486 self ._apply_third_party_auth_overrides (request , form_desc )
431487
@@ -693,6 +749,11 @@ def _add_year_of_birth_field(self, form_desc, required=True):
693749
694750 def _add_marketing_emails_opt_in_field (self , form_desc , required = False ):
695751 """Add a marketing email checkbox to form description.
752+
753+ If a SAML provider config has skip_registration_optional_checkboxes=True,
754+ the field will default to False (opt-out) and not be required, overriding
755+ the global settings.
756+
696757 Arguments:
697758 form_desc: A form description
698759 Keyword Arguments:
@@ -703,13 +764,29 @@ def _add_marketing_emails_opt_in_field(self, form_desc, required=False):
703764 platform_name = configuration_helpers .get_value ('PLATFORM_NAME' , settings .PLATFORM_NAME ),
704765 )
705766
767+ # Default: checkbox is checked, field requirement follows the passed parameter
768+ default_value = True
769+ field_required = required
770+
771+ # Check if SAML provider wants to skip optional checkboxes
772+ # This overrides both global settings and provider field overrides
773+ saml_config = self ._get_saml_provider_config ()
774+ if saml_config and saml_config .skip_registration_optional_checkboxes :
775+ log .info (
776+ "SAML provider %s has skip_registration_optional_checkboxes=True, "
777+ "setting default to False and required to False" ,
778+ saml_config .slug
779+ )
780+ default_value = False # User opts out by default when field is skipped
781+ field_required = False # Make field optional
782+
706783 form_desc .add_field (
707784 'marketing_emails_opt_in' ,
708785 label = opt_in_label ,
709786 field_type = "checkbox" ,
710787 exposed = True ,
711- default = True , # the checkbox will automatically be checked; meaning user has opted in
712- required = required ,
788+ default = default_value ,
789+ required = field_required ,
713790 )
714791
715792 def _add_field_with_configurable_select_options (self , field_name , field_label , form_desc , required = False ):
@@ -1150,22 +1227,47 @@ def _apply_third_party_auth_overrides(self, request, form_desc):
11501227
11511228 for field_name in self .DEFAULT_FIELDS + self .EXTRA_FIELDS :
11521229 if field_name in field_overrides :
1153- form_desc .override_field_properties (
1154- field_name , default = field_overrides [field_name ]
1155- )
1156-
1157- if (
1158- field_name not in ['terms_of_service' , 'honor_code' ] and
1159- field_overrides [field_name ] and
1160- hide_registration_fields_except_tos
1161- ):
1230+ # Special handling for marketing_emails_opt_in:
1231+ # If SAML provider config has skip_registration_optional_checkboxes=True,
1232+ # don't let the provider's get_register_form_data override the default
1233+ skip_override = False
1234+ if field_name == 'marketing_emails_opt_in' :
1235+ saml_config = self ._get_saml_provider_config ()
1236+ if saml_config and saml_config .skip_registration_optional_checkboxes :
1237+ log .debug (
1238+ "Skipping provider override for marketing_emails_opt_in "
1239+ "due to SAML config for provider: %s" ,
1240+ saml_config .slug
1241+ )
1242+ skip_override = True
1243+
1244+ if not skip_override :
11621245 form_desc .override_field_properties (
1163- field_name ,
1164- field_type = "hidden" ,
1165- label = "" ,
1166- instructions = "" ,
1246+ field_name , default = field_overrides [field_name ]
11671247 )
11681248
1249+ if (
1250+ field_name not in ['terms_of_service' , 'honor_code' ] and
1251+ field_overrides [field_name ] and
1252+ hide_registration_fields_except_tos
1253+ ):
1254+ # When hiding a field, set default to False for checkbox fields
1255+ # like marketing_emails_opt_in to avoid auto-opting users in
1256+ field_default = field_overrides [field_name ]
1257+ if field_name == 'marketing_emails_opt_in' :
1258+ field_default = False
1259+ log .info (
1260+ "Hiding marketing_emails_opt_in field and setting default to False"
1261+ )
1262+
1263+ form_desc .override_field_properties (
1264+ field_name ,
1265+ field_type = "hidden" ,
1266+ default = field_default ,
1267+ label = "" ,
1268+ instructions = "" ,
1269+ )
1270+
11691271 # Hide the confirm_email field
11701272 form_desc .override_field_properties (
11711273 "confirm_email" ,
0 commit comments