dound / gae-sessions Goto Github PK
View Code? Open in Web Editor NEWFast, lightweight Sessions middleware for Google App Engine (secure cookies, memcache, or datastore)
Home Page: http://wiki.github.com/dound/gae-sessions/
Fast, lightweight Sessions middleware for Google App Engine (secure cookies, memcache, or datastore)
Home Page: http://wiki.github.com/dound/gae-sessions/
Is it possible to have a session.extend() function that extends the expiration of the session with default: the default lifetime to the current session or otherwise accepting a timedelta as the new extension.
Hi there,
could anybody tell me how to set the expire time to 0(session cookie)? Latest commit added support of expire time value 0. But it does not mention how to use that feature. I have tired
app = SessionMiddleware(app, cookie_key=COOKIE_KEY, lifetime=datetime.timedelta(0)) which does not work.
Thanks
Hi,
I'm using gae-sessions on a gae app and it works great, except that when an ajax request is triggered on a page, the next non-ajax request from the page (for example - refreshing the page) - causes the session to become inactive (the logs show "received invalid cookie sig"), and so the user is logged out.
What could be the problem ?
Thanks,
I think a debug logging.info was sneaked in along with the Varying header changes. Consider applying the following patch:
--- init.py.old 2011-11-03 09:52:36.901687097 +0100
+++ init.py 2011-11-03 09:52:39.677700872 +0100
@@ -487,7 +487,6 @@
self.response_handler = None
if request.session.is_accessed():
from django.utils.cache import patch_vary_headers
logging.info("Varying")
patch_vary_headers(response, ('Cookie',))
return response
It would he handy to pass in a cookie_path variable to the SessionMiddleware to allow for multiple cookies / cookie_keys to be used on the same domain.
My case: I have a web app that has two distinct areas that required different security settings. One area doesn't allow session data to be stored in a cookie while the other one does. I am currently setting cookie_key to a different values but by doing so the first / alternative session get squashed.
If you have any suggestions - I'm all ears :)
I just run the demo-with-google-logins but it failed. I use windows7 and Google app engine launcher.
File "D:\Website\dound-gae-sessions-26bd298\demo-with-google-logins\gaesessions__init__.py", line 414, in init
raise ValueError("RFC2104 recommends you use at least a 32 character key. Try os.urandom(64) to make a key.")
ValueError: RFC2104 recommends you use at least a 32 character key. Try os.urandom(64) to make a key.
gaesessions doesn't work while unit testing under WebTest-1.2.3 and NoseGAE 0.1.7.
The issue is with the cookies being read from os.environ['HTTP_COOKIE']. Webtest doesn't seem to set that env variable. If I manually set it before making the get request it works fine.
More details here:
http://stackoverflow.com/questions/5348896/nosegae-unit-tests-with-gae-session-on-a-python-google-app-engine-project/
Trying your demo:
class LogoutPage(webapp.RequestHandler):
def get(self):
session = get_current_session()
if session.has_key('me'):
# update the user's record with total views
myuser = session['me']
myuser.past_view_count += session['pvsli']
myuser.put()
session.terminate()
redirect_with_msg(self, 'Logout complete: goodbye ' + myuser.user.nickname())
else:
redirect_with_msg(self, "How silly, you weren't logged in")
and I get
ERROR 2010-07-30 05:00:05,329 init.py:391] 'NoneType' object has no attribute 'has_key'
if session.has_key('me'):
AttributeError: 'NoneType' object has no attribute 'has_key'
Other than that, things are looking good. Thanks for writing gae-sessions.
To have the possibility of enable or disable these security features:
dev_appserver returns local time on windows when datetime.datetime.now() is called in __make_sid. This caused cookies to expire incorrectly since local time is formatted with the required GMT substring. I found that using datetime.datetime.utcnow() solved this.
Apparently, this is not a problem on Appserver production since google use UTC in the cloud.
I like gae-sessions, and I have made some great improvements in my fork:
https://github.com/MikeBrooks/gae-sessions
As a cryptographer the use of MD5 bothers me because it is a broken primitive. Although there are numerous vulnerabilities in md5, this doesn't undermine this session handler, however it isn't going to help. If GAE's os.urandom() is anything like /dev/urandom then it is a very good source of entropy and all values returned by this function have already passed though a hash function. In general you should choose one cryptographic hash fiction and use it everywhere, and a member of sha2 isn't a bad choice.
Cryptography should only be used when there is no other choice. It is better to have an absolute solution because when a cryptographic system breaks its bad. A good example is the ASP.NET padding oracle attack:
https://www.owasp.org/index.php/ASP.NET_POET_Vulnerability
An HMAC is useful for protecting a payload from being modified. However they always suffer from the "birthday attack". This attack is refering to the large number of input messages that produce the same output authentication code. For this attack it doesn't matter how long your secret is. It is best to avoid this scenario whenever possible, because its a waste of resources.
When gae-sessions is using the database only the SID value is needed. The introduction of an HMAC doesn't improve security, in fact it introduces the possibility of attack. In that if an attacker used the birthday attack he could create a new message with a timestamp in the future that has a valid signature which would cause the is_active() method to return true.
Hopefully an application's authentication system doesn't rely upon is_active(), but this is easy to avoid by removing the HMAC and verifying this value with the database.
Improvements:
(efficiency)Session id length cut in more than half
(efficiency)timestamp in SID has been reduced form 10 bytes to 4 bytes with bit packing
(efficiency)add a cron job to the demos to delete stale cookies (This should also be added to the install doc)
(efficiency)Hash functions used to generate session id cut from 3 to just 1
(Security)SIDs contain more entropy
(Security)removed use of md5()
(bug)SID_LEN can now be changed without causing offset exceptions
(bug)delete_expired_sessions function was not checking remaining cookies properly
While testing a new GAE application (1.3.7) w/ just gaesessions and webapp.template get_current_session() returns None in local enviorment.
Using this to test:
from gaesessions import get_current_session
import logging
session = get_current_session()
logging.info(session)
No entries are created in the datastore.
Is this a problem in 1.3.7?
Can i set non-fixed life time?
if set DEFAULT_LIFETIME = datetime.timedelta(days=1)
All life time is 1 day.
Sometimes the need to set 1 hour, but sometimes need to set 1 day.
The error log as below:
Traceback (most recent call last):
File "/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/__init__.py", line 511, in __call__
handler.get(*groups)
File "/base/data/home/apps/guessnumberftw/1.345814701810313210/guessnum.py", line 49, in get
if session.is_active():
AttributeError: 'NoneType' object has no attribute 'is_active'
I have already had 'appengine_config.py' which is copy from 'demo-with-google-logins', but it still donesn't work.
Hi, I am trying to load store, nested dictionary in session in one POST handler, and retrieve it in another GET post handler. It seems somehow it is not storing nested dictionaries and it is being emptied. Below is the sample LOGS from GAE debug session.
INFO 2013-04-27 00:03:54,962 genergy.py:715] SID=1367625833_21d8679ec0f7dab4c125da6e4ea2fa3b {'after': {}, 'after_dcs': 1, 'current_dcs': 1, 'current': {1: {'dc_state': u'', 'redundancy': u'N', 'users_servers': u'option1', 'dc_type': 'Closet', 'nbr_servers': 1.0, 'nbr_users': 25.0, 'user_host': u'300', 'server_user_ratio': 1.0, 'application': 'Email', 'dc_country': u'', 'carbon': u'343'}}, 'model': 'current', 'first': True}
INFO 2013-04-27 00:03:54,963 recording.py:673] Saved; key: appstats:034900, part: 21 bytes, full: 1619 bytes, overhead: 0.000 + 0.001; link: http://localhost:8082/_ah/stats/details?time=1367021034959
INFO 2013-04-27 00:03:54,970 dev_appserver.py:3104] "POST / HTTP/1.1" 302 -
INFO 2013-04-27 00:03:54,983 genergy.py:478] SID=1367625833_21d8679ec0f7dab4c125da6e4ea2fa3b {'after': {}, 'after_dcs': 1, 'current_dcs': 1, 'current': {}, 'model': 'current', 'first': True}
ERROR 2013-04-27 00:03:54,985 webapp2.py:1552] 1
Could you please check , whether nested dictionary values can be stored in sessions or not.
thanks
pradeep
I see the following backtrace semi-occasionally -- I think it happens with a stale cookie but I haven't really traced it down. Any suggestions?
ERROR:root:Exception encountered handling request Traceback (most recent call last): File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/tools/dev_appserver.py", line 3245, in _HandleRequest self._Dispatch(dispatcher, self.rfile, outfile, env_dict) File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/tools/dev_appserver.py", line 3186, in _Dispatch base_env_dict=env_dict) File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/tools/dev_appserver.py", line 531, in Dispatch base_env_dict=base_env_dict) File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/tools/dev_appserver.py", line 2410, in Dispatch self._module_dict) File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/tools/dev_appserver.py", line 2320, in ExecuteCGI reset_modules = exec_script(handler_path, cgi_path, hook) File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/tools/dev_appserver.py", line 2216, in ExecuteOrImportScript exec module_code in script_module.__dict__ File "/home/ianw/programs/easygeotag-svn/main.py", line 52, in main() File "/home/ianw/programs/easygeotag-svn/main.py", line 49, in main util.run_wsgi_app(application) File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/ext/webapp/util.py", line 97, in run_wsgi_app run_bare_wsgi_app(add_wsgi_middleware(application)) File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/ext/webapp/util.py", line 115, in run_bare_wsgi_app result = application(env, _start_response) File "/home/ianw/programs/easygeotag-svn/django.zip/django/core/handlers/wsgi.py", line 241, in __call__ File "/home/ianw/programs/easygeotag-svn/django.zip/django/core/handlers/base.py", line 76, in get_response File "/home/ianw/programs/easygeotag-svn/gaesessions/__init__.py", line 462, in process_request self.response_handler = self.wrapped_wsgi_middleware(None, lambda status, headers, exc_info : headers) File "/home/ianw/programs/easygeotag-svn/gaesessions/__init__.py", line 438, in __call__ _current_session = Session(lifetime=self.lifetime, no_datastore=self.no_datastore, cookie_only_threshold=self.cookie_only_thresh, cookie_key=self.cookie_key) File "/home/ianw/programs/easygeotag-svn/gaesessions/__init__.py", line 70, in __init__ self.__read_cookie() File "/home/ianw/programs/easygeotag-svn/gaesessions/__init__.py", line 99, in __read_cookie self.data = self.__decode_data(pdump) File "/home/ianw/programs/easygeotag-svn/gaesessions/__init__.py", line 192, in __decode_data eO[k] = db.model_from_protobuf(v) File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/ext/db/__init__.py", line 332, in model_from_protobuf return class_for_kind(entity.kind()).from_entity(entity) File "/home/ianw/programs/easygeotag-svn/.google_appengine/google/appengine/ext/db/__init__.py", line 266, in class_for_kind raise KindError('No implementation for kind \'%s\'' % kind) KindError: No implementation for kind 'Person'
The most basic functionality seems to cease working. This snippet shows counter: 1
no matter how many times I refresh.
import webapp2
import sys
sys.path.insert(0, 'libs')
from libs.gaesessions import get_current_session
class TestGaeHandler(webapp2.RequestHandler):
def get(self):
self.post()
def post(self):
session = get_current_session()
c = session.get('counter', 0)
session['counter'] = c+1
counter = session['counter']
self.response.headers['Content-Type'] = 'text/html; charset=UTF-8'
self.response.write('counter: '+str(counter))
app = webapp2.WSGIApplication([
('/api/service/test_gae', TestGaeHandler)
], debug=True)
Please advise. Thanks
So after attempting to migrate my project to python2.7, I learned that sessions is not working in python 2.7.
The error seems to stem from appengine_config.py. This issue could stem from my incompetence.
Here is the error message:
Traceback (most recent call last):
File "c:\Program Files (x86)\Google\google_appengine\google\appengine\runtime\wsgi.py", line 195, in Handle
result = handler(dict(self._environ), self._StartResponse)
File "d:\Documents\dna_manip\gaesessions\__init__.py", line 472, in __call__
return self.app(environ, my_start_response)
TypeError: 'NoneType' object is not callable
Cookies expiration dates can be set to the special value, 0, which means that the cookie should be forgotten when the browser closes. However, this special value doesn't seemt to be supported in gae-sessions. I'll attach a patch that works for me. I found that the code currently depends on unix timestamps being exactly 10 characters long, which is mildly disturbing, and means that I had to zero-extend the timestamp for it to work with '0'.
Using gae-sessions in Windows 7, 64-bit application. I am running into a problem where the session isn't initiated, therefore all subsequent session-related activity can't proceed. It does not occur on Windows XP and when deployed to appspot, for example. Any one running into similar problems?
PHP session id: e8a54701d4551b8762b8add875a552c4 <-- 32
gae-sessions DgU00 id:
"4jJlnuj3/6dqxnAHthD2rpxoyiJLG/r2oxl2XwzFw+0=1281681340_d6ef1ccc2ffd341c70daed2c2026c796gAJ9cQBVAm1lcQEoY2dvb2dsZS5hcHBlbmdpbmUuZGF0YXN0b3JlLmVudGl0eV9wYgpFbnRpdHlQcm90bwpxAm9xA1W5ajFqDGh1bmdzaW1vbDAwMnIhCxIGTXlVc2VyIhUxMDk4MTIzNjgzNTA1MzQzNDk0NzAMchcaD3Bhc3Rfdmlld19jb3VudCAAKgIIBXJHGgR1c2VyIAAqPUNKE2h1bmdzaW1vbEBnbWFpbC5jb21SCWdtYWlsLmNvbZABAJoBFTEwOTgxMjM2ODM1MDUzNDM0OTQ3MESCASELEgZNeVVzZXIiFTEwOTgxMjM2ODM1MDUzNDM0OTQ3MAxxBWJzfXEGVQVwdnNsaXEHSwpzhnEILg==" <-- 459
Is it necessary?
Security? I don't think so. "Man-in-the-middle attack" can get header information.
Right now if you end up with a cookie with an invalid signature, no session is returned but it's not possible to make a new session, since the invalid one is in the way. Instead, the invalid session should be terminated and replaced.
Can you create a MiddleWare for Django?
So we can access it via request.session.
Thanks.
To have the possibility of enable or disable these features:
Firstly, thanks for this great little library! <3
During development, I like to move around and rename classes. I'm storing instances in my sessions, so when gaesessions unpickles my objects which no longer match up with classes, everything explodes.
My fix was to wrap __decode_data() in a try: ... except: return None.
Can't run in python2.7 with gae 1.5.5
In the readme it says "If you want to gae-sessions with Django, add 'gaesessions.DjangoSessionMiddleware' to your list of MIDDLEWARE_CLASSES in your settings.py file." Where is settings.py?
The app "gaesessions" contains imports in its init.py (at least hmac, os, datetime, .os, google, time, logging, base64, .google, .datetime, pickle, Cookie, .base64, .pickle, .hmac, .time, .Cookie, hashlib, .hashlib, .logging). This can cause strange bugs due to recursive imports! You should either do the import lazily (within functions) or ignore the app settings/urlsauto with IGNORE_APP_SETTINGS and IGNORE_APP_URLSAUTO in your settings.py.
Sessions often don't get deleted from the datastore, and need to be cleaned up. For example, when the user lets the cookie expire.
The only two ways I can think of cleaning up (as it is right now):
A better way to deal with this (in my opinion) is to prepend a creation time to the sid ( "1273169252_cc4a5...8aec5" ) so that we can simply do a key-only query for old keys (i.e. key < a specific time). This also lets us avoid loading the payload when we do these types of deletes. Another benefit of this, is reducing the chances of sid collisions. The only way a collision can happen with this type of ssid is if two md5(os.urandom(16)) calls return the same hash in the same second.
I just cloned the repo and ran nosetest .
inside the tests
directory.
Here's a stacktrace of the failure:
Traceback (most recent call last):
File "/Users/john/.virtualenvs/collabspot/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/Users/john/Projects/python/gae-sessions/tests/test_gaesessions.py", line 75, in check_correct_usage
st.noop()
File "/Users/john/Projects/python/gae-sessions/tests/SessionTester.py", line 232, in noop
self.finish_request_and_check()
File "/Users/john/Projects/python/gae-sessions/tests/SessionTester.py", line 151, in finish_request_and_check
resp = self.app.post('/', dict(rpcs=b64encode(pickle.dumps(self.rpcs)), api_statuses=b64encode(pickle.dumps(self.api_statuses))))
File "/Users/john/Projects/python/gae-sessions/tests/webtest/__init__.py", line 209, in post
content_type=content_type)
File "/Users/john/Projects/python/gae-sessions/tests/webtest/__init__.py", line 189, in _gen_request
expect_errors=expect_errors)
File "/Users/john/Projects/python/gae-sessions/tests/SessionTester.py", line 59, in do_request
ret = super(AppWithMultipleClients, self).do_request(req, status, expect_errors)
File "/Users/john/Projects/python/gae-sessions/tests/webtest/__init__.py", line 361, in do_request
res.body
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webob-1.2.3/webob/response.py", line 361, in _body__get
% (self.content_length, len(body))
AssertionError: Content-Length is different from actual app_iter length (0!=224)
"Content-Length is different from actual app_iter length "
"(%r!=%r)"
>> % (self.content_length, len('KChscDAKTmFjY29weV9yZWcKX3JlY29uc3RydWN0b3IKcDEKKGNtYWluClNlc3Npb25TdGF0ZQpwMgpjX19idWlsdGluX18Kb2JqZWN0CnAzCk50cDQKUnA1CihkcDYKUydpbl9tYycKcDcKSTAwCnNTJ2luX2RiJwpwOApJMDAKc1MnZGF0YScKcDkKKGRwMTAKc1Mnc2lkJwpwMTEKTnNidHAxMgou'))
OS X 10.9 with AppEngine SDK 1.9.17 and Python 2.7
namespaces change the behaviour of datastore and memcache. For session management, it seems it's important to use a specific namespace to avoid accidently missing session data.
Here is a patch. It may work in earlier SDK's than 1.3.6 but you need to wait for the 1.3.6 release to deploy unless you registered your app as a trusted tester.
Hi, shouldn't the secure option be set when a https connection is used (e.g. https://myapp.appspot.com)?
Problem solved. I can't delete this post.
Hi,
GAE should be multi-threaded with python 2.7.
gae-sessions use global _current_session, so I think it will not be "compatible" ?
What do you think about it ?
There is a topic about GAE/Thread-Safe here : https://groups.google.com/forum/#!topic/google-appengine/QUXR8jy1CMg
Regards
Sylvain
What's the license?
In the example : del session.blah # remove 'blah' from the session
I think it should be
del session['blah'] # remove 'blah' from the session
Regards
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.