Wow, nice. You are probably right in not inheriting from PermissionMixin
and AbstractBaseUser and just re-implementing the needed functionality. I
ended up doing the same thing for my custom user and auth backend as well.
Not as convenient, but hey, it works right? ;-)

Bravo.

-James
On Jan 20, 2015 3:17 PM, "Erik Cederstrand" <[email protected]>
wrote:

> Ok, here's a stripped-down solution.
>
> I ended up creating a new SchoolUser user model with a OneToOne relation
> to my LegacyUser, to keep the LegacyUser model uncluttered. The SchoolUser
> implements all methods from AbstractBaseUser and PermissionsMixin but
> doesn't inherit from them, because I don't want the model fields that they
> contain.
>
> I also kept the SchoolUser independent from the standard Django User (i.e.
> no AUTH_USER_MODEL='SchoolUser' in settings.py), so I can still create
> superuser accounts for myself and my colleagues, that are not connected to
> a school user.
>
> Here's the code:
>
>
> settings.py:
> [...]
>
> AUTHENTICATION_BACKENDS = (
>     'django.contrib.auth.backends.ModelBackend',
>     'school_auth.backends.SchoolModelBackend',
> )
>
>
>
> school_auth/backend.py:
> from django.contrib.auth.backends import ModelBackend
> from .models import SchoolUser, LegacyUser
>
> class SchoolModelBackend(object):
>     def authenticate(self, school_id=None, username=None, password=None, 
> **kwargs):
>         if LegacyUser.validate(school=school_id, username=username, 
> password=password):
>             # Password hash validation
>             try:
>                 school_user = SchoolUser.objects.get(user__school=school_id, 
> user__name=username)
>             except SchoolUser.DoesNotExist:
>                 school_user = 
> SchoolUser.objects.create_user(school_id=school_id, username=username)
>             # Annotate the user object with the path of the backend.
>             school_user.backend = "%s.%s" % (self.__class__.__module__, 
> self.__class__.__name__)
>             return school_user
>         #
>         # if LDAP.validate(school=school_id, username=username, 
> password=password):
>         #     pass
>         # if WAYF.validate(school=school_id, username=username, 
> password=password):
>         #     pass
>         return None
>
>     def get_group_permissions(self, user_obj, obj=None):
>         raise NotImplementedError()
>
>     def get_all_permissions(self, user_obj, obj=None):
>         raise NotImplementedError()
>
>     def has_perm(self, user_obj, perm, obj=None):
>         if not user_obj.is_active:
>             return False
>         return perm in self.get_all_permissions(user_obj, obj)
>
>     def has_module_perms(self, user_obj, app_label):
>         if not user_obj.is_active:
>             return False
>         for perm in self.get_all_permissions(user_obj):
>             if perm[:perm.index('.')] == app_label:
>                 return True
>         return False
>
>     def get_user(self, user_id):
>         try:
>             return SchoolUser.objects.get(pk=user_id)
>         except SchoolUser.DoesNotExist:
>             return None
>
>
>
> school_auth/forms.py:
> from django.contrib.auth.forms import AuthenticationForm,
> PasswordResetForm, PasswordChangeForm
> from django import forms
> from django.utils.translation import ugettext_lazy as _
> from django.utils.text import capfirst
> from .models import LegacyUser, School, SchoolUser
> from .backends import SchoolModelBackend
>
> class SchoolAuthenticationForm(AuthenticationForm):
>     school = forms.ModelChoiceField(queryset=School.objects.active(), 
> empty_label=_('Please select a school'))
>     username = forms.CharField(max_length=40)
>     password = forms.CharField(label=_("Password"), 
> widget=forms.PasswordInput)
>
>     class Meta:
>         model = LegacyUser
>
>         fields = ['school', 'name', 'password']
>
>     def __init__(self, request=None, *args, **kwargs):
>         """
>         The 'request' parameter is set for custom auth use by subclasses.
>         The form data comes in via the standard 'data' kwarg.
>         """
>         self.request = request
>         self.user_cache = None
>         super().__init__(*args, **kwargs)
>
>         # Set the label for the "username" field.
>         self.username_field = 
> LegacyUser._meta.get_field(SchoolUser.USERNAME_FIELD)
>         if self.fields['username'].label is None:
>             self.fields['username'].label = 
> capfirst(self.username_field.verbose_name)
>
>     def clean(self):
>         school = self.cleaned_data.get('school')
>         username = self.cleaned_data.get('username')
>         password = self.cleaned_data.get('password')
>
>         if school and username and password:
>             self.user_cache = 
> SchoolModelBackend().authenticate(school_id=school.pk, username=username,
>                                                                   
> password=password)
>             if self.user_cache is None:
>                 raise forms.ValidationError(
>                     self.error_messages['invalid_login'],
>                     code='invalid_login',
>                     params={'username': self.username_field.verbose_name},
>                 )
>             else:
>                 self.confirm_login_allowed(self.user_cache)
>
>         return self.cleaned_data
>
>
>
> school_auth/models.py:
> from django.contrib.auth.models import PermissionsMixin, BaseUserManager,
> AbstractBaseUser
> from django.db import models
> from django.utils.translation import ugettext_lazy as _
> from django.utils import timezone
> from django.utils.crypto import salted_hmac
> from ..legacy.models import LegacyUser, School
>
> class SchoolUserManager(BaseUserManager):
>
>     def create_user(self, school_id, username):
>         user = LegacyUser.objects.get(school=school_id, name=username)
>         school_user = self.model(user=user)
>         school_user.save()
>         return school_user
>
>
> class SchoolUser(models.Model):
>     """
>     Custom User model. We don't inherit AbstractBaseUser because we don't 
> want the password field.
>     """
>     USERNAME_FIELD = 'name'
>
>     user = models.OneToOneField(User, null=False)
>     last_login = models.DateTimeField(_('last login'), default=timezone.now)
>
>     objects = SchoolUserManager()
>     REQUIRED_FIELDS = []
>
>     @property
>     def school(self):
>         return self.user.school
>
>     def __str__(self):
>         return self.get_username()
>
>     def get_username(self):
>         return self.user.name
>
>     @property
>     def is_active(self):
>         return self.user.active
>
>     @property
>     def is_staff(self):
>         return self.user.is_admin()
>
>     def natural_key(self):
>         return self.user.school_id, self.user.name
>
>     @staticmethod
>     def is_anonymous():
>         return False
>
>     @staticmethod
>     def is_authenticated():
>         return True
>
>     def set_password(self, raw_password):
>         self.user.set_password(raw_password)
>
>     def check_password(self, raw_password):
>         return self.user.validate_password(raw_password)
>
>     def set_unusable_password(self):
>         pass
>
>     @staticmethod
>     def has_usable_password():
>         return True
>
>     def get_full_name(self):
>         return self.user.name
>
>     def get_short_name(self):
>         return self.user.name
>
>     def get_session_auth_hash(self):
>         """
>         Returns an HMAC of the password field.
>         """
>         key_salt = 
> "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
>         return salted_hmac(key_salt, self.user.password).hexdigest()
>
>     def email_user(self, subject, message, from_email=None, **kwargs):
>         """
>         Sends an email to this User.
>         """
>         from django.core.mail import send_mail
>         send_mail(subject, message, from_email, [self.email], **kwargs)
>
>     @property
>     def is_superuser(self):
>         # This can never be a Django superuser
>         return False
>
>     def get_group_permissions(self, obj=None):
>         raise NotImplementedError()
>
>     def get_all_permissions(self, obj=None):
>         raise NotImplementedError()
>
>     def has_perm(self, perm, obj=None):
>         [...]  # My custom per-app permissions
>
>     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, app_label):
>         [...]  # My custom per-module permissions
>
>
>
> school_auth/urls.py:
> from django.conf.urls import url
> from django.contrib.auth.views import login, logout
> from .forms import SchoolAuthenticationForm
>
> urlpatterns = [
>     url(r'^login/$', login, kwargs={'authentication_form': 
> SchoolAuthenticationForm, 'template_name': 'school_auth/login.html'}, 
> name='school_auth.login'),
>     url(r'^logout/$', logout, name='school_auth.logout'),
> ]
>
>
> Thanks,
>
> Erik
>
>  --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/BC66EBBA-A032-42B1-8DB0-F2CFFEE48BA6%40cederstrand.dk
> <https://groups.google.com/d/msgid/django-users/BC66EBBA-A032-42B1-8DB0-F2CFFEE48BA6%40cederstrand.dk?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciXf_KgDQDY6DdGGja6%3D%2BON8CaLBbbBnkJDb92BzH6ZYrg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to