@@ -1338,6 +1338,31 @@ def log_successful_logout(sender, request, user, **kwargs): # pylint: disable=u
13381338 segment .track (request .user .id , 'edx.bi.user.account.logout' )
13391339
13401340
1341+ def _is_single_login_exempt (user ):
1342+ """
1343+ Return True if ``user`` is exempt from single-login enforcement.
1344+
1345+ ``PREVENT_CONCURRENT_LOGINS`` keeps a single active session per user and
1346+ deletes the previously registered session on each login. That is correct for
1347+ human accounts, but it breaks shared service/automation accounts (for
1348+ example the xqueue-watcher grader account) whose many concurrent workers all
1349+ authenticate as one user and would otherwise continually evict each other's
1350+ sessions.
1351+
1352+ Exemptions are opt-in and default to empty, so behaviour is unchanged unless
1353+ configured:
1354+
1355+ * ``SINGLE_LOGIN_EXEMPT_USERNAMES`` -- iterable of exact usernames.
1356+ * ``SINGLE_LOGIN_EXEMPT_GROUPS`` -- iterable of group names; a user in any of
1357+ these groups is exempt.
1358+ """
1359+ exempt_usernames = getattr (settings , 'SINGLE_LOGIN_EXEMPT_USERNAMES' , None ) or ()
1360+ if user .username in exempt_usernames :
1361+ return True
1362+ exempt_groups = getattr (settings , 'SINGLE_LOGIN_EXEMPT_GROUPS' , None ) or ()
1363+ return bool (exempt_groups ) and user .groups .filter (name__in = exempt_groups ).exists ()
1364+
1365+
13411366@receiver (user_logged_in )
13421367@receiver (user_logged_out )
13431368def enforce_single_login (sender , request , user , signal , ** kwargs ): # pylint: disable=unused-argument
@@ -1346,6 +1371,9 @@ def enforce_single_login(sender, request, user, signal, **kwargs): # pylint: di
13461371 to prevent concurrent logins.
13471372 """
13481373 if settings .FEATURES .get ('PREVENT_CONCURRENT_LOGINS' , False ):
1374+ if user and _is_single_login_exempt (user ):
1375+ # Shared service/automation accounts may hold concurrent sessions.
1376+ return
13491377 if signal == user_logged_in :
13501378 key = request .session .session_key
13511379 else :
0 commit comments