@@ -268,9 +268,16 @@ def post(self, request, *args, **kwargs):
268268 serializer .is_valid (raise_exception = True )
269269 username = serializer .validated_data .get ("username" )
270270 password = serializer .validated_data .get ("password" )
271+ called_station_id = serializer .validated_data .get ("called_station_id" )
272+ calling_station_id = serializer .validated_data .get ("calling_station_id" )
271273 user = self .get_user (request , username , password )
272274 if user and self .authenticate_user (request , user , password ):
273- data , status = self .get_replies (user , organization_id = request .auth )
275+ data , status = self .get_replies (
276+ user ,
277+ organization_id = request .auth ,
278+ called_station_id = called_station_id ,
279+ calling_station_id = calling_station_id ,
280+ )
274281 return Response (data , status = status )
275282 if app_settings .API_AUTHORIZE_REJECT :
276283 return Response (self .reject_attributes , status = self .reject_status )
@@ -296,7 +303,9 @@ def get_user(self, request, username, password):
296303 return user
297304 return None
298305
299- def get_replies (self , user , organization_id ):
306+ def get_replies (
307+ self , user , organization_id , called_station_id = None , calling_station_id = None
308+ ):
300309 """
301310 Returns user group replies and executes counter checks
302311 """
@@ -312,7 +321,12 @@ def get_replies(self, user, organization_id):
312321
313322 # Validate simultaneous use
314323 simultaneous_use = self ._check_simultaneous_use (
315- data , user , group_checks , organization_id
324+ data ,
325+ user ,
326+ group_checks ,
327+ organization_id ,
328+ called_station_id = called_station_id ,
329+ calling_station_id = calling_station_id ,
316330 )
317331 if simultaneous_use is not None :
318332 return simultaneous_use
@@ -326,7 +340,15 @@ def get_replies(self, user, organization_id):
326340
327341 return data , self .accept_status
328342
329- def _check_simultaneous_use (self , data , user , group_checks , organization_id ):
343+ def _check_simultaneous_use (
344+ self ,
345+ data ,
346+ user ,
347+ group_checks ,
348+ organization_id ,
349+ called_station_id = None ,
350+ calling_station_id = None ,
351+ ):
330352 """
331353 Check if user has exceeded simultaneous use limit
332354
@@ -338,11 +360,22 @@ def _check_simultaneous_use(self, data, user, group_checks, organization_id):
338360 # Exit early if the `Simultaneous-Use` check is not defined
339361 # in the RadiusGroup or if it permits unlimited concurrent sessions.
340362 return None
363+
341364 open_sessions = RadiusAccounting .objects .filter (
342365 username = user .username ,
343366 organization_id = organization_id ,
344367 stop_time__isnull = True ,
345- ).count ()
368+ )
369+ # In some corner cases, RADIUS accounting sessions
370+ # can remain open even though the user is not authenticated
371+ # on the NAS anymore, for this reason, we shall allow re-authentication
372+ # of the same client on the same NAS.
373+ if called_station_id and calling_station_id :
374+ open_sessions = open_sessions .exclude (
375+ called_station_id = called_station_id ,
376+ calling_station_id = calling_station_id ,
377+ )
378+ open_sessions = open_sessions .count ()
346379 if open_sessions >= max_simultaneous :
347380 data .update (self .reject_attributes .copy ())
348381 if "Reply-Message" not in data :
0 commit comments