models.py 4.37 KB
Newer Older
1 2
import logging

3
from django.conf import settings
4 5
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import UserManager as BaseUserManager
6
from django.core import validators
7
from django.db import models
8
from django.utils import timezone
9
from django.utils.crypto import salted_hmac
10
from django.utils.deconstruct import deconstructible
11
from django.utils.translation import ugettext_lazy as _
12

13
from ldapregister.models import LdapPerson
14 15 16 17 18 19
from limitmonitor import models as limitmonitor_models
from limitmonitor.task_resources import common as limitmonitor_common

log = logging.getLogger(__name__)


20 21 22 23 24 25 26 27 28
@deconstructible
class UsernameValidator(validators.RegexValidator):
    regex = r'^[A-Za-z][A-Za-z0-9]*$'
    message = _(
        'Enter a valid username. Must start with a letter, followed by letters and numbers.'
        ' No punctuation or special characters.'
    )


29 30 31 32 33
class UserManager(BaseUserManager):

    def create_user(self, username, email=None, password=None, **extra_fields):
        """Create regular users in LDAP, with no Django password."""

34
        return super(UserManager, self).create_user(username, email, password, **extra_fields)
35 36 37 38

    def create_superuser(self, username, email=None, password=None, **extra_fields):
        """Create superusers with a Django password."""

39
        return super(UserManager, self).create_superuser(username, email, password, **extra_fields)
40 41 42 43 44


class User(AbstractUser):
    objects = UserManager()
    REQUIRED_FIELDS = []
45 46 47 48 49 50 51 52 53 54 55 56
    username_validator = UsernameValidator()

    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        help_text=_('Required. Start with a letter, followed by letters and numbers.'),
        validators=[username_validator],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
57 58 59 60

    @classmethod
    def normalize_username(cls, username):
        username = super(User, cls).normalize_username(username)
61 62

        username = username.lower()
63 64
        suffix = "@" + settings.SITE_DOMAIN.lower()
        offset = 0 - len(suffix)
65 66

        if username.endswith(suffix):
67
            username = username[:offset]
68 69

        return username
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

    def get_ldap(self):
        return LdapPerson.objects.get(uid=self.get_username())

    def has_ldap(self):
        result = LdapPerson.objects.filter(uid=self.get_username())
        return len(result) == 1

    def create_ldap(self):
        username = self.get_username()
        LdapPerson.objects.create(uid=username, cn=username, sn=username)

    def set_ldap_password(self, raw_password):
        ldap_person = self.get_ldap()
        ldap_person.change_password(raw_password)

    def get_identity(self):
        # TODO: associated with https://code.puri.sm/purist/account_web/issues/25
88
        return self.get_username() + "@" + settings.SITE_DOMAIN.lower()
89 90 91 92 93 94 95 96 97 98

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):

        # save django user
        super(User, self).save(force_insert, force_update, using, update_fields)

        # create LDAP user (if required)
        if not self.has_ldap():
            self.create_ldap()

99
        # force null Django password (will use LDAP password instead)
100 101 102 103 104
        self.set_unusable_password()

        # create any missing limits
        limitmonitor_models.create_missing_user_limits(self)

105 106 107 108 109 110 111 112
        if settings.DEBUG_ALL_ACCESS:

            ssh = limitmonitor_common.get_openvpn_ssh_connection()
            renewal_date = timezone.now() + timezone.timedelta(weeks=5200)

            for limit in limitmonitor_models.Limit.objects.filter(user=self, is_active=False):
                limitmonitor_common.activate(ssh, limit, renewal_date=renewal_date)

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    def set_password(self, raw_password):

        # force null Django password (will use LDAP password)
        self.set_unusable_password()

        # create LDAP user (if required)
        if self.get_username():

            if not self.has_ldap():
                self.create_ldap()

            # set LDAP password
            self.set_ldap_password(raw_password)

    def get_session_auth_hash(self):
        """
        Return an HMAC of the password field.
        """
        key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
        return salted_hmac(key_salt, self.get_username()).hexdigest()  # FIXME: should use LDAP password value!