# -*- coding: utf-8 -*- # # LOGIN.PY -- Gère l'interface d'authentification à l'aide des modèles Django. # # Copyright (C) 2009-2010 Nicolas Dandrimont # Authors: Nicolas Dandrimont # Censor: Antoine Durand-Gasselin # # 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, see . import ldap from django.contrib.auth.models import Group, User, Permission from django.contrib.auth.backends import ModelBackend from django.views.decorators.debug import sensitive_variables from django.contrib.contenttypes.models import ContentType # Pour se connecter à la base ldap import lc_ldap.shortcuts from intranet import conn_pool, settings GROUPES_SPECIAUX = { # Dictionnaire de groupe spéciaux à attribuer selon le test correspondant "crans_paiement_ok": lambda u: u.paiement_ok(), "crans_imprimeur_club": lambda u: u.imprimeur_clubs(), "crans_respo_club": lambda u: u.clubs(), "crans_adherent": lambda u: 'aid' in u, "crans_club": lambda u: 'cid' in u, } USER_TYPE = ContentType.objects.get(app_label="auth", model="user") CRANS_MULTIMACHINES,created = Permission.objects.get_or_create(codename=u"crans_multimachines", name=u"crans_multimachines", content_type=USER_TYPE) DROITS_SPECIAUX = { # Dictionnaire de groupe devant contenir les droits correspondant "crans_cableur": [CRANS_MULTIMACHINES], "crans_imprimeur": [CRANS_MULTIMACHINES], "crans_apprenti": [CRANS_MULTIMACHINES], "crans_bureau": [CRANS_MULTIMACHINES], "crans_ma": [CRANS_MULTIMACHINES], } def get_or_create_cransgroup(name): """ Crée le groupe crans_name avec le droit crans_name. """ group, created = Group.objects.get_or_create(name=name) if created: permission,created = Permission.objects.get_or_create(codename=name, name=name, content_type=USER_TYPE) group.permissions.add(permission) if name in DROITS_SPECIAUX: group.permissions.add(*DROITS_SPECIAUX[name]) group.save() return group def refresh_droits(user, cl_user, allow_staff=False): """ Rafraîchit les droits de l'utilisateur django `user' depuis l'utilisateur LDAP `cl_user'. N'ajoute pas les droits crans si allow_staff=False (default) """ cl_droits_reels = set(x.value for x in cl_user.get('droits', [])) if allow_staff: cl_droits = cl_droits_reels else: cl_droits = set() # Droit membre actif générique if cl_droits_reels: cl_droits.add(u"MA") if cl_droits_reels and allow_staff: cl_droits.add(u"enabled") # Fais le calcul des droits d'accès user.is_staff = not cl_droits.isdisjoint([u"Nounou", u"Apprenti", u"Imprimeur"]) user.is_superuser = not cl_droits.isdisjoint([u"Nounou"]) # et celui des groupes groups = [] for cl_droit in cl_droits: groups.append(get_or_create_cransgroup(name=u"crans_%s" % cl_droit.lower())) for group in GROUPES_SPECIAUX: if GROUPES_SPECIAUX[group](cl_user): groups.append(get_or_create_cransgroup(name=group)) user.groups = [ group for group in user.groups.all() if not group.name.startswith('crans_') ] user.groups.add(*groups) user.save() def refresh_fields(user, cl_user): """ Rafraîchit les champs correspondants à l'utilisateur (nom, prénom, email) """ user.first_name = unicode(cl_user.get('prenom', [u"club"])[0]) user.last_name = unicode(cl_user['nom'][0]) mail = unicode(cl_user.get('mail', cl_user['uid'])[0]) if '@' not in mail: # Ne devrait pas arriver (pour migration) mail += u'@crans.org' user.email = mail user.save() def post_cas_login(sender, user, created, attributes, ticket, service, **kwargs): ldap_user = conn_pool.get_user(user) refresh_droits(user, ldap_user) refresh_fields(user, ldap_user) class LDAPUserBackend(ModelBackend): """ Authentifie un utilisateur à l'aide de la base LDAP """ supports_anonymous_user = False @sensitive_variables('password') def authenticate(self, username=None, password=None, **kwargs): """ Authentifie l'utilisateur sur la base LDAP. Crée un utilisateur django s'il n'existe pas encore. """ # Si ``username`` ou ``password`` 'est pas fourni, on quitte if not username or not password: return None # Sinon, on ouvre une connexion shortcut = lc_ldap.shortcuts.lc_ldap_test if settings.BASE_LDAP_TEST else lc_ldap.shortcuts.lc_ldap try: # On ouvre une connection à la base LDAP avec les credentials de l'user conn = shortcut(user=username, cred=password) myself = conn.search(dn=conn.dn, scope=ldap.SCOPE_BASE) ldap_user = myself[0] except IndexError: # Si pas de resultats, on renvoie ``None`` return None except ldap.INVALID_CREDENTIALS: # Si les identifiants sont invalides, on renvoie ``None`` return None django_username = username try: # On essaie de récupérer l'utilisateur dans la base user = User.objects.get(username=django_username) except User.DoesNotExist: # Si l'utilisateur n'est pas dans la base, on le cré user = User( username=django_username, password="LDAP Backend User!", ) user.save() conn_pool.CONNS[django_username] = conn refresh_droits(user, ldap_user) refresh_fields(user, ldap_user) return user def get_user(self, uid): """ Récupère l'objet django correspondant à l'uid """ try: return User.objects.get(pk=uid) except User.DoesNotExist: return None