0001-ozwillo-create-ozwillo-app-in-contrib-14935.patch
hobo/contrib/ozwillo/README.txt | ||
---|---|---|
1 |
To run this plugin well, you have to set some files in /etc/hobo/ozwillo : |
|
2 |
- the files are in the folder examples. |
|
3 |
- it's a common recipe for your publik, and two extracts of user and agent combo. |
|
4 | ||
5 |
You have to set several var in a settings.json too : |
|
6 |
-OZWILLO_SECRET |
|
7 |
-OZWILLO_ENV_DOMAIN (e.g: sictiam.dev.entrouvert.org) |
|
8 |
-OZWILLO_DESTRUCTION_URI |
|
9 |
-OZWILLO_DESTRUCTION_SECRET |
|
10 | ||
11 |
And finally you have to enable in INSTALLED_APPS hobo.contrib.ozwillo. |
hobo/contrib/ozwillo/examples/import-site-agents.json | ||
---|---|---|
1 |
[ |
|
2 |
{ |
|
3 |
"cells": [ |
|
4 |
{ |
|
5 |
"fields": { |
|
6 |
"extra_css_class": "", |
|
7 |
"groups": [], |
|
8 |
"order": 1, |
|
9 |
"placeholder": "content", |
|
10 |
"public": true, |
|
11 |
"restricted_to_unlogged": false, |
|
12 |
"slug": "services", |
|
13 |
"text": "<h2>Bienvenue</h2>\r\n" |
|
14 |
}, |
|
15 |
"model": "data.textcell" |
|
16 |
} |
|
17 |
], |
|
18 |
"fields": { |
|
19 |
"exclude_from_navigation": false, |
|
20 |
"groups": [], |
|
21 |
"order": 1, |
|
22 |
"parent": null, |
|
23 |
"public": false, |
|
24 |
"redirect_url": "", |
|
25 |
"slug": "index", |
|
26 |
"template_name": "standard", |
|
27 |
"title": "Accueil" |
|
28 |
} |
|
29 |
} |
|
30 |
] |
hobo/contrib/ozwillo/examples/import-site-template.json | ||
---|---|---|
1 |
[ |
|
2 |
{ |
|
3 |
"cells": [ |
|
4 |
{ |
|
5 |
"fields": { |
|
6 |
"extra_css_class": "", |
|
7 |
"groups": [], |
|
8 |
"order": 0, |
|
9 |
"placeholder": "content", |
|
10 |
"public": true, |
|
11 |
"restricted_to_unlogged": true, |
|
12 |
"slug": "", |
|
13 |
"text": "<h2>Bienvenue</h2>\r\n\r\n<p>Bienvenue sur votre compte usager.</p>\r\n\r\n<p>Pour suivre vos démarches en cours, créez votre compte personnel ou identifiez-vous depuis <a href=\"/login/\">la page de connexion</a>.</p>\r\n" |
|
14 |
}, |
|
15 |
"model": "data.textcell" |
|
16 |
}, |
|
17 |
{ |
|
18 |
"fields": { |
|
19 |
"extra_css_class": "", |
|
20 |
"groups": [], |
|
21 |
"order": 1, |
|
22 |
"placeholder": "content", |
|
23 |
"public": false, |
|
24 |
"restricted_to_unlogged": false, |
|
25 |
"slug": "", |
|
26 |
"text": "<h2>Bienvenue</h2>\r\n\r\n<p>Bienvenue sur votre compte usager.</p>\r\n" |
|
27 |
}, |
|
28 |
"model": "data.textcell" |
|
29 |
}, |
|
30 |
{ |
|
31 |
"fields": { |
|
32 |
"extra_css_class": "", |
|
33 |
"groups": [], |
|
34 |
"order": 2, |
|
35 |
"placeholder": "right", |
|
36 |
"public": true, |
|
37 |
"restricted_to_unlogged": false, |
|
38 |
"slug": "", |
|
39 |
"wcs_site": "" |
|
40 |
}, |
|
41 |
"model": "wcs.trackingcodeinputcell" |
|
42 |
}, |
|
43 |
{ |
|
44 |
"fields": { |
|
45 |
"extra_css_class": "", |
|
46 |
"groups": [], |
|
47 |
"order": 3, |
|
48 |
"placeholder": "right", |
|
49 |
"public": true, |
|
50 |
"restricted_to_unlogged": true, |
|
51 |
"slug": "", |
|
52 |
"text": "<h2>Demandes en cours</h2>\r\n\r\n<p>Connectez-vous pour voir vos demandes en cours.</p>\r\n" |
|
53 |
}, |
|
54 |
"model": "data.textcell" |
|
55 |
}, |
|
56 |
{ |
|
57 |
"fields": { |
|
58 |
"current_forms": true, |
|
59 |
"done_forms": false, |
|
60 |
"extra_css_class": "", |
|
61 |
"groups": [], |
|
62 |
"order": 4, |
|
63 |
"placeholder": "right", |
|
64 |
"public": false, |
|
65 |
"restricted_to_unlogged": false, |
|
66 |
"slug": "", |
|
67 |
"wcs_site": "" |
|
68 |
}, |
|
69 |
"model": "wcs.wcscurrentformscell" |
|
70 |
}, |
|
71 |
{ |
|
72 |
"fields": { |
|
73 |
"extra_css_class": "", |
|
74 |
"groups": [], |
|
75 |
"order": 5, |
|
76 |
"placeholder": "footer", |
|
77 |
"public": true, |
|
78 |
"restricted_to_unlogged": false, |
|
79 |
"slug": "", |
|
80 |
"text": "<p>Ce service est proposé par le <a href=\"http://www.sictiam.fr/\">SICTIAM</a>.</p>\r\n" |
|
81 |
}, |
|
82 |
"model": "data.textcell" |
|
83 |
}, |
|
84 |
{ |
|
85 |
"fields": { |
|
86 |
"category_reference": "eservices:nous-contacter", |
|
87 |
"extra_css_class": "", |
|
88 |
"groups": [], |
|
89 |
"limit": null, |
|
90 |
"manual_order": { |
|
91 |
"data": [] |
|
92 |
}, |
|
93 |
"order": 6, |
|
94 |
"ordering": "popularity", |
|
95 |
"placeholder": "content", |
|
96 |
"public": true, |
|
97 |
"restricted_to_unlogged": false, |
|
98 |
"slug": "" |
|
99 |
}, |
|
100 |
"model": "wcs.wcsformsofcategorycell" |
|
101 |
} |
|
102 |
], |
|
103 |
"fields": { |
|
104 |
"exclude_from_navigation": false, |
|
105 |
"groups": [], |
|
106 |
"order": 1, |
|
107 |
"parent": null, |
|
108 |
"public": true, |
|
109 |
"redirect_url": "", |
|
110 |
"slug": "index", |
|
111 |
"template_name": "two-columns", |
|
112 |
"title": "Accueil" |
|
113 |
} |
|
114 |
}, |
|
115 |
{ |
|
116 |
"cells": [ |
|
117 |
{ |
|
118 |
"fields": { |
|
119 |
"extra_css_class": "", |
|
120 |
"groups": [], |
|
121 |
"order": 0, |
|
122 |
"placeholder": "footer", |
|
123 |
"public": true, |
|
124 |
"restricted_to_unlogged": false, |
|
125 |
"slug": "" |
|
126 |
}, |
|
127 |
"model": "data.parentcontentcell" |
|
128 |
} |
|
129 |
], |
|
130 |
"fields": { |
|
131 |
"exclude_from_navigation": false, |
|
132 |
"groups": [], |
|
133 |
"order": 2, |
|
134 |
"parent": null, |
|
135 |
"public": true, |
|
136 |
"redirect_url": "https://connexion-instance_name.sictiam.dev.entrouvert.org/accounts/", |
|
137 |
"slug": "mon-compte", |
|
138 |
"template_name": "standard", |
|
139 |
"title": "Mon compte" |
|
140 |
} |
|
141 |
}, |
|
142 |
{ |
|
143 |
"cells": [ |
|
144 |
{ |
|
145 |
"fields": { |
|
146 |
"extra_css_class": "", |
|
147 |
"groups": [], |
|
148 |
"order": 0, |
|
149 |
"placeholder": "footer", |
|
150 |
"public": true, |
|
151 |
"restricted_to_unlogged": false, |
|
152 |
"slug": "" |
|
153 |
}, |
|
154 |
"model": "data.parentcontentcell" |
|
155 |
} |
|
156 |
], |
|
157 |
"fields": { |
|
158 |
"exclude_from_navigation": false, |
|
159 |
"groups": [], |
|
160 |
"order": 3, |
|
161 |
"parent": null, |
|
162 |
"public": true, |
|
163 |
"redirect_url": "https://demarches-instance_name.sictiam.dev.entrouvert.org/saisine-par-voie-electronique/tryauth", |
|
164 |
"slug": "nous-contacter", |
|
165 |
"template_name": "standard", |
|
166 |
"title": "Nous contacter" |
|
167 |
} |
|
168 |
} |
|
169 |
] |
hobo/contrib/ozwillo/examples/template_recipe.json | ||
---|---|---|
1 |
{ |
|
2 |
"steps" : [ |
|
3 |
{ |
|
4 |
"create-hobo" : { |
|
5 |
"url" : "https://${hobo}/" |
|
6 |
} |
|
7 |
}, |
|
8 |
{ |
|
9 |
"create-authentic" : { |
|
10 |
"title" : "Connexion", |
|
11 |
"url" : "https://${authentic}/" |
|
12 |
} |
|
13 |
}, |
|
14 |
{ |
|
15 |
"set-idp" : {} |
|
16 |
}, |
|
17 |
{ |
|
18 |
"create-superuser" : { |
|
19 |
"username" : "admin", |
|
20 |
"email" : "admin@example.net" |
|
21 |
} |
|
22 |
}, |
|
23 |
{ |
|
24 |
"create-combo" : { |
|
25 |
"template_name" : "portal-user", |
|
26 |
"title" : "Compte citoyen", |
|
27 |
"url" : "https://${combo}/" |
|
28 |
} |
|
29 |
}, |
|
30 |
{ |
|
31 |
"create-combo" : { |
|
32 |
"template_name" : "portal-agent", |
|
33 |
"title" : "Portail agent", |
|
34 |
"url" : "https://${combo_agent}/", |
|
35 |
"slug" : "portal-agent" |
|
36 |
} |
|
37 |
}, |
|
38 |
{ |
|
39 |
"create-wcs" : { |
|
40 |
"url" : "https://${wcs}/", |
|
41 |
"title" : "Démarches", |
|
42 |
"template_name": "export.wcs" |
|
43 |
} |
|
44 |
}, |
|
45 |
{ |
|
46 |
"create-fargo" : { |
|
47 |
"url" : "https://${fargo}/", |
|
48 |
"title" : "Porte documents" |
|
49 |
} |
|
50 |
}, |
|
51 |
{ |
|
52 |
"create-passerelle" : { |
|
53 |
"url" : "https://${passerelle}/", |
|
54 |
"title" : "Passerelle" |
|
55 |
} |
|
56 |
}, |
|
57 |
{ |
|
58 |
"set-theme" : { |
|
59 |
"theme" : "publik" |
|
60 |
} |
|
61 |
} |
|
62 |
], |
|
63 |
"variables" : { |
|
64 |
"authentic" : "connexion-instance_name.sictiam.dev.entrouvert.org", |
|
65 |
"combo" : "instance_name.sictiam.dev.entrouvert.org", |
|
66 |
"combo_agent" : "agents-instance_name.sictiam.dev.entrouvert.org", |
|
67 |
"hobo" : "hobo-instance_name.sictiam.dev.entrouvert.org", |
|
68 |
"wcs" : "demarches-instance_name.sictiam.dev.entrouvert.org", |
|
69 |
"passerelle": "passerelle-instance_name.sictiam.dev.entrouvert.org", |
|
70 |
"fargo": "porte-documents-instance_name.sictiam.dev.entrouvert.org" |
|
71 |
} |
|
72 |
} |
hobo/contrib/ozwillo/urls.py | ||
---|---|---|
1 |
# Ozwillo plugin to deploy |
|
2 |
# Copyright (C) 2017 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software: you can redistribute it and/or modify it |
|
5 |
# under the terms of the GNU Affero General Public License as published |
|
6 |
# by the Free Software Foundation, either version 3 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU Affero General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU Affero General Public License |
|
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from django.conf.urls import patterns, url, include |
|
18 | ||
19 |
from . import views |
|
20 | ||
21 | ||
22 |
urlpatterns = patterns('', |
|
23 |
url(r'create-publik-instance', views.create_publik_instance, name='ozwillo-create-publik-instance'), |
|
24 |
url(r'delete-publik-instance', views.delete_publik_instance, name='ozwillo-delete-publik-instance'), |
|
25 |
) |
|
26 |
hobo/contrib/ozwillo/views.py | ||
---|---|---|
1 |
# Ozwillo plugin to deploy Publik |
|
2 |
# Copyright (C) 2017 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software: you can redistribute it and/or modify it |
|
5 |
# under the terms of the GNU Affero General Public License as published |
|
6 |
# by the Free Software Foundation, either version 3 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU Affero General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU Affero General Public License |
|
15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 |
import os |
|
17 |
import logging |
|
18 |
import requests |
|
19 |
import io |
|
20 |
import json |
|
21 |
import subprocess |
|
22 |
import hmac |
|
23 |
import tempfile |
|
24 |
from hashlib import sha1 |
|
25 | ||
26 |
from django.conf import settings |
|
27 |
from django.http import HttpResponseForbidden, HttpResponseBadRequest, HttpResponseNotFound |
|
28 |
from django.core.management import call_command |
|
29 | ||
30 | ||
31 |
logger = logging.getLogger(__name__) |
|
32 | ||
33 |
def valid_signature_required(func): |
|
34 |
signature_header_name = 'X-Hub-Signature' |
|
35 |
api_secret = settings.OZWILLO_SECRET |
|
36 |
def wrapper(request): |
|
37 |
if signature_header_name in request.headers: |
|
38 |
if request.headers[signature_header_name].startswith('sha1='): |
|
39 |
algo, received_hmac = request.headers[signature_header_name].rsplit('=') |
|
40 |
computed_hmac = hmac.new(api_secret, request.data, sha1).hexdigest() |
|
41 |
# the received hmac is uppercase according to |
|
42 |
# http://doc.ozwillo.com/#ref-3-2-1 |
|
43 |
if received_hmac.lower() != computed_hmac: |
|
44 |
logger.error('Invalid HMAC') |
|
45 |
return HttpResponseForbidden('Invalid HMAC') |
|
46 |
else: |
|
47 |
logger.error('Invalid HMAC algo') |
|
48 |
return HttpResponseForbidden('Invalid HMAC algo') |
|
49 |
else: |
|
50 |
logger.error('No HMAC in the header') |
|
51 |
return HttpResponseForbidden('No HMAC in the header') |
|
52 |
return func(request) |
|
53 |
return wrapper |
|
54 | ||
55 |
def is_ozwillo_enabled(func): |
|
56 |
if not os.path.exists('/etc/hobo/ozwillo'): |
|
57 |
return HttpResponseNotFound('Owillo providing is not active here.') |
|
58 |
return func |
|
59 | ||
60 |
@is_ozwillo_enabled |
|
61 |
@valid_signature_required |
|
62 |
def create_publik_instance(request): |
|
63 |
data = json.loads(request.body) |
|
64 | ||
65 |
logger.debug(data) |
|
66 | ||
67 |
client_id = data.pop('client_id') |
|
68 |
client_secret = data.pop('client_secret') |
|
69 |
instance_id = data.pop('instance_id') |
|
70 |
instance_name = data.pop('organization_name', None) |
|
71 | ||
72 |
if not instance_name: |
|
73 |
return HttpResponseBadRequest('Missing parameter "instance_name"') |
|
74 | ||
75 |
registration_uri = data.pop('instance_registration_uri') |
|
76 |
organization = data['organization'] |
|
77 |
user = data['user'] |
|
78 | ||
79 |
services = {'services': [{ |
|
80 |
'local_id': 'publik', |
|
81 |
'name': 'Publik - %s' % (instance_name), |
|
82 |
'service_uri':'https://connexion-%s.%s/accounts/oidc/login' % (instance_name, settings.OZWILLO_ENV_DOMAIN), |
|
83 |
'description': 'Gestion de la relation usagers', |
|
84 |
'tos_uri': 'https://publik.entrouvert.com/', |
|
85 |
'policy_uri': 'https://publik.entrouvert.com/', |
|
86 |
'icon': 'https://publik.entrouvert.com/static/img/logo-publik.png', |
|
87 |
'payment_option': 'FREE', |
|
88 |
'target_audience': ['PUBLIC_BODIES', |
|
89 |
'CITIZENS', |
|
90 |
'COMPANIES'], |
|
91 |
'contacts': ['https://publik.entrouvert.com/'], |
|
92 |
'redirect_uris':['https://connexion-%s.%s/accounts/oidc/callback' % (instance_name, settings.OZWILLO_ENV_DOMAIN)], |
|
93 |
}], |
|
94 |
'instance_id': instance_id, |
|
95 |
'destruction_uri': settings.OZWILLO_DESTRUCTION_URI, |
|
96 |
'destruction_secret': settings.OZWILLO_DESTRUCTION_SECRET, |
|
97 |
'needed_scopes': [] |
|
98 |
} |
|
99 | ||
100 |
logger.debug(services) |
|
101 | ||
102 |
template_recipe = json.load(open('/etc/hobo/ozwillo/template_recipe.json', 'rb')) |
|
103 |
var = template_recipe['variables'] |
|
104 |
for key, value in var.items(): |
|
105 |
var[key] = value.replace('instance_name', instance_name) |
|
106 | ||
107 |
template_recipe['variables'] = var |
|
108 |
domain = var['combo'] |
|
109 |
domain_agent = var['combo_agent'] |
|
110 |
imp_site_template = json.load(open('/etc/hobo/ozwillo/import-site-template.json', 'r')) |
|
111 | ||
112 |
for row in imp_site_template: |
|
113 |
row['fields']['redirect_url'] = row['fields']['redirect_url'].replace('instance_name', instance_name) |
|
114 | ||
115 |
combo_file_handle, combo_file_path = tempfile.mkstemp() |
|
116 |
recipe_file_handle, recipe_file_path = tempfile.mkstemp() |
|
117 | ||
118 |
with io.open(combo_file_path, 'w', encoding='utf-8') as f: |
|
119 |
f.write(unicode(json.dumps(imp_site_template, ensure_ascii=False))) |
|
120 | ||
121 |
with io.open(recipe_file_path, 'w', encoding='utf-8') as f: |
|
122 |
f.write(unicode(json.dumps(template_recipe, ensure_ascii=False))) |
|
123 | ||
124 |
call_command('cook', recipe_file_path) |
|
125 |
subprocess.call(['sudo', '-u', 'combo', 'combo-manage', |
|
126 |
'tenant_command', 'import_site', |
|
127 |
combo_file_path, '-d', domain]) |
|
128 |
subprocess.call(['sudo', '-u', 'combo', 'combo-manage', |
|
129 |
'tenant_command', 'import_site', |
|
130 |
'/etc/hobo/import-site-agents.json', '-d', domain_agent]) |
|
131 | ||
132 |
os.remove(combo_file_path) |
|
133 |
os.remove(recipe_file_path) |
|
134 | ||
135 |
headers = {'Content-type': 'application/json', 'Accept': 'application/json'} |
|
136 |
requests.post(registration_uri, data=json.dumps(services), auth=(client_id, client_secret), headers=headers) |
|
137 | ||
138 |
@is_ozwillo_enabled |
|
139 |
@valid_signature_required |
|
140 |
def delete_publik_instance(request): |
|
141 |
pass |
|
142 |
hobo/urls.py | ||
---|---|---|
32 | 32 |
url(r'^login/local/$', login_local), # to be used as backup, in case of idp down |
33 | 33 |
url(r'^accounts/mellon/', include('mellon.urls')), |
34 | 34 |
) |
35 |
if 'hobo.contrib.ozwillo' in settings.INSTALLED_APPS: |
|
36 |
urlpatterns += patterns('', |
|
37 |
url(r'ozwillo/', include('hobo.contrib.ozwillo.urls')) |
|
38 |
) |
|
35 |
- |