first commit
This commit is contained in:
commit
9eb63aa696
|
@ -0,0 +1,9 @@
|
||||||
|
Outils LDAP pour l'institu Curie
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Pour convertir des exports LDIF AD ou SUN:
|
||||||
|
|
||||||
|
curie2supann ad.ldif sun.ldif >supann.ldif
|
||||||
|
|
||||||
|
Ne sont exportés que les entrées pour lesquelles des enregistrements coté AD et
|
||||||
|
SUN sont trouvés.
|
|
@ -0,0 +1,195 @@
|
||||||
|
#!env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Mode d'emploi:
|
||||||
|
# exporter l'AD
|
||||||
|
# ldapsearch -E pr=2147483647/noprompt -H ldap://ad-server -D user -w password -b 'dc=curie,dc=lan' '(&(objectClass=user)(sAMAccountType=805306368))' >curie.ldif
|
||||||
|
# convertir vers SUPANN
|
||||||
|
# ./ldif_ad2supann.py <curie.ldif >curie2.ldif
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import unicodedata
|
||||||
|
import collections
|
||||||
|
|
||||||
|
import ldif
|
||||||
|
import ldap.dn
|
||||||
|
|
||||||
|
DC = 'curie'
|
||||||
|
O = 'Institut curie'
|
||||||
|
UAI = '{UAI}ATROUVER'
|
||||||
|
BASE_DN = 'dc=%s,dc=fr' % ldap.dn.escape_dn_chars(DC)
|
||||||
|
|
||||||
|
|
||||||
|
def lowercase_keys(d):
|
||||||
|
return dict((k.lower(), v) for k, v in d.iteritems())
|
||||||
|
|
||||||
|
|
||||||
|
def strip_accents(s):
|
||||||
|
s = unicode(s, 'utf-8')
|
||||||
|
return ''.join(c for c in unicodedata.normalize('NFD', s)
|
||||||
|
if unicodedata.category(c) != 'Mn').encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
class Error(Exception):
|
||||||
|
def __init__(self, dn, *args):
|
||||||
|
self.dn = dn
|
||||||
|
self.args = args
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '%s: %s' % (self.dn, ' '.join(map(str, self.args)))
|
||||||
|
|
||||||
|
|
||||||
|
class CurieLdifParser(ldif.LDIFParser):
|
||||||
|
'''Conversion LDAP Institut Curie vers SUPANN
|
||||||
|
|
||||||
|
Il faut aggréger les données venant de l'annuaire AD et de l'annuaire LDAP Sun
|
||||||
|
|
||||||
|
Attributs obligatoires:
|
||||||
|
|
||||||
|
uid <- AD employeeNumber ou LDAP uid @curie
|
||||||
|
givenname <- LDAP ICPrenomNaissance
|
||||||
|
sn <- LDAP ICNomNaissance
|
||||||
|
supannAliasLogin <- AD samAccountName ou LDAP ICLogin
|
||||||
|
userPassword <- {SASL}[samAccountName]@curie
|
||||||
|
supannListeRouge <- FALSE
|
||||||
|
|
||||||
|
Attribut optionnel:
|
||||||
|
|
||||||
|
telephoneNumber <- telephoneNumber
|
||||||
|
|
||||||
|
si LDAP.ICEntite == 'Recherche':
|
||||||
|
suppanEntiteAffectationPrincipale = LDAP.ICEquipeRecherche[0]['OU']
|
||||||
|
supannEntiteAffectation = LDAP.ICEntite
|
||||||
|
sinon si LDAP.ICEntite == 'Hopital'
|
||||||
|
supannEntiteAffectation = LDAP.ICEntite
|
||||||
|
sinon si LDAP.ICEneite == 'SI'
|
||||||
|
supannEntiteAffectation = LDAP.ICEntite
|
||||||
|
sinon:
|
||||||
|
error
|
||||||
|
|
||||||
|
Les erreurs seront disponible sur la sortie erreur.
|
||||||
|
'''
|
||||||
|
|
||||||
|
errors = None
|
||||||
|
users = None
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.errors = []
|
||||||
|
self.users = kwargs.pop('users', None) or collections.defaultdict(lambda: {})
|
||||||
|
ldif.LDIFParser.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def assert_sv_attribute(self, entry, name):
|
||||||
|
assert name in entry, 'attribut %s manquant' % name
|
||||||
|
assert len(entry[name]) == 1, 'plus d\'un attribut %s' % name
|
||||||
|
return entry[name][0]
|
||||||
|
|
||||||
|
def handle(self, dn, entry):
|
||||||
|
entry = lowercase_keys(entry)
|
||||||
|
try:
|
||||||
|
if 'employeenumber' in entry:
|
||||||
|
self.handle_ad(dn, entry)
|
||||||
|
elif 'ICPersonne' in entry['objectclass']:
|
||||||
|
self.handle_sun(dn, entry)
|
||||||
|
else:
|
||||||
|
raise Error(dn, 'entrée ignorée, car absence d\'attribut employeeNumber ou '
|
||||||
|
'objectClass=ICPersonne')
|
||||||
|
except AssertionError, e:
|
||||||
|
self.errors.append(Error(dn, str(e)))
|
||||||
|
|
||||||
|
def handle_ad(self, dn, entry):
|
||||||
|
uid = self.assert_sv_attribute(entry, 'employeenumber')
|
||||||
|
supann_alias_login = self.assert_sv_attribute(entry, 'samaccountname')
|
||||||
|
user_password = '{SASL}' + supann_alias_login + '@curie'
|
||||||
|
supann_liste_rouge = 'FALSE'
|
||||||
|
|
||||||
|
self.users[uid].update({
|
||||||
|
'uid': uid,
|
||||||
|
'supannAliasLogin': supann_alias_login,
|
||||||
|
'userPassword': user_password,
|
||||||
|
'supannListeRouge': supann_liste_rouge,
|
||||||
|
})
|
||||||
|
self.users[uid].setdefault('_source', set()).add('ad')
|
||||||
|
|
||||||
|
def handle_sun(self, dn, entry):
|
||||||
|
uid = self.assert_sv_attribute(entry, 'uid')
|
||||||
|
try:
|
||||||
|
ic_entite = self.assert_sv_attribute(entry, 'icentite')
|
||||||
|
except AssertionError:
|
||||||
|
ic_entite = None
|
||||||
|
else:
|
||||||
|
assert ic_entite in ('Recherche', 'Hopital', 'SI'), \
|
||||||
|
'valeur d\'ICEntite inconnue: %s' % ic_entite
|
||||||
|
supann_entite_affectation = ic_entite
|
||||||
|
prenom = self.assert_sv_attribute(entry, 'icprenomnaissance')
|
||||||
|
nom = self.assert_sv_attribute(entry, 'icnomnaissance')
|
||||||
|
telephone = entry.get('telephoneNumber', [])
|
||||||
|
if ic_entite == 'Recherche':
|
||||||
|
ic_equipe_recherche = self.assert_sv_attribute(entry, 'icequiperecherche')
|
||||||
|
ic_equipe_recherche_dn = ldap.dn.str2dn(ic_equipe_recherche)
|
||||||
|
assert ic_equipe_recherche[0][0][0].lower() == 'ou', ('ICEquipeRecherche ne contient '
|
||||||
|
'pas le DN d\'une OU: %s'
|
||||||
|
% ic_equipe_recherche)
|
||||||
|
supann_entite_affectation_principale = ic_equipe_recherche_dn[0][0][1]
|
||||||
|
else:
|
||||||
|
supann_entite_affectation_principale = None
|
||||||
|
d = {
|
||||||
|
'uid': uid,
|
||||||
|
'sn': nom,
|
||||||
|
'givenName': prenom,
|
||||||
|
'cn': strip_accents('%s %s' % (prenom, nom)).strip(),
|
||||||
|
}
|
||||||
|
if supann_entite_affectation:
|
||||||
|
d['supannEntiteAffectation'] = supann_entite_affectation
|
||||||
|
if telephone:
|
||||||
|
d['telephoneNumber'] = telephone
|
||||||
|
if supann_entite_affectation:
|
||||||
|
d['supannEntiteAffectationPrincipale'] = supann_entite_affectation_principale
|
||||||
|
self.users[uid].update(d)
|
||||||
|
self.users[uid].setdefault('_source', set()).add('sun')
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
users = None
|
||||||
|
if not sys.argv[1:]:
|
||||||
|
print 'Utilisation : curie2supann LDIF_FILE [LDIF_FILE..]'
|
||||||
|
print
|
||||||
|
print 'Le nouveau fichier LDIF est émis sur la sortie standard et les erreurs sur la sortie'
|
||||||
|
print 'erreur.'
|
||||||
|
sys.exit(1)
|
||||||
|
for path in sys.argv[1:]:
|
||||||
|
parser = CurieLdifParser(open(path), users=users)
|
||||||
|
parser.parse()
|
||||||
|
users = parser.users
|
||||||
|
|
||||||
|
if parser.errors:
|
||||||
|
print >>sys.stderr, path, 'ERRORS:', len(parser.errors)
|
||||||
|
for error in parser.errors:
|
||||||
|
print >>sys.stderr, ' -', error
|
||||||
|
else:
|
||||||
|
print >>sys.stderr, path, 'OK'
|
||||||
|
writer = ldif.LDIFWriter(sys.stdout)
|
||||||
|
for uid in users:
|
||||||
|
d = users[uid]
|
||||||
|
if d['_source'] != set(['ad', 'sun']):
|
||||||
|
msg = 'uid=%s uniquement dans l\'annuaire %s' % (uid, list(d['_source'])[0])
|
||||||
|
print >>sys.stderr, msg
|
||||||
|
else:
|
||||||
|
# make it globally unique
|
||||||
|
d['uid'] = d['uid'] + '@curie'
|
||||||
|
dn = [[('uid', d['uid'], 1)],
|
||||||
|
[('ou', 'people', 1)],
|
||||||
|
[('dc', DC, 1)],
|
||||||
|
[('dc', 'fr', 1)]]
|
||||||
|
entry = {}
|
||||||
|
for k, v in d.items():
|
||||||
|
if k.startswith('_'):
|
||||||
|
continue
|
||||||
|
if isinstance(v, list):
|
||||||
|
entry[k] = v
|
||||||
|
else:
|
||||||
|
entry[k] = [v]
|
||||||
|
writer.unparse(ldap.dn.dn2str(dn), entry)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -0,0 +1,5 @@
|
||||||
|
python-curie (0.0.0-1) jessie; urgency=low
|
||||||
|
|
||||||
|
* Initial package, targetting jessie.
|
||||||
|
|
||||||
|
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Mon, 9 May 2016 13:59:28 +0200
|
|
@ -0,0 +1 @@
|
||||||
|
ldaptools.egg-info/*
|
|
@ -0,0 +1 @@
|
||||||
|
7
|
|
@ -0,0 +1,14 @@
|
||||||
|
Source: python-curie
|
||||||
|
Section: python
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: Benjamin Dauvergne <bdauvergne@entrouvert.com>
|
||||||
|
Build-Depends: python-setuptools (>= 0.6b3), python-all (>= 2.6), debhelper (>= 7.4.3)
|
||||||
|
Standards-Version: 3.9.1
|
||||||
|
X-Python-Version: >= 2.7
|
||||||
|
Homepage: http://dev.entrouvert.org/projects/gi-psl/
|
||||||
|
|
||||||
|
Package: python-curie
|
||||||
|
Architecture: all
|
||||||
|
Depends: ${python:Depends}
|
||||||
|
XB-Python-Version: ${python:Versions}
|
||||||
|
Description: LDAP tools for Curie institute
|
|
@ -0,0 +1,25 @@
|
||||||
|
This package was debianized by Benjamin Dauvergne <bdauvergne@entrouvert.com> on
|
||||||
|
Mon, 11 Feb 2016 21:00:09 +0200
|
||||||
|
|
||||||
|
Upstream Author: Benjamin Dauvergne <bdauvergne@entrouvert.com>
|
||||||
|
|
||||||
|
Copyright (c) 2011 Entr'ouvert;
|
||||||
|
|
||||||
|
License is GNU GPL v3.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation; either version 3 of the License, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
On Debian GNU/Linux systems, the complete text of the GNU General Public
|
||||||
|
License can be found in `/usr/share/common-licenses/GPL'.
|
|
@ -0,0 +1 @@
|
||||||
|
python-ldap python-ldap
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@ --with python2
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
from setuptools.command.sdist import sdist
|
||||||
|
|
||||||
|
|
||||||
|
class eo_sdist(sdist):
|
||||||
|
def run(self):
|
||||||
|
print "creating VERSION file"
|
||||||
|
if os.path.exists('VERSION'):
|
||||||
|
os.remove('VERSION')
|
||||||
|
version = get_version()
|
||||||
|
version_file = open('VERSION', 'w')
|
||||||
|
version_file.write(version)
|
||||||
|
version_file.close()
|
||||||
|
sdist.run(self)
|
||||||
|
print "removing VERSION file"
|
||||||
|
if os.path.exists('VERSION'):
|
||||||
|
os.remove('VERSION')
|
||||||
|
|
||||||
|
|
||||||
|
def get_version():
|
||||||
|
'''Use the VERSION, if absent generates a version with git describe, if not
|
||||||
|
tag exists, take 0.0.0- and add the length of the commit log.
|
||||||
|
'''
|
||||||
|
if os.path.exists('VERSION'):
|
||||||
|
with open('VERSION', 'r') as v:
|
||||||
|
return v.read()
|
||||||
|
if os.path.exists('.git'):
|
||||||
|
p = subprocess.Popen(['git', 'describe', '--dirty', '--match=v*'], stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
result = p.communicate()[0]
|
||||||
|
if p.returncode == 0:
|
||||||
|
result = result.split()[0][1:]
|
||||||
|
else:
|
||||||
|
result = '0.0.0-%s' % len(subprocess.check_output(
|
||||||
|
['git', 'rev-list', 'HEAD']).splitlines())
|
||||||
|
return result.replace('-', '.').replace('.g', '+g')
|
||||||
|
return '0.0.0'
|
||||||
|
|
||||||
|
|
||||||
|
setup(name="curie",
|
||||||
|
version=get_version(),
|
||||||
|
license="AGPLv3+",
|
||||||
|
description="LDAP tools for Curie institute",
|
||||||
|
long_description=open('README.rst').read(),
|
||||||
|
url="http://dev.entrouvert.org/projects/ldaptools/",
|
||||||
|
author="Entr'ouvert",
|
||||||
|
author_email="authentic@listes.entrouvert.com",
|
||||||
|
maintainer="Benjamin Dauvergne",
|
||||||
|
maintainer_email="bdauvergne@entrouvert.com",
|
||||||
|
packages=['curie'],
|
||||||
|
include_package_data=True,
|
||||||
|
install_requires=['setuptools', 'python-ldap'],
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': ['curie2supann=curie.curie2supann:main'],
|
||||||
|
},
|
||||||
|
zip_safe=False,
|
||||||
|
cmdclass={'sdist': eo_sdist})
|
Reference in New Issue