tags fix
authorOlivier Larchevêque <olivier.larcheveque@auf.org>
Fri, 18 Oct 2013 16:50:56 +0000 (12:50 -0400)
committerOlivier Larchevêque <olivier.larcheveque@auf.org>
Fri, 18 Oct 2013 16:50:56 +0000 (12:50 -0400)
21 files changed:
.gitignore
CHANGES
MANIFEST.in
auf/django/saml/admin.py
auf/django/saml/backends.py
auf/django/saml/decorators.py
auf/django/saml/forms.py
auf/django/saml/models.py [new file with mode: 0644]
auf/django/saml/monkey.py
auf/django/saml/settings.py
auf/django/saml/templatetags/saml.py
auf/django/saml/templatetags/saml_tags.py [new file with mode: 0644]
auf/django/saml/tests/__init__.py [new file with mode: 0644]
auf/django/saml/tests/common.py [new file with mode: 0644]
auf/django/saml/tests/saml.py [new file with mode: 0644]
auf/django/saml/tests/settings.py [new file with mode: 0644]
auf/django/saml/tests/templates/test_tags.html [new file with mode: 0644]
auf/django/saml/tests/urls.py [new file with mode: 0644]
auf/django/saml/views.py
doc/integration.rst
tox.ini [new file with mode: 0644]

index 40a0928..509646e 100644 (file)
@@ -20,3 +20,7 @@ doc/_*
 doc/build
 doc/pip-log.txt
 dist
+
+.tox
+.coverage
+htmlcov
diff --git a/CHANGES b/CHANGES
index d9ace8c..037b68e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,14 @@
+1.19
+----
+
+* ajouts tests
+
+* mise à jour doc intégration
+
+* fix settings
+
+* incompatible avec Django < 1.3 (takes_context - simple_tag)
+
 1.18
 ----
 
index 53fd1ed..44f655e 100644 (file)
@@ -1,2 +1,3 @@
 recursive-include auf/django/saml/templates *
 recursive-include auf/django/saml/static *
+recursive-include auf/django/saml/tests/templates *
index ae8989e..dad94c5 100644 (file)
@@ -3,9 +3,11 @@
 from views import redirect_to_login, redirect_to_logout
 from django.contrib.admin import site
 
+
 def saml_login(request, extra_context=None):
     return redirect_to_login(request)
 
+
 def saml_logout(request, extra_context=None):
     return redirect_to_logout(request)
 
@@ -13,4 +15,3 @@ def saml_logout(request, extra_context=None):
 # l'authentification pour communiquer avec l'IdP
 site.login = saml_login
 site.logout = saml_logout
-
index c3568c4..823ca0f 100644 (file)
@@ -19,6 +19,7 @@ class _BackendMixin:
         logger.info(info)
         return clean_username
 
+
 class FakeSPBackend(_BackendMixin, ModelBackend,):
     """
     On autentifie uniquement sur le username
@@ -36,7 +37,7 @@ class RealSPBackend(_BackendMixin, RemoteUserBackend):
     """
     Backend reposant sur le id.auf.org
     """
-    create_unknown_user = getattr(settings, 'SAML_AUTO_CREATION', True)
+    create_unknown_user = settings.SAML_AUTO_CREATION
 
 
 if settings.SAML_AUTH:
index 88dcf6b..cb79c50 100644 (file)
@@ -5,7 +5,8 @@ from permissions import is_employe
 from settings import SAML_REDIRECT_FIELD_NAME
 
 
-def employe_required(function=None,
+def employe_required(
+        function=None,
         redirect_field_name=SAML_REDIRECT_FIELD_NAME,
         login_url=None):
     """
@@ -21,7 +22,8 @@ def employe_required(function=None,
     return _wrapped_view
 
 
-def login_required(function=None,
+def login_required(
+        function=None,
         redirect_field_name=SAML_REDIRECT_FIELD_NAME,
         login_url=None):
     """
index d516ca4..a194982 100644 (file)
@@ -21,4 +21,3 @@ class RemoteUserForm(forms.Form):
                 raise forms.ValidationError("Aucun utilisateur\
                 local.")
         return self.cleaned_data
-
diff --git a/auf/django/saml/models.py b/auf/django/saml/models.py
new file mode 100644 (file)
index 0000000..e69de29
index c4a9b08..511662e 100644 (file)
@@ -29,7 +29,8 @@ if saml_settings.SAML_AUTO_AUTH_URLS:
         LOGOUT_URL = '/sandbox/logout'
     info += u"\n* LOGIN_URL: %s" % LOGIN_URL
     info += u"\n* LOGOUT_URL: %s" % LOGOUT_URL
-    info += u"\n* REDIRECT_FIELD_NAME: %s" % saml_settings.SAML_REDIRECT_FIELD_NAME
+    info += u"\n* REDIRECT_FIELD_NAME: %s" % \
+            saml_settings.SAML_REDIRECT_FIELD_NAME
 
     django.contrib.auth.REDIRECT_FIELD_NAME = \
         saml_settings.SAML_REDIRECT_FIELD_NAME
@@ -55,7 +56,7 @@ def custom_admin_view(self, view, cacheable=False):
         """
         if not self.has_permission(request):
             return HttpResponseForbidden(
-                    _(u"Votre compte ne permet pas d'accéder à cette page"))
+                _(u"Votre compte ne permet pas d'accéder à cette page"))
         return view(request, *args, **kwargs)
 
     if view.__name__ == 'index':
@@ -63,5 +64,6 @@ def custom_admin_view(self, view, cacheable=False):
     else:
         return original_admin_view(self, view, cacheable=False)
 
-logger.info(u"Patch de la admin.site pour gérer le login forcé de la page d'index")
+logger.info(u"Patch de la admin.site pour \
+        gérer le login forcé de la page d'index")
 site.__class__.admin_view = custom_admin_view
index 47c454f..ee23603 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 """
-Ce module définit toutes les constantes utilisées par le paquet 
+Ce module définit toutes les constantes utilisées par le paquet
 auf.django.saml. Chacune peut être surchargée dans les settings
 chargés par Django, typiquement le fichier project/conf.py.
 """
@@ -15,16 +15,24 @@ SAML_AUTO_AUTH_URLS = getattr(settings, 'SAML_AUTO_AUTH_URLS', True)
 
 # Variable utilisée pour fournir au serveur d'identités les
 # adresses de retour du site.
-SAML_REDIRECT_FIELD_NAME = getattr(settings, '', 'ReturnTo')
+SAML_REDIRECT_FIELD_NAME = getattr(
+    settings, 'SAML_REDIRECT_FIELD_NAME', 'ReturnTo')
 
 # URL de la page où l'utilisateur sera redirigé après déconnexion
-SAML_LOGOUT_REDIRECT_URL = getattr(settings,'', '/')
+SAML_LOGOUT_REDIRECT_URL = getattr(settings, 'SAML_LOGOUT_REDIRECT_URL', '/')
 
 # URL où est mappée la fonction login du module Apache Mellon
-SAML_MELLON_LOGIN_URL = getattr(settings, '', '/mellon/login')
+SAML_MELLON_LOGIN_URL = getattr(
+    settings, 'SAML_MELLON_LOGIN_URL', '/mellon/login')
 
 # URL où est mappée la fonction logout du module Apache Mellon
-SAML_MELLON_LOGOUT_URL = getattr(settings, '', '/mellon/logout')
+SAML_MELLON_LOGOUT_URL = getattr(
+    settings, 'SAML_MELLON_LOGOUT_URL', '/mellon/logout')
 
-# URL où l'utilisateur peut modifier les propriétés globales de son profil 
-SAML_CHANGE_PASSWORD_URL = getattr(settings, '', 'http://id.auf.org/profile')
+# URL où l'utilisateur peut modifier les propriétés globales de son profil
+SAML_CHANGE_PASSWORD_URL = getattr(
+    settings, 'SAML_CHANGE_PASSWORD_URL', 'http://id.auf.org/profile')
+
+# Si l'auth passe, mais que le user n'existe pas ce flag pilote la création
+# locale dans l'application
+SAML_AUTO_CREATION = getattr(settings, 'SAML_AUTO_CREATION', True)
index f58e456..b19be9f 100644 (file)
@@ -1,34 +1,4 @@
 # -*- coding: utf-8 -*-
 
-from django import template
-from auf.django.saml.views import redirect_to_login, redirect_to_logout
-
-register = template.Library()
-
-
-class UrlNode(template.Node):
-
-    def __init__(self, fct, url):
-        self.fct = fct
-        self.url = url
-
-    def render(self, context):
-        return self.fct(context['request'], self.url, do_redirect=False)
-
-
-def mellon_login_url(parser, token):
-    try:
-        tag_name, url, = token.split_contents()
-    except:
-        url = None
-    return UrlNode(redirect_to_login, url)
-register.tag('mellon_login_url', mellon_login_url)
-
-
-def mellon_logout_url(parser, token):
-    try:
-        tag_name, url, = token.split_contents()
-    except:
-        url = None
-    return UrlNode(redirect_to_logout, url)
-register.tag('mellon_logout_url', mellon_logout_url)
+# backward compatibilty
+from .saml_tags import *  # noqa
diff --git a/auf/django/saml/templatetags/saml_tags.py b/auf/django/saml/templatetags/saml_tags.py
new file mode 100644 (file)
index 0000000..f1bd555
--- /dev/null
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+from django import template
+
+from auf.django.saml.views import redirect_to_login, redirect_to_logout
+
+register = template.Library()
+
+
+@register.simple_tag(takes_context=True, name='mellon_login_url')
+def mellon_login_url(context, url=None):
+    request = context['request']
+    return redirect_to_login(request, redirect_to=url, do_redirect=False)
+
+
+@register.simple_tag(takes_context=True, name='mellon_logout_url')
+def mellon_logout_url(context, url=None):
+    request = context['request']
+    return redirect_to_logout(request, redirect_to=url, do_redirect=False)
diff --git a/auf/django/saml/tests/__init__.py b/auf/django/saml/tests/__init__.py
new file mode 100644 (file)
index 0000000..3e8b690
--- /dev/null
@@ -0,0 +1 @@
+from .saml import TemplateTagTest  # flake8: noqa
diff --git a/auf/django/saml/tests/common.py b/auf/django/saml/tests/common.py
new file mode 100644 (file)
index 0000000..8f86a70
--- /dev/null
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+
+from django.test import TestCase
+from django.test.client import Client
+
+
+class CommonTest(TestCase):
+
+    def setUp(self):
+        self.client = Client()
diff --git a/auf/django/saml/tests/saml.py b/auf/django/saml/tests/saml.py
new file mode 100644 (file)
index 0000000..5602a03
--- /dev/null
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from django.core.urlresolvers import reverse
+
+from auf.django.saml import settings
+
+from .common import CommonTest
+
+
+class TemplateTagTest(CommonTest):
+    """
+    Teste les fonctionnalités des templatetags SAML.
+    """
+    url = reverse('test_tags')
+
+    def setUp(self):
+        super(TemplateTagTest, self).setUp()
+        self.url = reverse('test_tags')
+        self.response = self.client.get(self.url)
+
+    def test_templatetag_login_var(self):
+        """
+        Test le rendu du templatetag *mellon_login_url* avec une variable en
+        paramètre.
+        """
+        regex = "test_templatetag_login_var:(.*)\?%s=(.*)\n" % (
+            settings.SAML_REDIRECT_FIELD_NAME, )
+        m = re.search(regex, self.response.content)
+        login_url, redirect_url = m.groups()
+        self.assertEqual(login_url, settings.SAML_MELLON_LOGIN_URL)
+        self.assertEqual(redirect_url, self.url)
+
+    def test_templatetag_login_default(self):
+        """
+        Test le rendu du templatetag *mellon_login_url* sans paramètre.
+        """
+        regex = "test_templatetag_login_default:(.*)\?%s=(.*)\n" % (
+            settings.SAML_REDIRECT_FIELD_NAME, )
+        m = re.search(regex, self.response.content)
+        login_url, redirect_url = m.groups()
+        self.assertEqual(login_url, settings.SAML_MELLON_LOGIN_URL)
+        self.assertEqual(redirect_url, self.url)
+
+    def test_templatetag_login_string(self):
+        """
+        Test le rendu du templatetag *mellon_login_url* avec paramètre string.
+        """
+        regex = "test_templatetag_login_string:(.*)\?%s=(.*)\n" % (
+            settings.SAML_REDIRECT_FIELD_NAME, )
+        m = re.search(regex, self.response.content)
+        login_url, redirect_url = m.groups()
+        self.assertEqual(login_url, settings.SAML_MELLON_LOGIN_URL)
+        self.assertEqual(redirect_url, '/admin')
+
+    def test_templatetag_logout_var(self):
+        """
+        Test le rendu du templatetag *mellon_logout_url* avec une variable en
+        paramètre.
+        """
+        regex = "test_templatetag_logout_var:(.*)\?%s=(.*)\n" % (
+            settings.SAML_REDIRECT_FIELD_NAME, )
+        m = re.search(regex, self.response.content)
+        logout_url, redirect_url = m.groups()
+        self.assertEqual(logout_url, reverse('local_logout'))
+        self.assertEqual(redirect_url, self.url)
+
+    def test_templatetag_logout_default(self):
+        """
+        Test le rendu du templatetag *mellon_logout_url* sans paramètre.
+        """
+        regex = "test_templatetag_logout_default:(.*)\?%s=(.*)\n" % (
+            settings.SAML_REDIRECT_FIELD_NAME, )
+        m = re.search(regex, self.response.content)
+        logout_url, redirect_url = m.groups()
+        self.assertEqual(logout_url, reverse('local_logout'))
+        self.assertEqual(redirect_url, settings.SAML_LOGOUT_REDIRECT_URL)
+
+    def test_templatetag_logout_string(self):
+        """
+        Test le rendu du templatetag *mellon_logout_url* avec paramètre string.
+        """
+        regex = "test_templatetag_logout_string:(.*)\?%s=(.*)\n" % (
+            settings.SAML_REDIRECT_FIELD_NAME, )
+        m = re.search(regex, self.response.content)
+        logout_url, redirect_url = m.groups()
+        self.assertEqual(logout_url, reverse('local_logout'))
+        self.assertEqual(redirect_url, '/admin')
diff --git a/auf/django/saml/tests/settings.py b/auf/django/saml/tests/settings.py
new file mode 100644 (file)
index 0000000..0be039e
--- /dev/null
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+
+import os
+
+
+USE_I18N = False
+
+SECRET_KEY = 'secret'
+
+ROOT_URLCONF = 'auf.django.saml.tests.urls'
+
+DATABASES = {'default':
+            {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:', }}
+
+INSTALLED_APPS = ('django.contrib.auth',
+                  'django.contrib.contenttypes',
+                  'django.contrib.sessions',
+                  'django.contrib.admin',
+                  'auf.django.saml', )
+
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'auf.django.saml.middleware.SPMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+)
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+    'django.contrib.auth.context_processors.auth',
+    'django.core.context_processors.debug',
+    'django.core.context_processors.i18n',
+    'django.core.context_processors.media',
+    'django.core.context_processors.static',
+    'django.core.context_processors.request',
+    'django.core.context_processors.tz',
+    'django.contrib.messages.context_processors.messages',
+    )
+
+TEMPLATE_DIRS = (
+    os.path.join(os.path.dirname(__file__), 'templates'),
+    )
diff --git a/auf/django/saml/tests/templates/test_tags.html b/auf/django/saml/tests/templates/test_tags.html
new file mode 100644 (file)
index 0000000..97dbc72
--- /dev/null
@@ -0,0 +1,14 @@
+{% load saml_tags %}
+
+test_templatetag_login_default:{% mellon_login_url %}
+
+test_templatetag_login_string:{% mellon_login_url '/admin' %}
+
+test_templatetag_login_var:{% mellon_login_url request.get_full_path %}
+
+
+test_templatetag_logout_default:{% mellon_logout_url %}
+
+test_templatetag_logout_string:{% mellon_logout_url '/admin' %}
+
+test_templatetag_logout_var:{% mellon_logout_url request.get_full_path %}
diff --git a/auf/django/saml/tests/urls.py b/auf/django/saml/tests/urls.py
new file mode 100644 (file)
index 0000000..d949ffd
--- /dev/null
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+
+from django.conf.urls.defaults import patterns, include, url
+from django.views.generic import TemplateView
+
+from django.contrib import admin
+
+
+admin.autodiscover()
+
+urlpatterns = patterns(
+    '',
+    (r'^', include('auf.django.saml.urls')),
+    (r'^admin/', include(admin.site.urls)),
+    url(r'^test_tags/', TemplateView.as_view(template_name="test_tags.html"),
+        name='test_tags'),
+    )
index 7c46548..d13e179 100644 (file)
@@ -5,13 +5,15 @@ from django.contrib.auth import login as auth_login
 from django.contrib.auth import logout as auth_logout
 from django.template import RequestContext
 from django.shortcuts import render_to_response, redirect
+
 from forms import RemoteUserForm
+
 from settings import SAML_REDIRECT_FIELD_NAME,\
-        SAML_MELLON_LOGIN_URL,\
-        SAML_MELLON_LOGOUT_URL,\
-        SAML_CHANGE_PASSWORD_URL,\
-        SAML_LOGOUT_REDIRECT_URL, \
-        SAML_AUTH
+    SAML_MELLON_LOGIN_URL,\
+    SAML_MELLON_LOGOUT_URL,\
+    SAML_CHANGE_PASSWORD_URL,\
+    SAML_LOGOUT_REDIRECT_URL, \
+    SAML_AUTH
 
 
 def redirect_to_login(request, redirect_to=None, do_redirect=True):
@@ -21,10 +23,11 @@ def redirect_to_login(request, redirect_to=None, do_redirect=True):
         base_url = SAML_MELLON_LOGIN_URL
     else:
         base_url = reverse('sandbox_login')
-    url = "%s?%s=%s" % (base_url,
-            SAML_REDIRECT_FIELD_NAME,
-            redirect_to,
-            )
+    url = "%s?%s=%s" % (
+        base_url,
+        SAML_REDIRECT_FIELD_NAME,
+        redirect_to,
+        )
     if do_redirect:
         return redirect(url)
     else:
@@ -34,10 +37,11 @@ def redirect_to_login(request, redirect_to=None, do_redirect=True):
 def redirect_to_logout(request, redirect_to=None, do_redirect=True):
     if redirect_to is None:
         redirect_to = SAML_LOGOUT_REDIRECT_URL
-    url = "%s?%s=%s" % (reverse('local_logout'),
-            SAML_REDIRECT_FIELD_NAME,
-            redirect_to,
-            )
+    url = "%s?%s=%s" % (
+        reverse('local_logout'),
+        SAML_REDIRECT_FIELD_NAME,
+        redirect_to,
+        )
     if do_redirect:
         return redirect(url)
     else:
@@ -59,7 +63,8 @@ def login_form(request, ):
         form = RemoteUserForm(request)
 
     c = {'form': form}
-    return render_to_response("saml/login_form.html",
+    return render_to_response(
+        "saml/login_form.html",
         c,
         context_instance=RequestContext(request))
 
index ed450c6..5f39587 100644 (file)
@@ -13,7 +13,7 @@ déconnexion** si le user est connecté ou non:
 
 .. code-block:: guess
 
-    {% load saml %}
+    {% load saml_tags %}
     
     {% if request.user.is_authenticated %}
         {% mellon_logout_url %}
diff --git a/tox.ini b/tox.ini
new file mode 100644 (file)
index 0000000..127af5c
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,19 @@
+[tox]
+envlist = django1.4
+
+[testenv]
+deps =
+    coverage
+    pep8
+
+commands =
+    coverage erase
+    coverage run --source="{envsitepackagesdir}/auf/django/saml/" {envdir}/bin/django-admin.py test saml --settings=auf.django.saml.tests.settings
+    pep8 -r  --statistics  --count {envsitepackagesdir}/auf/django/saml/
+    coverage report
+    coverage html
+
+[testenv:django1.4]
+deps =
+    {[testenv]deps}
+    django==1.4