@@ -53,53 +53,61 @@ def oidc_complete(request, auth_organization_id):
5353
5454 if error :
5555 context ["error" ] = error
56-
5756 if error_description :
5857 context ["error_description" ] = error_description
5958
60- # Token exhange process
61- if authorization_code :
59+ if error or error_description :
60+ return render ( request , 'oidc/oidc_complete.html' , context )
6261
63- try :
64- # STEP 1: Get auth organization using its id
65- organization = get_object_or_404 ( Auth_Organization , pk = auth_organization_id )
62+ if not authorization_code :
63+ context [ "error" ] = "Authorization Code not provided!"
64+ return render ( request , 'oidc/oidc_complete.html' , context )
6665
67- if organization :
66+ try :
67+ # STEP 1: Get auth organization using its id
68+ organization = get_object_or_404 (Auth_Organization , pk = auth_organization_id )
69+
70+ # STEP 2: Get access token
71+ access_token , token_error = get_access_token (organization , authorization_code )
72+ if token_error :
73+ context ["error" ] = token_error
74+ return render (request , 'oidc/oidc_complete.html' , context )
75+ else :
76+ # STEP 3: Get user info
77+ user_info , user_info_error = get_user_info (organization , access_token )
78+ if user_info_error :
79+ context ["error" ] = user_info_error
80+ return render (request , 'oidc/oidc_complete.html' , context )
81+ else :
82+ if not isinstance (user_info , dict ):
83+ context ["error" ] = "Invalid user info payload from OIDC provider."
84+ return render (request , 'oidc/oidc_complete.html' , context )
6885
69- # STEP 2: Get access token
70- access_token , token_error = get_access_token (organization , authorization_code )
86+ user_email = user_info .get ("email" , None )
87+ user_nickname = user_info .get ("nickname" , None )
88+ if not user_email :
89+ context ["error" ] = "Unable to extract email from user info."
90+ return render (request , 'oidc/oidc_complete.html' , context )
7191
72- if token_error :
73- context ["error" ] = token_error
92+ user_email = str (user_email ).strip ().lower ()
93+
94+ if user_nickname is not None :
95+ user_nickname = str (user_nickname ).strip () or None
96+
97+ # get user with this email
98+ user = get_user_by_email (user_email )
99+
100+ # STEP 4: Check if user exists and user is created using oidc and oidc orgnaization matches this one
101+ if user :
102+ login (request , user , backend = BACKEND )
103+ # Redirect the user home page
104+ return redirect ('pages:home' )
74105 else :
75- # STEP 3: Get user info
76- user_info , user_info_error = get_user_info (organization , access_token )
77- if user_info_error :
78- context ["error" ] = user_info_error
79- else :
80-
81- # get email and nickname (username) of the user
82- user_email = user_info .get ("email" , None )
83- user_nickname = user_info .get ("nickname" , None )
84- if user_email :
85- # get user with this email
86- user = get_user_by_email (user_email )
87- # STEP 4: Check if user exists and user is created using oidc and oidc orgnaization matches this one
88- if user :
89- login (request , user , backend = BACKEND )
90- # Redirect the user home page
91- return redirect ('pages:home' )
92- else :
93- return register_and_authenticate_user (request , user_email , user_nickname , organization )
94-
95- else :
96- context ["error" ] = "Unable to extract email from user info! Please contact platform"
97- else :
98- context ["error" ] = "Invalid Organization ID!"
99- except Exception as e :
100- context ["error" ] = f"{ e } "
106+ return register_and_authenticate_user (request , user_email , user_nickname , organization )
101107
102- return render (request , 'oidc/oidc_complete.html' , context )
108+ except Exception as e :
109+ context ["error" ] = f"{ e } "
110+ return render (request , 'oidc/oidc_complete.html' , context )
103111
104112
105113def get_access_token (organization , authorization_code ):
@@ -181,14 +189,21 @@ def register_and_authenticate_user(request, user_email, user_nickname, organizat
181189
182190
183191def create_unique_username (username ):
192+ # Normalize the username to remove unsupported characters and ensure it's route-safe.
193+ username = normalize_username (username )
194+
195+ # Truncate the username to fit within the maximum length allowed by the User model.
196+ max_username_length = User ._meta .get_field ("username" ).max_length
197+ username = username [:max_username_length ]
198+
184199 # Check if the username already exists
185200 if User .objects .filter (username = username ).exists ():
186201 # If the username already exists, modify it to make it unique
187202 suffix = 1
188- new_username = f" { username } _ { suffix } "
203+ new_username = with_suffix ( username , suffix , max_username_length )
189204 while User .objects .filter (username = new_username ).exists ():
190205 suffix += 1
191- new_username = f" { username } _ { suffix } "
206+ new_username = with_suffix ( username , suffix , max_username_length )
192207 return new_username
193208 else :
194209 # If the username doesn't exist, use it as is
@@ -201,3 +216,22 @@ def get_user_by_email(email):
201216 return user
202217 except User .DoesNotExist :
203218 return None
219+
220+
221+ def normalize_username (username ):
222+ # Keep OIDC names readable while removing unsupported chars.
223+ # Keep in sync with profile URL regex: [-a-zA-Z0-9_]+
224+ cleaned = re .sub (r'[^a-zA-Z0-9_-]' , '' , username .strip ())
225+ if not cleaned :
226+ raise ValueError ("OIDC username contains no valid route-safe characters" )
227+
228+ return cleaned
229+
230+
231+ def with_suffix (base_username , suffix , max_username_length ):
232+ suffix = f"_{ suffix } "
233+ limit = max_username_length - len (suffix )
234+ if limit < 1 :
235+ raise ValueError ("Unable to create unique username within max length" )
236+
237+ return f"{ base_username [:limit ]} { suffix } "
0 commit comments