diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..de19513
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,3 @@
+include COPYING
+include VERSION
+include MANIFEST.in
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..8b33fc8
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+import sys
+import os
+import subprocess
+
+from setuptools import setup, find_packages
+from distutils.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():
+ if os.path.exists('VERSION'):
+ version_file = open('VERSION', 'r')
+ version = version_file.read()
+ version_file.close()
+ return version
+ if os.path.exists('.git'):
+ p = subprocess.Popen(['git', 'describe', '--dirty', '--match=v*'], stdout=subprocess.PIPE)
+ result = p.communicate()[0]
+ if p.returncode == 0:
+ version = result.split()[0][1:]
+ version = version.replace('-', '.').replace('.g', '+g')
+ return version
+ return '0'
+
+
+setup(
+ name='authentic2-gnm',
+ version=get_version(),
+ license='AGPLv3',
+ description='Authentic2 GNM plugin',
+ author="Entr'ouvert",
+ author_email="info@entrouvert.com",
+ packages=find_packages('src'),
+ package_dir={
+ '': 'src',
+ },
+ package_data={
+ },
+ install_requires=[
+ 'authentic2',
+ ],
+ entry_points={
+ 'authentic2.plugin': [
+ 'authentic2-gnm = authentic2_gnm:Plugin',
+ ],
+ },
+ cmdclass={
+ 'sdist': eo_sdist},
+ zip_safe=False,
+)
diff --git a/src/authentic2_gnm/__init__.py b/src/authentic2_gnm/__init__.py
new file mode 100644
index 0000000..9193f8c
--- /dev/null
+++ b/src/authentic2_gnm/__init__.py
@@ -0,0 +1,27 @@
+# authentic2_gnm - Authentic2 plugin for GNM
+# Copyright (C) 2017 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import django.apps
+
+class AppConfig(django.apps.AppConfig):
+ name = 'authentic2_gnm'
+
+default_app_config = 'authentic2_gnm.AppConfig'
+
+
+class Plugin(object):
+ def get_apps(self):
+ return [__name__]
diff --git a/src/authentic2_gnm/templatetags/__init__.py b/src/authentic2_gnm/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/authentic2_gnm/templatetags/gnm.py b/src/authentic2_gnm/templatetags/gnm.py
new file mode 100644
index 0000000..e651e4a
--- /dev/null
+++ b/src/authentic2_gnm/templatetags/gnm.py
@@ -0,0 +1,53 @@
+# authentic2_gnm - Authentic2 plugin for GNM
+# Copyright (C) 2017 Entr'ouvert
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import urlparse
+import xml.etree.ElementTree as ET
+
+from django import template
+from django.conf import settings
+
+register = template.Library()
+
+
+@register.filter
+def is_coming_for(request):
+ try:
+ authn_request = ET.fromstring(request.session['saml:authnRequest'])
+ next_url = authn_request.findall(
+ '{urn:oasis:names:tc:SAML:2.0:protocol}Extensions/{https://www.entrouvert.com/}next_url')[0].text
+ except (KeyError, IndexError):
+ return 'unknown'
+ target_path = urlparse.urlparse(next_url).path
+ for prefix in ('manage', 'admin', 'backoffice'):
+ if target_path.startswith('/%s/' % prefix):
+ return 'backoffice'
+
+ target_domain = urlparse.urlparse(next_url).netloc
+ target_service = None
+ for service_type in settings.KNOWN_SERVICES.keys():
+ for service_data in settings.KNOWN_SERVICES[service_type].values():
+ if urlparse.urlparse(service_data['url']).netloc == target_domain:
+ target_service = service_data
+ break
+ if target_service:
+ if target_service.get('is-portal-agent'):
+ return 'backoffice'
+ if service_type in ('hobo', 'passerelle'):
+ return 'backoffice'
+ break
+
+ return 'frontoffice'