From 5dbce99e650f7c0e5e3b38b5c6c4d7817d111118 Mon Sep 17 00:00:00 2001 From: Kloadut Date: Sun, 7 Oct 2012 23:51:40 +0200 Subject: [PATCH] user_add function --- lib/yunohost_ldap.py | 47 ++++++++++++++++++++++++++++----- lib/yunohost_messages.py | 22 +++++++++++++--- lib/yunohost_user.py | 57 +++++++++++++++++++++++++++++++++++++--- yunohost | 4 +-- 4 files changed, 114 insertions(+), 16 deletions(-) diff --git a/lib/yunohost_ldap.py b/lib/yunohost_ldap.py index 4dc166a2..9b21ecf3 100644 --- a/lib/yunohost_ldap.py +++ b/lib/yunohost_ldap.py @@ -2,6 +2,8 @@ import sys import ldap +import ldap.modlist as modlist +import re import getpass import yunohost_messages as msg @@ -18,7 +20,7 @@ class YunoHostLDAP: self.conn.simple_bind_s('cn=admin,' + self.base, self.pwd) except ldap.INVALID_CREDENTIALS: print(msg.error + _('Wrong credentials')) - sys.exit(1) + sys.exit(msg.ECONNREFUSED) def disconnect(self): """ Unbind from LDAP """ @@ -26,7 +28,7 @@ class YunoHostLDAP: try: self.conn.unbind_s() except: - print(msg.error + _('A problem occured on LDAP unbind')) + print(msg.error + _('A problem occured during LDAP unbind')) return False else: return True @@ -38,9 +40,9 @@ class YunoHostLDAP: base = self.base try: - result = self.conn.search_s(base, ldap.SCOPE_ONELEVEL, filter, attrs) - except Exception: - print(msg.error + _('An error occured on LDAP search')) + result = self.conn.search_s(base, ldap.SCOPE_SUBTREE, filter, attrs) + except: + print(msg.error + _('An error occured during LDAP search')) return False if result: @@ -51,5 +53,38 @@ class YunoHostLDAP: result_list.append(entry) return result_list else: - print(_('No result found')) return False + + def add(self, rdn, attr_dict): + """ Add LDAP entry """ + + dn = rdn + ',' + self.base + ldif = modlist.addModlist(attr_dict) + + try: + self.conn.add_s(dn, ldif) + except: + print(msg.error + _('An error occured during LDAP entry creation')) + return False + else: + return True + + + def validate(self, regex_dict): + for attr, pattern in regex_dict.items(): + if re.match(pattern, attr): + continue + else: + print(msg.error + _('Invalid value') + ' "' + attr + '"') + sys.exit(msg.EINVAL) + return True + + def validate_uniqueness(self, value_dict): + for attr, value in value_dict.items(): + if not self.search(filter=attr + '=' + value): + continue + else: + print(msg.error + _('Attribute already exists') + ' "' + attr + '=' + value + '"') + sys.exit(msg.EEXIST) + return True + diff --git a/lib/yunohost_messages.py b/lib/yunohost_messages.py index d192cdc5..5dc2130c 100644 --- a/lib/yunohost_messages.py +++ b/lib/yunohost_messages.py @@ -1,6 +1,20 @@ # -*- coding: utf-8 -*- -error = "\033[31m\033[1m" + _("Error:") + "\033[m " -interrupt = "\033[31m\033[1m" + _("Interrupt:") + "\033[m " -notice = "\033[34m\033[1m" + _("Notice:") + "\033[m " -success = "\033[33m\033[1m" + _("Success:") + "\033[m " +""" Colored status messages """ +error = "\033[31m\033[1m" + _("Error:") + "\033[m " # Red +interrupt = "\033[31m\033[1m" + _("Interrupt:") + "\033[m " # Red +notice = "\033[34m\033[1m" + _("Notice:") + "\033[m " # Cyan +success = "\033[32m\033[1m" + _("Success:") + "\033[m " # Green + + +""" Error codes """ +EACCES = 13 # Permission denied +EEXIST = 17 # Exists +EINVAL = 22 # Invalid argument +EUSERS = 87 # Too many users +ECONNREFUSED = 111 # Connection refused +EDQUOTA = 122 # Quota exceeded +ECANCELED = 125 # Operation Canceled +ENOTFOUND = 167 # Not found +EUNDEFINED = 168 # Undefined +ELDAP = 169 # LDAP operation error diff --git a/lib/yunohost_user.py b/lib/yunohost_user.py index 5c12b0f7..d390a103 100644 --- a/lib/yunohost_user.py +++ b/lib/yunohost_user.py @@ -2,9 +2,11 @@ import sys import ldap -import ldap.modlist as modlist import yunohost_ldap import yunohost_messages as msg +import crypt +import random +import string import getpass # Initialize LDAP @@ -16,8 +18,18 @@ def user_list(args): # TODO : fix def user_add(args): + """ + Add user to LDAP + + Keyword argument: + args -- Dictionnary of values (can be empty) + + Returns: + Boolean + """ required_args = ['username', 'mail', 'firstname', 'lastname'] + # Input missing values try: for arg in required_args: if not args[arg]: @@ -28,11 +40,48 @@ def user_add(args): pwd2 = getpass.getpass('Retype password:') if args['password'] != pwd2: print(msg.error + _("Passwords doesn't match")) - sys.exit(1) + sys.exit(msg.EINVAL) except KeyboardInterrupt, EOFError: print("\n" + msg.interrupt + _("User not created")) - sys.exit(1) + sys.exit(msg.ECANCELED) + # Manage values + fullname = args['firstname'] + ' ' + args['lastname'] + rdn = 'cn=' + fullname + ',ou=users' + char_set = string.ascii_uppercase + string.digits + salt = ''.join(random.sample(char_set,8)) + salt = '$1$' + salt + '$' + pwd = "{CRYPT}" + crypt.crypt(str(args['password']), salt) + attr_dict = { + 'objectClass' : ['mailAccount', 'inetOrgPerson'], + 'givenName' : args['firstname'], + 'sn' : args['lastname'], + 'displayName' : fullname, + 'cn' : fullname, + 'uid' : args['username'], + 'mail' : args['mail'], + 'userPassword' : pwd + } - print(args) + # Validate values + yldap.validate({ + args['username'] : r'^[a-z0-9_]+$', + args['mail'] : r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,6}$' + }) + yldap.validate_uniqueness({ + 'uid' : args['username'], + 'cn' : fullname, + 'mail' : args['mail'], + 'mailalias' : args['mail'] + }) + + if yldap.add(rdn, attr_dict): + print('\n ' + msg.success + _('User successfully created') + '\n') + for attr, value in attr_dict.items(): + if attr != 'objectClass': + print('\033[35m\033[1m ' + attr + ': \033[m' + value) + return True + else: + print(msg.error + _('An error occured during user creation')) + return False diff --git a/yunohost b/yunohost index 447c3bed..a8ac1f57 100755 --- a/yunohost +++ b/yunohost @@ -49,7 +49,7 @@ def str_to_func(astr): func = getattr(mod, function) except NameError: print(msg.error + _('Function is not defined')) - sys.exit(1) + sys.exit(msg.EUNDEFINED) else: return func @@ -66,7 +66,7 @@ def dict_to_parsers(action_dict): """ # Intialize parsers - parsers = subparsers_category = subparsers_action = dict() + parsers = subparsers_category = subparsers_action = {} parsers['general'] = argparse.ArgumentParser() subparsers = parsers['general'].add_subparsers()