django-session-security icon indicating copy to clipboard operation
django-session-security copied to clipboard

Session incorrectly times out early if there is a long running request

Open yscumc opened this issue 11 years ago • 33 comments

Using:

Firefox 19.0.2 with Firebug Django (1.5) django-session-security (2.0.3)

Problem:

If there's a long running request, the last activity stored in request.session['_session_security'] is immediately set during the beginning of the request, but it is not returned to the client browser until the request is completed 45 seconds later. Since the session values are stored as cookies on the client side, all the ping requests during this 45 seconds which updated the last activity will be overwritten. When the long running request is finally completed, the last activity stored in request.session['_session_security'] will be set to 45 seconds ago. If the next request is to the ping view, then all will be fine as the ping view updates the last activity. However, the the request request is another long running request, or something else which does NOT have the idleFor parameter (which means anything other than the ping request), then delta.seconds would be larger than EXPIRE_AFTER and logout(request) would be called. Any subsequent ping requests would return "logout" as a response, although the page the user is viewing would not immediately be logged out.

To reproduce:

  1. Use these settings:

Settings for session_security

SESSION_SECURITY_WARN_AFTER = 10 # Default 540 SESSION_SECURITY_EXPIRE_AFTER = 30 # Default 600 SESSION_EXPIRE_AT_BROWSER_CLOSE = True

  1. Open Firebug and enable Net to see the AJAX connections
  2. Create a page which requests something via AJAX that takes about 45 seconds for the request to complete, which upon completion would create another identical request.
  3. Log in and move the mouse when the warning comes on, then wait until the next warning comes on and move the mouse again.

Here's an example of the requests to the ping view found from Firebug

First Request

GET /session_security/ping/?csrfmiddlewaretoken=ZJgthGOkE5JTR1sS5uxYsc5fn9wd2vgG&idleFor=0&_=1364238435092 HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Referer: http://localhost:8000/home/
Cookie: csrftoken=ZJgthGOkE5JTR1sS5uxYsc5fn9wd2vgG; sessionid=py3o4zs90uiojw3ylyb7hxo287n40om4
Connection: keep-alive

HTTP/1.0 200 OK
Date: Mon, 25 Mar 2013 19:07:15 GMT
Server: WSGIServer/0.1 Python/2.7.3
Vary: Cookie
Content-Type: text/html; charset=utf-8
Set-Cookie: sessionid=py3o4zs90uiojw3ylyb7hxo287n40om4; httponly; Path=/

0

Second Request, after long running request finished and started again

GET /session_security/ping/?csrfmiddlewaretoken=ZJgthGOkE5JTR1sS5uxYsc5fn9wd2vgG&idleFor=1&_=1364238445135 HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Referer: http://localhost:8000/home/
Cookie: csrftoken=ZJgthGOkE5JTR1sS5uxYsc5fn9wd2vgG; sessionid=py3o4zs90uiojw3ylyb7hxo287n40om4
Connection: keep-alive

HTTP/1.0 200 OK
Date: Mon, 25 Mar 2013 19:07:25 GMT
Server: WSGIServer/0.1 Python/2.7.3
Vary: Cookie
Content-Type: text/html; charset=utf-8
Set-Cookie: sessionid=ipub9bxy50x3kleq5w2ekzbrxz0gdfa1; httponly; Path=/

logout

Two things are wrong here:

  1. After receiving the logout response, the page is not immediately logged out. As long as I continue to move my mouse in the page when the warning comes up, I can stay on the page indefinitely, even though all the subsequent AJAX responses say logout. However, refreshing the page redirects me to the login screen, which means I was logged out.
  2. The logout response is incorrect since the "idleFor" is only 1 and it's been only 10 seconds since the last request. The logout really should not be triggered for another 29 seconds.

yscumc avatar Mar 25 '13 19:03 yscumc

By default, django stores session data in the database. However, it probably only does so at the end of the request. To fix this, we could make the middleware force a database write i think with request.session.write() but I don't think we should do that by default.

Ideally, SESSION_SECURITY_EXPIRE_AFTER should be higher than the longest possible request on your website. Can't you set it that way ?

I could reproduce the problem on /sleep/ (new url in the test project). Did not test it with your pull request thought.

What do you suggest ?

Also, thanks a lot for your feedback !

jpic avatar Mar 28 '13 16:03 jpic

Yes you are right, I assumed the session data was stored on the client side because of the behavior, but I just confirmed that the cookie only contains a session ID. I don't really have any suggestions and I was hoping you would lol. I have increased SESSION_SECURITY_EXPIRE_AFTER on my site and I was using the low values just for testing.

I think this can probably be documented as a trivial bug that won't need to be fixed as long as SESSION_SECURITY_EXPIRE_AFTER is longer than the timeout for a request.

The tests doesn't run on my machine because it's missing selenium and I haven't had a chance to figure out how to set that up yet:

running test
ImportError: No module named selenium.webdriver.common.keys

yscumc avatar Mar 28 '13 16:03 yscumc

On Thu, Mar 28, 2013 at 5:52 PM, yscumc [email protected] wrote:

I don't really have any suggestions and I was hoping you would lol. I have increased SESSION_SECURITY_EXPIRE_AFTER on my site and I was using the low values just for testing.

I think this can probably be documented as a trivial bug that won't need to be fixed as long as SESSION_SECURITY_EXPIRE_AFTER is longer than the timeout for a request.

I'm thinking that maybe we could have a setting that forces writing the session last activity at the beginning of the request.

This should be documented indeed.

The tests doesn't run on my machine because it's missing selenium and I haven't had a chance to figure out how to set that up yet:

running test ImportError: No module named selenium.webdriver.common.keys

Oops, sounds like you need to pip install selenium :)

jpic avatar Mar 28 '13 17:03 jpic

Wow pip makes working with python easier than pie =)

Turns out I also needed unittest_data_provider. Installed it and it ran with my FF 19.0.2.

Not sure if this was supposed to happen but four tests failed:

======================================================================
FAIL: test_double_hide_warning (session_security.tests.script.ScriptTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "E:\Projects\Third Party\django-session-security\session_security\tests\script.py", line 154, in test_double_hide
_warning
    self.assertWarningShows(9)
  File "E:\Projects\Third Party\django-session-security\session_security\tests\script.py", line 73, in assertWarningShow
s
    self.fail('Warning did not make it into DOM')
AssertionError: Warning did not make it into DOM

======================================================================
FAIL: test_double_window_inactivity (session_security.tests.script.ScriptTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "E:\Projects\Third Party\django-session-security\session_security\tests\script.py", line 139, in test_double_wind
ow_inactivity
    self.assertWarningShows(9)
  File "E:\Projects\Third Party\django-session-security\session_security\tests\script.py", line 73, in assertWarningShow
s
    self.fail('Warning did not make it into DOM')
AssertionError: Warning did not make it into DOM

======================================================================
FAIL: test_single_hide_warning (session_security.tests.script.ScriptTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "E:\Projects\Third Party\django-session-security\session_security\tests\script.py", line 131, in test_single_hide
_warning
    self.assertWarningShows(9)
  File "E:\Projects\Third Party\django-session-security\session_security\tests\script.py", line 73, in assertWarningShow
s
    self.fail('Warning did not make it into DOM')
AssertionError: Warning did not make it into DOM

======================================================================
FAIL: test_single_window_inactivity (session_security.tests.script.ScriptTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "E:\Projects\Third Party\django-session-security\session_security\tests\script.py", line 118, in test_single_wind
ow_inactivity
    self.assertWarningShows(9)
  File "E:\Projects\Third Party\django-session-security\session_security\tests\script.py", line 73, in assertWarningShow
s
    self.fail('Warning did not make it into DOM')
AssertionError: Warning did not make it into DOM

----------------------------------------------------------------------
Ran 11 tests in 149.273s

FAILED (failures=4)
Destroying test database for alias 'default'...

First time I used selenium... pretty cool stuff.

yscumc avatar Mar 29 '13 18:03 yscumc

Did you run it from your own project ?

It should be run from the test_project in this repo ...

... but yeah, it tries to be good, here's a nice link if you're thirsty of knowledge ;) http://www.tdd-django-tutorial.com/

jpic avatar Mar 30 '13 01:03 jpic

Nope, I ran it within django-session-security as setup.py test. I did get a lot of errors like the following though:

Traceback (most recent call last):
  File "C:\Python27\lib\wsgiref\handlers.py", line 85, in run
    self.result = application(self.environ, self.start_response)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 73, in __call__
    return super(StaticFilesHandler, self).__call__(environ, start_response)
  File "C:\Python27\lib\site-packages\django\core\handlers\wsgi.py", line 255, in __call__
    response = self.get_response(request)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 63, in get_response
    return self.serve(request)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 56, in serve
    return serve(request, self.file_path(request.path), insecure=True)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\views.py", line 38, in serve
    absolute_path = finders.find(normalized_path)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 239, in find
    result = finder.find(path, all=all)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 79, in find
    matched_path = self.find_location(root, path, prefix)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 96, in find_location
    path = safe_join(root, path)
  File "C:\Python27\lib\site-packages\django\utils\_os.py", line 77, in safe_join
    'path component (%s)' % (final_path, base_path))
ValueError: The joined path (E:\jquery.js) is located outside of the base path component (E:\Projects\Third Party\django
-session-security\test_project\static)

From one of the command prompt you showed earlier, I'm guessing you're using Linux, cygwin, etc but I'm running Windows. Do you think this would make a difference?

Thanks for the link, I'd love to read it and hopefully I'll be able to get around to it lol

yscumc avatar Apr 01 '13 14:04 yscumc

Try python manage.py test session_security from test_project directory.

On Mon, Apr 1, 2013 at 4:10 PM, yscumc [email protected] wrote:

Nope, I ran it within django-session-security as setup.py test. I did get a lot of errors like the following though:

Traceback (most recent call last): File "C:\Python27\lib\wsgiref\handlers.py", line 85, in run self.result = application(self.environ, self.start_response) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 73, in call return super(StaticFilesHandler, self).call(environ, start_response) File "C:\Python27\lib\site-packages\django\core\handlers\wsgi.py", line 255, in call response = self.get_response(request) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 63, in get_response return self.serve(request) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 56, in serve return serve(request, self.file_path(request.path), insecure=True) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\views.py", line 38, in serve absolute_path = finders.find(normalized_path) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 239, in find result = finder.find(path, all=all) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 79, in find matched_path = self.find_location(root, path, prefix) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 96, in find_location path = safe_join(root, path) File "C:\Python27\lib\site-packages\django\utils_os.py", line 77, in safe_join 'path component (%s)' % (final_path, base_path)) ValueError: The joined path (E:\jquery.js) is located outside of the base path component (E:\Projects\Third Party\django -session-security\test_project\static)

From one of the command prompt you showed earlier, I'm guessing you're using Linux, cygwin, etc but I'm running Windows. Do you think this would make a difference?

Thanks for the link, I'd love to read it and hopefully I'll be able to get around to it lol

— Reply to this email directly or view it on GitHubhttps://github.com/yourlabs/django-session-security/issues/1#issuecomment-15716623 .

http://yourlabs.org http://blog.yourlabs.org Customer is king - Le client est roi - El cliente es rey.

jpic avatar Apr 02 '13 10:04 jpic

Still got same failure...

E:\Projects\Third Party\django-session-security\test_project>python manage.py test session_security

...

Traceback (most recent call last):
  File "C:\Python27\lib\wsgiref\handlers.py", line 85, in run
    self.result = application(self.environ, self.start_response)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 73, in __call__
    return super(StaticFilesHandler, self).__call__(environ, start_response)
  File "C:\Python27\lib\site-packages\django\core\handlers\wsgi.py", line 255, in __call__
    response = self.get_response(request)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 63, in get_response
    return self.serve(request)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 56, in serve
    return serve(request, self.file_path(request.path), insecure=True)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\views.py", line 38, in serve
    absolute_path = finders.find(normalized_path)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 239, in find
    result = finder.find(path, all=all)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 79, in find
    matched_path = self.find_location(root, path, prefix)
  File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 96, in find_location
    path = safe_join(root, path)
  File "C:\Python27\lib\site-packages\django\utils\_os.py", line 77, in safe_join
    'path component (%s)' % (final_path, base_path))
ValueError: The joined path (E:\jquery.js) is located outside of the base path component (E:\Projects\Third Party\django
-session-security\test_project\static)
F..
======================================================================
FAIL: test_double_hide_warning (session_security.tests.script.ScriptTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 154, in test_double_hide_warning
    self.assertWarningShows(9)
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 73, in assertWarningShows
    self.fail('Warning did not make it into DOM')
AssertionError: Warning did not make it into DOM

======================================================================
FAIL: test_double_window_inactivity (session_security.tests.script.ScriptTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 139, in test_double_window_inactivity
    self.assertWarningShows(9)
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 73, in assertWarningShows
    self.fail('Warning did not make it into DOM')
AssertionError: Warning did not make it into DOM

======================================================================
FAIL: test_single_hide_warning (session_security.tests.script.ScriptTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 131, in test_single_hide_warning
    self.assertWarningShows(9)
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 73, in assertWarningShows
    self.fail('Warning did not make it into DOM')
AssertionError: Warning did not make it into DOM

======================================================================
FAIL: test_single_window_inactivity (session_security.tests.script.ScriptTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 118, in test_single_window_inactivity
    self.assertWarningShows(9)
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 73, in assertWarningShows
    self.fail('Warning did not make it into DOM')
AssertionError: Warning did not make it into DOM

----------------------------------------------------------------------
Ran 11 tests in 148.446s

FAILED (failures=4)
Destroying test database for alias 'default'...

yscumc avatar Apr 02 '13 13:04 yscumc

Interresting, it might be all due to jquery.js not being found.

In the test_project, try this command: ./manage.py findstatic jquery.js

It should output something like this:

Found 'jquery.js' here:
  /home/jpic/env/src/session-security/test_project/static/jquery.js

If it doesn't then that might be the problem to fix windows OS support.

On Tue, Apr 2, 2013 at 3:53 PM, yscumc [email protected] wrote:

Still got same failure...

E:\Projects\Third Party\django-session-security\test_project>python manage.py test session_security

...

Traceback (most recent call last): File "C:\Python27\lib\wsgiref\handlers.py", line 85, in run self.result = application(self.environ, self.start_response) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 73, in call return super(StaticFilesHandler, self).call(environ, start_response) File "C:\Python27\lib\site-packages\django\core\handlers\wsgi.py", line 255, in call response = self.get_response(request) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 63, in get_response return self.serve(request) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\handlers.py", line 56, in serve return serve(request, self.file_path(request.path), insecure=True) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\views.py", line 38, in serve absolute_path = finders.find(normalized_path) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 239, in find result = finder.find(path, all=all) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 79, in find matched_path = self.find_location(root, path, prefix) File "C:\Python27\lib\site-packages\django\contrib\staticfiles\finders.py", line 96, in find_location path = safe_join(root, path) File "C:\Python27\lib\site-packages\django\utils_os.py", line 77, in safe_join 'path component (%s)' % (final_path, base_path)) ValueError: The joined path (E:\jquery.js) is located outside of the base path component (E:\Projects\Third Party\django -session-security\test_project\static)

F..

FAIL: test_double_hide_warning (session_security.tests.script.ScriptTestCase)

Traceback (most recent call last): File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 154, in test_double_hide_warning self.assertWarningShows(9) File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 73, in assertWarningShows self.fail('Warning did not make it into DOM') AssertionError: Warning did not make it into DOM

FAIL: test_double_window_inactivity (session_security.tests.script.ScriptTestCase)

Traceback (most recent call last): File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 139, in test_double_window_inactivity self.assertWarningShows(9) File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 73, in assertWarningShows self.fail('Warning did not make it into DOM') AssertionError: Warning did not make it into DOM

FAIL: test_single_hide_warning (session_security.tests.script.ScriptTestCase)

Traceback (most recent call last): File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 131, in test_single_hide_warning self.assertWarningShows(9) File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 73, in assertWarningShows self.fail('Warning did not make it into DOM') AssertionError: Warning did not make it into DOM

FAIL: test_single_window_inactivity (session_security.tests.script.ScriptTestCase)

Traceback (most recent call last): File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 118, in test_single_window_inactivity self.assertWarningShows(9) File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 73, in assertWarningShows self.fail('Warning did not make it into DOM') AssertionError: Warning did not make it into DOM


Ran 11 tests in 148.446s

FAILED (failures=4) Destroying test database for alias 'default'...

— Reply to this email directly or view it on GitHubhttps://github.com/yourlabs/django-session-security/issues/1#issuecomment-15776185 .

http://yourlabs.org http://blog.yourlabs.org Customer is king - Le client est roi - El cliente es rey.

jpic avatar Apr 02 '13 14:04 jpic

Seems to have found it

E:\Projects\Third Party\django-session-security\test_project>manage.py findstatic jquery.js
Found 'jquery.js' here:
  E:\Projects\Third Party\django-session-security\test_project\static\jquery.js

yscumc avatar Apr 02 '13 14:04 yscumc

Ok, I have changed the test_project template to use {% static %} instead of {{ STATIC_URL }}, it might work for you.

On Tue, Apr 2, 2013 at 4:53 PM, yscumc [email protected] wrote:

Seems to have found it

E:\Projects\Third Party\django-session-security\test_project>manage.py findstatic jquery.js Found 'jquery.js' here: E:\Projects\Third Party\django-session-security\test_project\static\jquery.js

— Reply to this email directly or view it on GitHubhttps://github.com/yourlabs/django-session-security/issues/1#issuecomment-15779882 .

http://yourlabs.org http://blog.yourlabs.org Customer is king - Le client est roi - El cliente es rey.

jpic avatar Apr 02 '13 15:04 jpic

How long does the tests normally take? I no longer get the ValueError exceptions, but it seems to be hung on the 3rd or 4th test case (after the 3rd period):


E:\Projects\Third Party\django-session-security\test_project>python manage.py test session_security
Creating test database for alias 'default'...
C:\Python27\lib\site-packages\django\conf\urls\defaults.py:3: DeprecationWarning: django.conf.urls.defaults is deprecate
d; use django.conf.urls instead
  DeprecationWarning)

...Not Found: /favicon.ico
Not Found: /favicon.ico

It's been about 15 mins and there's been no change.

Btw, I'm using Django 1.5.

yscumc avatar Apr 02 '13 15:04 yscumc

It depends, but ~3 minutes on travis which is pretty slow: https://travis-ci.org/yourlabs/django-session-security

jpic avatar Apr 02 '13 16:04 jpic

Ok it was still running after 2 hours so I closed the browser window and it finally moved on. Here are the results:

E:\Projects\Third Party\django-session-security\test_project>python manage.py test session_security
Creating test database for alias 'default'...
C:\Python27\lib\site-packages\django\conf\urls\defaults.py:3: DeprecationWarning: django.conf.urls.defaults is deprecate
d; use django.conf.urls instead
  DeprecationWarning)

...Not Found: /favicon.ico
Not Found: /favicon.ico
ENot Found: /favicon.ico
.Not Found: /favicon.ico
Not Found: /favicon.ico
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 59719)
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\django\test\testcases.py", line 998, in _handle_request_noblock
    self.process_request(request, client_address)
  File "C:\Python27\lib\SocketServer.py", line 310, in process_request
    self.finish_request(request, client_address)
  File "C:\Python27\lib\SocketServer.py", line 323, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Python27\lib\site-packages\django\core\servers\basehttp.py", line 150, in __init__
    super(WSGIRequestHandler, self).__init__(*args, **kwargs)
  File "C:\Python27\lib\SocketServer.py", line 638, in __init__
    self.handle()
  File "C:\Python27\lib\wsgiref\simple_server.py", line 116, in handle
    self.raw_requestline = self.rfile.readline()
  File "C:\Python27\lib\socket.py", line 447, in readline
    data = self._sock.recv(self._rbufsize)
error: [Errno 10054] An existing connection was forcibly closed by the remote host
----------------------------------------
.Not Found: /favicon.ico
Not Found: /favicon.ico
.Not Found: /favicon.ico
Not Found: /favicon.ico
.Not Found: /favicon.ico
...
======================================================================
ERROR: test_double_dont_show_warning (session_security.tests.script.ScriptTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 143, in test_double_dont_show_warning
    self.new_window()
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 30, in new_window
    while self.warning_element() is False:
  File "C:\Python27\lib\site-packages\session_security\tests\script.py", line 42, in warning_element
    '#session_security_warning')[0]
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 373, in find_elements_by_css_selecto
r
    return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 688, in find_elements
    {'using': by, 'value': value})['value']
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 160, in execute
    self.error_handler.check_response(response)
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 149, in check_response
    raise exception_class(message, screen, stacktrace)
NoSuchWindowException: Message: u'Window not found. The browser window may have been closed.' ; Stacktrace: Method nsCom
mandProcessor.prototype.execute threw an error in file:///c:/users/yas7005/appdata/local/temp/tmp5x67jx/extensions/fxdri
[email protected]/components/command_processor.js

----------------------------------------------------------------------
Ran 11 tests in 8308.441s

FAILED (errors=1)
Destroying test database for alias 'default'...

Much better than before, but not sure why that test froze

yscumc avatar Apr 02 '13 17:04 yscumc

Does it manage to open 2 firefox windows ? "double" tests should spawn a second window.

jpic avatar Apr 04 '13 09:04 jpic

Yes I think there's one point where there's more than one window open. However, I already had FF open when I was running the tests and perhaps this situation affects the tests. I thought I saw some commands the first time I ran that test that looked as if a new FF profile was being created but it doesn't seem to be the case looking at Process Explorer. I have too many tabs open and don't want to close them yet but I guess I should try it again sometime when I have no tabs open.

yscumc avatar Apr 04 '13 13:04 yscumc

Selenium should create a new profile per test, so your current session should not affect it.

On Thu, Apr 4, 2013 at 3:58 PM, yscumc [email protected] wrote:

Yes I think there's one point where there's more than one window open. However, I already had FF open when I was running the tests and perhaps this situation affects the tests. I thought I saw some commands the first time I ran that test that looked as if a new FF profile was being created but it doesn't seem to be the case looking at Process Explorer. I have too many tabs open and don't want to close them yet but I guess I should try it again sometime when I have no tabs open.

— Reply to this email directly or view it on GitHubhttps://github.com/yourlabs/django-session-security/issues/1#issuecomment-15898521 .

http://yourlabs.org http://blog.yourlabs.org Customer is king - Le client est roi - El cliente es rey.

jpic avatar Apr 04 '13 14:04 jpic

Ok I guess that wasn't the issue then.

It doesn't bother me that the test failed though as long as it works normally so I'll just leave it as is unless you want to look into it and want more info.

yscumc avatar Apr 04 '13 14:04 yscumc

I have nothing against windows, but it doesn't like me very much so I try to avoid it ;)

On Thu, Apr 4, 2013 at 4:46 PM, yscumc [email protected] wrote:

Ok I guess that wasn't the issue then.

It doesn't bother me that the test failed though as long as it works normally so I'll just leave it as is unless you want to look into it and want more info.

— Reply to this email directly or view it on GitHubhttps://github.com/yourlabs/django-session-security/issues/1#issuecomment-15901561 .

http://yourlabs.org http://blog.yourlabs.org Customer is king - Le client est roi - El cliente es rey.

jpic avatar Apr 04 '13 14:04 jpic

Haha understood

yscumc avatar Apr 04 '13 16:04 yscumc

Did you try again with recent selenium, firefox and django updates ?

Maybe tests will run better on windows nowadays ...

jpic avatar Oct 30 '14 22:10 jpic

Hi @yscumc,

Did you find a solution ?

Thanks

jpic avatar Feb 06 '15 11:02 jpic

Thanks for the follow up. Unfortunately I haven't found a real solution for the actual problem. I did find a solution for our specific case though; after the programmer who wrote the long running request left, I just modified it to poll at an interval instead lol.

Regarding the testing with selenium, sorry I forgot to reply. I meant to try it again and get back to you but I haven't gotten around to it yet and I'm not sure there would be time to in the near future.

yscumc avatar Feb 10 '15 16:02 yscumc

Did you try just calling sessionSecurity.activity() in js as much as needed ? Maybe with a recursive setTimeout() callback or something.

It worked for #38

jpic avatar Feb 11 '15 00:02 jpic

Nope I haven't, but I doubt it would work in this case. If I remember correctly, the problem was due to Django persisting the session data to the db at the END of the request. The long running request, which is started early, will overwrite the session data from the later requests, even if the later requests indicate activity.

In #38, the user doesn't move the mouse because the main interaction with the page is listening to the audio. Therefore, no activity indication was sent to the server.

In this case, the user actually moves the mouse during the long running requests and sends off activity data to the server. However, when the long running request returns, it overwrites all the previous session data, leading the next request to trigger the logout response.

Unfortunately, I'm not sure there can be a fix for this, as it's an inherent behavior of how Django handles the session data. If there's a way to flush the session data periodically during the long running request, that should fix the problem.

yscumc avatar Feb 11 '15 17:02 yscumc

On Wed, Feb 11, 2015 at 5:05 PM, yscumc [email protected] wrote:

Nope I haven't, but I doubt it would work in this case. If I remember correctly, the problem was due to Django persisting the session data to the db at the END of the request. The long running request, which is started early, will overwrite the session data from the later requests, even if the later requests indicate activity.

Wouldn't you add the long running request URL to PASSIVE_URLS to avoid it updating the user's last activity in that case ?

http://yourlabs.org http://blog.yourlabs.org Customer is king - Le client est roi - El cliente es rey.

jpic avatar Feb 11 '15 17:02 jpic

I don't think this would work either, though I'm less certain this time.

Django writes all the session data encoding in a single string as session_data in the django_session table. Even if the session_security's session data is not updated in the long running request, the rest of the session data will be. That data won't include the latest session_security data containing the user's activity and it will be re-encoded as a string back into the django_session table. The next request will decode this session_data and it won't include the latest session_security activity either.

However, this is all conjectures so maybe it'll behave differently?

yscumc avatar Feb 11 '15 17:02 yscumc

I was thinking:

  1. long polling to PASSIVE_URLS, to prevent any accuracy you have described and
  2. call sessionSecurity.activity() in JS meanwhile, to trigger update of last session when necessary

Would that work ?

On Wed, Feb 11, 2015 at 5:40 PM, yscumc [email protected] wrote:

I don't think this would work either, though I'm less certain this time.

Django writes all the session data encoding in a single string as session_data in the django_session table. Even if the session_security's session data is not updated in the long running request, the rest of the session data will be. That data won't include the latest session_security data containing the user's activity and it will be re-encoded as a string back into the django_session table. The next request will decode this session_data and it won't include the latest session_security activity either.

However, this is all conjectures so maybe it'll behave differently?

— Reply to this email directly or view it on GitHub https://github.com/yourlabs/django-session-security/issues/1#issuecomment-73926302 .

http://yourlabs.org http://blog.yourlabs.org Customer is king - Le client est roi - El cliente es rey.

jpic avatar Feb 12 '15 02:02 jpic

It's alright if you can't test it, as long as this proposal looks good enough for you then we can close this issue ;)

jpic avatar Feb 14 '15 10:02 jpic

Unfortunately, I don't think that would work. Sorry if I wasn't clear in my explanation before but I have interpreted it as you have said and based on what I've seen and tried previously, I do not believe it would work. From my understanding, Django writes the entire encoded session dict to the database at the end of the request, regardless of whether you have manually changed the last activity information in that request or not. PASSIVE_URL only prevent session_security from processing the request, but it does not prevent the regular Django session handling. Therefore, session_security's last activity information will get overwritten with stale data at the end of the long request, because the entire session data is overwritten.

Now I have not tested this hypothesis directly, so I am not 100% certain this is the case, but at the time I encountered this problem, I did a bunch of testing on this issue and this was my conclusion. It seems to be an inherent problem in the way Django handles the saving of session data and the only way I can think of to fix this is to somehow tell Django to update the session data to/from the database periodically before the end of the long request so that it will share the data more nicely with other concurrent requests. I believe the root of this issue is actually a concurrency problem.

I don't have any qualms about this issue being closed as I have worked around it, but it could still be an issue for others. But from the lack of activity on this issue, it looks like this is a rare problem that no one else encountered. It would probably be a good idea to document this known problem somewhere if you wish to close this issue.

yscumc avatar Feb 15 '15 05:02 yscumc