mon_django / mon_django / auth /

import datetime
import re

from django.utils.encoding import smart_str, force_unicode
from django.utils.hashcompat import md5_constructor, sha_constructor

from django.core import exceptions

from mon_django.core import get_db
from mon_django.core.fields import AutoField, DateTimeField
from mon_django.core.queryset import QuerySet

UNUSABLE_PASSWORD = u'!' # This will never be a valid hash

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':
            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.")

class UserManager(object):
    def __init__(self, model=None):
        if model:
            self.model = model

    def create(self, **kwargs):
        obj = self.model(**kwargs)
        return obj

    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
        return u

    def create_user(self, username, email, password=None):
        Creates and saves a User with the given username, e-mail and password.

        now =
        # Normalize the address by lowercasing the domain part of the email
        # address.
            email_name, domain_part = email.strip().split('@', 1)
        except ValueError:
            email = '@'.join([email_name, domain_part.lower()])

        user = self.model(username=username, email=email, is_staff=False,
                         is_active=True, is_superuser=False, last_login=now,

        if password:
        return user 

    def get_collection(self):
        collection = get_db()['mon_django__auth__users']
        collection.ensure_index('username', unique=True)
        return collection

    def count(self):
        return self.get_collection().count()

    def _get_query(self, **kwargs):
        query = {}

        for p, v in kwargs.iteritems():
            lst = p.split('__', 1)
            mod = ''
            if len(lst) > 1:
                p, mod = lst

            if p == 'pk' or p == 'id':
                p = '_id'

            if p in self.model.field_types:
                v = self.model.field_types[p].get_prep_value(v)

            if p in self.model.valid_fields:
                if not mod:
                    query[p] = v
                elif mod == 'iexact':
                    query[p] = re.compile(v, re.I)
                    raise TypeError("'%s' is an invalid modifier for this function" % mod)     
                raise TypeError("'%s' is an invalid keyword argument for this function" % p)     
        return query

    def get(self, **kwargs):
        query = self._get_query(**kwargs)
        result = self.get_collection().find(query)
        num = result.count()
        if num == 1:
            results = result[0]
            return User(**result[0])
        if not num:
            raise self.model.DoesNotExist("User matching query does not exist.") 

        raise self.model.MultipleObjectsReturned("get() returned more than one User -- it returned %s! Lookup parameters were %s"
                % (num, kwargs))

    def filter(self, **kwargs):
        query = self._get_query(**kwargs)
        result = self.get_collection().find(query)
        return QuerySet(self.model, result)

    def all(self):
        return self

class User(object):
    objects = UserManager()
    _default_manager = objects

    valid_fields = ('username', 'first_name', 'last_name', 'email', 'password',
                    'is_staff', 'is_active', 'is_superuser', 'last_login',
                    'date_joined', 'groups', 'user_permissions', '_id')

    valid_attrs = ('_params', 'backend', '_profile_cache')

    field_types = {
        'last_login' : DateTimeField(),
        '_id' : AutoField()

    DoesNotExist = exceptions.ObjectDoesNotExist
    MultipleObjectsReturned = exceptions.MultipleObjectsReturned

    class Meta:
        object_name = 'User'
    _meta = Meta()

    def __init__(self, **kwargs):
        self._params = {}
        for p in kwargs.iterkeys():
            if p in self.valid_fields:
                if p in self.field_types:
                    self._params[p] = self.field_types[p].to_python(kwargs[p])
                    self._params[p] = kwargs[p]
                raise TypeError("'%s' is an invalid keyword argument for this function" % p) 

    def __str__(self):
        return force_unicode(self).encode('utf-8')

    def __unicode__(self):
        return self.username

    def __repr__(self):
            u = unicode(self)
        except (UnicodeEncodeError, UnicodeDecodeError):
            u = '[Bad Unicode data]'
        return smart_str(u'<%s: %s>' % (self.__class__.__name__, u))

    def __getattr__(self, name):
        if name == 'id' or name == 'pk':
            name = '_id'
        if name in self.valid_attrs:
            return object.__getattr__(self, name)
        if not name in self.valid_fields:
            raise AttributeError("'User' object has no attribute '%s'" % name)
            return self._params[name]
        except KeyError:
            return '' # TODO: Create defaults.
    def __setattr__(self, name, value):
        if name == 'id' or name == 'pk':
            name = '_id'
        if name in self.valid_attrs:
            object.__setattr__(self, name, value)
        if not name in self.valid_fields:
            raise AttributeError("'User' object has no attribute '%s'" % name)
        self._params[name] = value

    def is_authenticated(self):
        return True

    def has_usable_password(self):
        return self.password != UNUSABLE_PASSWORD

    def set_unusable_password(self):
        self.password = UNUSABLE_PASSWORD

    def get_profile(self):
        Returns site-specific profile for this user. Raises
        SiteProfileNotAvailable if this site does not allow profiles.
        if not hasattr(self, '_profile_cache'):
            from django.conf import settings
            if not getattr(settings, 'AUTH_PROFILE_MODULE', False):
                raise SiteProfileNotAvailable('You need to set AUTH_PROFILE_MO'
                                              'DULE in your project settings')
                app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')
            except ValueError:
                raise SiteProfileNotAvailable('app_label and model_name should'
                        ' be separated by a dot in the AUTH_PROFILE_MODULE set'

                from django.db import models
                model = models.get_model(app_label, model_name)
                if model is None:
                    raise SiteProfileNotAvailable('Unable to load the profile '
                        'model, check AUTH_PROFILE_MODULE in your project sett'
                self._profile_cache = model._default_manager.using(self._state.db).get(
                self._profile_cache.user = self
            except (ImportError, exceptions.ImproperlyConfigured):
                raise SiteProfileNotAvailable
        return self._profile_cache

    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)

    def save(self):

    def check_password(self, raw_password):
        Returns a boolean of whether the raw_password was correct. Handles
        encryption formats behind the scenes.
        # Backwards-compatibility check. Older passwords won't include the
        # algorithm or salt.
        if '$' not in self.password:
            is_correct = (self.password == get_hexdigest('md5', '', raw_password))
            if is_correct:
                # Convert the password to the new, more secure format.
            return is_correct
        return check_password(raw_password, self.password)

UserManager.model = User

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)

class Group(object):

class Permission(object):

class SiteProfileNotAvailable(Exception):

class EmptyManager(UserManager):
    def get_query_set(self):
        return self.get_empty_query_set()
    def all(self):
        return []

class AnonymousUser(object):
    id = None
    username = ''
    is_staff = False
    is_active = False
    is_superuser = False
    _groups = EmptyManager()
    _user_permissions = EmptyManager()

    def __init__(self):

    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 get_group_permissions(self, obj=None):
        return set()

    def get_all_permissions(self, obj=None):
        return _user_get_all_permissions(self, obj=obj)

    def has_perm(self, perm, obj=None):
        return _user_has_perm(self, perm, obj=obj)

    def has_perms(self, perm_list, obj=None):
        for perm in perm_list:
            if not self.has_perm(perm, obj):
                return False
        return True

    def has_module_perms(self, module):
        return _user_has_module_perms(self, module)

    def get_and_delete_messages(self):
        return []

    def is_anonymous(self):
        return True

    def is_authenticated(self):
        return False