Ticket #2066: session_engines.diff
File session_engines.diff, 25.6 KB (added by , 17 years ago) |
---|
-
django/test/client.py
4 4 from urlparse import urlparse 5 5 from django.conf import settings 6 6 from django.contrib.auth import authenticate, login 7 from django.contrib.sessions.models import Session8 from django.contrib.sessions.middleware import SessionWrapper9 7 from django.core.handlers.base import BaseHandler 10 8 from django.core.handlers.wsgi import WSGIRequest 11 9 from django.core.signals import got_request_exception … … 129 127 def _session(self): 130 128 "Obtain the current session variables" 131 129 if 'django.contrib.sessions' in settings.INSTALLED_APPS: 130 engine = __import__(settings.SESSION_ENGINE, {}, {}, ['']) 132 131 cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None) 133 132 if cookie: 134 return SessionWrapper(cookie.value)133 return engine.SessionClass(cookie.value) 135 134 return {} 136 135 session = property(_session) 137 136 … … 229 228 """ 230 229 user = authenticate(**credentials) 231 230 if user and 'django.contrib.sessions' in settings.INSTALLED_APPS: 232 obj = Session.objects.get_new_session_object()233 231 engine = __import__(settings.SESSION_ENGINE, {}, {}, ['']) 232 234 233 # Create a fake request to store login details 235 234 request = HttpRequest() 236 request.session = SessionWrapper(obj.session_key)235 request.session = engine.SessionClass() 237 236 login(request, user) 238 237 239 238 # Set the cookie to represent the session 240 self.cookies[settings.SESSION_COOKIE_NAME] = obj.session_key239 self.cookies[settings.SESSION_COOKIE_NAME] = request.session.session_key 241 240 self.cookies[settings.SESSION_COOKIE_NAME]['max-age'] = None 242 241 self.cookies[settings.SESSION_COOKIE_NAME]['path'] = '/' 243 242 self.cookies[settings.SESSION_COOKIE_NAME]['domain'] = settings.SESSION_COOKIE_DOMAIN 244 243 self.cookies[settings.SESSION_COOKIE_NAME]['secure'] = settings.SESSION_COOKIE_SECURE or None 245 244 self.cookies[settings.SESSION_COOKIE_NAME]['expires'] = None 246 245 247 # Set the session values 248 Session.objects.save(obj.session_key, request.session._session, 249 datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)) 246 # Save the session values 247 request.session.save() 250 248 251 249 return True 252 250 else: -
django/conf/global_settings.py
270 270 SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only). 271 271 SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request. 272 272 SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser. 273 SESSION_ENGINE = 'django.contrib.sessions.engines.db' # The module to store session data 274 SESSION_FILE_PATH = '/tmp/' # Directory to store session files if using the file session module 273 275 274 276 ######### 275 277 # CACHE # -
django/contrib/sessions/middleware.py
1 1 from django.conf import settings 2 from django.contrib.sessions.models import Session3 from django.core.exceptions import SuspiciousOperation4 2 from django.utils.cache import patch_vary_headers 5 3 import datetime 6 4 7 TEST_COOKIE_NAME = 'testcookie'8 TEST_COOKIE_VALUE = 'worked'9 10 class SessionWrapper(object):11 def __init__(self, session_key):12 self.session_key = session_key13 self.accessed = False14 self.modified = False15 16 def __contains__(self, key):17 return key in self._session18 19 def __getitem__(self, key):20 return self._session[key]21 22 def __setitem__(self, key, value):23 self._session[key] = value24 self.modified = True25 26 def __delitem__(self, key):27 del self._session[key]28 self.modified = True29 30 def keys(self):31 return self._session.keys()32 33 def items(self):34 return self._session.items()35 36 def get(self, key, default=None):37 return self._session.get(key, default)38 39 def pop(self, key, *args):40 return self._session.pop(key, *args)41 42 def set_test_cookie(self):43 self[TEST_COOKIE_NAME] = TEST_COOKIE_VALUE44 45 def test_cookie_worked(self):46 return self.get(TEST_COOKIE_NAME) == TEST_COOKIE_VALUE47 48 def delete_test_cookie(self):49 del self[TEST_COOKIE_NAME]50 51 def _get_session(self):52 # Lazily loads session from storage.53 self.accessed = True54 try:55 return self._session_cache56 except AttributeError:57 if self.session_key is None:58 self._session_cache = {}59 else:60 try:61 s = Session.objects.get(session_key=self.session_key,62 expire_date__gt=datetime.datetime.now())63 self._session_cache = s.get_decoded()64 except (Session.DoesNotExist, SuspiciousOperation):65 self._session_cache = {}66 # Set the session_key to None to force creation of a new67 # key, for extra security.68 self.session_key = None69 return self._session_cache70 71 _session = property(_get_session)72 73 5 class SessionMiddleware(object): 6 """ 7 Django Session Middleware 8 """ 74 9 def process_request(self, request): 75 request.session = SessionWrapper(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)) 10 engine = __import__(settings.SESSION_ENGINE, {}, {}, ['']) 11 request.session = engine.SessionStore(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)) 76 12 77 13 def process_response(self, request, response): 78 14 # If request.session was modified, or if response.session was set, save … … 86 22 if accessed: 87 23 patch_vary_headers(response, ('Cookie',)) 88 24 if modified or settings.SESSION_SAVE_EVERY_REQUEST: 89 if request.session.session_key:90 session_key = request.session.session_key91 else:92 obj = Session.objects.get_new_session_object()93 session_key = obj.session_key94 95 25 if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE: 96 26 max_age = None 97 27 expires = None 98 28 else: 99 29 max_age = settings.SESSION_COOKIE_AGE 100 expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")101 new_session = Session.objects.save(session_key, request.session._session,102 datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))103 response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,30 expires = datetime.datetime.strftime(datetime.datetime.utcnow() + \ 31 datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT") 32 request.session.save() 33 response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key, 104 34 max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, 105 35 secure=settings.SESSION_COOKIE_SECURE or None) 106 36 return response -
django/contrib/sessions/engines/base.py
1 from django.conf import settings 2 from django.utils.cache import patch_vary_headers 3 import base64, md5, datetime, random, os, sys 4 import cPickle as pickle 5 6 TEST_COOKIE_NAME = 'testcookie' 7 TEST_COOKIE_VALUE = 'worked' 8 9 class SessionBase(object): 10 """ 11 MetaClass for all Session classes. 12 """ 13 def __init__(self, session_key=None): 14 self._session_key = session_key 15 self.accessed = False 16 self.modified = False 17 18 def __contains__(self, key): 19 return key in self._session 20 21 def __getitem__(self, key): 22 return self._session[key] 23 24 def __setitem__(self, key, value): 25 self._session[key] = value 26 self.modified = True 27 28 def __delitem__(self, key): 29 del self._session[key] 30 self.modified = True 31 32 def keys(self): 33 return self._session.keys() 34 35 def items(self): 36 return self._session.items() 37 38 def get(self, key, default=None): 39 return self._session.get(key, default) 40 41 def pop(self, key, *args): 42 return self._session.pop(key, *args) 43 44 def set_test_cookie(self): 45 self[TEST_COOKIE_NAME] = TEST_COOKIE_VALUE 46 47 def test_cookie_worked(self): 48 return self.get(TEST_COOKIE_NAME) == TEST_COOKIE_VALUE 49 50 def delete_test_cookie(self): 51 del self[TEST_COOKIE_NAME] 52 53 def encode(self, session_dict): 54 "Returns the given session dictionary pickled and encoded as a string." 55 pickled = pickle.dumps(session_dict) 56 pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest() 57 return base64.encodestring(pickled + pickled_md5) 58 59 def decode(self, session_data): 60 encoded_data = base64.decodestring(session_data) 61 pickled, tamper_check = encoded_data[:-32], encoded_data[-32:] 62 if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check: 63 from django.core.exceptions import SuspiciousOperation 64 raise SuspiciousOperation, "User tampered with session cookie." 65 try: 66 return pickle.loads(pickled) 67 # Unpickling can cause a variety of exceptions. If something happens, 68 # just return an empty dictionary (an empty session). 69 except: 70 return {} 71 72 def _get_new_session_key(self): 73 "Returns session key that isn't being used." 74 # The random module is seeded when this Apache child is created. 75 # Use person_id and SECRET_KEY as added salt. 76 while 1: 77 session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1), 78 os.getpid(), time.time(), settings.SECRET_KEY)).hexdigest() 79 if not self.exists(session_key): 80 break 81 return session_key 82 83 def _get_session_key(self): 84 if self._session_key: 85 return self._session_key 86 else: 87 self._session_key = self._get_new_session_key() 88 return self._session_key 89 90 def _set_session_key(self, session_key): 91 self._session_key = session_key 92 93 session_key = property(_get_session_key, _set_session_key) 94 95 def _get_session(self): 96 # Lazily loads session from storage. 97 self.accessed = True 98 try: 99 return self._session_cache 100 except AttributeError: 101 if self.session_key is None: 102 self._session_cache = {} 103 else: 104 self._session_cache = self.load() 105 return self._session_cache 106 107 _session = property(_get_session) 108 109 def exists(self, session_key): 110 """ 111 returns True if the the session_key already exists in the 112 session store 113 """ 114 raise NotImplementedError 115 116 def save(self): 117 """ 118 saves self._session associated self.session_key in the 119 session store 120 """ 121 raise NotImplementedError 122 123 def delete(self, session_key): 124 """ 125 deletes the session data associated with session_key 126 """ 127 raise NotImplementedError 128 129 def load(self): 130 """ 131 returns a dictionary with the session data from the session 132 store associated with self.session_key 133 """ 134 raise NotImplementedError 135 -
django/contrib/sessions/engines/file.py
1 import base64, md5, random, sys, datetime, os 2 import cPickle as pickle 3 from django.conf import settings 4 from django.contrib.sessions.models import Session 5 from django.contrib.sessions.engines.base import SessionBase 6 from django.core.exceptions import SuspiciousOperation 7 from django.utils.cache import patch_vary_headers 8 import datetime 9 10 class SessionStore(SessionBase): 11 """ 12 Implements a file based session store. 13 """ 14 def __init__(self, session_key=None): 15 self.storage_path = settings.SESSION_FILE_PATH 16 self.file_prefix = settings.SESSION_COOKIE_NAME 17 super(SessionStore, self).__init__(session_key) 18 19 def _key_to_file(self, session_key=None): 20 if session_key is None: 21 session_key = self.session_key 22 return os.path.join(self.storage_path, self.file_prefix + session_key) 23 24 def load(self): 25 session_data = {} 26 try: 27 session_file = open(self._key_to_file(), "rb") 28 try: 29 session_data = self.decode(session_file.read()) 30 except(EOFError, SuspiciousOperation): 31 self._session_key = self._get_new_session_key() 32 self._session_cache = {} 33 #save to minimize collision 34 self.save() 35 finally: 36 session_file.close() 37 except(IOError): 38 pass 39 return session_data 40 41 def save(self): 42 try: 43 f = open(self._key_to_file(self.session_key), "wb") 44 try: 45 f.write(self.encode(self._session)) 46 finally: 47 f.close() 48 except(IOError, EOFError): 49 pass 50 51 def exists(self, session_key): 52 if os.path.exists(self._key_to_file(session_key)): 53 return True 54 return False 55 56 def delete(self, session_key): 57 try: 58 os.unlink(self._key_to_file(session_key)) 59 except OSError: 60 pass 61 62 def clean(self): 63 pass 64 No newline at end of file -
django/contrib/sessions/engines/cache.py
1 import base64, md5, random, sys, datetime, os 2 from django.conf import settings 3 from django.contrib.sessions.engines.base import SessionBase 4 from django.core.exceptions import SuspiciousOperation 5 from django.utils.cache import patch_vary_headers 6 from django.core.cache import cache 7 8 class SessionStore(SessionBase): 9 """ 10 Implements a cache based session store. 11 """ 12 def __init__(self, session_key=None): 13 self._cache = cache 14 super(SessionStore, self).__init__(session_key) 15 16 def load(self): 17 session_data = self._cache.get(self.session_key) 18 return session_data 19 20 def save(self): 21 self._cache.set(self.session_key, self._session, settings.SESSION_COOKIE_AGE) 22 23 def exists(self, session_key): 24 if self._cache.get(session_key): 25 return True 26 return False 27 28 def delete(self, session_key): 29 self._cache.delete(session_key) 30 No newline at end of file -
django/contrib/sessions/engines/db.py
1 from django.conf import settings 2 from django.contrib.sessions.models import Session 3 from django.contrib.sessions.engines.base import SessionBase 4 from django.core.exceptions import SuspiciousOperation 5 import datetime 6 7 class SessionStore(SessionBase): 8 """ 9 Implements database session store 10 """ 11 def __init__(self, session_key=None): 12 super(SessionStore, self).__init__(session_key) 13 14 def load(self): 15 try: 16 s = Session.objects.get(session_key=self.session_key, 17 expire_date__gt=datetime.datetime.now()) 18 return self.decode(s.session_data) 19 except (Session.DoesNotExist, SuspiciousOperation): 20 # Create a new session_key for extra security. 21 self.session_key = self._get_new_session_key() 22 self._session_cache = {} 23 #save to minimize collision 24 self.save() 25 return {} 26 27 def exists(self, session_key): 28 try: 29 Session.objects.get(session_key=session_key) 30 except Session.DoesNotExist: 31 return False 32 return True 33 34 def save(self): 35 s = Session(self.session_key, self.encode(self._session), datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)) 36 s.save() 37 38 def delete(self, session_key): 39 try: 40 s = Session.objects.get(session_key=session_key) 41 s.delete() 42 except Session.DoesNotExist: 43 pass 44 No newline at end of file -
django/contrib/sessions/tests.py
1 1 r""" 2 >>> s = SessionWrapper(None) 2 >>> db_session = DatabaseSession() 3 >>> db_session.modified 4 False 5 >>> db_session['cat'] = "dog" 6 >>> db_session.modified 7 True 8 >>> db_session.pop('cat') 9 'dog' 10 >>> db_session.pop('some key', 'does not exist') 11 'does not exist' 12 >>> db_session.save() 13 >>> db_session.exists(db_session.session_key) 14 True 15 >>> db_session.delete(db_session.session_key) 16 >>> db_session.exists(db_session.session_key) 17 False 3 18 4 Inject data into the session cache. 5 >>> s._session_cache = {} 6 >>> s._session_cache['some key'] = 'exists' 19 >>> file_session = FileSession() 20 >>> file_session.modified 21 False 22 >>> file_session['cat'] = "dog" 23 >>> file_session.modified 24 True 25 >>> file_session.pop('cat') 26 'dog' 27 >>> file_session.pop('some key', 'does not exist') 28 'does not exist' 29 >>> file_session.save() 30 >>> file_session.exists(file_session.session_key) 31 True 32 >>> file_session.delete(file_session.session_key) 33 >>> file_session.exists(file_session.session_key) 34 False 7 35 8 >>> s.pop('some key') 9 'exists' 10 11 >>> s.pop('some key', 'does not exist') 36 >>> cache_session = CacheSession() 37 >>> cache_session.modified 38 False 39 >>> cache_session['cat'] = "dog" 40 >>> cache_session.modified 41 True 42 >>> cache_session.pop('cat') 43 'dog' 44 >>> cache_session.pop('some key', 'does not exist') 12 45 'does not exist' 46 >>> cache_session.save() 47 >>> cache_session.exists(cache_session.session_key) 48 True 49 >>> cache_session.delete(cache_session.session_key) 50 >>> cache_session.exists(cache_session.session_key) 51 False 13 52 """ 14 53 15 from django.contrib.sessions.middleware import SessionWrapper 54 from django.contrib.sessions.engines.db import SessionStore as DatabaseSession 55 from django.contrib.sessions.engines.cache import SessionStore as CacheSession 56 from django.contrib.sessions.engines.file import SessionStore as FileSession 57 from django.conf import settings 16 58 17 59 if __name__ == '__main__': 18 60 import doctest -
django/contrib/sessions/models.py
1 import base64, md5, random, sys, datetime 1 import base64, md5, random, sys, datetime, os, time 2 2 import cPickle as pickle 3 3 from django.db import models 4 4 from django.utils.translation import gettext_lazy as _ … … 14 14 def get_new_session_key(self): 15 15 "Returns session key that isn't being used." 16 16 # The random module is seeded when this Apache child is created. 17 # Use person_id andSECRET_KEY as added salt.17 # Use SECRET_KEY as added salt. 18 18 while 1: 19 session_key = md5.new(str(random.randint(0, sys.maxint - 1)) + str(random.randint(0, sys.maxint - 1)) + settings.SECRET_KEY).hexdigest() 19 session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1), 20 os.getpid(), time.time(), settings.SECRET_KEY)).hexdigest() 20 21 try: 21 22 self.get(session_key=session_key) 22 23 except self.model.DoesNotExist: -
docs/sessions.txt
10 10 Enabling sessions 11 11 ================= 12 12 13 Sessions are implemented via a piece of middleware_ and a Django model.13 Sessions are implemented via a piece of middleware_. 14 14 15 To enable session functionality, do the se two things:15 To enable session functionality, do the following: 16 16 17 17 * Edit the ``MIDDLEWARE_CLASSES`` setting and make sure 18 18 ``MIDDLEWARE_CLASSES`` contains ``'django.contrib.sessions.middleware.SessionMiddleware'``. 19 19 The default ``settings.py`` created by ``django-admin.py startproject`` has 20 20 ``SessionMiddleware`` activated. 21 21 22 * Add ``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting, and 23 run ``manage.py syncdb`` to install the single database table that stores 24 session data. 22 * If using the default database session engine add ``'django.contrib.sessions'`` 23 to your ``INSTALLED_APPS`` setting, and run ``manage.py syncdb`` to install 24 the single database table that stores session data. 25 26 * If using the file based session engine set the ``SESSION_FILE_PATH`` setting in 27 ``settings.py`` to the directory that you want sessions stored. 28 29 * If using the cache based session engine ensure that the Django cache_ framework 30 is configured correctly. 25 31 26 32 If you don't want to use sessions, you might as well remove the 27 33 ``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES`` and ``'django.contrib.sessions'`` 28 34 from your ``INSTALLED_APPS``. It'll save you a small bit of overhead. 29 35 30 36 .. _middleware: ../middleware/ 37 .. _cache: ../cache/ 31 38 32 39 Using sessions in views 33 40 ======================= … … 65 72 cookies. Due to the way cookies work, you won't be able to test this 66 73 until the user's next page request. See "Setting test cookies" below for 67 74 more information. 68 75 ` 69 76 * ``test_cookie_worked()`` 70 77 Returns either ``True`` or ``False``, depending on whether the user's 71 78 browser accepted the test cookie. Due to the way cookies work, you'll … … 153 160 Using sessions out of views 154 161 =========================== 155 162 156 Internally, each session is just a normal Django model. The ``Session`` model 163 The ``SessionStore`` which implements the session storage method can be imported 164 and a API is available to manipulate the session data outside of a view:: 165 166 >>> from django.contrib.sessions.engines.db import SessionStore 167 >>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead') 168 >>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10) 169 >>> s['last_login'] 170 datetime.datetime(2005, 8, 20, 13, 35, 0) 171 >>> s.save() 172 173 Or if you are using the ``django.contrib.sessions.engine.db`` each 174 session is just a normal Django model. The ``Session`` model 157 175 is defined in ``django/contrib/sessions/models.py``. Because it's a normal 158 176 model, you can access sessions using the normal Django database API:: 159 177 160 178 >>> from django.contrib.sessions.models import Session 161 179 >>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead') 162 180 >>> s.expire_date 163 datetime.datetime(2005, 8, 20, 13, 35, 12) 181 datetime.datetime(2005, 8, 20, 13, 35, 12) 164 182 165 183 Note that you'll need to call ``get_decoded()`` to get the session dictionary. 166 184 This is necessary because the dictionary is stored in an encoded format:: … … 239 257 240 258 A few `Django settings`_ give you control over session behavior: 241 259 260 **New in Django development version** 261 262 SESSION_ENGINE 263 -------------- 264 265 Default: ``django.contrib.sessions.engines.db`` 266 267 Django sessions have configurable backends for the method of storage. The 268 setting ``SESSION_ENGINE`` in ``settings.py`` refers to the module which implements 269 the session backend. 270 Django comes with three session engines: 271 272 * ``'django.contrib.sessions.engines.db'`` is the default session storage method. 273 All data is encoded and stored in the database. 274 275 * ``'django.contrib.sessions.engines.file'`` a simple file based session storage 276 method. Each session is encoded and stored in individual files on the server. 277 278 * ``'django.contrib.sessions.engines.cache'`` based on the Django cache_ framework. 279 Sessions are stored in the configured cache backend. 280 281 .. _cache: ../cache/ 282 283 SESSION_FILE_PATH 284 ----------------- 285 286 Default: ``/tmp/`` 287 288 If the module associated with ``SESSION_ENGINE`` is ``'django.contrib.sessions.file'`` 289 this is the directory which session files are stored in. 290 242 291 SESSION_COOKIE_AGE 243 292 ------------------ 244 293