From e132c9a56c071eb0c2df2aa89e35f1f9db8ab9f3 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sun, 25 May 2014 00:55:02 +0200 Subject: [PATCH] add user creation manager code - add OSUSER_* settings - add UserManager, GroupManager and ShadowManager for user creation --- gnuviechadmin/gnuviechadmin/settings/base.py | 9 +++ gnuviechadmin/osusers/models.py | 83 +++++++++++++++++++- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/gnuviechadmin/gnuviechadmin/settings/base.py b/gnuviechadmin/gnuviechadmin/settings/base.py index feb7976..23c2338 100644 --- a/gnuviechadmin/gnuviechadmin/settings/base.py +++ b/gnuviechadmin/gnuviechadmin/settings/base.py @@ -276,3 +276,12 @@ INSTALLED_APPS += ( # Don't need to use South when setting up a test database. SOUTH_TESTS_MIGRATE = False ########## END SOUTH CONFIGURATION + + +########## CUSTOM APP CONFIGURATION +OSUSER_MINUID = int(get_env_variable('GVA_MIN_OS_UID')) +OSUSER_MINGID = int(get_env_variable('GVA_MIN_OS_GID')) +OSUSER_USERNAME_PREFIX = get_env_variable('GVA_OSUSER_PREFIX') +OSUSER_HOME_BASEPATH = get_env_variable('GVA_OSUSER_HOME_BASEPATH') +OSUSER_DEFAULT_SHELL = get_env_variable('GVA_OSUSER_DEFAULT_SHELL') +########## END CUSTOM APP CONFIGURATION diff --git a/gnuviechadmin/osusers/models.py b/gnuviechadmin/osusers/models.py index fe728d5..d73e27e 100644 --- a/gnuviechadmin/osusers/models.py +++ b/gnuviechadmin/osusers/models.py @@ -1,10 +1,25 @@ -from django.db import models +from datetime import date +import os + +from django.db import models, transaction +from django.conf import settings from django.core.exceptions import ValidationError +from django.utils import timezone from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext as _ from model_utils.models import TimeStampedModel +from passlib.hash import sha512_crypt +from passlib.utils import generate_password + + +class GroupManager(models.Manager): + + def get_next_gid(self): + q = self.aggregate(models.Max('gid')) + return max(settings.OSUSER_MINGID, q['gid__max'] + 1) + @python_2_unicode_compatible class Group(TimeStampedModel, models.Model): @@ -16,6 +31,8 @@ class Group(TimeStampedModel, models.Model): passwd = models.CharField( _('Group password'), max_length=128, blank=True) + objects = GroupManager() + class Meta: verbose_name = _('Group') verbose_name_plural = _('Groups') @@ -24,6 +41,52 @@ class Group(TimeStampedModel, models.Model): return '{0} ({1})'.format(self.groupname, self.gid) +class UserManager(models.Manager): + + def get_next_uid(self): + q = self.aggregate(models.Max('uid')) + return max(settings.OSUSER_MINUID, q['uid__max'] + 1) + + def get_next_username(self): + count = 1 + usernameformat = "{0}{1:02d}" + nextuser = usernameformat.format(settings.OSUSER_USERNAME_PREFIX, + count) + for user in self.values('username').filter( + username__startswith=settings.OSUSER_USERNAME_PREFIX).order_by( + 'username'): + if user == nextuser: + count += 1 + nextuser = usernameformat.format( + settings.OSUSER_USERNAME_PREFIX, count) + else: + break + return nextuser + + def create_user(self, username=None, password=None): + uid = self.get_next_uid() + gid = Group.objects.get_next_gid() + if username is None: + username = self.get_next_username() + if password is None: + password = generate_password() + homedir = os.path.join(settings.OSUSER_HOME_BASEPATH, username) + autocommit = transaction.get_autocommit() + if autocommit: + transaction.set_autocommit(False) + group = Group.objects.create(groupname=username, gid=gid) + user = self.create(username=username, group=group, uid=uid, + homedir=homedir, + shell=settings.OSUSER_DEFAULT_SHELL) + shadow = Shadow.objects.create_shadow(user=user, password=password) + user.save() + shadow.save() + transaction.commit() + if autocommit: + transaction.set_autocommit(True) + return user + + @python_2_unicode_compatible class User(TimeStampedModel, models.Model): username = models.CharField( @@ -35,6 +98,8 @@ class User(TimeStampedModel, models.Model): homedir = models.CharField(_('Home directory'), max_length=256) shell = models.CharField(_('Login shell'), max_length=64) + objects = UserManager() + class Meta: verbose_name = _('User') verbose_name_plural = _('Users') @@ -43,6 +108,20 @@ class User(TimeStampedModel, models.Model): return '{0} ({1})'.format(self.username, self.uid) +class ShadowManager(models.Manager): + + def create_shadow(self, user, password): + changedays = (timezone.now().date() - date(1970, 1, 1)).days + pwhash = sha512_crypt.encrypt(password) + shadow = self.create( + user=user, changedays=changedays, + minage=0, maxage=None, gracedays=7, + inactdays=30, expiredays=None, passwd=pwhash + ) + shadow.save() + return shadow + + @python_2_unicode_compatible class Shadow(TimeStampedModel, models.Model): user = models.OneToOneField(User, primary_key=True, verbose_name=_('User')) @@ -77,6 +156,8 @@ class Shadow(TimeStampedModel, models.Model): ' number of days since Jan 1, 1970'), blank=True, null=True, default=None) + objects = ShadowManager() + class Meta: verbose_name = _('Shadow password') verbose_name_plural = _('Shadow passwords')