@@ -60,57 +60,61 @@ def get_userinfo(self, access_token, id_token, payload):
6060 return userinfo
6161
6262 def get_or_create_user (self , access_token , id_token , payload ):
63- """Return a User based on userinfo. Get or create a new user if no user matches the Sub.
64-
65- Parameters:
66- - access_token (str): The access token.
67- - id_token (str): The ID token.
68- - payload (dict): The user payload.
69-
70- Returns:
71- - User: An existing or newly created User instance.
72-
73- Raises:
74- - Exception: Raised when user creation is not allowed and no existing user is found.
75- """
63+ """Return a User based on userinfo. Create a new user if no match is found."""
7664
7765 user_info = self .get_userinfo (access_token , id_token , payload )
66+ email = user_info .get ("email" )
67+
68+ # Get user's full name from OIDC fields defined in settings
69+ full_name = self .compute_full_name (user_info )
70+ short_name = user_info .get (settings .USER_OIDC_FIELD_TO_SHORTNAME )
7871
79- # Compute user full name from OIDC name fields as defined in settings
80- names_list = [
81- user_info [field ]
82- for field in settings .USER_OIDC_FIELDS_TO_FULLNAME
83- if user_info .get (field )
84- ]
8572 claims = {
86- "email" : user_info . get ( " email" ) ,
87- "full_name" : " " . join ( names_list ) or None ,
88- "short_name" : user_info . get ( settings . USER_OIDC_FIELD_TO_SHORTNAME ) ,
73+ "email" : email ,
74+ "full_name" : full_name ,
75+ "short_name" : short_name ,
8976 }
9077
9178 sub = user_info .get ("sub" )
92- if sub is None :
79+ if not sub :
9380 raise SuspiciousOperation (
9481 _ ("User info contained no recognizable user identification" )
9582 )
9683
97- try :
98- user = User .objects .get (sub = sub , is_active = True )
99- except User .DoesNotExist :
100- if self .get_settings ("OIDC_CREATE_USER" , True ):
101- user = User .objects .create (
102- sub = sub ,
103- password = "!" , # noqa: S106
104- ** claims ,
105- )
106- else :
107- user = None
108- else :
109- has_changed = any (
110- value and value != getattr (user , key ) for key , value in claims .items ()
111- )
112- if has_changed :
113- updated_claims = {key : value for key , value in claims .items () if value }
114- self .UserModel .objects .filter (sub = sub ).update (** updated_claims )
84+ user = self .get_existing_user (sub , email )
85+
86+ if user :
87+ self .update_user_if_needed (user , claims )
88+ elif self .get_settings ("OIDC_CREATE_USER" , True ):
89+ user = User .objects .create (sub = sub , password = "!" , ** claims ) # noqa: S106
11590
11691 return user
92+
93+ def compute_full_name (self , user_info ):
94+ """Compute user's full name based on OIDC fields in settings."""
95+ name_fields = settings .USER_OIDC_FIELDS_TO_FULLNAME
96+ full_name = " " .join (
97+ user_info [field ] for field in name_fields if user_info .get (field )
98+ )
99+ return full_name or None
100+
101+ def get_existing_user (self , sub , email ):
102+ """Fetch existing user by sub or email."""
103+ try :
104+ return User .objects .get (sub = sub , is_active = True )
105+ except User .DoesNotExist :
106+ if email and settings .OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION :
107+ try :
108+ return User .objects .get (email = email , is_active = True )
109+ except User .DoesNotExist :
110+ pass
111+ return None
112+
113+ def update_user_if_needed (self , user , claims ):
114+ """Update user claims if they have changed."""
115+ has_changed = any (
116+ value and value != getattr (user , key ) for key , value in claims .items ()
117+ )
118+ if has_changed :
119+ updated_claims = {key : value for key , value in claims .items () if value }
120+ self .UserModel .objects .filter (sub = user .sub ).update (** updated_claims )
0 commit comments