def save_user_session_membership(sender, **kwargs): session = kwargs.get('instance', None) if pkg_resources.get_distribution('channels').version >= '2': # If you get into this code block, it means we upgraded channels, but # didn't make the settings.SESSIONS_PER_USER feature work raise RuntimeError( 'save_user_session_membership must be updated for channels>=2: ' 'http://channels.readthedocs.io/en/latest/one-to-two.html#requirements' ) if 'runworker' in sys.argv: # don't track user session membership for websocket per-channel sessions return if not session: return user_id = session.get_decoded().get(SESSION_KEY, None) if not user_id: return if UserSessionMembership.objects.filter(user=user_id, session=session).exists(): return # check if user_id from session has an id match in User before saving if User.objects.filter(id=int(user_id)).exists(): UserSessionMembership(user_id=user_id, session=session, created=timezone.now()).save() expired = UserSessionMembership.get_memberships_over_limit(user_id) for membership in expired: Session.objects.filter( session_key__in=[membership.session_id]).delete() membership.delete() if len(expired): consumers.emit_channel_notification( 'control-limit_reached_{}'.format(user_id), dict(group_name='control', reason='limit_reached'))
def test_session_overlimit(admin, post): AlwaysPassBackend.user = admin with override_settings( AUTHENTICATION_BACKENDS=(AlwaysPassBackend.get_backend_path(), ), SESSION_COOKIE_NAME='session_id', SESSIONS_PER_USER=3): sessions_to_deprecate = [] for _ in range(5): response = post('/api/login/', data={ 'username': admin.username, 'password': admin.password, 'next': '/api/' }, expect=302, middleware=SessionMiddleware(), format='multipart') session_key = re.findall( r'session_id=[a-zA-z0-9]+', str(response.cookies['session_id']))[0][len('session_id='):] sessions_to_deprecate.append( Session.objects.get(session_key=session_key)) sessions_to_deprecate[0].expire_date = tz_now() - timedelta( seconds=1000) sessions_to_deprecate[0].save() sessions_overlimit = [ x.session for x in UserSessionMembership.get_memberships_over_limit(admin) ] assert sessions_to_deprecate[0] not in sessions_overlimit assert sessions_to_deprecate[1] in sessions_overlimit for session in sessions_to_deprecate[2:]: assert session not in sessions_overlimit
def save_user_session_membership(sender, **kwargs): session = kwargs.get('instance', None) if not session: return user_id = session.get_decoded().get(SESSION_KEY, None) if not user_id: return if UserSessionMembership.objects.filter(user=user_id, session=session).exists(): return # check if user_id from session has an id match in User before saving if User.objects.filter(id=int(user_id)).exists(): UserSessionMembership(user_id=user_id, session=session, created=timezone.now()).save() expired = UserSessionMembership.get_memberships_over_limit(user_id) for membership in expired: Session.objects.filter(session_key__in=[membership.session_id]).delete() membership.delete() if len(expired): consumers.emit_channel_notification('control-limit_reached_{}'.format(user_id), dict(group_name='control', reason='limit_reached'))