diff --git a/authentic2/COPYING b/authentic2/COPYING
new file mode 100644
index 0000000..718cb94
--- /dev/null
+++ b/authentic2/COPYING
@@ -0,0 +1,2 @@
+authentic2-plugin-template is entirely under the copyright of Entr'ouvert and
+distributed under the license AGPLv3 or later.
diff --git a/authentic2/MANIFEST.in b/authentic2/MANIFEST.in
new file mode 100644
index 0000000..5f87890
--- /dev/null
+++ b/authentic2/MANIFEST.in
@@ -0,0 +1,3 @@
+include COPYING
+recursive-include src/authentic2_plugin_template/templates *.html
+recursive-include src/authentic2_plugin_template/static *.js *.css *.png
diff --git a/authentic2/README b/authentic2/README
new file mode 100644
index 0000000..3688845
--- /dev/null
+++ b/authentic2/README
@@ -0,0 +1,20 @@
+** THIS IS A TEMPLATE PROJECT **
+
+To rename it to your taste:
+
+ $ ./adapt.sh
+
+** THIS IS A TEMPLATE PROJECT **
+Authentic2 Plugin Template
+==========================
+
+Install
+-------
+
+You just have to install the package in your virtualenv and relaunch, it will
+be automatically loaded by authentic2.
+
+Settings
+--------
+
+** DESCRIBE CUSTOM SETTINGS HERE **
diff --git a/authentic2/adapt.sh b/authentic2/adapt.sh
new file mode 100755
index 0000000..d9fb451
--- /dev/null
+++ b/authentic2/adapt.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+set -x
+
+echo "Give project name (it must match regexp ^[a-z][a-z0-9-]+$ )"
+read PROJECT_NAME
+
+if ! echo $PROJECT_NAME | grep -q '^[a-z][a-z0-9-]\+$'; then
+ echo "Invalid project name:" $PROJECT_NAME
+ exit 1
+fi
+
+UPPER_UNDERSCORED=`echo $PROJECT_NAME | tr a-z A-Z | sed 's/-/_/g'`
+LOWER_UNDERSCORED=`echo $PROJECT_NAME | sed 's/-/_/g'`
+TITLECASE=`echo $PROJECT_NAME | sed 's/-/ /g;s/.*/\L&/; s/[a-z]*/\u&/g'`
+
+echo Project name: $PROJECT_NAME
+echo Uppercase underscored: $UPPER_UNDERSCORED
+echo Lowercase underscored: $LOWER_UNDERSCORED
+echo Titlecase: $TITLECASE
+
+if [ -d .git ]; then
+ MV='git mv'
+else
+ MV=mv
+fi
+
+sed -i \
+ -e "s/authentic2_plugin_template/$LOWER_UNDERSCORED/g" \
+ -e "s/authentic2-plugin-template/$PROJECT_NAME/g" \
+ -e "s/A2_TEMPLATE_/A2_$UPPER_UNDERSCORED_/g" \
+ -e "s/Authentic2 Plugin Template/$TITLECASE/g" \
+ setup.py src/*/*.py README COPYING MANIFEST.in
+$MV src/authentic2_plugin_template/static/authentic2_plugin_template \
+ src/authentic2_plugin_template/static/$LOWER_UNDERSCORED
+$MV src/authentic2_plugin_template/templates/authentic2_plugin_template \
+ src/authentic2_plugin_template/templates/$LOWER_UNDERSCORED
+$MV src/authentic2_plugin_template src/$LOWER_UNDERSCORED
diff --git a/authentic2/setup.py b/authentic2/setup.py
new file mode 100755
index 0000000..0bb96e4
--- /dev/null
+++ b/authentic2/setup.py
@@ -0,0 +1,65 @@
+#!/usr/bin/python
+from setuptools import setup, find_packages
+import os
+
+def get_version():
+ import glob
+ import re
+ import os
+
+ version = None
+ for d in glob.glob('src/*'):
+ if not os.path.isdir(d):
+ continue
+ module_file = os.path.join(d, '__init__.py')
+ if not os.path.exists(module_file):
+ continue
+ for v in re.findall("""__version__ *= *['"](.*)['"]""",
+ open(module_file).read()):
+ assert version is None
+ version = v
+ if version:
+ break
+ assert version is not None
+ if os.path.exists('.git'):
+ import subprocess
+ p = subprocess.Popen(['git','describe','--dirty','--match=v*'],
+ stdout=subprocess.PIPE)
+ result = p.communicate()[0]
+ assert p.returncode == 0, 'git returned non-zero'
+ new_version = result.split()[0][1:]
+ assert new_version.split('-')[0] == version, '__version__ must match the last git annotated tag'
+ version = new_version.replace('-', '.')
+ return version
+
+README = file(os.path.join(
+ os.path.dirname(__file__),
+ 'README')).read()
+
+setup(name='authentic2-plugin-template',
+ version=get_version(),
+ license='AGPLv3',
+ description='Authentic2 Plugin Template',
+ long_description=README,
+ author="Entr'ouvert",
+ author_email="info@entrouvert.com",
+ packages=find_packages('src'),
+ package_dir={
+ '': 'src',
+ },
+ package_data={
+ 'authentic2_plugin_template': [
+ 'templates/authentic2_plugin_template/*.html',
+ 'static/authentic2_plugin_template/js/*.js',
+ 'static/authentic2_plugin_template/css/*.css',
+ 'static/authentic2_plugin_template/img/*.png',
+ ],
+ },
+ install_requires=[
+ ],
+ entry_points={
+ 'authentic2.plugin': [
+ 'authentic2-plugin-template= authentic2_plugin_template:Plugin',
+ ],
+ },
+)
diff --git a/authentic2/src/authentic2_plugin_template/__init__.py b/authentic2/src/authentic2_plugin_template/__init__.py
new file mode 100644
index 0000000..3de27b7
--- /dev/null
+++ b/authentic2/src/authentic2_plugin_template/__init__.py
@@ -0,0 +1,62 @@
+__version__ = '1.0.0'
+
+class Plugin(object):
+ def get_before_urls(self):
+ from . import urls
+ return urls.urlpatterns
+
+ def get_after_urls(self):
+ return []
+
+ def get_apps(self):
+ return [__name__]
+
+ def get_before_middleware(self):
+ return []
+
+ def get_after_middleware(self):
+ return []
+
+ def get_authentication_backends(self):
+ return []
+
+ def get_auth_frontends(self):
+ return []
+
+ def get_idp_backends(self):
+ return []
+
+ def get_admin_modules(self):
+ from . import dashboard
+ return dashboard.get_admin_modules()
+
+ def service_list(self, request):
+ '''For IdP plugins this method add links to the user homepage.
+
+ It must return a list of authentic2.utils.Service objects, each
+ object has a name and can have an url and some actions.
+
+ Service(name=name[, url=url[, actions=actions]])
+
+ Actions are a list of tuples, whose parts are
+ - first the name of the action,
+ - the HTTP method for calling the action,
+ - the URL for calling the action,
+ - the paramters to pass to this URL as a sequence of key-value tuples.
+ '''
+ return []
+
+ def logout_list(self, request):
+ '''For IdP or SP plugins this method add actions to logout from remote
+ IdP or SP.
+
+ It must returns a list of HTML fragments, each fragment is
+ responsible for calling the view doing the logout. Views are usually
+ called using or tags and finally redirect to an
+ icon indicating success or failure for the logout.
+
+ Authentic2 provide two such icons through the following URLs:
+ - os.path.join(settings.STATIC_URL, 'authentic2/img/ok.png')
+ - os.path.join(settings.STATIC_URL, 'authentic2/img/ok.png')
+ '''
+ return []
diff --git a/authentic2/src/authentic2_plugin_template/admin.py b/authentic2/src/authentic2_plugin_template/admin.py
new file mode 100644
index 0000000..08eef26
--- /dev/null
+++ b/authentic2/src/authentic2_plugin_template/admin.py
@@ -0,0 +1,5 @@
+from django.contrib import admin
+
+from . import models
+
+# registrer your admin editable models here using admin.register
diff --git a/authentic2/src/authentic2_plugin_template/app_settings.py b/authentic2/src/authentic2_plugin_template/app_settings.py
new file mode 100644
index 0000000..da34e12
--- /dev/null
+++ b/authentic2/src/authentic2_plugin_template/app_settings.py
@@ -0,0 +1,23 @@
+class AppSettings(object):
+ __DEFAULTS = {
+ 'ENABLE': True,
+ }
+
+ def __init__(self, prefix):
+ self.prefix = prefix
+
+ def _setting(self, name, dflt):
+ from django.conf import settings
+ return getattr(settings, self.prefix+name, dflt)
+
+ def __getattr__(self, name):
+ if name not in self.__DEFAULTS:
+ raise AttributeError(name)
+ return self._setting(name, self.__DEFAULTS[name])
+
+# Ugly? Guido recommends this himself ...
+# http://mail.python.org/pipermail/python-ideas/2012-May/014969.html
+import sys
+app_settings = AppSettings('A2_PLUGIN_TEMPLATE_')
+app_settings.__name__ = __name__
+sys.modules[__name__] = app_settings
diff --git a/authentic2/src/authentic2_plugin_template/dashboard.py b/authentic2/src/authentic2_plugin_template/dashboard.py
new file mode 100644
index 0000000..48882ba
--- /dev/null
+++ b/authentic2/src/authentic2_plugin_template/dashboard.py
@@ -0,0 +1,11 @@
+from django.utils.translation import ugettext_lazy as _
+
+from admin_tools.dashboard import modules
+
+
+def get_admin_modules():
+ '''Show Client model in authentic2 admin'''
+ model_list = modules.ModelList(_('Authentic2 Plugin Template'),
+ models=('authentic2_plugin_template.models.*',))
+ return (model_list,)
+
diff --git a/authentic2/src/authentic2_plugin_template/forms.py b/authentic2/src/authentic2_plugin_template/forms.py
new file mode 100644
index 0000000..32d64dc
--- /dev/null
+++ b/authentic2/src/authentic2_plugin_template/forms.py
@@ -0,0 +1,3 @@
+from django import forms
+
+
diff --git a/authentic2/src/authentic2_plugin_template/migrations/__init__.py b/authentic2/src/authentic2_plugin_template/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/authentic2/src/authentic2_plugin_template/models.py b/authentic2/src/authentic2_plugin_template/models.py
new file mode 100644
index 0000000..c0f6f87
--- /dev/null
+++ b/authentic2/src/authentic2_plugin_template/models.py
@@ -0,0 +1,4 @@
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+# put your models here
diff --git a/authentic2/src/authentic2_plugin_template/static/authentic2_plugin_template/.keepme b/authentic2/src/authentic2_plugin_template/static/authentic2_plugin_template/.keepme
new file mode 100644
index 0000000..e69de29
diff --git a/authentic2/src/authentic2_plugin_template/templates/authentic2_plugin_template/index.html b/authentic2/src/authentic2_plugin_template/templates/authentic2_plugin_template/index.html
new file mode 100644
index 0000000..5d16e06
--- /dev/null
+++ b/authentic2/src/authentic2_plugin_template/templates/authentic2_plugin_template/index.html
@@ -0,0 +1 @@
+{% comment %}placeholder{% endcomment %}
diff --git a/authentic2/src/authentic2_plugin_template/urls.py b/authentic2/src/authentic2_plugin_template/urls.py
new file mode 100644
index 0000000..578c4c0
--- /dev/null
+++ b/authentic2/src/authentic2_plugin_template/urls.py
@@ -0,0 +1,14 @@
+from django.conf.urls import patterns, url
+
+from authentic2.decorators import setting_enabled, required
+
+from . import app_settings
+from .views import index
+
+urlpatterns = required(
+ setting_enabled('ENABLE', settings=app_settings),
+ patterns('',
+ url('^authentic2_plugin_template/$', index,
+ name='authentic2-plugin-template-index'),
+ )
+)
diff --git a/authentic2/src/authentic2_plugin_template/views.py b/authentic2/src/authentic2_plugin_template/views.py
new file mode 100644
index 0000000..ad5596b
--- /dev/null
+++ b/authentic2/src/authentic2_plugin_template/views.py
@@ -0,0 +1,10 @@
+from django.shortcuts import render
+
+
+from . import decorators
+
+__ALL_ = [ 'sso' ]
+
+@decorators.plugin_enabled
+def index(request):
+ return render(request, 'authentic2_plugin_template/index.html')