@@ -554,10 +554,19 @@ def sync_user_ldap_attributes(user):
554554 """
555555 Sync LDAP attributes to UserProfile for a specific user.
556556
557- This fetches key attributes from LDAP (mail, department, title, etc.)
558- and stores them in the user's UserProfile. This is especially useful
559- for SSO users who authenticate via Google/SAML but need LDAP attributes
560- for form prefilling.
557+ This fetches key attributes from LDAP and stores them in the user's
558+ UserProfile. This is especially useful for SSO users who authenticate
559+ via Google/SAML but need LDAP attributes for form prefilling.
560+
561+ The mapping of UserProfile fields to LDAP attributes is configurable via:
562+
563+ FORMS_WORKFLOWS_LDAP_PROFILE_MAPPING = {
564+ 'employee_id': 'extensionAttribute1', # Custom ID number attribute
565+ 'department': 'department',
566+ 'title': 'title',
567+ 'phone': 'telephoneNumber',
568+ 'office_location': 'physicalDeliveryOfficeName',
569+ }
561570
562571 Args:
563572 user: Django User object
@@ -582,6 +591,25 @@ def sync_user_ldap_attributes(user):
582591 logger .debug ("python-ldap not installed, skipping attribute sync" )
583592 return None
584593
594+ # Default mapping of UserProfile fields to LDAP attributes
595+ default_mapping = {
596+ "employee_id" : "employeeID" ,
597+ "department" : "department" ,
598+ "title" : "title" ,
599+ "phone" : "telephoneNumber" ,
600+ "office_location" : "physicalDeliveryOfficeName" ,
601+ }
602+
603+ # Get custom mapping from settings, falling back to defaults
604+ profile_mapping = getattr (
605+ settings , "FORMS_WORKFLOWS_LDAP_PROFILE_MAPPING" , default_mapping
606+ )
607+
608+ # Merge with defaults for any missing fields
609+ for key , value in default_mapping .items ():
610+ if key not in profile_mapping :
611+ profile_mapping [key ] = value
612+
585613 # Get LDAP connection settings
586614 bind_dn = getattr (settings , "AUTH_LDAP_BIND_DN" , "" )
587615 bind_password = getattr (settings , "AUTH_LDAP_BIND_PASSWORD" , "" )
@@ -628,19 +656,11 @@ def sync_user_ldap_attributes(user):
628656 raise
629657
630658 try :
631- # Attributes to fetch from LDAP
632- ldap_attrs = [
633- "mail" ,
634- "department" ,
635- "title" ,
636- "telephoneNumber" ,
637- "mobile" ,
638- "employeeID" ,
639- "physicalDeliveryOfficeName" ,
640- "company" ,
641- "givenName" ,
642- "sn" ,
643- ]
659+ # Build list of LDAP attributes to fetch from the mapping
660+ # Include additional common attributes for synced_attrs dict
661+ ldap_attrs = list (set (profile_mapping .values ()))
662+ ldap_attrs .extend (["mail" , "mobile" , "company" , "givenName" , "sn" ])
663+ ldap_attrs = list (set (ldap_attrs )) # Remove duplicates
644664
645665 # Search for the user
646666 search_filter = f"(sAMAccountName={ escape_filter_chars (user .username )} )"
@@ -668,37 +688,32 @@ def get_attr(attrs, name):
668688 return val [0 ]
669689 return None
670690
671- # Map LDAP attributes
691+ # Build synced_attrs from LDAP response using the configured mapping
692+ for profile_field , ldap_attr in profile_mapping .items ():
693+ synced_attrs [profile_field ] = get_attr (user_attrs , ldap_attr )
694+
695+ # Also include common attributes for logging/debugging
672696 synced_attrs ["mail" ] = get_attr (user_attrs , "mail" )
673- synced_attrs ["department" ] = get_attr (user_attrs , "department" )
674- synced_attrs ["title" ] = get_attr (user_attrs , "title" )
675- synced_attrs ["phone" ] = get_attr (user_attrs , "telephoneNumber" )
676697 synced_attrs ["mobile" ] = get_attr (user_attrs , "mobile" )
677- synced_attrs ["employee_id" ] = get_attr (user_attrs , "employeeID" )
678- synced_attrs ["office_location" ] = get_attr (
679- user_attrs , "physicalDeliveryOfficeName"
680- )
681698 synced_attrs ["company" ] = get_attr (user_attrs , "company" )
682699 synced_attrs ["first_name" ] = get_attr (user_attrs , "givenName" )
683700 synced_attrs ["last_name" ] = get_attr (user_attrs , "sn" )
684701
685702 # Update or create UserProfile
686703 profile , created = UserProfile .objects .get_or_create (user = user )
687704
688- # Sync attributes to profile
689- profile_fields = {
690- "department" : synced_attrs .get ("department" ),
691- "title" : synced_attrs .get ("title" ),
692- "phone" : synced_attrs .get ("phone" ),
693- "employee_id" : synced_attrs .get ("employee_id" ),
694- "office_location" : synced_attrs .get ("office_location" ),
695- }
696-
705+ # Sync attributes to profile using the configured mapping
697706 updated = False
698- for field , value in profile_fields .items ():
699- if value and hasattr (profile , field ):
700- setattr (profile , field , value )
701- updated = True
707+ for profile_field in profile_mapping .keys ():
708+ value = synced_attrs .get (profile_field )
709+ if value and hasattr (profile , profile_field ):
710+ current_value = getattr (profile , profile_field , None )
711+ if current_value != value :
712+ setattr (profile , profile_field , value )
713+ updated = True
714+ logger .debug (
715+ f"Updated { profile_field } for user '{ user .username } ': { value } "
716+ )
702717
703718 if updated or created :
704719 profile .save ()
0 commit comments