Created
December 27, 2009 21:36
-
-
Save ghinch/264408 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: appengine_django/auth/middleware.py | |
=================================================================== | |
--- appengine_django/auth/middleware.py (revision 100) | |
+++ appengine_django/auth/middleware.py (working copy) | |
@@ -12,8 +12,6 @@ | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
-from django.contrib.auth.models import AnonymousUser | |
- | |
from google.appengine.api import users | |
from appengine_django.auth.models import User | |
@@ -26,7 +24,8 @@ | |
if user: | |
request._cached_user = User.get_djangouser_for_user(user) | |
else: | |
- request._cached_user = AnonymousUser() | |
+ from django.contrib.auth import get_user | |
+ request._cached_user = get_user(request) | |
return request._cached_user | |
Index: appengine_django/auth/models.py | |
=================================================================== | |
--- appengine_django/auth/models.py (revision 100) | |
+++ appengine_django/auth/models.py (working copy) | |
@@ -20,6 +20,7 @@ | |
from django.core.exceptions import ImproperlyConfigured | |
from django.db import models | |
from django.utils.encoding import smart_str | |
+from django.utils.hashcompat import md5_constructor, sha_constructor | |
import urllib | |
from django.db.models.manager import EmptyManager | |
@@ -27,9 +28,87 @@ | |
from google.appengine.api import users | |
from google.appengine.ext import db | |
-from appengine_django.models import BaseModel | |
+from appengine_django.models import BaseModel, ModelManager | |
+UNUSABLE_PASSWORD = '!' # This will never be a valid hash | |
+class UserNotUniqueError(Exception): | |
+ pass | |
+ | |
+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) | |
+ | |
+ if algorithm == 'md5': | |
+ return md5_constructor(salt + raw_password).hexdigest() | |
+ elif algorithm == 'sha1': | |
+ return sha_constructor(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('$') | |
+ return hsh == get_hexdigest(algo, salt, raw_password) | |
+ | |
+def check_unique(username): | |
+ query = User.all().filter('username=', username) | |
+ user = query.get() | |
+ if user: | |
+ raise UserNotUniqueError | |
+ | |
+class UserManager(ModelManager): | |
+ def get(self, *args, **kwargs): | |
+ if 'pk' in kwargs: | |
+ uname = kwargs['pk'] | |
+ elif 'username' in kwargs: | |
+ uname = kwargs['username'] | |
+ else: | |
+ return False | |
+ query = self.owner.all().filter('username =', uname) | |
+ user = query.get() | |
+ if user: | |
+ user.id = user.username | |
+ else: | |
+ user = AnonymousUser | |
+ return user | |
+ | |
+ def create_user(self, username, email, key_name, aeuser=None, password=None): | |
+ "Creates and saves a User with the given username, e-mail and password." | |
+ user = self.owner(username=username, email= email.strip().lower(), key_name=key_name, user=aeuser) | |
+ if password: | |
+ user.set_password(password) | |
+ else: | |
+ user.set_unusable_password() | |
+ user.put() | |
+ return user | |
+ | |
+ def create_superuser(self, username, email, password): | |
+ u = self.create_user(username, email, password) | |
+ u.is_staff = True | |
+ u.is_active = True | |
+ u.is_superuser = True | |
+ u.put() | |
+ return u | |
+ | |
+ def make_random_password(self, length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'): | |
+ "Generates a random password with the given length and given allowed_chars" | |
+ # Note that default value of allowed_chars does not have "I" or letters | |
+ # that look like it -- just to avoid confusion. | |
+ from random import choice | |
+ return ''.join([choice(allowed_chars) for i in range(length)]) | |
+ | |
class User(BaseModel): | |
"""A model with the same attributes and methods as a Django user model. | |
@@ -38,11 +117,11 @@ | |
classmethod that should be used to retrieve a DjangoUser instance from a App | |
Engine user object. | |
""" | |
- user = db.UserProperty(required=True) | |
- username = db.StringProperty(required=True) | |
+ user = db.UserProperty() | |
+ username = db.StringProperty(required=True, validator=check_unique) | |
first_name = db.StringProperty() | |
last_name = db.StringProperty() | |
- email = db.EmailProperty() | |
+ email = db.EmailProperty(required=True) | |
password = db.StringProperty() | |
is_staff = db.BooleanProperty(default=False, required=True) | |
is_active = db.BooleanProperty(default=True, required=True) | |
@@ -69,18 +148,27 @@ | |
return django_user | |
def set_password(self, raw_password): | |
- raise NotImplementedError | |
+ 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) | |
def check_password(self, raw_password): | |
- raise NotImplementedError | |
+ """ | |
+ Returns a boolean of whether the raw_password was correct. Handles | |
+ encryption formats behind the scenes. | |
+ """ | |
+ return check_password(raw_password, self.password) | |
def set_unusable_password(self): | |
- raise NotImplementedError | |
+ # Sets a value that will never be a valid hash | |
+ self.password = UNUSABLE_PASSWORD | |
def has_usable_password(self): | |
- raise NotImplementedError | |
+ return self.password != UNUSABLE_PASSWORD | |
- def get_group_permissions(self): | |
+ def gee_grnup_permissions(self): | |
return self.user_permissions | |
def get_all_permissions(self): | |
@@ -152,6 +240,7 @@ | |
raise SiteProfileNotAvailable | |
return self._profile_cache | |
+User.objects = UserManager(User) | |
class Group(BaseModel): | |
"""Group model not fully implemented yet.""" | |
@@ -170,3 +259,68 @@ | |
"""Permission model not fully implemented yet.""" | |
# TODO: Implement this model, requires contenttypes | |
name = db.StringProperty() | |
+ | |
+class AnonymousUser(object): | |
+ id = None | |
+ username = '' | |
+ is_staff = False | |
+ is_active = False | |
+ is_superuser = False | |
+ _groups = EmptyManager() | |
+ _user_permissions = EmptyManager() | |
+ | |
+ def __init__(self): | |
+ pass | |
+ | |
+ def __unicode__(self): | |
+ return 'AnonymousUser' | |
+ | |
+ def __str__(self): | |
+ return unicode(self).encode('utf-8') | |
+ | |
+ def __eq__(self, other): | |
+ return isinstance(other, self.__class__) | |
+ | |
+ def __ne__(self, other): | |
+ return not self.__eq__(other) | |
+ | |
+ def __hash__(self): | |
+ return 1 # instances always return the same hash value | |
+ | |
+ def save(self): | |
+ raise NotImplementedError | |
+ | |
+ def delete(self): | |
+ raise NotImplementedError | |
+ | |
+ def set_password(self, raw_password): | |
+ raise NotImplementedError | |
+ | |
+ def check_password(self, raw_password): | |
+ raise NotImplementedError | |
+ | |
+ def _get_groups(self): | |
+ return self._groups | |
+ groups = property(_get_groups) | |
+ | |
+ def _get_user_permissions(self): | |
+ return self._user_permissions | |
+ user_permissions = property(_get_user_permissions) | |
+ | |
+ def has_perm(self, perm, obj=None): | |
+ return False | |
+ | |
+ def has_perms(self, perm_list, obj=None): | |
+ return False | |
+ | |
+ def has_module_perms(self, module): | |
+ return False | |
+ | |
+ def get_and_delete_messages(self): | |
+ return [] | |
+ | |
+ def is_anonymous(self): | |
+ return True | |
+ | |
+ def is_authenticated(self): | |
+ return False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment