#!/usr/bin/env python # -*- coding: utf-8 -*- """Outil de gestion d'annuaire LDAP pour l'AuF. Copyright ©2009-2012 Agence universitaire de la Francophonie Licence : GPL version 3 Auteur : Progfou Dépendances Debian : python >= 2.5, auf-refer Usage : auf-annuaire.py | ldapmodify -x -c -D "cn=admin,o=AUF" -y /etc/ldap.secret """ import os import aufrefer LDAP_HOST = '127.0.0.1' LDAP_BASE = 'ou=People,o=AUF' LDAP_BINDDN = 'cn=admin,' + LDAP_BASE LDAP_PWFILE = ['~/.ldap.secret', '/etc/ldap.secret'] LDAP_INIT_LDIF = u"""dn: ou=People,o=AuF changeType: add objectClass: top objectClass: organizationalUnit ou: People """ ISO_3166 = aufrefer.get('iso-3166-fr.json') NOMS_BUREAU = aufrefer.get('bureaux.json') PAYS_IMPLANT = aufrefer.get('pays-implant.json') PHOTO_FILENAME = "/var/lib/auf-refer-photos/%s.jpg" def noms_bureau(cc): for code, data in NOMS_BUREAU.items(): if cc.upper() in data[1]: return code, data[0] return u'### implantation inconnue ###', u'### implantation inconnue ###' class LdapEntry(object): _attributes_order = [ 'objectClass', 'sn', 'givenName', 'cn', 'ou', 'c', 'mail', 'o', 'userPassword', 'telephoneNumber', 'uid', ] def __init__(self, dn, d=None, **kv): self.dn = dn if d: self.dict = d else: self.dict = { } self.dict.update(kv) def get(self, attribute): return self.dict.get(attribute, None) def set(self, attribute, value): old_value = self.dict.get(attribute, None) self.dict[attribute] = value return old_value def from_ldif(self, ldif): raise RuntimeError('Note implemented') def _to_ldif_line(self, attribute, value): to_encode = False for c in value: if c < ' ' or 'z' < c: to_encode = True break if to_encode: attribute = attribute + ':' if type(value) == unicode: value = value.encode('utf-8') value = value.encode('base64').replace('\n', '') return u'%s: %s' % (attribute, value) def to_ldif(self, changeType=None): ldif = [ ] ldif.append(self._to_ldif_line(u'dn', self.dn)) if changeType: ldif.append(u'changeType: %s' % changeType) set_keys = set(self.dict.keys()) set_attr_order = set(self._attributes_order) for k in set_keys & set_attr_order: for e in self.dict[k]: ldif.append(self._to_ldif_line(k, e)) for k in set_keys - set_attr_order: for e in self.dict[k]: ldif.append(self._to_ldif_line(k, e)) ldif.append(u'') return '\n'.join(ldif).encode('utf-8') class AnnuaireAuF(object): _attributes = [ 'adel', 'redir', 'nom', 'mdp', 'implant', 'coda', 'tel_ext', 'tel_ip', ] def __init__(self, ldap_base): self.ldap_base = ldap_base self.data = None def json2ldap(self, json_dict): implant = json_dict['implant'].upper() CC = PAYS_IMPLANT.get(implant, implant) nom_bureau_court, nom_bureau_long = noms_bureau(CC) adel = json_dict['adel'] user, domain = adel.rsplit('@', 1) cn = user.title().replace('-De-', '-de-').replace('.', ' ') if user.count('.') == 1: prenom, nom = cn.rsplit(' ', 1) else: # cas des noms vietnamiens nom, prenom = cn.rsplit(' ', 1) login = json_dict['login'] nom_affichage = json_dict['nom'] and json_dict['nom'] or cn ldap_dict = { } ldap_dict['objectClass'] = [ u'top', u'person', u'organizationalPerson', u'inetOrgPerson', u'inetLocalMailRecipient', u'mozillaAbPersonAlpha', ] ldap_dict['sn'] = [ nom ] ldap_dict['givenName'] = [ prenom ] ldap_dict['cn'] = [ nom_affichage ] ldap_dict['ou'] = [ u'People', nom_bureau_court, nom_bureau_long ] ldap_dict['c'] = [ CC ] ldap_dict['mail'] = [ adel ] ldap_dict['o'] = [ u'AuF', u'Agence universitaire de la Francophonie' ] if json_dict.has_key('mdp') and json_dict['mdp']: ldap_dict['userPassword'] = [ '{CRYPT}' + json_dict['mdp'] ] if json_dict.has_key('tel_ip') and json_dict['tel_ip']: ldap_dict['telephoneNumber'] = [ json_dict['tel_ip'] ] ldap_dict['uid'] = [ user ] if login is not None and login and login != user: ldap_dict['uid'].append(login) # objectClass: inetLocalMailRecipient ldap_dict['mailLocalAddress'] = [ json_dict['redir'] ] ldap_dict['mailHost'] = [ 'imaps://mail.%s:993' % json_dict['redir'].rsplit('@', 1)[1] ] # photo JPEG photo_filename = PHOTO_FILENAME % adel if os.path.exists(photo_filename): ldap_dict['jpegPhoto'] = [ file(photo_filename, 'rb').read() ] #ldap_dict['photo'] = [ file(photo_filename, 'rb').read() ] # compte POSIX if json_dict['employe']: ldap_dict['objectClass'].append(u'posixAccount') ldap_dict['uidNumber'] = [ str(2000 + int(json_dict['employe']['id'])) ] ldap_dict['gidNumber'] = [ str(100) ] ldap_dict['homeDirectory'] = [ '/home/auf/%s' % user ] ldap_dict['loginShell'] = [ '/bin/false' ] # message d'absence if json_dict['vacation']: ldap_dict['description'] = [ json_dict['vacation']['message'] ] debut = json_dict['vacation']['debut'] debut = '%s/%s/%s' % (debut[8:10], debut[5:7], debut[0:4]) fin = json_dict['vacation']['fin'] fin = '%s/%s/%s' % (fin[8:10], fin[5:7], fin[0:4]) ldap_dict['l'] = [ u'Absence du %s au %s' % (debut, fin) ] # identification unique ldap_dn = u'mail=%s,%s' % (adel, self.ldap_base) return ldap_dn, ldap_dict def load(self): self.data = [ ] employes = aufrefer.get('datamaster-employe.json') employes = dict([(e['courriel'],e) for e in employes if e['courriel']]) vacation = aufrefer.get('vacation.json') vacation = dict([(v['adel'],v) for v in vacation if v['adel']]) for json_dict in aufrefer.get('annuaire.json'): try: json_dict['employe'] = employes[json_dict['adel']] except: json_dict['employe'] = None try: json_dict['vacation'] = vacation[json_dict['adel']] except: json_dict['vacation'] = None ldap_dn, ldap_dict = self.json2ldap(json_dict) self.data.append(LdapEntry(ldap_dn, ldap_dict)) def to_ldif(self): ldif = [ LDAP_INIT_LDIF ] for d in self.data: ldif.append(d.to_ldif(changeType='add')) ldif.append('') return '\n'.join(ldif) def search(self, name): return filter(lambda x: x['adel'].find(name) >= 0, self.data) def update_ldap(self, base=LDAP_BASE, host=LDAP_HOST, binddn=LDAP_BINDDN, pwfile=LDAP_PWFILE): pass if __name__ == '__main__': annuaire = AnnuaireAuF(LDAP_BASE) annuaire.load() #print "search('andre'): %s" % \ # map(lambda x: x['adel'], annuaire.search('andre')) print annuaire.to_ldif(),