diff --git a/MANIFEST.in b/MANIFEST.in
index 3b98a56..acc0b2e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -13,9 +13,6 @@ recursive-include hobo/locale *.po *.mo
recursive-include hobo/environment/locale *.po *.mo
recursive-include hobo/agent/authentic2/locale *.po *.mo
recursive-include tests *.py *.json
-recursive-include hobo/contrib/ozwillo/scripts *.py
-recursive-include hobo/contrib/ozwillo/examples *.json
-include hobo/contrib/ozwillo/README.rst
include hobo/multitenant/README
include MANIFEST.in
include COPYING
diff --git a/hobo/contrib/ozwillo/README.rst b/hobo/contrib/ozwillo/README.rst
deleted file mode 100644
index 0abc2a6..0000000
--- a/hobo/contrib/ozwillo/README.rst
+++ /dev/null
@@ -1,105 +0,0 @@
-Ozwillo contrib app for SICTIAM
-===============================
-
-Install on Debian
------------------
-
-1. add `hobo.contrib.ozwillo` to INSTALLED_APPS
-
-2. copy files from examples/ into /etc/hobo/ozwillo/ (must be readable by all)
-
-3. copy following line in /etc/sudoers.d/sictiam::
-
- hobo ALL=(ALL:ALL) NOPASSWD: ALL
-
-4. set the following variables in `/etc/hobo/settings.d/10_ozwillo.py`:
-
- - OZWILLO_SECRET
- - OZWILLO_ENV_DOMAIN (e.g: sictiam.dev.entrouvert.org)
- - OZWILLO_DESTRUCTION_URI
- - OZWILLO_DESTRUCTION_SECRET
- - OZWILLO_PLATEFORM (https://dev.entrouvert.org/projects/sictiam/wiki/Raccordement_OpenID_Connect_%C3%A0_Ozwillo for the values)
- - OZWILLO_SERVICES (use only for the destruction, explained down)
-
- Exemple::
-
- OZWILLO_DESTRUCTION_SECRET = "mysecret"
- OZWILLO_DESTRUCTION_URI = "https://hobo-sve.test-demarches.sictiam.fr/ozwillo/delete-publik-instance/"
- OZWILLO_ENABLED = True,
- OZWILLO_ENV_DOMAIN = "test-demarches.sictiam.fr"
- OZWILLO_PLATEFORM = "https://accounts.ozwillo-preprod.eu/"
- OZWILLO_SECRET = "myothersecret"
- OZWILLO_SERVICES = {
- "authentic-multitenant": [
- "connexion-",
- "authentic2-multitenant-manage"
- ],
- "combo_agent": [
- "agents-",
- "combo-manage"
- ],
- "combo_usager": [
- "",
- "combo-manage"
- ],
- "fargo": [
- "porte-documents-",
- "fargo-manage"
- ],
- "hobo": [
- "hobo-",
- "hobo-manage"
- ],
- "passerelle": [
- "passerelle-",
- "passerelle-manage"
- ],
- "wcs": [
- "demarches-",
- "wcsctl"
- ]
- }
-
-Design
-------
-
-The views create-publik-instance receive an ozwillo request with some clients
-informations (secret and id), the ozwillo user sending the request, the
-organization name (which is the collectivity's name to deploy) and the
-registration uri (where you're supposed to POST when the job's done).
-
-The script modify a template_recipe by replacing every 'instance_name' by the
-actual organization name, and same for the combo user extract (rewritting all
-the url_redirect fields).
-
-The script then launch a cook and three commands :
-- the import of the combo user with the modified extract
-- the import of the combo agent
-- a runscript creating a role (same as the one in wcs linked to the form sve
-'agents sve'), a provider (the details are in the page linked for the parameter
-OZWILLO_PLATEFORM) and an admin User in Authentic who is the ozwillo user
-sending the request.
-
-In the final acknowledgement response, the script sends a 'services'
-dictionnary for ozillo to set some links and parameters in its backoffice about
-the app deployed).
-
-OZWILLO_SERVICES is a dict following this pattern: 'service_user':
-['service_prefix', 'service_command_manager']. E.G::
-
- {
- "authentic-multitenant": ["connexion-", "authentic2-multitenant-manage"],
- "combo_agent": ["agents-", "combo-manage"],
- "combo_usager": ["", "combo-manage"],
- "fargo": ["porte-documents-", "fargo-manage"],
- "hobo": ["hobo-", "hobo-manage"],
- "passerelle": ["passerelle-", "passerelle-manage"],
- "wcs": ["demarches-", "wcsctl"]
- }
-
-Destruction
-===========
-
-For the complete destruction of w.c.s. instances it's necessary that in the
-default skeleton (`/var/lib/wcs/skeletons/export.zip`) the `config.pck` file
-contains a key `postgresql.createdb-connection-params`.
diff --git a/hobo/contrib/ozwillo/__init__.py b/hobo/contrib/ozwillo/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/hobo/contrib/ozwillo/admin.py b/hobo/contrib/ozwillo/admin.py
deleted file mode 100644
index dc9525d..0000000
--- a/hobo/contrib/ozwillo/admin.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from django.contrib import admin
-
-from .models import OzwilloInstance
-
-
-class OzwilloInstanceAdmin(admin.ModelAdmin):
- list_display = ['id', 'domain_slug', 'external_ozwillo_id', 'state', 'created', 'modified']
- list_filter = ['state', 'created', 'modified']
-
-admin.site.register(OzwilloInstance, OzwilloInstanceAdmin)
diff --git a/hobo/contrib/ozwillo/examples/import-site-agents.json b/hobo/contrib/ozwillo/examples/import-site-agents.json
deleted file mode 100644
index 866c2e6..0000000
--- a/hobo/contrib/ozwillo/examples/import-site-agents.json
+++ /dev/null
@@ -1,30 +0,0 @@
-[
- {
- "cells": [
- {
- "fields": {
- "extra_css_class": "",
- "groups": [],
- "order": 1,
- "placeholder": "content",
- "public": true,
- "restricted_to_unlogged": false,
- "slug": "services",
- "text": "
Bienvenue
\r\n"
- },
- "model": "data.textcell"
- }
- ],
- "fields": {
- "exclude_from_navigation": false,
- "groups": [],
- "order": 1,
- "parent": null,
- "public": false,
- "redirect_url": "",
- "slug": "index",
- "template_name": "standard",
- "title": "Accueil"
- }
- }
-]
diff --git a/hobo/contrib/ozwillo/examples/import-site-template.json b/hobo/contrib/ozwillo/examples/import-site-template.json
deleted file mode 100644
index e3c8aa3..0000000
--- a/hobo/contrib/ozwillo/examples/import-site-template.json
+++ /dev/null
@@ -1,169 +0,0 @@
-[
- {
- "cells": [
- {
- "fields": {
- "extra_css_class": "",
- "groups": [],
- "order": 0,
- "placeholder": "content",
- "public": true,
- "restricted_to_unlogged": true,
- "slug": "",
- "text": "Bienvenue
\r\n\r\nBienvenue sur votre compte usager.
\r\n\r\nPour suivre vos démarches en cours, créez votre compte personnel ou identifiez-vous depuis la page de connexion.
\r\n"
- },
- "model": "data.textcell"
- },
- {
- "fields": {
- "extra_css_class": "",
- "groups": [],
- "order": 1,
- "placeholder": "content",
- "public": false,
- "restricted_to_unlogged": false,
- "slug": "",
- "text": "Bienvenue
\r\n\r\nBienvenue sur votre compte usager.
\r\n"
- },
- "model": "data.textcell"
- },
- {
- "fields": {
- "extra_css_class": "",
- "groups": [],
- "order": 2,
- "placeholder": "right",
- "public": true,
- "restricted_to_unlogged": false,
- "slug": "",
- "wcs_site": ""
- },
- "model": "wcs.trackingcodeinputcell"
- },
- {
- "fields": {
- "extra_css_class": "",
- "groups": [],
- "order": 3,
- "placeholder": "right",
- "public": true,
- "restricted_to_unlogged": true,
- "slug": "",
- "text": "Demandes en cours
\r\n\r\nConnectez-vous pour voir vos demandes en cours.
\r\n"
- },
- "model": "data.textcell"
- },
- {
- "fields": {
- "current_forms": true,
- "done_forms": false,
- "extra_css_class": "",
- "groups": [],
- "order": 4,
- "placeholder": "right",
- "public": false,
- "restricted_to_unlogged": false,
- "slug": "",
- "wcs_site": ""
- },
- "model": "wcs.wcscurrentformscell"
- },
- {
- "fields": {
- "extra_css_class": "",
- "groups": [],
- "order": 5,
- "placeholder": "footer",
- "public": true,
- "restricted_to_unlogged": false,
- "slug": "",
- "text": "Ce service est proposé par le SICTIAM.
\r\n"
- },
- "model": "data.textcell"
- },
- {
- "fields": {
- "category_reference": "eservices:nous-contacter",
- "extra_css_class": "",
- "groups": [],
- "limit": null,
- "manual_order": {
- "data": []
- },
- "order": 6,
- "ordering": "popularity",
- "placeholder": "content",
- "public": true,
- "restricted_to_unlogged": false,
- "slug": ""
- },
- "model": "wcs.wcsformsofcategorycell"
- }
- ],
- "fields": {
- "exclude_from_navigation": false,
- "groups": [],
- "order": 1,
- "parent": null,
- "public": true,
- "redirect_url": "",
- "slug": "index",
- "template_name": "two-columns",
- "title": "Accueil"
- }
- },
- {
- "cells": [
- {
- "fields": {
- "extra_css_class": "",
- "groups": [],
- "order": 0,
- "placeholder": "footer",
- "public": true,
- "restricted_to_unlogged": false,
- "slug": ""
- },
- "model": "data.parentcontentcell"
- }
- ],
- "fields": {
- "exclude_from_navigation": false,
- "groups": [],
- "order": 2,
- "parent": null,
- "public": true,
- "redirect_url": "[idp_url]accounts/",
- "slug": "mon-compte",
- "template_name": "standard",
- "title": "Mon compte"
- }
- },
- {
- "cells": [
- {
- "fields": {
- "extra_css_class": "",
- "groups": [],
- "order": 0,
- "placeholder": "footer",
- "public": true,
- "restricted_to_unlogged": false,
- "slug": ""
- },
- "model": "data.parentcontentcell"
- }
- ],
- "fields": {
- "exclude_from_navigation": false,
- "groups": [],
- "order": 3,
- "parent": null,
- "public": true,
- "redirect_url": "[eservices_url]",
- "slug": "nous-contacter",
- "template_name": "standard",
- "title": "Nous contacter"
- }
- }
-]
diff --git a/hobo/contrib/ozwillo/examples/template_recipe.json b/hobo/contrib/ozwillo/examples/template_recipe.json
deleted file mode 100644
index 5b11fbd..0000000
--- a/hobo/contrib/ozwillo/examples/template_recipe.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- "steps": [
- {
- "create-hobo": {
- "url": "https://${hobo}/",
- "primary": true
- }
- },
- {
- "create-authentic": {
- "title": "Connexion",
- "url": "https://${authentic}/"
- }
- },
- {
- "set-idp": {}
- },
- {
- "create-combo": {
- "template_name": "portal-user",
- "title": "Compte citoyen",
- "url": "https://${combo}/"
- }
- },
- {
- "create-combo": {
- "slug": "portal-agent",
- "template_name": "portal-agent",
- "title": "Portail agent",
- "url": "https://${combo_agent}/"
- }
- },
- {
- "create-wcs": {
- "template_name": "export.zip",
- "title": "D\u00e9marches",
- "url": "https://${wcs}/"
- }
- },
- {
- "create-fargo": {
- "title": "Porte documents",
- "url": "https://${fargo}/"
- }
- },
- {
- "create-passerelle": {
- "title": "Passerelle",
- "url": "https://${passerelle}/"
- }
- },
- {
- "set-theme": {
- "theme": "publik"
- }
- }
- ],
- "variables": {
- "authentic": "connexion-instance_name.sictiam.dev.entrouvert.org",
- "combo": "instance_name.sictiam.dev.entrouvert.org",
- "combo_agent": "agents-instance_name.sictiam.dev.entrouvert.org",
- "fargo": "porte-documents-instance_name.sictiam.dev.entrouvert.org",
- "hobo": "hobo-instance_name.sictiam.dev.entrouvert.org",
- "passerelle": "passerelle-instance_name.sictiam.dev.entrouvert.org",
- "wcs": "demarches-instance_name.sictiam.dev.entrouvert.org"
- }
-}
diff --git a/hobo/contrib/ozwillo/management/__init__.py b/hobo/contrib/ozwillo/management/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/hobo/contrib/ozwillo/management/commands/__init__.py b/hobo/contrib/ozwillo/management/commands/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/hobo/contrib/ozwillo/management/commands/ozwillo_worker.py b/hobo/contrib/ozwillo/management/commands/ozwillo_worker.py
deleted file mode 100644
index 53328b0..0000000
--- a/hobo/contrib/ozwillo/management/commands/ozwillo_worker.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Ozwillo plugin to deploy Publik
-# 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 logging
-
-from hobo.contrib.ozwillo.models import OzwilloInstance
-
-from django.db.transaction import atomic
-from django.core.management.base import BaseCommand
-
-
-class Command(BaseCommand):
- def add_arguments(self, parser):
- parser.add_argument('args', nargs='*')
-
- @atomic
- def handle(self, *args, **options):
- qs = OzwilloInstance.objects.select_for_update()
-
- # deployment
- if args:
- # allow deploying manually failed instances
- to_deploy = qs.fiter(
- domain_slug__in=args,
- state__in=[OzwilloInstance.STATE_TO_DEPLOY, OzwilloInstance.STATE_DEPLOY_ERROR])
- else:
- # deploy everything to be deployed
- to_deploy = qs.filter(
- state=OzwilloInstance.STATE_TO_DEPLOY)
- for instance in to_deploy:
- try:
- with atomic():
- instance.deploy()
- except Exception:
- logger.exception(u'ozwillo: deploying %s from CRON failed', instance)
- instance.deploy_error()
-
- # destruction
- if args:
- # allow deploying manually failed instances
- to_destroy = qs.filter(
- domain_slug__in=args,
- state__in=[OzwilloInstance.STATE_TO_DESTROY, OzwilloInstance.STATE_DESTROY_ERROR])
- else:
- # destroy everything to be destroyed
- to_destroy = qs.filter(state=OzwilloInstance.STATE_TO_DESTROY)
- for instance in to_destroy:
- try:
- with atomic():
- instance.destroy()
- except Exception:
- logger.exception(u'ozwillo: destroying %s from CRON failed', instance)
- instance.destroy_error()
-
-logger = logging.getLogger(__name__)
diff --git a/hobo/contrib/ozwillo/migrations/0001_initial.py b/hobo/contrib/ozwillo/migrations/0001_initial.py
deleted file mode 100644
index 87ff97c..0000000
--- a/hobo/contrib/ozwillo/migrations/0001_initial.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ]
-
- operations = [
- migrations.CreateModel(
- name='OzwilloInstance',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('domain_slug', models.CharField(unique=True, max_length=250)),
- ('external_ozwillo_id', models.CharField(max_length=450)),
- ],
- ),
- ]
diff --git a/hobo/contrib/ozwillo/migrations/0002_auto_20180517_1047.py b/hobo/contrib/ozwillo/migrations/0002_auto_20180517_1047.py
deleted file mode 100644
index 75d0d01..0000000
--- a/hobo/contrib/ozwillo/migrations/0002_auto_20180517_1047.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.11.13 on 2018-05-17 10:47
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-import django.utils.timezone
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('ozwillo', '0001_initial'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='ozwilloinstance',
- name='created',
- field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
- preserve_default=False,
- ),
- migrations.AddField(
- model_name='ozwilloinstance',
- name='deploy_data',
- field=models.TextField(null=True),
- ),
- migrations.AddField(
- model_name='ozwilloinstance',
- name='modified',
- field=models.DateTimeField(auto_now=True, default=django.utils.timezone.now),
- ),
- migrations.AddField(
- model_name='ozwilloinstance',
- name='state',
- field=models.CharField(choices=[(b'new', b'new'), (b'to_deploy', b'to_deploy'), (b'deployed', b'deployed'), (b'deploy_error', b'deploy_error'), (b'to_destroy', b'to_destroy'), (b'destroy_error', b'destroy_error'), (b'destroyed', b'destroyed')], default=b'deployed', max_length=16),
- ),
- migrations.AlterField(
- model_name='ozwilloinstance',
- name='external_ozwillo_id',
- field=models.CharField(max_length=450, unique=True),
- ),
- migrations.AlterField(
- model_name='ozwilloinstance',
- name='modified',
- field=models.DateTimeField(auto_now=True),
- ),
- migrations.AlterField(
- model_name='ozwilloinstance',
- name='state',
- field=models.CharField(choices=[(b'new', b'new'), (b'to_deploy', b'to_deploy'), (b'deployed', b'deployed'), (b'deploy_error', b'deploy_error'), (b'to_destroy', b'to_destroy'), (b'destroy_error', b'destroy_error'), (b'destroyed', b'destroyed')], default=b'new', max_length=16),
- ),
- ]
diff --git a/hobo/contrib/ozwillo/migrations/0003_auto_20180524_0828.py b/hobo/contrib/ozwillo/migrations/0003_auto_20180524_0828.py
deleted file mode 100644
index de56993..0000000
--- a/hobo/contrib/ozwillo/migrations/0003_auto_20180524_0828.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.11.13 on 2018-05-24 08:28
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('ozwillo', '0002_auto_20180517_1047'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='ozwilloinstance',
- name='domain_slug',
- field=models.CharField(max_length=250),
- ),
- ]
diff --git a/hobo/contrib/ozwillo/migrations/__init__.py b/hobo/contrib/ozwillo/migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/hobo/contrib/ozwillo/models.py b/hobo/contrib/ozwillo/models.py
deleted file mode 100644
index db0f713..0000000
--- a/hobo/contrib/ozwillo/models.py
+++ /dev/null
@@ -1,285 +0,0 @@
-# Ozwillo plugin to deploy Publik
-# 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 logging
-import os
-import subprocess
-import tempfile
-import json
-
-import requests
-
-from django.conf import settings
-from django.db import models
-from django.db.transaction import atomic
-from django.utils.text import slugify
-from django.core.management import call_command
-from django.db import connection
-
-from tenant_schemas.utils import tenant_context
-
-
-class OzwilloInstance(models.Model):
- STATE_NEW = 'new'
- STATE_TO_DEPLOY = 'to_deploy'
- STATE_DEPLOY_ERROR = 'deploy_error'
- STATE_DEPLOYED = 'deployed'
- STATE_TO_DESTROY = 'to_destroy'
- STATE_DESTROY_ERROR = 'destroy_error'
- STATE_DESTROYED = 'destroyed'
-
- STATES = [
- (STATE_NEW, 'new'),
- (STATE_TO_DEPLOY, 'to_deploy'),
- (STATE_DEPLOYED, 'deployed'),
- (STATE_DEPLOY_ERROR, 'deploy_error'),
- (STATE_TO_DESTROY, 'to_destroy'),
- (STATE_DESTROY_ERROR, 'destroy_error'),
- (STATE_DESTROYED, 'destroyed'),
- ]
-
- state = models.CharField(max_length=16, default=STATE_NEW, choices=STATES)
- created = models.DateTimeField(auto_now_add=True)
- modified = models.DateTimeField(auto_now=True)
- domain_slug = models.CharField(max_length=250)
- external_ozwillo_id = models.CharField(max_length=450, unique=True)
- deploy_data = models.TextField(null=True)
-
- def __unicode__(self):
- return self.domain_slug
-
- def __repr__(self):
- return '' % (
- self.external_ozwillo_id, self.domain_slug, self.state)
-
- @property
- def data(self):
- return json.loads(self.deploy_data) if self.deploy_data else None
-
- def to_deploy(self):
- assert self.state == self.STATE_NEW
- try:
- with atomic():
- # lock the new instance to prevent collision with the CRON job
- OzwilloInstance.objects.select_for_update().filter(id=self.id)
- # instance starts with the NEW state, to prevent the CRON from
- # deploying instance juste created
- # only instance in the state STATE_TO_DEPLOY are deployed.
- self.state = self.STATE_TO_DEPLOY
- self.save()
- self.deploy()
- except Exception:
- # something failed, still make the instance to be deployed
- # an reraise exception
- self.state = self.STATE_TO_DEPLOY
- self.save()
- raise
-
- def to_destroy(self):
- assert self.state == self.STATE_DEPLOYED
- self.state = self.STATE_TO_DESTROY
- self.save()
-
- def deploy_error(self):
- assert self.state in [self.STATE_DEPLOY_ERROR, self.STATE_TO_DEPLOY]
- if self.state == self.STATE_TO_DEPLOY:
- self.state = self.STATE_DEPLOY_ERROR
- self.save()
-
- def deploy(self):
- logger.info(u'ozwillo: deploy start for %s', self)
- data = self.data
- if not data:
- logger.warning(u'ozwillo: unable to deploy, no data')
- return
-
- # Request parsing
- client_id = data['client_id']
- client_secret = data['client_secret']
- instance_id = data['instance_id']
- instance_name = data['organization_name']
- instance_name = slugify(instance_name)
- registration_uri = data['instance_registration_uri']
- user = data['user']
-
- # Cook new platform
- template_recipe = json.load(open('/etc/hobo/ozwillo/template_recipe.json', 'rb'))
- var = template_recipe['variables']
- for key, value in var.items():
- var[key] = value.replace('instance_name', instance_name)
-
- template_recipe['variables'] = var
- domain = var['combo']
- domain_agent = var['combo_agent']
- domain_passerelle = var['passerelle']
- logger.info(u'ozwillo: cooking %s', template_recipe)
-
- with tempfile.NamedTemporaryFile() as recipe_file:
- json.dump(template_recipe, recipe_file)
- recipe_file.flush()
-
- # cook play with the tenant context, we must protect from that
- with tenant_context(connection.tenant):
- call_command('cook', recipe_file.name, timeout=1000, verbosity=0)
-
- # Load user portal template
- logger.info(u'ozwillo: loading combo template')
- run_command([
- 'sudo', '-u', 'combo',
- 'combo-manage', 'tenant_command', 'import_site',
- '/etc/hobo/ozwillo/import-site-template.json',
- '-d', domain
- ])
-
- # Load agent portal template
- logger.info(u'ozwillo: loading combo agent template')
- run_command([
- 'sudo', '-u', 'combo',
- 'combo-manage', 'tenant_command', 'import_site',
- '/etc/hobo/ozwillo/import-site-agents.json',
- '-d', domain_agent
- ])
-
- # Configure OIDC Ozwillo authentication
- logger.info(u'ozwillo: configuring OIDC ozwillo authentication')
- domain_name = 'connexion-%s.%s' % (instance_name, settings.OZWILLO_ENV_DOMAIN)
- if run_command([
- 'sudo', '-u', 'authentic-multitenant',
- 'authentic2-multitenant-manage', 'tenant_command', 'oidc-register-issuer',
- '-d', domain_name,
- '--scope', 'profile',
- '--scope', 'email',
- '--issuer', settings.OZWILLO_PLATEFORM,
- '--client-id', client_id,
- '--client-secret', client_secret,
- '--claim-mapping', 'given_name first_name always_verified',
- '--claim-mapping', 'family_name last_name always_verified',
- '--ou-slug', 'default',
- '--claim-mapping', 'email email required',
- 'Ozwillo'
- ]):
- # creation of the admin user depends upon the creation of provider
- logger.info(u'ozwillo: creating admin user')
- create_user_script = os.path.dirname(__file__) + '/scripts/create_user_ozwillo.py'
- run_command([
- 'sudo', '-u', 'authentic-multitenant',
- 'authentic2-multitenant-manage', 'tenant_command', 'runscript', '-d', domain_name,
- create_user_script, user['email_address'], user['id'], user['name']
- ])
-
- # Load passerelle template
- logger.info(u'ozwillo: loading passerelle template')
- run_command([
- 'sudo', '-u', 'passerelle',
- 'passerelle-manage', 'tenant_command', 'import_site',
- '/etc/hobo/ozwillo/import-site-passerelle.json',
- '--import-user', '-d', domain_passerelle
- ])
-
- # Sending done event to Ozwillo
- services = {
- 'services': [{
- 'local_id': 'publik',
- 'name': 'Publik - %s' % (instance_name),
- 'service_uri': 'https://connexion-%s.%s/accounts/oidc/login?iss=%s'
- % (instance_name, settings.OZWILLO_ENV_DOMAIN,
- settings.OZWILLO_PLATEFORM),
- 'description': 'Gestion de la relation usagers',
- 'tos_uri': 'https://publik.entrouvert.com/',
- 'policy_uri': 'https://publik.entrouvert.com/',
- 'icon': 'https://publik.entrouvert.com/static/img/logo-publik-64x64.png',
- 'payment_option': 'FREE',
- 'target_audience': ['PUBLIC_BODIES',
- 'CITIZENS',
- 'COMPANIES'],
- 'contacts': ['https://publik.entrouvert.com/'],
- 'redirect_uris': ['https://connexion-%s.%s/accounts/oidc/callback/'
- % (instance_name, settings.OZWILLO_ENV_DOMAIN)],
- }],
- 'instance_id': instance_id,
- 'destruction_uri': settings.OZWILLO_DESTRUCTION_URI,
- 'destruction_secret': settings.OZWILLO_DESTRUCTION_SECRET,
- 'needed_scopes': []
- }
- logger.info(u'ozwillo: sending registration request, %r', services)
- headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
- response = requests.post(
- registration_uri,
- data=json.dumps(services),
- auth=(client_id, client_secret),
- headers=headers)
- logger.info(u'ozwillo: registration response, status=%s content=%r',
- response.status_code, response.content)
- self.state = self.STATE_DEPLOYED
- self.save()
- logger.info(u'ozwillo: deploy finished')
-
- def destroy_error(self):
- assert self.state in [self.STATE_DESTROY_ERROR, self.STATE_TO_DESTROY]
- if self.state == self.STATE_TO_DESTROY:
- self.state = self.STATE_DESTROY_ERROR
- self.save()
-
-
- def destroy(self):
- logger.info(u'ozwillo: destroy start for %s', self)
- instance_slug = self.domain_slug
- services = settings.OZWILLO_SERVICES.copy()
- # w.c.s. is handled differently
- wcs = services.pop('wcs')
-
- for s, infos in services.items():
- # to get the two combo instances which have same service
- service_user = s.split('_')[0]
-
- tenant = '%s%s.%s' % (infos[0], instance_slug, settings.OZWILLO_ENV_DOMAIN)
-
- run_command([
- 'sudo', '-u', service_user, infos[1],
- 'delete_tenant', '--force-drop', tenant
- ])
-
- tenant = '%s%s.%s' % (wcs[0], instance_slug, settings.OZWILLO_ENV_DOMAIN)
- run_command([
- 'sudo', '-u', 'wcs',
- wcs[1], '-f', '/etc/wcs/wcs-au-quotidien.cfg',
- 'delete_tenant', '--force-drop', tenant
- ])
-
- logger.info(u'ozwillo: destroy finished')
- self.state = self.STATE_DESTROYED
- self.save()
-
-
-def run_command(args):
- try:
- process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- except OSError as e:
- logger.error('ozwillo: launching subprocess %s raised error %s', args, e)
- return False
- logger.info('ozwillo: launching subprocess with pid %s : %s', process.pid, args)
- stdoutdata, stderrdata = process.communicate()
- if process.returncode != 0:
- logger.error('ozwillo: subprocess %s failed returncode=%s stdout=%r stderr=%r',
- process.pid, process.returncode, stdoutdata, stderrdata)
- return False
- logger.info('ozwillo: subprocess terminated')
- return True
-
-
-logger = logging.getLogger(__name__)
-
-
diff --git a/hobo/contrib/ozwillo/scripts/create_user_ozwillo.py b/hobo/contrib/ozwillo/scripts/create_user_ozwillo.py
deleted file mode 100644
index d8d1658..0000000
--- a/hobo/contrib/ozwillo/scripts/create_user_ozwillo.py
+++ /dev/null
@@ -1,55 +0,0 @@
-import sys
-import logging
-
-from django.contrib.auth import get_user_model
-
-from authentic2_auth_oidc.models import OIDCAccount
-from authentic2_auth_oidc.models import OIDCProvider
-from authentic2.a2_rbac.models import Role, OrganizationalUnit
-
-
-def create_user(user_id, email_addressi, user_name, provider):
- while True:
- new_user = User.objects.create()
- oidc_account, created = OIDCAccount.objects.select_related().get_or_create(provider=provider, sub=user_id, defaults={'user': new_user})
- if created:
- if OIDCAccount.objects.filter(provider=provider, sub=user_id).count() > 1:
- oidc_account.delete()
- new_user.delete()
- continue
- break
- else:
- new_user.delete()
- new_user = oidc_account.user
- break
-
- new_user.email = email_address
- new_user.ou = provider.ou
- new_user.is_superuser = True
- new_user.is_staff = True
- new_user.first_name = 'admin'
- new_user.last_name = user_name
- new_user.save()
-
- return new_user
-
-
-# create agent_sve role
-ou = OrganizationalUnit.objects.get(default=True)
-role, created = Role.objects.get_or_create(uuid='3f3367d817bb4a9aa98e7ed6c83b5b09',
- defaults={'name': u'Agents SVE',
- 'ou': ou})
-
-# set the provider for the user creation
-provider = OIDCProvider.objects.get(name='Ozwillo')
-
-# get user info from args sent to the script
-args = sys.argv
-email_address = args[1]
-user_id = args[2]
-user_name = args[3]
-
-# create admin user in Publik from Ozwillo
-User = get_user_model()
-user = create_user(user_id, email_address, user_name, provider)
-logging.info('owzillo provisionning: user created with uuid: %s', user.uuid)
diff --git a/hobo/contrib/ozwillo/scripts/synchronize_ozwillo_users.py b/hobo/contrib/ozwillo/scripts/synchronize_ozwillo_users.py
deleted file mode 100644
index 1ab4bfd..0000000
--- a/hobo/contrib/ozwillo/scripts/synchronize_ozwillo_users.py
+++ /dev/null
@@ -1,148 +0,0 @@
-# Ozwillo plugin to deploy Publik
-# Copyright (C) 2017-2019 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 json
-import datetime
-import logging
-from urllib import urlencode
-import pprint
-import os
-
-import requests
-from robobrowser.browser import RoboBrowser
-
-from django.utils.six.moves.urllib import parse as urlparse
-
-from hobo.multitenant.middleware import TenantMiddleware
-from tenant_schemas.utils import tenant_context
-
-
-def run_on_all_tenants(f):
- for tenant in TenantMiddleware.get_tenants():
- with tenant_context(tenant):
- try:
- f(tenant)
- except:
- logging.exception('unable to provision')
-
-def provision_users(tenant):
- from django.conf import settings
-
- if not getattr(settings, 'OZWILLO_ADMIN', None):
- logging.warning('No OZWILLO_ADMIN setting found')
- return
-
- logger = logging.getLogger('ozwillo_synchro')
- from authentic2_auth_oidc.models import OIDCProvider
- for provider in OIDCProvider.objects.all():
- if 'ozwillo' in provider.issuer or 'accounts.sictiam.fr' in provider.issuer:
- auth_url = provider.authorization_endpoint
- token_url = provider.token_endpoint
- client_id = provider.client_id
- client_secret = provider.client_secret
- redirect_uri = urlparse.urljoin(tenant.get_base_url(), '/accounts/oidc/callback/')
- instance_users_url = urlparse.urljoin(token_url.replace('accounts', 'kernel'), '/apps/acl/instance/')
- break
- else:
- logger.warning('No ozwillo OIDC provider found for %s', tenant.get_base_url())
- return
-
- session = requests.Session()
- session.verify = False
-
- br = RoboBrowser(user_agent='Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0',
- session=session)
-
- query = urlencode({
- 'client_id': client_id,
- 'response_type': 'code',
- 'scope': 'openid offline_access',
- 'prompt': 'consent',
- 'redirect_uri': redirect_uri
- })
- response = br.open(auth_url + '?%s' % query)
- response = br._states[-1].response
- if br._states[-1].response.status_code != 200:
- logger.warning(u'OIDC authorization request failed: %s %r', response.status_code, response._content[:1000])
- return
- referer = br.response.request.url
- br.session.headers['Referer'] = referer
- form = br.get_form(action='/a/login')
- form['u'] = settings.OZWILLO_ADMIN[0]
- form['pwd'] = settings.OZWILLO_ADMIN[1]
- br.submit_form(form=form)
- referer = br.response.request.url
- br.session.headers['Referer'] = referer
- form = br.get_form()
- br.submit_form(form=form, allow_redirects=False)
-
- if 'Location' not in br.response.headers:
- logger.warning(u'Not authorization form %r %r', response.status_code, response._content[:1000])
- return
-
- cb_url = urlparse.urlparse(br.response.headers['location'])
-
- code = urlparse.parse_qs(cb_url.query)['code'][0]
-
- logger.info('Getting token from %s', token_url)
- response = requests.post(token_url, auth=(client_id, client_secret),
- data={
- 'code': code,
- 'redirect_uri': redirect_uri,
- 'grant_type': 'authorization_code'})
- logger.info('Got %s', response.json())
- access_token = response.json()['access_token']
- logger.info('Getting instance users from %s', instance_users_url + client_id)
- response = requests.get(instance_users_url + client_id,
- headers={'Authorization': 'Bearer %s' % access_token})
- logger.info('Got %s', response.json())
-
- from django.contrib.auth import get_user_model
- from authentic2_auth_oidc.models import OIDCAccount
-
- User = get_user_model()
-
- for user in response.json():
- logging.info('Provisionning email %s with sub %s', user['user_email_address'], user['user_id'])
- while True:
- new_user = User.objects.create()
- oidc_account, created = OIDCAccount.objects.select_related().get_or_create(provider=provider, sub=user['user_id'], defaults={'user': new_user})
- if created:
- if OIDCAccount.objects.filter(provider=provider, sub=user['user_id']).count() > 1:
- oidc_account.delete()
- new_user.delete()
- continue
- logging.info('provisionned with uuid %s', new_user.uuid)
- break
- else:
- new_user.delete()
- new_user = oidc_account.user
- break
- save = False
- if new_user.username != user['user_name']:
- new_user.username = user['user_name']
- save = True
- if new_user.email != user['user_email_address']:
- new_user.email = user['user_email_address']
- save = True
- if new_user.ou != provider.ou:
- new_user.ou = provider.ou
- save = True
- if save:
- new_user.save()
-
-
-run_on_all_tenants(provision_users)
diff --git a/hobo/contrib/ozwillo/urls.py b/hobo/contrib/ozwillo/urls.py
deleted file mode 100644
index 04887f3..0000000
--- a/hobo/contrib/ozwillo/urls.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Ozwillo plugin to deploy
-# 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 .
-
-from django.conf.urls import url, include
-
-from . import views
-
-
-urlpatterns = [
- url(r'create-publik-instance', views.create_publik_instance, name='ozwillo-create-publik-instance'),
- url(r'delete-publik-instance', views.delete_publik_instance, name='ozwillo-delete-publik-instance'),
-]
diff --git a/hobo/contrib/ozwillo/views.py b/hobo/contrib/ozwillo/views.py
deleted file mode 100644
index 1862727..0000000
--- a/hobo/contrib/ozwillo/views.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# Ozwillo plugin to deploy Publik
-# 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 logging
-import json
-import hmac
-import threading
-from hashlib import sha1
-
-from django.views.decorators.csrf import csrf_exempt
-from django.conf import settings
-from django.http import (HttpResponseForbidden, HttpResponseBadRequest,
- HttpResponseNotFound, HttpResponse)
-from django.utils.text import slugify
-from django.db import DatabaseError
-from django.db.transaction import atomic
-
-from .models import OzwilloInstance
-
-logger = logging.getLogger(__name__)
-
-
-def valid_signature_required(setting):
- '''Validate Ozwillo signatures'''
- signature_header_name = 'HTTP_X_HUB_SIGNATURE'
-
- def decorator(func):
- def wrapper(request, *args, **kwargs):
- api_secret = getattr(settings, setting)
- if signature_header_name in request.META:
- if request.META[signature_header_name].startswith('sha1='):
- algo, received_hmac = request.META[signature_header_name].rsplit('=')
- computed_hmac = hmac.new(api_secret, request.content, sha1).hexdigest()
- # the received hmac is uppercase according to
- # http://doc.ozwillo.com/#ref-3-2-1
- if received_hmac.lower() != computed_hmac:
- logger.error(u'ozwillo: invalid HMAC')
- return HttpResponseForbidden('invalid HMAC')
- else:
- logger.error(u'ozwillo: invalid HMAC algo')
- return HttpResponseForbidden('invalid HMAC algo')
- else:
- logger.error(u'ozwillo: no HMAC in the header')
- return HttpResponseForbidden('no HMAC in the header')
- return func(request, *args, **kwargs)
- return wrapper
- return decorator
-
-
-def is_ozwillo_enabled(func):
- def wrapper(request):
- if not getattr(settings, 'OZWILLO_ENABLED', False):
- return HttpResponseNotFound('owillo providing is not active here.')
- return func(request)
- return wrapper
-
-
-@csrf_exempt
-@is_ozwillo_enabled
-@valid_signature_required(setting='OZWILLO_SECRET')
-def create_publik_instance(request):
- try:
- data = json.loads(request.text)
- except ValueError:
- logger.warning(u'ozwillo: received non JSON request')
- return HttpResponseBadRequest('invalid JSON content')
-
- logger.info(u'ozwillo: create publik instance request, %r', data)
-
- if 'organization_name' not in data.keys():
- logger.warning(u'ozwillo: missing organization_name')
- return HttpResponseBadRequest('missing parameter "organization_name"')
-
- org_name = slugify(data['organization_name'])
- # forbid creation of an instance if a not destroyed previous one exists
- if OzwilloInstance.objects.exclude(state=OzwilloInstance.STATE_DESTROYED).filter(domain_slug=org_name):
- logger.warning(u'ozwillo: instance %s already exists', org_name)
- return HttpResponseBadRequest('instance %s already exists' % org_name)
-
- try:
- instance = OzwilloInstance.objects.create(
- external_ozwillo_id=data['instance_id'],
- state=OzwilloInstance.STATE_NEW,
- domain_slug=org_name,
- # deploy_data is a TextField containing JSON
- deploy_data=json.dumps(data, indent=4))
- except DatabaseError as e:
- logger.warning(u'ozwillo: could not create instance_id %r org_name %r: %r',
- data['instance_id'], org_name, e)
- return HttpResponseBadRequest(u'cannot create the instance: %r', e)
-
- # immediate deploy in a thread
- def thread_function(data):
- try:
- instance.to_deploy()
- except Exception:
- logger.exception(u'ozwillo: error occured duging initial deploy request %s', org_name)
- thread = threading.Thread(target=thread_function, args=(data,))
- thread.start()
-
- return HttpResponse()
-
-
-@csrf_exempt
-@is_ozwillo_enabled
-@valid_signature_required(setting='OZWILLO_DESTRUCTION_SECRET')
-@atomic
-def delete_publik_instance(request):
- try:
- data = json.loads(request.text)
- except ValueError:
- logger.warning(u'ozwillo: received non JSON request')
- return HttpResponseBadRequest('invalid JSON content')
-
- logger.info(u'ozwillo: delete publik instance request (%r)', data)
-
- try:
- instance_id = data['instance_id']
- except KeyError:
- logger.warning(u'ozwillo: no instance id in destroy request (%r)', data)
- return HttpResponseBadRequest('no instance id')
- try:
- instance = OzwilloInstance.objects.select_for_update().get(
- external_ozwillo_id=instance_id,
- # only deployed instances can be destroyed
- state=OzwilloInstance.STATE_DEPLOYED)
- except OzwilloInstance.DoesNotExist:
- return HttpResponseBadRequest('no instance with id %s' % data['instance_id'])
- instance.to_destroy()
- logger.info(u'ozwillo: destroy registered for %s (%s)', instance.domain_slug, instance.external_ozwillo_id)
- return HttpResponse(status=200)
diff --git a/hobo/urls.py b/hobo/urls.py
index 6bb1df6..d61d60c 100644
--- a/hobo/urls.py
+++ b/hobo/urls.py
@@ -57,8 +57,3 @@ urlpatterns += [
url(r'^login/local/$', login_local), # to be used as backup, in case of idp down
url(r'^accounts/mellon/', include('mellon.urls')),
]
-
-if 'hobo.contrib.ozwillo' in settings.INSTALLED_APPS:
- urlpatterns += [
- url(r'ozwillo/', include('hobo.contrib.ozwillo.urls')),
- ]
diff --git a/tests/settings.py b/tests/settings.py
index c77a383..ef37567 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -2,9 +2,8 @@ import os
LANGUAGE_CODE = 'en-us'
BROKER_URL = 'memory://'
-OZWILLO_SECRET = 'secret'
-INSTALLED_APPS += ('hobo.contrib.ozwillo', 'hobo.agent.common')
+INSTALLED_APPS += ('hobo.agent.common', )
ALLOWED_HOSTS.append('localhost')