Première version : mise en route du suivi.
authorCyril Robert <Cyril Robert crobert@inverse.ca>
Tue, 16 Feb 2010 20:12:15 +0000 (15:12 -0500)
committerCyril Robert <Cyril Robert crobert@inverse.ca>
Tue, 16 Feb 2010 20:12:15 +0000 (15:12 -0500)
21 files changed:
.gitignore [new file with mode: 0644]
auf_roa_authentification_backend/__init__.py [new file with mode: 0644]
auf_roa_authentification_backend/backends.py [new file with mode: 0644]
auf_roa_authentification_backend/models.py [new file with mode: 0644]
auf_roa_authentification_backend/serializers.py [new file with mode: 0644]
auf_roa_authentification_backend/tests.py [new file with mode: 0644]
auf_roa_authentification_backend/views.py [new file with mode: 0644]
exemple-client/__init__.py [new file with mode: 0644]
exemple-client/client/__init__.py [new file with mode: 0644]
exemple-client/client/models.py [new file with mode: 0644]
exemple-client/client/tests.py [new file with mode: 0644]
exemple-client/client/views.py [new file with mode: 0644]
exemple-client/conf.py.edit [new file with mode: 0644]
exemple-client/manage.py [new file with mode: 0644]
exemple-client/settings.py [new file with mode: 0644]
exemple-client/templates/container_base.html [new file with mode: 0644]
exemple-client/templates/index.html [new file with mode: 0644]
exemple-client/templates/login.html [new file with mode: 0644]
exemple-client/templates/login_form.html [new file with mode: 0644]
exemple-client/urls.py [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..f3a6bf6
--- /dev/null
@@ -0,0 +1,31 @@
+# All compiled binaries..
+*.pyc
+*.pyo
+
+# Fichier temporaires:
+.*.swp
+*~
+\#*#
+*.db
+
+# Ignore merged stuff
+*.orig
+*.rej
+
+# Configuration du projet - par environnement
+conf.py
+django.wsgi
+
+# les évaluations passées en PDF
+evaluation/docs/*
+
+# buildout
+.installed.cfg
+bin
+develop-eggs
+downloads
+eggs
+log
+parts
+project/media/uploads
+tmp
diff --git a/auf_roa_authentification_backend/__init__.py b/auf_roa_authentification_backend/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/auf_roa_authentification_backend/backends.py b/auf_roa_authentification_backend/backends.py
new file mode 100644 (file)
index 0000000..58eeae0
--- /dev/null
@@ -0,0 +1,72 @@
+# -*- 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 models import AufUser 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).hexdigest ()
+
+        # Cherche les comptes roa+locaux
+        remoteUser = localUser = None
+        try:
+            remoteUser = RemoteUser.objects.get (email=email)
+        except Exception as inst:
+            #print type(inst)     # the exception instance
+            #print inst.args      # arguments stored in .args
+            #print inst
+            pass
+        try:
+            localUser = DjangoUser.objects.get (username=username)
+        except: pass
+
+        # 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.first_name,
+                        last_name = remoteUser.last_name,
+                        is_staff = False,
+                        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 = False,
+                        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.first_name
+                localUser.last_name = remoteUser.last_name
+                # pass distant en md5
+                if remoteUser.password == md5pass:
+                    localUser.set_password (password)
+                    localUser.save ()
+                    user = localUser
+
+        return user
diff --git a/auf_roa_authentification_backend/models.py b/auf_roa_authentification_backend/models.py
new file mode 100644 (file)
index 0000000..88b5736
--- /dev/null
@@ -0,0 +1,14 @@
+from django.db import models
+from django.conf import settings
+
+class AufUser (models.Model):
+    email = models.CharField (primary_key=True, max_length=60, db_column='courriel')
+    password = models.CharField (max_length=35, db_column='motdepasse')
+    first_name = models.CharField (max_length=50, db_column='prenom')
+    last_name = models.CharField (max_length=50, db_column='nom')
+    @staticmethod
+    def get_resource_url_list():
+        return u"%suser/" % settings.ROA_BASE_URL
+    class Meta:
+        db_table = 'utilisateurs'
+        managed = False
diff --git a/auf_roa_authentification_backend/serializers.py b/auf_roa_authentification_backend/serializers.py
new file mode 100644 (file)
index 0000000..c5b6550
--- /dev/null
@@ -0,0 +1,31 @@
+from django.conf import settings
+from django.utils.xmlutils import SimplerXMLGenerator
+
+from django.core.serializers.xml_serializer import Serializer as XMLSerializer, \
+                                                   Deserializer as XMLDeserializer
+
+class Serializer(XMLSerializer):
+    """
+    A test serializer which removes ``django-objects`` xml tag from default
+    Django's xml serializer, adapt it to your own usage.
+    """
+    
+    def start_serialization(self):
+        """
+        Start serialization -- open the XML document and the root element.
+        """
+        self.xml = SimplerXMLGenerator(self.stream, self.options.get("encoding", settings.DEFAULT_CHARSET))
+        self.xml.startDocument()
+        self.xml.startElement("django-test", {"version" : "1.0"})
+
+    def end_serialization(self):
+        """
+        End serialization -- end the document.
+        """
+        self.indent(0)
+        self.xml.endElement("django-test")
+        self.xml.endDocument()
+
+
+class Deserializer(XMLDeserializer):
+    pass
diff --git a/auf_roa_authentification_backend/tests.py b/auf_roa_authentification_backend/tests.py
new file mode 100644 (file)
index 0000000..2247054
--- /dev/null
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
diff --git a/auf_roa_authentification_backend/views.py b/auf_roa_authentification_backend/views.py
new file mode 100644 (file)
index 0000000..60f00ef
--- /dev/null
@@ -0,0 +1 @@
+# Create your views here.
diff --git a/exemple-client/__init__.py b/exemple-client/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/exemple-client/client/__init__.py b/exemple-client/client/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/exemple-client/client/models.py b/exemple-client/client/models.py
new file mode 100644 (file)
index 0000000..71a8362
--- /dev/null
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/exemple-client/client/tests.py b/exemple-client/client/tests.py
new file mode 100644 (file)
index 0000000..2247054
--- /dev/null
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
diff --git a/exemple-client/client/views.py b/exemple-client/client/views.py
new file mode 100644 (file)
index 0000000..282647e
--- /dev/null
@@ -0,0 +1,37 @@
+from django.http import HttpResponseRedirect
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth import authenticate, login
+from django.contrib.auth.views import logout
+from django.shortcuts import render_to_response
+from django.template import Context, RequestContext
+
+@login_required
+def index (request):
+    return render_to_response ("index.html", \
+            Context ({"user": request.user}), \
+            context_instance = RequestContext(request))
+
+def login_view (request):
+    error = None
+
+    # Identification envoyee
+    if request.method == "POST":
+        try:
+            username = request.POST['email']
+            password = request.POST['pass']
+        except:
+            error = ""
+
+        user = authenticate (username=username, password=password)
+        if user is not None:
+            login(request, user)
+            return HttpResponseRedirect (request.GET['next'])
+        else:
+            error = "Compte invalide."
+
+    return render_to_response ("login.html", \
+            Context ({"error": error}), \
+            context_instance = RequestContext(request))
+
+def logout_view (request):
+    return logout (request, "/")
diff --git a/exemple-client/conf.py.edit b/exemple-client/conf.py.edit
new file mode 100644 (file)
index 0000000..c10957a
--- /dev/null
@@ -0,0 +1,11 @@
+# -*- encoding: utf-8 -*-
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+AUTH_PASSWORD_REQUIRED = False
+
+DATABASE_ENGINE = 'sqlite'
+DATABASE_NAME = 'dev.db'
+DATABASE_USER = ''
+DATABASE_PASSWORD = ''
+DATABASE_HOST = ''
+DATABASE_PORT = ''
diff --git a/exemple-client/manage.py b/exemple-client/manage.py
new file mode 100644 (file)
index 0000000..5e78ea9
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+try:
+    import settings # Assumed to be in the same directory.
+except ImportError:
+    import sys
+    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+    sys.exit(1)
+
+if __name__ == "__main__":
+    execute_manager(settings)
diff --git a/exemple-client/settings.py b/exemple-client/settings.py
new file mode 100644 (file)
index 0000000..a71d96b
--- /dev/null
@@ -0,0 +1,104 @@
+# Django settings for exemple_client project.
+import os
+from conf import DEBUG, TEMPLATE_DEBUG, AUTH_PASSWORD_REQUIRED, \
+    DATABASE_ENGINE, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD, \
+    DATABASE_HOST, DATABASE_PORT
+
+if DEBUG:
+    import sys
+    sys.path.append ("../../")
+
+ADMINS = (
+    # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'America/Montreal'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = ''
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+MEDIA_URL = ''
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/media/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = 'm1$u@d+jhgt#n=8t0z))=xg=92q(p+km8#16km)lx_b6^l+vt8'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.load_template_source',
+    'django.template.loaders.app_directories.load_template_source',
+#     'django.template.loaders.eggs.load_template_source',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+)
+
+ROOT_URLCONF = 'urls'
+
+TEMPLATE_DIRS = (
+    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+    # Always use forward slashes, even on Windows.
+    # Don't forget to use absolute paths, not relative paths.
+    os.path.join(os.path.dirname(__file__), 'templates').replace('\\', '/'),
+)
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django_roa',
+    'django_roa.remoteauth',
+    'client',
+    'auf_roa_authentification_backend',
+)
+
+###################3
+# Important! 
+
+AUTHENTICATION_BACKENDS = (
+    'auf_roa_authentification_backend.backends.CascadeBackend',
+)
+ROA_MODELS = True   # set to False if you'd like to develop/test locally
+ROA_FORMAT = 'django'
+ROA_HEADERS = {
+    'Content-Type': 'application/x-www-form-urlencoded',
+}
+ROA_DJANGO_ERRORS = True # useful to ease debugging if you use test server
+
+ROA_MODEL_NAME_MAPPING = (
+    ('remoteauth.', 'auth.'),
+)
+ROA_BASE_URL = 'http://localhost:8003/auth/'
+SERIALIZATION_MODULES = {
+    'django' : 'auf_roa_authentification_backend.serializers',
+}
+
diff --git a/exemple-client/templates/container_base.html b/exemple-client/templates/container_base.html
new file mode 100644 (file)
index 0000000..282d2ef
--- /dev/null
@@ -0,0 +1,8 @@
+<html>
+<head>
+    <title>ROA</title>
+</head>
+<body>
+<div id="contenu">{% block contenu %}{% endblock %}</div>
+</body>
+</html>
diff --git a/exemple-client/templates/index.html b/exemple-client/templates/index.html
new file mode 100644 (file)
index 0000000..f5f7cf0
--- /dev/null
@@ -0,0 +1,9 @@
+{% extends "container_base.html" %}
+
+{% block contenu %}
+<h1>AUF-ROA</h1>
+
+Utilisateur: {{ user.username }}
+<a href="{% url client.views.logout_view %}">Logout</a>
+
+{% endblock %}
diff --git a/exemple-client/templates/login.html b/exemple-client/templates/login.html
new file mode 100644 (file)
index 0000000..d079aa2
--- /dev/null
@@ -0,0 +1,13 @@
+{% extends "container_base.html" %}
+
+{% block contenu %}
+<h1>AUF-ROA</h1>
+
+{% if error %}
+    <p class="error">{{error}}</p>
+{%endif%}
+    <p>
+    {% include 'login_form.html' %}
+    </p>
+
+{% endblock %}
diff --git a/exemple-client/templates/login_form.html b/exemple-client/templates/login_form.html
new file mode 100644 (file)
index 0000000..f668042
--- /dev/null
@@ -0,0 +1,18 @@
+<form method="post">
+    <table cellspacing="0" cellpadding="0" border="0" summary="" class="Rech">
+        <tbody>
+            <tr>
+                <td>Utilisateur :</td>
+                <td><input type="text" size="32" name="email"/></td>
+            </tr>
+            <tr>
+                <td>Mot de passe :</td>
+                <td><input type="password" size="32" name="pass"/></td>
+            </tr>
+            <tr>
+                <td colspan="2"><br/>
+                    <input type="submit" value="Continuer" name="entrer"/></td>
+            </tr>
+        </tbody>
+    </table>
+</form>
diff --git a/exemple-client/urls.py b/exemple-client/urls.py
new file mode 100644 (file)
index 0000000..5136d45
--- /dev/null
@@ -0,0 +1,20 @@
+from django.conf.urls.defaults import *
+
+# Uncomment the next two lines to enable the admin:
+from django.contrib import admin
+admin.autodiscover()
+
+urlpatterns = patterns('',
+    # Example:
+    # (r'^exemple_client/', include('exemple_client.foo.urls')),
+
+    # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 
+    # to INSTALLED_APPS to enable admin documentation:
+    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+    # Uncomment the next line to enable the admin:
+    (r'^admin/', include(admin.site.urls)),
+    (r'^$', 'client.views.index'),
+    (r'^accounts/login/', 'client.views.login_view'),
+    (r'^accounts/logout/', 'client.views.logout_view'),
+)
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..03dadd5
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,26 @@
+# -*- encoding: utf-8 -*-
+from setuptools import setup, find_packages
+import sys, os
+
+version = '1.0'
+
+setup(name='auf_roa_authentification_backend',
+      version=version,
+      description="Backend pour l'authentification centralisée par ROA",
+      long_description="""\
+""",
+      classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+      keywords='',
+      author='Cyril Robert',
+      author_email='cyril.robert@auf.org',
+      url='',
+      license='GPL',
+      packages=find_packages(exclude=['ez_setup', 'tests', "exemple-client", "exemple-client.*"]),
+      #packages = ["auf_roa_authentification_backend",],
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=['django', 'django_roa'],
+      entry_points="""
+      # -*- Entry points: -*-
+      """,
+      )