0244-Prepare-merge-into-authentic2.patch
COPYING | ||
---|---|---|
1 |
authentic2-auth-fc is entirely under the copyright of Entr'ouvert and |
|
2 |
distributed under the license AGPLv3 or later. |
MANIFEST.in | ||
---|---|---|
1 |
include COPYING |
|
2 |
recursive-include src/authentic2_auth_fc/templates *.html |
|
3 |
recursive-include src/authentic2_auth_fc/static *.css *.png *.svg |
|
4 |
recursive-include src/authentic2_auth_fc/locale *.po *.mo |
|
5 |
recursive-include src/authentic2_auth_fc *.json |
|
6 |
include VERSION |
|
7 |
include MANIFEST.in |
README | ||
---|---|---|
1 |
================== |
|
2 |
authentic2-auth-fc |
|
3 |
================== |
|
4 | ||
5 |
Authentic2 plugin to authenticate against *France Connect* the french |
|
6 |
citizen and entreprise SSO. |
|
7 | ||
8 |
Installation |
|
9 |
============ |
|
10 | ||
11 |
Install with `pip install authentic2-auth-fc` |
|
12 | ||
13 |
Settings |
|
14 |
======== |
|
15 | ||
16 |
Add `A2_FC_ENABLE = True` to your `local_settings.py` file |
|
17 |
Define the needed parameters:: |
|
18 | ||
19 |
A2_FC_CLIENT_ID = 'id assigned by DISIC' |
|
20 |
A2_FC_CLIENT_SECRET = 'secret assigned by DISIC' |
|
21 |
A2_FC_VERIFY_CERTIFICATE = False # True for production |
|
22 | ||
23 |
A2_FC_CREATE = True set the plugin in provisionning mode. If a sub is unknown, |
|
24 |
a user is created instead of asking authentication. |
|
25 | ||
26 |
When the create mode is enabled, the link for unlinking is hidden on the |
|
27 |
profile frontend. This is due to the not yet implemented need of asking |
|
28 |
the user credentiels when unlinking a user created without any other credential |
|
29 |
that the authentication delegation. Unlinking meaning, loosing access to this |
|
30 |
account at the end of the current session. To enable unlinking when create is |
|
31 |
unabled use A2_FC_ENABLE_UNLINK_WHEN_CREATE = True. |
|
32 | ||
33 |
A2_FC_LOGOUT_WHEN_UNLINK = True is using to trigger a logout toward the OP |
|
34 |
after unlinking. |
|
35 | ||
36 |
Platforms |
|
37 |
========= |
|
38 | ||
39 |
When testing against another platform than FranceConnect you must change |
|
40 |
the default endpoints URL in your `local_settings.py` file:: |
|
41 | ||
42 |
A2_FC_AUTHORIZE_URL = 'https://fcp.integ01.dev-franceconnect.fr/api/v1/authorize' |
|
43 |
A2_FC_TOKEN_URL = 'https://fcp.integ01.dev-franceconnect.fr/api/v1/token' |
|
44 |
A2_FC_USERINFO_URL = 'https://fcp.integ01.dev-franceconnect.fr/api/v1/userinfo' |
|
45 |
A2_FC_LOGOUT_URL = 'https://fcp.integ01.dev-franceconnect.fr/api/v1/logout' |
|
46 | ||
47 |
Data Providers |
|
48 |
============== |
|
49 | ||
50 |
You can define data provider endpoints with the following dictionnary : |
|
51 | ||
52 |
A2_FC_FD_LIST = { |
|
53 |
'revenu_fiscal_de_reference': [ |
|
54 |
{ |
|
55 |
'name': 'OpenDataSoft', |
|
56 |
'url': 'https://datafranceconnect.opendatasoft.com/api/records/1.0/search', |
|
57 |
'query_dic': {'dataset': 'guichet-des-bretons', }, |
|
58 |
}, |
|
59 |
], |
|
60 |
} |
|
61 | ||
62 |
Data is requested using the login or link endpoint view giving space delimited |
|
63 |
scopes in the `fd_scopes` get parameter : |
|
64 | ||
65 |
fc/callback/?next=%2F&fd_scopes=revenu_fiscal_de_reference scolarite |
|
66 | ||
67 |
The data received is recorded in the session with a dictionnary named `fc-data` |
|
68 |
with scopes as keys and lists of data as values. A data is a tuple |
|
69 |
FD name and data content. |
|
70 | ||
71 |
fc_data_dic = { |
|
72 |
scope_name = [ |
|
73 |
[FD_name, data], |
|
74 |
], |
|
75 |
} |
|
76 | ||
77 |
Attribute mapping |
|
78 |
================= |
|
79 | ||
80 |
You can map France Connect attributes to Authentic2 attributes through the |
|
81 |
setting A2_FC_USER_INFO_MAPPINGS. A2_FC_USER_INFO_MAPPINGS is a dictionnary |
|
82 |
whose keys are authentic2's attribute names and value can be France Connect |
|
83 |
attribute names or dictionnary with the following keys: |
|
84 | ||
85 |
- `value` : a static value which will be assigned to the authentic2 attribute, |
|
86 |
can be any Python value, |
|
87 |
- `ref` : the name of a France Connect attribute, |
|
88 |
- `translation` : a transformation name among: |
|
89 |
- @insee-communes@ : translate the value using mapping from INSEE code of |
|
90 |
communes to their name, |
|
91 |
- @insee-countries@ : translate the value using mapping from INSEE code of |
|
92 |
countries to their name, |
|
93 |
- @simple@ : lookup the value using the dictionnary in @translation_simple@. |
|
94 |
- `compute`: compute a value using a known function, only known function for now |
|
95 |
is @today@ which returns @datetime.date.today()@. |
|
96 |
- `verified`: set the verified flag on the value. |
|
97 | ||
98 |
Exemple: |
|
99 | ||
100 |
A2_FC_USER_INFO_MAPPINGS = { |
|
101 |
'first_name': 'given_name', |
|
102 |
'last_name': 'family_name', |
|
103 |
'birthdate': { 'ref': 'birthdate', 'translation': 'isodate' }, |
|
104 |
'birthplace': { 'ref': 'birthplace', 'translation': 'insee-communes' }, |
|
105 |
'birthcountry': { 'ref': 'birthcountry', 'translation': 'insee-countries' }, |
|
106 |
'birthplace_insee': 'birthplace', |
|
107 |
'birthcountry_insee': 'birthcountry', |
|
108 |
'title': { |
|
109 |
'ref': 'gender', |
|
110 |
'translation': 'simple', |
|
111 |
'translation_simple': { |
|
112 |
'male': 'Monsieur', |
|
113 |
'female': 'Madame', |
|
114 |
} |
|
115 |
}, |
|
116 |
'gender': 'gender', |
|
117 |
'validated': { 'value': True }, |
|
118 |
'validation_date': { 'compute': 'today' }, |
|
119 |
'validation_context': { 'value': 'France Connect' }, |
|
120 |
} |
debian/changelog | ||
---|---|---|
1 |
python-authentic2-auth-fc (1.0.1-0) wheezy; urgency=low |
|
2 | ||
3 |
* First upstream release |
|
4 | ||
5 |
-- Benjamin Dauvergne <bdauvergne@entrouvert.org> Thu, 2 Dec 2014 12:00:29 +0100 |
debian/compat | ||
---|---|---|
1 |
7 |
debian/control | ||
---|---|---|
1 |
Source: python-authentic2-auth-fc |
|
2 |
Maintainer: Benjamin Dauvergne <info@entrouvert.com> |
|
3 |
Section: python |
|
4 |
Priority: optional |
|
5 |
Build-Depends: python-setuptools (>= 0.6b3), python-all (>= 2.6), debhelper (>= 7.4.3), |
|
6 |
python-django (>= 1.5) |
|
7 |
Standards-Version: 3.9.1 |
|
8 |
X-Python-Version: >= 2.6 |
|
9 | ||
10 |
Package: python-authentic2-auth-fc |
|
11 |
Architecture: all |
|
12 |
Depends: ${misc:Depends}, |
|
13 |
python-authentic2 (>= 2.1.2.1009), |
|
14 |
python-requests, |
|
15 |
python-requests-oauthlib |
|
16 |
Description: FranceConnect authentication frontend for Authentic2 |
|
17 |
debian/rules | ||
---|---|---|
1 |
#!/usr/bin/make -f |
|
2 | ||
3 |
# This file was automatically generated by stdeb 0.6.0+git at |
|
4 |
# Fri, 14 Jun 2013 17:33:52 +0200 |
|
5 | ||
6 |
%: |
|
7 |
dh $@ --with python2 --buildsystem=python_distutils |
|
8 | ||
9 |
debian/source/format | ||
---|---|---|
1 |
3.0 (quilt) |
getlasso.sh | ||
---|---|---|
1 |
#!/bin/sh |
|
2 | ||
3 |
# Get venv site-packages path |
|
4 |
DSTDIR=`python -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())'` |
|
5 | ||
6 |
# Get not venv site-packages path |
|
7 |
# Remove first path (assuming that is the venv path) |
|
8 |
NONPATH=`echo $PATH | sed 's/^[^:]*://'` |
|
9 |
SRCDIR=`PATH=$NONPATH python -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())'` |
|
10 | ||
11 |
# Clean up |
|
12 |
rm -f $DSTDIR/lasso.* |
|
13 |
rm -f $DSTDIR/_lasso.* |
|
14 | ||
15 |
# Link |
|
16 |
ln -sv $SRCDIR/lasso.py $DSTDIR |
|
17 |
ln -sv $SRCDIR/_lasso.* $DSTDIR |
|
18 | ||
19 |
exit 0 |
|
20 |
setup.py | ||
---|---|---|
1 |
#!/usr/bin/python |
|
2 |
import sys |
|
3 |
import os |
|
4 |
import subprocess |
|
5 |
import glob |
|
6 | ||
7 |
from setuptools import setup, find_packages |
|
8 |
from setuptools.command.install_lib import install_lib as _install_lib |
|
9 |
from distutils.command.build import build as _build |
|
10 |
from distutils.command.sdist import sdist |
|
11 |
from distutils.cmd import Command |
|
12 | ||
13 | ||
14 |
class compile_translations(Command): |
|
15 |
description = 'compile message catalogs to MO files via django compilemessages' |
|
16 |
user_options = [] |
|
17 | ||
18 |
def initialize_options(self): |
|
19 |
pass |
|
20 | ||
21 |
def finalize_options(self): |
|
22 |
pass |
|
23 | ||
24 |
def run(self): |
|
25 |
curdir = os.getcwd() |
|
26 |
try: |
|
27 |
os.environ.pop('DJANGO_SETTINGS_MODULE', None) |
|
28 |
from django.core.management import call_command |
|
29 |
for dir in glob.glob('src/*'): |
|
30 |
for path, dirs, files in os.walk(dir): |
|
31 |
if 'locale' not in dirs: |
|
32 |
continue |
|
33 |
os.chdir(os.path.realpath(path)) |
|
34 |
call_command('compilemessages') |
|
35 |
os.chdir(curdir) |
|
36 |
except ImportError: |
|
37 |
|
|
38 |
sys.stderr.write('!!! Please install Django >= 1.4 to build translations') |
|
39 |
|
|
40 |
|
|
41 |
os.chdir(curdir) |
|
42 | ||
43 | ||
44 |
class build(_build): |
|
45 |
sub_commands = [('compile_translations', None)] + _build.sub_commands |
|
46 | ||
47 | ||
48 |
class eo_sdist(sdist): |
|
49 | ||
50 |
def run(self): |
|
51 |
print "creating VERSION file" |
|
52 |
if os.path.exists('VERSION'): |
|
53 |
os.remove('VERSION') |
|
54 |
version = get_version() |
|
55 |
version_file = open('VERSION', 'w') |
|
56 |
version_file.write(version) |
|
57 |
version_file.close() |
|
58 |
sdist.run(self) |
|
59 |
print "removing VERSION file" |
|
60 |
if os.path.exists('VERSION'): |
|
61 |
os.remove('VERSION') |
|
62 | ||
63 |
class install_lib(_install_lib): |
|
64 |
def run(self): |
|
65 |
self.run_command('compile_translations') |
|
66 |
_install_lib.run(self) |
|
67 | ||
68 |
def get_version(): |
|
69 |
'''Use the VERSION, if absent generates a version with git describe, if not |
|
70 |
tag exists, take 0.0.0- and add the length of the commit log. |
|
71 |
''' |
|
72 |
if os.path.exists('VERSION'): |
|
73 |
with open('VERSION', 'r') as v: |
|
74 |
return v.read() |
|
75 |
if os.path.exists('.git'): |
|
76 |
p = subprocess.Popen(['git','describe','--dirty','--match=v*'], |
|
77 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
78 |
result = p.communicate()[0] |
|
79 |
if p.returncode == 0: |
|
80 |
return result.split()[0][1:].replace('-', '.') |
|
81 |
else: |
|
82 |
return '0.0.0-%s' % len( |
|
83 |
subprocess.check_output( |
|
84 |
['git', 'rev-list', 'HEAD']).splitlines()) |
|
85 |
return '0.0.0' |
|
86 | ||
87 |
README = file(os.path.join( |
|
88 |
os.path.dirname(__file__), |
|
89 |
'README')).read() |
|
90 | ||
91 |
setup(name='authentic2-auth-fc', |
|
92 |
version=get_version(), |
|
93 |
license='AGPLv3', |
|
94 |
description='Authentic2 FranceConnect plugin', |
|
95 |
long_description=README, |
|
96 |
author="Entr'ouvert", |
|
97 |
url='https://repos.entrouvert.org/authentic2-auth-fc.git', |
|
98 |
author_email="info@entrouvert.com", |
|
99 |
packages=find_packages('src'), |
|
100 |
package_dir={ |
|
101 |
'': 'src', |
|
102 |
}, |
|
103 |
package_data={ |
|
104 |
'authentic2_auth_fc': [ |
|
105 |
'templates/authentic2_auth_fc/*.html', |
|
106 |
'static/authentic2_auth_fc/css/*.css', |
|
107 |
'static/authentic2_auth_fc/img/*.png', |
|
108 |
'static/authentic2_auth_fc/img/*.svg', |
|
109 |
'locale/fr/LC_MESSAGES/django.po', |
|
110 |
'locale/fr/LC_MESSAGES/django.mo', |
|
111 |
'*.json', |
|
112 |
], |
|
113 |
}, |
|
114 |
install_requires=[ |
|
115 |
'authentic2', |
|
116 |
'requests', |
|
117 |
'requests-oauthlib', |
|
118 |
], |
|
119 |
entry_points={ |
|
120 |
'authentic2.plugin': [ |
|
121 |
'authentic2-auth-fc = authentic2_auth_fc:Plugin', |
|
122 |
], |
|
123 |
}, |
|
124 |
cmdclass={ |
|
125 |
'build': build, |
|
126 |
'install_lib': install_lib, |
|
127 |
'compile_translations': compile_translations, |
|
128 |
'sdist': eo_sdist}, |
|
129 |
zip_safe=False, |
|
130 |
) |
tests/settings.py | ||
---|---|---|
1 |
import os |
|
2 | ||
3 |
LANGUAGE_CODE = 'en' |
|
4 |
DATABASES = { |
|
5 |
'default': { |
|
6 |
'ENGINE': os.environ.get('DB_ENGINE', 'django.db.backends.sqlite3'), |
|
7 |
'TEST': { |
|
8 |
'NAME': 'a2-test', |
|
9 |
}, |
|
10 |
} |
|
11 |
} |
tox.ini | ||
---|---|---|
1 |
# Tox (http://tox.testrun.org/) is a tool for running tests |
|
2 |
# in multiple virtualenvs. This configuration file will run the |
|
3 |
# test suite on all supported python versions. To use it, "pip install tox" |
|
4 |
# and then run "tox" from this directory. |
|
5 | ||
6 |
[tox] |
|
7 |
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/authentic2-auth-fc/ |
|
8 |
envlist = {coverage,nocoverage}-{dj18}-{pg,sqlite} |
|
9 | ||
10 |
[testenv] |
|
11 |
# django.contrib.auth is not tested it does not work with our templates |
|
12 |
whitelist_externals = |
|
13 |
/bin/mv |
|
14 |
setenv = |
|
15 |
AUTHENTIC2_SETTINGS_FILE=tests/settings.py |
|
16 |
DJANGO_SETTINGS_MODULE=authentic2.settings |
|
17 |
sqlite: DB_ENGINE=django.db.backends.sqlite3 |
|
18 |
pg: DB_ENGINE=django.db.backends.postgresql_psycopg2 |
|
19 |
coverage: COVERAGE=--junitxml=junit-{envname}.xml --cov-report xml --cov=src/ --cov-config .coveragerc |
|
20 |
fast: FAST=--nomigrations |
|
21 |
usedevelop = |
|
22 |
coverage: True |
|
23 |
nocoverage: False |
|
24 |
deps = |
|
25 |
dj18: django>1.8,<1.9 |
|
26 |
dj19: django>1.8,<1.9 |
|
27 |
pg: psycopg2<2.7 |
|
28 |
coverage |
|
29 |
pytest-cov |
|
30 |
pytest-django |
|
31 |
mock |
|
32 |
pytest |
|
33 |
lxml |
|
34 |
cssselect |
|
35 |
pylint |
|
36 |
pylint-django |
|
37 |
django-webtest |
|
38 |
WebTest |
|
39 |
pyquery |
|
40 |
httmock |
|
41 |
pytest-catchlog |
|
42 |
pytz |
|
43 |
../authentic2 |
|
44 |
commands = |
|
45 |
./getlasso.sh |
|
46 |
py.test {env:FAST:} {env:COVERAGE:} {posargs:tests/} |
|
47 |
- |