From f8627444ac12cb18f55d3fea0e628c103725ea38 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 1 May 2012 23:14:38 -0700 Subject: [PATCH 1/4] Synchronized User class with Django 1.4 implementation (and comments). --- mango/auth.py | 109 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 43 deletions(-) diff --git a/mango/auth.py b/mango/auth.py index a551f81..6d3eea2 100644 --- a/mango/auth.py +++ b/mango/auth.py @@ -1,7 +1,7 @@ from mango import Model, database as db from django.utils.encoding import smart_str from django.contrib import auth -from django.contrib.auth.models import UNUSABLE_PASSWORD, get_hexdigest, check_password +from django.contrib.auth.models import make_password, check_password, is_password_usable import datetime import urllib @@ -15,42 +15,60 @@ def get_absolute_url(self): return "/users/%s/" % urllib.quote(smart_str(self.username)) def is_anonymous(self): + """ + Always returns False. This is a way of comparing User objects to + anonymous users. + """ return False def is_authenticated(self): + """ + Always return True. This is a way to tell if the user has been + authenticated in templates. + """ return True def get_full_name(self): + """ + Returns the first_name plus the last_name, with a space in between. + """ full_name = u'%s %s' % (self.first_name, self.last_name) return full_name.strip() def set_password(self, raw_password): - import random - algo = 'sha1' - 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) + self.password = make_password(raw_password) def check_password(self, raw_password): - if '$' not in self.password: - is_correct = (self.password == get_hexdigest('md5', '', raw_password)) - if is_correct: - self.set_password(raw_password) - self.save() - return is_correct - return check_password(raw_password, self.password) + """ + Returns a boolean of whether the raw_password was correct. Handles + hashing formats behind the scenes. + """ + def setter(raw_password): + self.set_password(raw_password) + self.save() + return check_password(raw_password, self.password, setter) def set_unusable_password(self): - self.password = UNUSABLE_PASSWORD + # Sets a value that will never be a valid hash + self.password = make_password(None) def has_usable_password(self): - return self.password != UNUSABLE_PASSWORD - - def get_group_permissions(self): + return is_password_usable(self.password) + + def get_group_permissions(self, obj=None): + """ + Returns a list of permission strings that this user has through his/her + groups. This method queries all available auth backends. If an object + is passed in, only permissions matching this object are returned. + """ permissions = set() for backend in auth.get_backends(): if hasattr(backend, "get_group_permissions"): - permissions.update(backend.get_group_permissions(self)) + if obj is not None: + permissions.update(backend.get_group_permissions(self, + obj)) + else: + permissions.update(backend.get_group_permissions(self)) return permissions def get_all_permissions(self): @@ -60,43 +78,48 @@ def get_all_permissions(self): permissions.update(backend.get_all_permissions(self)) return permissions - def has_perm(self, perm): - if not self.is_active: - return False - - if self.is_superuser: + def has_perm(self, perm, obj=None): + """ + Returns True if the user has the specified permission. This method + queries all available auth backends, but returns immediately if any + backend returns True. Thus, a user who has permission from a single + auth backend is assumed to have permission in general. If an object is + provided, permissions for this specific object are checked. + """ + + # Active superusers have all permissions. + if self.is_active and self.is_superuser: return True - for backend in auth.get_backends(): - if hasattr(backend, "has_perm"): - if backend.has_perm(self, perm): - return True - return False + # Otherwise we need to check the backends. + return _user_has_perm(self, perm, obj) - def has_perms(self, perm_list): + def has_perms(self, perm_list, obj=None): + """ + Returns True if the user has each of the specified permissions. If + object is passed, it checks if the user has all required perms for this + object. + """ for perm in perm_list: - if not self.has_perm(perm): + if not self.has_perm(perm, obj): return False return True def has_module_perms(self, app_label): - if not self.is_active: - return False - - if self.is_superuser: + """ + Returns True if the user has any permissions in the given app label. + Uses pretty much the same logic as has_perm, above. + """ + # Active superusers have all permissions. + if self.is_active and self.is_superuser: return True - for backend in auth.get_backends(): - if hasattr(backend, "has_module_perms"): - if backend.has_module_perms(self, app_label): - return True - return False - - def get_and_delete_messages(self): - return [] + return _user_has_module_perms(self, app_label) def email_user(self, subject, message, from_email=None): - from django.core.mail import send_mail + """ + Sends an email to this User. + """ send_mail(subject, message, from_email, [self.email]) def get_profile(self): From 98e58e9a424b7ef39c2dc6fd7d7804f767ce9b61 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 1 May 2012 23:15:18 -0700 Subject: [PATCH 2/4] Changed from datetime library to django.utils timezone. --- mango/session.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mango/session.py b/mango/session.py index 0237e44..201712a 100644 --- a/mango/session.py +++ b/mango/session.py @@ -1,7 +1,7 @@ -import datetime from django.contrib.sessions.backends.base import SessionBase, CreateError from django.utils.encoding import force_unicode from mango import database as db, OperationFailure +from django.utils import timezone class SessionStore(SessionBase): """ @@ -10,7 +10,7 @@ class SessionStore(SessionBase): def load(self): s = db.sessions.find_one( { 'session_key': self.session_key, - 'expire_date': {'$gt': datetime.datetime.now()}}) + 'expire_date': {'$gt': timezone.now()}}) if s: return self.decode(force_unicode(s['session_data'])) else: From af35a5015844534b85766b62c8e2a094c10da3c8 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 1 May 2012 23:17:05 -0700 Subject: [PATCH 3/4] Change accesses and changes to .session_key and ._session_key to match Django 1.4 DB backend. --- mango/session.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mango/session.py b/mango/session.py index 201712a..ec6f134 100644 --- a/mango/session.py +++ b/mango/session.py @@ -25,7 +25,7 @@ def exists(self, session_key): def create(self): while True: - self.session_key = self._get_new_session_key() + self._session_key = self._get_new_session_key() try: # Save immediately to ensure we have a unique entry in the # database. @@ -45,7 +45,7 @@ def save(self, must_create=False): entry). """ obj = { - 'session_key': self.session_key, + 'session_key': self._get_or_create_session_key(), 'session_data': self.encode(self._get_session(no_load=must_create)), 'expire_date': self.get_expiry_date() } @@ -60,7 +60,7 @@ def save(self, must_create=False): def delete(self, session_key=None): if session_key is None: - if self._session_key is None: + if self.session_key is None: return - session_key = self._session_key + session_key = self.session_key db.sessions.remove({'session_key': session_key}) From 80eb670f3808e3b82c463f1bea6c2c0cf6aaecd8 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Tue, 1 May 2012 23:24:32 -0700 Subject: [PATCH 4/4] Using existing *or* created session key. Again, modeled off Django 1.4 DB backend implementation. --- mango/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mango/session.py b/mango/session.py index ec6f134..9be1a94 100644 --- a/mango/session.py +++ b/mango/session.py @@ -50,7 +50,7 @@ def save(self, must_create=False): 'expire_date': self.get_expiry_date() } res = db.sessions.update( - {'session_key': self.session_key}, + {'session_key': obj['session_key']}, {'$set': obj}, upsert=True, safe=True,