diff --git a/userausfall/admin.py b/userausfall/admin.py index 00b5d97..d0695f4 100644 --- a/userausfall/admin.py +++ b/userausfall/admin.py @@ -1,6 +1,5 @@ from django.contrib import admin -from django.contrib.auth.admin import UserAdmin from userausfall.models import User -admin.site.register(User, UserAdmin) +admin.site.register(User) diff --git a/userausfall/ldap.py b/userausfall/ldap.py new file mode 100644 index 0000000..e1ff065 --- /dev/null +++ b/userausfall/ldap.py @@ -0,0 +1,21 @@ +from django.conf import settings +from ldap3 import Server, Connection, SYNC + + +def create_account(username, raw_password): + server = Server("localhost") + # The SAFE_SYNC client strategy doesn't seem to be present in Buster version of ldap3. We might want to use it as + # soon as it is available (multithreading). + connection = Connection( + server, + settings.USERAUSFALL_LDAP["ADMIN_USER_DN"], + settings.USERAUSFALL_LDAP["ADMIN_USER_PASSWORD"], + client_strategy=SYNC, + auto_bind=True, + ) + is_success = connection.add( + f"cn={username},dc=local", + ["simpleSecurityObject", "organizationalRole"], + {"userPassword": raw_password}, + ) + return is_success diff --git a/userausfall/migrations/0005_delete_accountrequest.py b/userausfall/migrations/0005_delete_accountrequest.py new file mode 100644 index 0000000..132ed0e --- /dev/null +++ b/userausfall/migrations/0005_delete_accountrequest.py @@ -0,0 +1,16 @@ +# Generated by Django 2.2.20 on 2021-05-19 08:10 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('userausfall', '0004_user_confidant'), + ] + + operations = [ + migrations.DeleteModel( + name='AccountRequest', + ), + ] diff --git a/userausfall/models.py b/userausfall/models.py index 55efac2..1b85750 100644 --- a/userausfall/models.py +++ b/userausfall/models.py @@ -6,6 +6,18 @@ from django.db import models from django.utils import timezone from django.utils.translation import gettext_lazy as _ +from userausfall import ldap + + +class MissingUserAttribute(Exception): + """The user object is missing a required attribute.""" + pass + + +class PasswordMismatch(Exception): + """The given password does not match the user's password.""" + pass + class UserManager(BaseUserManager): use_in_migrations = True @@ -51,22 +63,12 @@ class User(AbstractBaseUser, PermissionsMixin): }, blank=True, ) - first_name = models.CharField(_('first name'), max_length=30, blank=True) - last_name = models.CharField(_('last name'), max_length=150, blank=True) email = models.EmailField(_('email address'), unique=True, blank=True) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_('Designates whether the user can log into this admin site.'), ) - is_active = models.BooleanField( - _('active'), - default=True, - help_text=_( - 'Designates whether this user should be treated as active. ' - 'Unselect this instead of deleting accounts.' - ), - ) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) confidant = models.ForeignKey("User", on_delete=models.SET_NULL, null=True) @@ -87,29 +89,16 @@ class User(AbstractBaseUser, PermissionsMixin): def get_confidant_email(self): return "" - def get_full_name(self): - """ - Return the first_name plus the last_name, with a space in between. - """ - full_name = '%s %s' % (self.first_name, self.last_name) - return full_name.strip() - - def get_short_name(self): - """Return the short name for the user.""" - return self.first_name - def email_user(self, subject, message, from_email=None, **kwargs): """Send an email to this user.""" send_mail(subject, message, from_email, [self.email], **kwargs) - -class AccountRequest(models.Model): - created_time = models.DateTimeField(auto_now_add=True) - - email = models.EmailField() - is_verified = models.BooleanField(default=False) - - confidant_email = models.EmailField(blank=True) - is_trustable = models.BooleanField(default=False) - - username = models.CharField(max_length=100, blank=True) + def create_ldap_account(self, raw_password): + """Create the LDAP account which corresponds to this user.""" + if not self.username: + raise MissingUserAttribute("User is missing a username.") + if not self.confidant: + raise MissingUserAttribute("User is missing a confirmed confidant.") + if not self.check_password(raw_password): + raise PasswordMismatch("The given password does not match the user's password.") + return ldap.create_account(self.username, raw_password) diff --git a/userausfall/rest_api/serializers.py b/userausfall/rest_api/serializers.py index 97ced7b..c4acdbd 100644 --- a/userausfall/rest_api/serializers.py +++ b/userausfall/rest_api/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from userausfall.models import AccountRequest, User +from userausfall.models import User class UserSerializer(serializers.ModelSerializer): diff --git a/userausfall/settings.py b/userausfall/settings.py index 1815e91..3486771 100644 --- a/userausfall/settings.py +++ b/userausfall/settings.py @@ -149,3 +149,8 @@ REST_FRAMEWORK = { 'rest_framework.authentication.SessionAuthentication', ), } + +USERAUSFALL_LDAP = { + 'ADMIN_USER_DN': 'cn=admin,dc=local', + 'ADMIN_USER_PASSWORD': os.environ.get('USERAUSFALL_LDAP_PASSWORD'), +} diff --git a/userausfall/signals.py b/userausfall/signals.py index f5a984b..e69de29 100644 --- a/userausfall/signals.py +++ b/userausfall/signals.py @@ -1,10 +0,0 @@ -from django.db.models.signals import post_save -from django.dispatch import receiver - -from userausfall.models import AccountRequest - - -@receiver(post_save, sender=AccountRequest) -def account_request_saved(sender, instance: AccountRequest, **kwargs): - if instance.is_verified and instance.is_trustable and instance.username: - print('Create account and send password mail')