I am creating a PAS plugin for a new Plone 5.1 site, which would pass username and password on to a different server for authentication. It stores a few items in the session, for now a session id from the auth server, and a full name.
I now run into problems when reading from the session. At first, all is fine, but when I go to a page with an error, for example simply a non-existing page triggering a 404 NotFound, it starts going wrong. Subsequent calls to normal pages, even just a javascript, give an exception:
2018-03-02T16:07:51 ERROR client.myplugin KeyError getting SESSION for request http://127.0.0.1:8080/Plone/++resource++protect.js
Traceback (most recent call last):
File ".../myplugin/plugins.py", line 31, in get_session
return request.SESSION
File "/Users/maurits/shared-eggs/cp27m/Zope2-2.13.26-py2.7.egg/ZPublisher/HTTPRequest.py", line 1380, in __getattr__
v = self.get(key, default, returnTaints=returnTaints)
File "/Users/maurits/shared-eggs/cp27m/Zope2-2.13.26-py2.7.egg/ZPublisher/HTTPRequest.py", line 1337, in get
v = v()
File "/Users/maurits/shared-eggs/cp27m/Zope2-2.13.26-py2.7.egg/Products/Sessions/SessionDataManager.py", line 101, in getSessionData
return self._getSessionDataObject(key)
File "/Users/maurits/shared-eggs/cp27m/Zope2-2.13.26-py2.7.egg/Products/Sessions/SessionDataManager.py", line 188, in _getSessionDataObject
ob = container.new_or_existing(key)
File "/Users/maurits/shared-eggs/cp27m/Zope2-2.13.26-py2.7.egg/Products/Transience/Transience.py", line 839, in new_or_existing
item = self.get(key, _marker)
File "/Users/maurits/shared-eggs/cp27m/Zope2-2.13.26-py2.7.egg/Products/Transience/Transience.py", line 495, in get
item = self._move_item(k, current_ts, default)
File "/Users/maurits/shared-eggs/cp27m/Zope2-2.13.26-py2.7.egg/Products/Transience/Transience.py", line 314, in _move_item
if abucket.get(k, None) is not None:
File "/Users/maurits/shared-eggs/cp27m/ZODB-5.3.0-py2.7.egg/ZODB/Connection.py", line 796, in setstate
p, serial = self._storage.load(oid)
File "/Users/maurits/shared-eggs/cp27m/ZODB-5.3.0-py2.7.egg/ZODB/mvccadapter.py", line 143, in load
r = self._storage.loadBefore(oid, self._start)
File "/Users/maurits/shared-eggs/cp27m/tempstorage-4.0.1-py2.7.egg/tempstorage/TemporaryStorage.py", line 187, in loadBefore
raise POSException.POSKeyError(oid)
POSKeyError: 0x13
In this case I actually catch the error and ignore it, so the visitor would not immediately notice, but she is no longer authenticated.
Sometimes it also just works. I don't know why. Maybe it only fails when a BTree in the session needs to be reshuffled or something.
In the traceback I first got a KeyError, but I updated tempstorage
from 4.0 to 4.0.1 to see if that would fix it (see https://github.com/zopefoundation/tempstorage/issues/5), but that just turns the KeyError into a POSKeyError.
Strangely I get other tracebacks in between, which seem not related to any request:
2018-03-02T16:07:51 ERROR ZODB.Connection Couldn't load state for BTrees.OOBTree.OOBTree 0x13
Traceback (most recent call last):
File "/Users/maurits/shared-eggs/cp27m/ZODB-5.3.0-py2.7.egg/ZODB/Connection.py", line 796, in setstate
p, serial = self._storage.load(oid)
File "/Users/maurits/shared-eggs/cp27m/ZODB-5.3.0-py2.7.egg/ZODB/mvccadapter.py", line 143, in load
r = self._storage.loadBefore(oid, self._start)
File "/Users/maurits/shared-eggs/cp27m/tempstorage-4.0.1-py2.7.egg/tempstorage/TemporaryStorage.py", line 187, in loadBefore
raise POSException.POSKeyError(oid)
POSKeyError: 0x13
I created a Python Script that ought to trigger it, even in a fresh Zope database:
print 'setting value in session'
session = context.REQUEST.SESSION
# Same:
# sdm = context.session_data_manager
# session = sdm.getSessionData(create=True)
print session.get('foobar')
session.set('foobar', 'snap')
print session.get('foobar')
# To temporarily trigger an error, uncomment the next line:
# 1/0
return printed
In theory, calling this script once, should work fine. Then visit a non existing page, to trigger a 404 exception, or uncomment the 1/0
for a ZeroDivisionError
. Then call the script again, and it should trigger a POSKeyError. I saw that in the Plone coredev buildout too, so without my PAS plugin:
2018-03-02 13:49:03 ERROR Zope.SiteErrorLog 1519994943.60.99781176981 http://127.0.0.1:8080/testsession
Traceback (innermost last):
Module ZPublisher.Publish, line 138, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 48, in call_object
Module Shared.DC.Scripts.Bindings, line 322, in __call__
Module Shared.DC.Scripts.Bindings, line 359, in _bindAndExec
Module Products.PythonScripts.PythonScript, line 344, in _exec
Module script, line 2, in testsession
- <PythonScript at /testsession>
- Line 2
Module ZPublisher.HTTPRequest, line 1380, in __getattr__
Module ZPublisher.HTTPRequest, line 1337, in get
Module Products.Sessions.SessionDataManager, line 101, in getSessionData
Module Products.Sessions.SessionDataManager, line 188, in _getSessionDataObject
Module Products.Transience.Transience, line 839, in new_or_existing
Module Products.Transience.Transience, line 495, in get
Module Products.Transience.Transience, line 314, in _move_item
Module ZODB.Connection, line 796, in setstate
Module ZODB.mvccadapter, line 143, in load
Module tempstorage.TemporaryStorage, line 187, in loadBefore
POSKeyError: 0x12
Except: it doesn't always trigger. So it's tricky. Maybe it only goes wrong when the same browser is doing too many requests (for css/js in dev mode) in short succession. But once it is triggered, every request that tries to access the session will fail, until you restart Zope.
I couldn't trigger it in Plone 4.3 and 5.0 at all. It could be that this is because these still use older ZODB versions.
In Plone 5.2 I got an AttributeError for request.SESSION
, because the session machinery (see http://zope.readthedocs.io/en/latest/zope2book/Sessions.html#default-configuration) is apparently not setup in Zope 4.
Am I using sessions wrongly?
Should I be using plone.session
instead? But I don't quite see how I would use that to write something to a session without using the exact same Zope session machinery that is failing me.
I may need to switch to storing some stuff in a cookie instead.