Permalink
Browse files

queryset-refactor: Merged to [6340]

git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6341 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent ca33d30 commit 28a4aa6f49b11881d43a585f118a3d0537ba9084 @adrianholovaty adrianholovaty committed Sep 15, 2007
View
@@ -87,6 +87,7 @@ answer newbie questions, and generally made Django that much better:
Matt Croydon <http://www.postneo.com/>
flavio.curella@gmail.com
Jure Cuhalev <gandalf@owca.info>
+ John D'Agostino <john.dagostino@gmail.com>
dackze+django@gmail.com
David Danier <goliath.mailinglist@gmx.de>
Dirk Datzert <dummy@habmalnefrage.de>
@@ -271,12 +271,14 @@
# SESSIONS #
############
-SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever you want.
-SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
-SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
-SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
-SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
-SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
+SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever you want.
+SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
+SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
+SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
+SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
+SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
+SESSION_ENGINE = 'django.contrib.sessions.backends.db' # The module to store session data
+SESSION_FILE_PATH = '/tmp/' # Directory to store session files if using the file session module
#########
# CACHE #
@@ -10,6 +10,10 @@ def authenhandler(req, **kwargs):
# that so that the following import works
os.environ.update(req.subprocess_env)
+ # apache 2.2 requires a call to req.get_basic_auth_pw() before
+ # req.user and friends are available.
+ req.get_basic_auth_pw()
+
# check for PythonOptions
_str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
@@ -15,25 +15,43 @@
except NameError:
from sets import Set as set # Python 2.3 fallback
+def get_hexdigest(algorithm, salt, raw_password):
+ """
+ Returns a string of the hexdigest of the given plaintext password and salt
+ using the given algorithm ('md5', 'sha1' or 'crypt').
+ """
+ raw_password, salt = smart_str(raw_password), smart_str(salt)
+ if algorithm == 'crypt':
+ try:
+ import crypt
+ except ImportError:
+ raise ValueError('"crypt" password algorithm not supported in this environment')
+ return crypt.crypt(raw_password, salt)
+ # The rest of the supported algorithms are supported by hashlib, but
+ # hashlib is only available in Python 2.5.
+ try:
+ import hashlib
+ except ImportError:
+ if algorithm == 'md5':
+ import md5
+ return md5.new(salt + raw_password).hexdigest()
+ elif algorithm == 'sha1':
+ import sha
+ return sha.new(salt + raw_password).hexdigest()
+ else:
+ if algorithm == 'md5':
+ return hashlib.md5(salt + raw_password).hexdigest()
+ elif algorithm == 'sha1':
+ return hashlib.sha1(salt + raw_password).hexdigest()
+ raise ValueError("Got unknown password algorithm type in password.")
+
def check_password(raw_password, enc_password):
"""
Returns a boolean of whether the raw_password was correct. Handles
encryption formats behind the scenes.
"""
algo, salt, hsh = enc_password.split('$')
- if algo == 'md5':
- import md5
- return hsh == md5.new(smart_str(salt + raw_password)).hexdigest()
- elif algo == 'sha1':
- import sha
- return hsh == sha.new(smart_str(salt + raw_password)).hexdigest()
- elif algo == 'crypt':
- try:
- import crypt
- except ImportError:
- raise ValueError, "Crypt password algorithm not supported in this environment."
- return hsh == crypt.crypt(smart_str(raw_password), smart_str(salt))
- raise ValueError, "Got unknown password algorithm type in password."
+ return hsh == get_hexdigest(algo, salt, raw_password)
class SiteProfileNotAvailable(Exception):
pass
@@ -162,10 +180,10 @@ def get_full_name(self):
return full_name.strip()
def set_password(self, raw_password):
- import sha, random
+ import random
algo = 'sha1'
- salt = sha.new(str(random.random())).hexdigest()[:5]
- hsh = sha.new(salt + smart_str(raw_password)).hexdigest()
+ salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
+ hsh = get_hexdigest(algo, salt, raw_password)
self.password = '%s$%s$%s' % (algo, salt, hsh)
def check_password(self, raw_password):
@@ -176,8 +194,7 @@ def check_password(self, raw_password):
# Backwards-compatibility check. Older passwords won't include the
# algorithm or salt.
if '$' not in self.password:
- import md5
- is_correct = (self.password == md5.new(smart_str(raw_password)).hexdigest())
+ is_correct = (self.password == get_hexdigest('md5', '', raw_password))
if is_correct:
# Convert the password to the new, more secure format.
self.set_password(raw_password)
@@ -0,0 +1,143 @@
+import base64
+import md5
+import os
+import random
+import sys
+import time
+from django.conf import settings
+from django.core.exceptions import SuspiciousOperation
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+class SessionBase(object):
+ """
+ Base class for all Session classes.
+ """
+
+ TEST_COOKIE_NAME = 'testcookie'
+ TEST_COOKIE_VALUE = 'worked'
+
+ def __init__(self, session_key=None):
+ self._session_key = session_key
+ self.accessed = False
+ self.modified = False
+
+ def __contains__(self, key):
+ return key in self._session
+
+ def __getitem__(self, key):
+ return self._session[key]
+
+ def __setitem__(self, key, value):
+ self._session[key] = value
+ self.modified = True
+
+ def __delitem__(self, key):
+ del self._session[key]
+ self.modified = True
+
+ def keys(self):
+ return self._session.keys()
+
+ def items(self):
+ return self._session.items()
+
+ def get(self, key, default=None):
+ return self._session.get(key, default)
+
+ def pop(self, key, *args):
+ return self._session.pop(key, *args)
+
+ def set_test_cookie(self):
+ self[self.TEST_COOKIE_NAME] = self.TEST_COOKIE_VALUE
+
+ def test_cookie_worked(self):
+ return self.get(self.TEST_COOKIE_NAME) == self.TEST_COOKIE_VALUE
+
+ def delete_test_cookie(self):
+ del self[self.TEST_COOKIE_NAME]
+
+ def encode(self, session_dict):
+ "Returns the given session dictionary pickled and encoded as a string."
+ pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
+ pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
+ return base64.encodestring(pickled + pickled_md5)
+
+ def decode(self, session_data):
+ encoded_data = base64.decodestring(session_data)
+ pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
+ if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
+ raise SuspiciousOperation("User tampered with session cookie.")
+ try:
+ return pickle.loads(pickled)
+ # Unpickling can cause a variety of exceptions. If something happens,
+ # just return an empty dictionary (an empty session).
+ except:
+ return {}
+
+ def _get_new_session_key(self):
+ "Returns session key that isn't being used."
+ # The random module is seeded when this Apache child is created.
+ # Use settings.SECRET_KEY as added salt.
+ while 1:
+ session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1),
+ os.getpid(), time.time(), settings.SECRET_KEY)).hexdigest()
+ if not self.exists(session_key):
+ break
+ return session_key
+
+ def _get_session_key(self):
+ if self._session_key:
+ return self._session_key
+ else:
+ self._session_key = self._get_new_session_key()
+ return self._session_key
+
+ def _set_session_key(self, session_key):
+ self._session_key = session_key
+
+ session_key = property(_get_session_key, _set_session_key)
+
+ def _get_session(self):
+ # Lazily loads session from storage.
+ self.accessed = True
+ try:
+ return self._session_cache
+ except AttributeError:
+ if self.session_key is None:
+ self._session_cache = {}
+ else:
+ self._session_cache = self.load()
+ return self._session_cache
+
+ _session = property(_get_session)
+
+ # Methods that child classes must implement.
+
+ def exists(self, session_key):
+ """
+ Returns True if the given session_key already exists.
+ """
+ raise NotImplementedError
+
+ def save(self):
+ """
+ Saves the session data.
+ """
+ raise NotImplementedError
+
+ def delete(self, session_key):
+ """
+ Clears out the session data under this key.
+ """
+ raise NotImplementedError
+
+ def load(self):
+ """
+ Loads the session data and returns a dictionary.
+ """
+ raise NotImplementedError
+
@@ -0,0 +1,26 @@
+from django.conf import settings
+from django.contrib.sessions.backends.base import SessionBase
+from django.core.cache import cache
+
+class SessionStore(SessionBase):
+ """
+ A cache-based session store.
+ """
+ def __init__(self, session_key=None):
+ self._cache = cache
+ super(SessionStore, self).__init__(session_key)
+
+ def load(self):
+ session_data = self._cache.get(self.session_key)
+ return session_data or {}
+
+ def save(self):
+ self._cache.set(self.session_key, self._session, settings.SESSION_COOKIE_AGE)
+
+ def exists(self, session_key):
+ if self._cache.get(session_key):
+ return True
+ return False
+
+ def delete(self, session_key):
+ self._cache.delete(session_key)
@@ -0,0 +1,49 @@
+from django.conf import settings
+from django.contrib.sessions.models import Session
+from django.contrib.sessions.backends.base import SessionBase
+from django.core.exceptions import SuspiciousOperation
+import datetime
+
+class SessionStore(SessionBase):
+ """
+ Implements database session store
+ """
+ def __init__(self, session_key=None):
+ super(SessionStore, self).__init__(session_key)
+
+ def load(self):
+ try:
+ s = Session.objects.get(
+ session_key = self.session_key,
+ expire_date__gt=datetime.datetime.now()
+ )
+ return self.decode(s.session_data)
+ except (Session.DoesNotExist, SuspiciousOperation):
+
+ # Create a new session_key for extra security.
+ self.session_key = self._get_new_session_key()
+ self._session_cache = {}
+
+ # Save immediately to minimize collision
+ self.save()
+ return {}
+
+ def exists(self, session_key):
+ try:
+ Session.objects.get(session_key=session_key)
+ except Session.DoesNotExist:
+ return False
+ return True
+
+ def save(self):
+ Session.objects.create(
+ session_key = self.session_key,
+ session_data = self.encode(self._session),
+ expire_date = datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)
+ )
+
+ def delete(self, session_key):
+ try:
+ Session.objects.get(session_key=session_key).delete()
+ except Session.DoesNotExist:
+ pass
Oops, something went wrong.

0 comments on commit 28a4aa6

Please sign in to comment.