move
authorOlivier Larchevêque <olivier.larcheveque@gmail.com>
Tue, 20 Sep 2011 19:08:37 +0000 (15:08 -0400)
committerOlivier Larchevêque <olivier.larcheveque@gmail.com>
Tue, 20 Sep 2011 19:08:37 +0000 (15:08 -0400)
17 files changed:
.gitignore [new file with mode: 0644]
CHANGES [new file with mode: 0644]
auf/__init__.py [new file with mode: 0644]
auf/django/__init__.py [new file with mode: 0644]
auf/django/auth/__init__.py [new file with mode: 0644]
auf/django/auth/backends.py [new file with mode: 0644]
auf/django/auth/context_processors.py [new file with mode: 0644]
auf/django/auth/decorateurs.py [new file with mode: 0644]
auf/django/auth/forms.py [new file with mode: 0644]
auf/django/auth/models.py [new file with mode: 0644]
auf/django/auth/utils.py [new file with mode: 0644]
auf/django/employe/__init__.py [new file with mode: 0644]
auf/django/employe/management/__init__.py [new file with mode: 0644]
auf/django/employe/management/commands/__init__.py [new file with mode: 0644]
auf/django/employe/management/commands/employes.py [new file with mode: 0755]
setup.cfg [new file with mode: 0644]
setup.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..499a075
--- /dev/null
@@ -0,0 +1,4 @@
+*.pyc
+*egg-info
+build
+dist
diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..908212f
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,40 @@
+auf.django.auth
+===============
+
+0.5.6
+-----
+
+* Ajout de la commande bin/django employes importer pour prépopuler les users Django
+
+0.5.5
+-----
+
+* fix print
+
+0.5.4
+-----
+
+* fix utf-8
+
+
+0.5.3 (indisponible)
+-----
+
+* fix résidu merge
+
+
+0.5.2
+-----
+
+* FIX : USERS_AS_STAFF 
+
+
+0.5.1
+-----
+
+* Par défaut, les users Django sont staff
+
+0.5
+---
+
+* Création du module auth basé sur ref_authentication
diff --git a/auf/__init__.py b/auf/__init__.py
new file mode 100644 (file)
index 0000000..35cf25b
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except:
+    # bootstrapping
+    pass
diff --git a/auf/django/__init__.py b/auf/django/__init__.py
new file mode 100644 (file)
index 0000000..35cf25b
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except:
+    # bootstrapping
+    pass
diff --git a/auf/django/auth/__init__.py b/auf/django/auth/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auf/django/auth/backends.py b/auf/django/auth/backends.py
new file mode 100644 (file)
index 0000000..c2c75d8
--- /dev/null
@@ -0,0 +1,79 @@
+# -*- encoding: utf-8 -*-
+
+import hashlib, sys
+
+from django.conf import settings
+from django.contrib.auth.backends import ModelBackend
+from django.contrib.auth.models import User as DjangoUser, check_password
+
+from datamaster_modeles.models import Authentification as RemoteUser
+
+class CascadeBackend(ModelBackend):
+    def authenticate(self, username=None, password=None):
+        user = None
+
+        # Prep des données
+        if username.endswith ("@auf.org"):
+            username = username.replace ("@auf.org", "")
+
+        email = "%s@auf.org" % username
+        md5pass = hashlib.md5(password.encode('utf-8')).hexdigest()
+
+        # Cherche les comptes roa+locaux
+        remoteUser = localUser = None
+        try:
+            if settings.AUTH_PASSWORD_REQUIRED:
+                remoteUser = RemoteUser.objects.get (courriel=email, motdepasse=md5pass)
+            else:
+                remoteUser = RemoteUser.objects.get (courriel=email)
+        except:
+            pass
+        try:
+            localUser = DjangoUser.objects.get (username=username)
+        except: pass
+        
+        # remoteUser : prenom et nom à partir de courriel
+        if remoteUser:
+            prenom_nom = email.replace('@auf.org','')
+            prenom, sep, nom = prenom_nom.partition('.')
+            remoteUser.prenom = prenom.title()
+            remoteUser.nom = nom.title()
+        
+        # Si on a pas besoin du mdp, on doit copier qd meme,
+        # il ne faut jamais retourner un "RemoteUser" ici
+        if not settings.AUTH_PASSWORD_REQUIRED:
+            if remoteUser and not localUser:
+                localUser = DjangoUser (username = username,
+                        email = email, 
+                        first_name = remoteUser.prenom,
+                        last_name = remoteUser.nom,
+                        is_staff = True,
+                        is_active = True,
+                        is_superuser = False)
+                localUser.set_password (password)
+                localUser.save ()
+            user = localUser
+        # Gestion des comptes roa vs. local
+        else:
+            # Local existe pas, on doit de tte facon le creer
+            if not localUser:
+                localUser = DjangoUser (username = username,
+                        email = email, 
+                        is_staff = True,
+                        is_active = True,
+                        is_superuser = False)
+            # Cas du compte local seul, on verifie le mot de passe
+            elif not remoteUser:
+                if localUser.check_password (password):
+                    user = localUser
+            # Compte roa, on valide le mot de passe distant et on
+            # met a jour la copie locale
+            if remoteUser:
+                localUser.first_name = remoteUser.prenom
+                localUser.last_name = remoteUser.nom
+                # pass distant en md5
+                localUser.set_password (password)
+                localUser.save ()
+                user = localUser
+
+        return user
diff --git a/auf/django/auth/context_processors.py b/auf/django/auth/context_processors.py
new file mode 100644 (file)
index 0000000..8b2ba9d
--- /dev/null
@@ -0,0 +1,17 @@
+# -*- encoding: utf-8 -*-
+
+from utils import employe_auf
+
+def auth(request):
+    """
+    Fournit des informations relatives à l'AUF
+    """
+    def est_employe_auf():
+        if hasattr(request, 'user'):
+            return employe_auf(request.user)
+        else:
+            return False
+
+    return {
+        'est_employe_auf' : est_employe_auf(),
+    }
diff --git a/auf/django/auth/decorateurs.py b/auf/django/auth/decorateurs.py
new file mode 100644 (file)
index 0000000..f20d0b6
--- /dev/null
@@ -0,0 +1,18 @@
+# -*- encoding: utf-8 -*-
+
+from django.contrib.auth.decorators import user_passes_test
+from django.contrib.auth import REDIRECT_FIELD_NAME
+from utils import employe_auf
+
+def employe_auf_requis(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
+    """
+    S'assure que le membre connecté dispose d'un compte dans ref_autentification
+    Redirige vers la page de login, si nécessaire
+    """
+    actual_decorator = user_passes_test(
+        employe_auf,
+        redirect_field_name=redirect_field_name
+    )
+    if function:
+        return actual_decorator(function)
+    return actual_decorator
diff --git a/auf/django/auth/forms.py b/auf/django/auth/forms.py
new file mode 100644 (file)
index 0000000..1c805bf
--- /dev/null
@@ -0,0 +1,21 @@
+# -*- encoding: utf-8 -*-
+
+import django.contrib.auth
+from django.contrib.auth.forms import  UserCreationForm, UserChangeForm
+from models import AUFUser, USERNAME_LENGTH, USERNAME_REGEXP, USERNAME_HELP
+
+class AUFUserCreationForm(UserCreationForm):
+    username = forms.RegexField(label=_("Username"), max_length=USERNAME_LENGTH, regex=USERNAME_REGEXP,
+        help_text = _(USERNAME_HELP),
+        error_messages = {'invalid': _(USERNAME_HELP)})
+
+class AUFUserChangeForm(UserChangeForm):
+    username = forms.RegexField(label=_("Username"), max_length=USERNAME_LENGTH, regex=USERNAME_REGEXP,
+        help_text = _(USERNAME_HELP),
+        error_messages = {'invalid': _(USERNAME_HELP)})
+
+# Remplace les formulaires pour fonctionner avec le modèle patché des users Django
+django.contrib.auth.forms.UserCreationForm = AUFUserCreationForm
+django.contrib.auth.forms.UserChangeForm = AUFUserChangeForm
+django.contrib.auth.forms.UserChangeForm.Meta.exclude = ('password', )
+
diff --git a/auf/django/auth/models.py b/auf/django/auth/models.py
new file mode 100644 (file)
index 0000000..6d4b6ac
--- /dev/null
@@ -0,0 +1,47 @@
+# -*- encoding: utf-8 -*-
+
+from django.db import models
+from django.db.models.signals import pre_save, pre_init, pre_delete
+from django.contrib.auth.models import User, UserManager, get_hexdigest, check_password as django_check_password
+from django.core.validators import email_re
+from django.utils.translation import ugettext_lazy as _
+import django.contrib.auth
+import django.contrib.auth.forms
+
+USERNAME_LENGTH = 75
+USERNAME_REGEXP = email_re
+USERNAME_HELP =  "L'identifiant doît être un courriel."
+
+
+def set_password(user, raw_password):
+    """Défini un mot de passe md5"""
+    user.password = get_hexdigest('md5', '', raw_password)
+
+def check_password(user, raw_password):
+    """
+    Test la correspondance du mot de passe md5.
+    S'il a été haché avec le système django par défaut,
+    il le transforme sous pour le crypter en md5.
+    """
+    if len(user.password) != 32:
+        if django_check_password(raw_password, user.password):
+            user.set_password(raw_password)
+            user.save()
+    return get_hexdigest('md5', '', raw_password) == user.password
+
+
+def save(user, **kwargs):
+    return super(User, user).save(**kwargs)
+
+def delete(user, **kwargs):
+    return super(User, user).delete(**kwargs)
+
+
+django.contrib.auth.models.User._meta.get_field_by_name('username')[0].max_length = USERNAME_LENGTH
+django.contrib.auth.models.User._meta.get_field_by_name('username')[0].help_text = USERNAME_HELP
+django.contrib.auth.models.User._meta.get_field_by_name('password')[0].help_text = "<a href=\"password/\">Changer le mot de passe</a>"
+
+django.contrib.auth.models.User.set_password = set_password
+django.contrib.auth.models.User.check_password = check_password
+django.contrib.auth.models.User.save = save
+django.contrib.auth.models.User.delete = delete
diff --git a/auf/django/auth/utils.py b/auf/django/auth/utils.py
new file mode 100644 (file)
index 0000000..11072e3
--- /dev/null
@@ -0,0 +1,8 @@
+# -*- encoding: utf-8 -*-
+
+#from datamaster_modeles.models import Authentification
+
+def employe_auf(userDjango):
+    """Test si le user est un employé de l'AUF à partir de la Employe"""
+    return True
+#    return userDjango.is_authenticated() and Authentification.objects.filter(courriel=userDjango.email, actif=1).count() == 1
diff --git a/auf/django/employe/__init__.py b/auf/django/employe/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auf/django/employe/management/__init__.py b/auf/django/employe/management/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auf/django/employe/management/commands/__init__.py b/auf/django/employe/management/commands/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auf/django/employe/management/commands/employes.py b/auf/django/employe/management/commands/employes.py
new file mode 100755 (executable)
index 0000000..59f9704
--- /dev/null
@@ -0,0 +1,42 @@
+# -*- encoding: utf-8 -*-
+
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import User 
+from datamaster_modeles.models import Authentification as RemoteUser
+
+class Command(BaseCommand):
+    help = u"""
+        * importer : création des users Django à partir des employés.
+    """
+
+    def handle(self, *args, **options):
+        if len(args) != 1:
+            print self.help
+            return
+
+        command = args[0]
+        if command.lower() == u"importer":
+            self.importer()
+            return "\nImportation terminée"
+
+    def importer(self):
+        employes = RemoteUser.objects.filter(actif=True)
+        for employe in employes:
+
+            username = employe.courriel.replace(u"@auf.org", u"")
+            prenom, sep, nom = username.partition('.')
+            
+            if User.objects.filter(username=username).exists():
+                print "~ %s" % User.objects.get(username=username)
+                continue
+
+            user = User()
+            user.username = username
+            user.first_name = prenom.title()
+            user.last_name = nom.title()
+            user.email = employe.courriel
+            user.is_staff = True
+            user.is_active = True
+            user.is_superuser = False
+            user.save()
+            print "+ %s" % user
diff --git a/setup.cfg b/setup.cfg
new file mode 100644 (file)
index 0000000..01bb954
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,3 @@
+[egg_info]
+tag_build = dev
+tag_svn_revision = true
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..6072928
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,32 @@
+from setuptools import setup, find_packages
+import sys, os
+
+name = 'auf.django.auth'
+version = '0.5.6'
+
+setup(name=name,
+      version=version,
+      description="Module d'autentification Django de l'AUF",
+      long_description="""\
+""",
+      classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+      keywords='AUF auth django',
+      author='Olivier Larchev\xc3\xaaque',
+      author_email='olivier.larcheveque@auf.org',
+      url='http://pypi.auf.org/%s' % name,
+      license='GPL',
+      namespace_packages = ['auf', ],
+      packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
+      include_package_data=True,
+      zip_safe=False,
+      dependency_links = [
+        'http://pypi.auf.org/datamaster_modeles',
+      ],
+      install_requires=[
+          # -*- Extra requirements: -*-
+          'datamaster_modeles',
+      ],
+      entry_points="""
+      # -*- Entry points: -*-
+      """,
+      )