4078 lines
182 KiB
Markdown
4078 lines
182 KiB
Markdown
Brouillon de notes
|
||
Recherche documentaire sur les différents concepts en jeu pour l'approvisionnement et la synchronisation des référentiels (dans le cadre de l'authentification et de la gestion des identités)
|
||
|
||
Stage P.Marillonnet
|
||
|
||
Compilation :
|
||
|
||
`markdown doc.md > doc.html
|
||
|
||
# TODOs
|
||
* Rédiger au propre les parties suffisamment documentées.
|
||
* Scripts création markdown temporaire avec encodage html correct ?? (accents et caractères spéciaux)
|
||
* Pour chaque projet libre, présenter un court historique de la naissance du projet (quels besoins ? quels instigateurs ? quelle licence ? quelle année ? quel(s) prédecesseur(s) ?)
|
||
* Etudier préface du 'lasso book': concepts intéressants à expliquer + pdf lasso
|
||
* Placer au fur et a mesure le contenu dans le rapport (draft_report\d*.md)
|
||
* Tests avec tox, cf la structure des fichiers tox.ini
|
||
|
||
# Avant de commencer
|
||
|
||
## Acronymes
|
||
|
||
# Annuaires
|
||
//BOOKMARK
|
||
|
||
## SupAnn
|
||
|
||
## PABX ?
|
||
## NIS ?
|
||
## DNS/Whois ? (pas vraiment de la GI ?)
|
||
|
||
# Mécanismes d'authentification et implémentations
|
||
## SASL (RFC2222)
|
||
TODO Paul
|
||
## OpenID Connect
|
||
Utilisé pour la plateforme FranceConnect
|
||
Plus facile à mettre en place que des solutions basées SAML ?
|
||
|
||
# Identity Management
|
||
|
||
## Principes généraux
|
||
|
||
## Approvisionnement
|
||
|
||
## Implémentations
|
||
# SSO (et SLO)
|
||
|
||
# Synchronisation
|
||
|
||
# Fédération d'identités
|
||
## Présentation
|
||
Concept très propre à la France
|
||
Contraintes imposées par la Loi Informatique et Libertés (cf CNIL)
|
||
techno-agnostic côté SP
|
||
transparence pour l'utilisateur
|
||
utilisation de la page de login de l'organisme de l'utilisateur pour l'identification et l'authentification sur le site ayant mis en place la fédération d'identités
|
||
|
||
Interdiction d'un croisement implicite des données, sans en avertir l'utilisateur
|
||
|
||
Plus grande probabilité de véracité des informations utilisateur
|
||
Ces infos proviennent de sources sûres et à jour
|
||
|
||
TODO un SVG à faire ici, expliquant les mécanismes de la FI
|
||
|
||
TODO Relever les cas d'utilisation dans l'administration, les collectivités, et le monde de l'enseignement supérieur
|
||
## Standards
|
||
### Shibboleth
|
||
Appli Java
|
||
Dépendances :
|
||
Sprint
|
||
OpenSAML
|
||
Licence Apache
|
||
|
||
# Contrôle d'accès
|
||
|
||
## XACML
|
||
//TODIG
|
||
|
||
## ALFA
|
||
//TODIG
|
||
|
||
# Formulaires
|
||
|
||
# POC
|
||
## Presentation
|
||
Dans le cadre du projet Campus Condorcet, les annuaires de différents établissements doivent être regroupés en un méta-annuaire central. Aussi des problématiques d'homogénéisation de données hétérogènes se pose.
|
||
|
||
La phase de travail préparatoire à la réalisation du projet a consisté en le développement d'un POC (*Proof Of Concept*) permettant d'illustrer la procédure de constitution du méta-annuaire.
|
||
|
||
Le POC implémente un mécanisme simple d'ajout d'un compte invité ayant recours à un fournisseur de service, qui lui même repose sur un fournisseur d'identité SAML2 configuré pour assurer le SSO (*Single Sign-On*).
|
||
|
||
## Déroulement de l'ajout du compte invité dans l'application POC
|
||
|
||
Suivant un scenario classique de SSO, l'authentification depuis le fournisseur de service (SP) est déléguée à un fournisseur d'identité (IdP). Le fournisseur d'identité conclut la phase d'authentification par le renvoi d'une assertion SAML validant l'authentification.
|
||
|
||
De nombreuses informations présentes dans l'assertion SAML seront ensuites réutilisées par le fournisseur de service. Le contenu complet de l'assertion SAML est consultable en annexes de ce document, à titre indicatif. On remarquera la normalisation de la majorité des entrées (noeuds, attributs, corps) XML des messages SAML.
|
||
|
||
En particulier, les champs SAML permettant d'identifier l'utilisateur connecté sont récupérés de l'assertion. Ces champs permettent de déterminer si l'utilisateur n'est pas déjà renseigné dans le méta-annuaire OpenLDAP (annuaire d'aggrégation des référentiels d'identités des établissements partenaires du projet).
|
||
|
||
Si l'utilisateur ne se trouve pas dans le méta-annuaire, la procédure d'ajout du compte doit être effectuée. Un formulaire est alors proposé à l'utilisateur, il lui permet de valider ses données d'identités et de choisir une unité d'affectation.
|
||
|
||
La création et la gestion du formulaire sont prises en charge par l'outil w.c.s. Cet outil se base sur la notion de workflow, c'est-à-dire la cohabitation de procédures automatisées de traitement de l'information d'un part, et le recours à des actions manuelles de la part d'agents d'autre part.
|
||
|
||
Une fois le formulaire rempli par l'utilisateur, le workflow est configuré pour l'envoi automatique d'un email à un agent, pour la confirmation de création du compte.
|
||
|
||
Le plugin Passerelle permet la communication avec l'annuaire, permettant l'ajout de l'entrée LDAP correspondant au compte nouvellement créé.
|
||
|
||
L'appel au plugin Passerelle doit être effectué en tant que phase du workflow. La validation de la demande doit être rendue possible par la génération d'un lien envoyé par email à l'agent.
|
||
|
||
TODO modification du contenu du message, pour ajouter la possibilité d'envoyer les données directement dans l'annuaire.
|
||
FIXME quelle marge de manoeuvre sur la modification et l'ajout de données utilisateurs par l'agent ?
|
||
|
||
L'agent reçoit un email dont le contenu est :
|
||
```
|
||
Bonjour,
|
||
|
||
Un nouveau formulaire a =C3=A9t=C3=A9 compl=C3=A9t=C3=A9, vous pouvez le co=
|
||
nsulter
|
||
en suivant ce lien :
|
||
http://wcs.example.com/backoffice/management/traitement/16/
|
||
|
||
|
||
Pour r=C3=A9f=C3=A9rence, voici le d=C3=A9tail du formulaire :
|
||
|
||
Email=C2=A0:
|
||
toto@nowhere.null
|
||
|
||
Prenom=C2=A0:
|
||
toto
|
||
|
||
Nom=C2=A0:
|
||
t
|
||
|
||
NameID=C2=A0:
|
||
tt
|
||
|
||
Unite d'affectation=C2=A0:
|
||
hello
|
||
```
|
||
|
||
Par ailleurs, l'ajout d'un connecteur LDAP dans le plugin Passerelle permet de valider le formulaire et decréer l'entrée LDAP correspondante, par une requête GET sur l'URL:
|
||
http://<serveur w.c.s>/wcs/<numero id reponse formulaire>
|
||
|
||
La modification de l'email généré se fait à l'aide de la classe EmailsDirectory défini dans le code source de w.c.s. (cf wcs.git/wcs/forms.py)
|
||
|
||
Cette classe est chargée d'enregistrer des templates d'email envoyés en fonction de la configuration du workflow associé au formulaire.
|
||
|
||
Nous retrouvons le template de l'email ci-dessus dans le fichier formdefs, à la ligne 1276.
|
||
Le template est complété à l'aide de variables passées en paramètres. Elles sont pour l'instant au nombre de trois: name, url, details.
|
||
|
||
TODO Nous étudions maintenant la possibilité d'ajouter une quatrième variable correspondant à l'URL de validation exposée par l'API Passerelle.
|
||
|
||
|
||
```
|
||
./backoffice/management.py:33:from qommon.admin.emails import EmailsDirectory
|
||
./backoffice/management.py:72: mail_subject = EmailsDirectory.get_subject('tracking-code-reminder')
|
||
./backoffice/management.py:73: mail_body = EmailsDirectory.get_body('tracking-code-reminder')
|
||
```
|
||
|
||
Cf qommon/emails.py
|
||
qommon/admin/emails.py
|
||
|
||
L'envoi de l'email est effectué dans wcs.git/wcs/workflows.py
|
||
|
||
Une option rapide a mettre en place: rajouter dans le formulaire l'URL de validation de celui-ci (validation au sens de Passerelle, une URL localhost:8007/wcs/<id>
|
||
|
||
|
||
Problème non réentrance des vues du SP si inférence du numéro d'identifiant de la réponse au formulaire. Cette donnée ne devrait pas être manipulée avant création de l'entrée par WCS.
|
||
C'est un ID autoincrémenté, mais cela pose quand même problème.
|
||
|
||
./lib/python2.7/site-packages/quixote/publish.py:291:def get_publisher():
|
||
|
||
Localiser la fonction de génération et d'envoi de l'email
|
||
|
||
dans wcs/qommon/emails.py
|
||
|
||
L'email est modifiable dans l'onglet Paramètres de l'interface backoffice de w.c.s.
|
||
|
||
```
|
||
Bonjour,
|
||
|
||
Un nouveau formulaire a été complété, vous pouvez le consulter
|
||
en suivant ce lien :
|
||
[form_url_backoffice]
|
||
|
||
Si nécessaire, vous pouvez approuver la demande en cliquant sur le lien http://localhost:8007/ldap/test3/wcs/[form_number]/
|
||
|
||
[if-any details]
|
||
Pour référence, voici le détail du formulaire :
|
||
|
||
[details]
|
||
[end]
|
||
```
|
||
|
||
Pas de modif ?
|
||
|
||
Pistes d'identifications du bug:
|
||
- regeneration des fichiers de traduction .po ? non
|
||
- basculer GNOME en anglais pour forcer l'envoi du mail dans la locale adéquate ? non
|
||
- installation de wcs à l'aide du paquet Debian ? non
|
||
- modification en dur du template de l'email dans le code ? non
|
||
- prise en compte de modifs avec l'utilitaire wcsctl.py ? non
|
||
- rechargement de la config Apache ? non
|
||
- mauvaise conf SMTP ? voir exim4-light ? peu probable ... TODO
|
||
- template de l'email persistant, dans la base ? à voir, la commande wcsctl.py shell ne fonctionne pas pour l'instant TODO
|
||
- inspection pdb ? à voir TODO
|
||
- externalisation des templates d'email dans un repertoire extérieur au projet ? TODO
|
||
- exploration de la base, des migrations, pour comprendre la façon dont sont stockées les objets de template d'emails
|
||
|
||
|
||
Debugger : le template de l'email semble avoir été enrgistré:
|
||
```
|
||
(Pdb) EmailsDirectory.emails_dict
|
||
{'new_user': {'category': 'Workflow', 'default_body': 'Hello,\n\n[if-any user]\nThis mail is a reminder about the form you just submitted; you can consult it\nwith this link: [url]\n[else]\nThis mail is a reminder about the form you just submitted.\n[end]\n\n[if-any details]\nFor reference, here are the details:\n\n[details]\n[end]\n', 'description': 'Notification of creation to user', 'hint': None, 'enabled': False, 'default_subject': 'New form ([name])'}, 'change_user': {'category': 'Workflow', 'default_body': 'Hello,\n\n[if-any form_status_changed]\nStatus of the form you submitted just changed (from "[before]" to "[after]").\n[end]\n\n[if-any user]\nYou can consult it with this link:\n[url]\n[end]\n\n[if-any form_comment]New comment: [form_comment][end]\n\n[if-any evolution]\n[evolution]\n[end]\n', 'description': 'Notification of change to user', 'hint': 'Available variables: user, url, before, after, evolution', 'enabled': False, 'default_subject': 'Form status change'}, 'new_receiver': {'category': 'Workflow', 'default_body': 'Hello,\n\nA new form has been submitted, you can see it with this link:\n[form_url_backoffice]\n\nIf necessary, please validate the submission by visiting:\nhttp://localhost:8007/ldap/test3/wcs/[form_number]/\n\n[if-any details]\nFor reference, here are the details:\n\n[details]\n[end]\n', 'description': 'Notification of creation to receiver', 'hint': 'Available variables: name, url, details', 'enabled': False, 'default_subject': 'New form ([name])'}}
|
||
(Pdb)
|
||
```
|
||
|
||
Pas d'anomalie detectee au debugger Python pour l'instant
|
||
|
||
Stack trace:
|
||
```
|
||
(Pdb) w
|
||
/home/paul/devel/wcs/wcsctl.py(8)<module>()
|
||
-> ctl.run(sys.argv[1:])
|
||
/home/paul/devel/wcs/wcs/qommon/ctl.py(159)run()
|
||
-> return cmd.run(args, options)
|
||
/home/paul/devel/wcs/wcs/qommon/ctl.py(69)run()
|
||
-> return self.execute(base_options, sub_options, args)
|
||
/home/paul/devel/wcs/wcs/ctl/start.py(69)execute()
|
||
-> import publisher
|
||
/home/paul/devel/wcs/wcs/publisher.py(39)<module>()
|
||
-> from root import RootDirectory
|
||
/home/paul/devel/wcs/wcs/root.py(37)<module>()
|
||
-> import forms.root
|
||
/home/paul/devel/wcs/wcs/forms/root.py(49)<module>()
|
||
-> from wcs.formdef import FormDef
|
||
> /home/paul/devel/wcs/wcs/formdef.py(1299)<module>()
|
||
-> EmailsDirectory.register('change_receiver', N_('Notification of change to receiver'),
|
||
```
|
||
|
||
Pas d'anomalie non plus sur la pile; c'est bien les sources qui sont executees et non le paquet Debian annexe
|
||
|
||
Il faudrait maintenant inspecter la trace de la fonction chargee d'envoyer l'email, pour vérifier la façon dont le template est récupéré.
|
||
Comment mentionné précédemment, cette fonction est implementée dans le fichier wcs.git/wcs/common/emails.py
|
||
|
||
Pour l'instant, impossible de récuperer un shell dans ce fichier à l'aide de pdb.set_trace()
|
||
|
||
L'exécution de la commande
|
||
python setup.py install
|
||
ne résout pas non plus le problème.
|
||
|
||
Finalement, la modification du template est rendue possible par les icônes cliquables dans la section "Fabrique de workflow".
|
||
L'action à paramétrer ici est "Juste envoyé" -> "Envoyer un courriel à Destinataire"
|
||
Nous paramétrons l'email envoyé pour qu'il soit de la forme:
|
||
```
|
||
Bonjour,
|
||
|
||
Un nouveau formulaire a été complété, vous pouvez le consulter
|
||
en suivant ce lien :
|
||
[form_url_backoffice]
|
||
|
||
|
||
Si necessaire, veuillez valider la demande en visitant le lien :
|
||
http://localhost:8007/ldap/test3/wcs/[form_number]/
|
||
|
||
[if-any details]
|
||
Pour référence, voici le détail du formulaire :
|
||
|
||
[details]
|
||
[end]
|
||
```
|
||
//TODO template pas très pro
|
||
L'idéal serait de définir une variable *validation_url*, pour ne pas avoir à exposer l'URL de l'API de Passerelle directement dans le template de l'email.
|
||
Nous pouvons maintenant nous pencher sur le scénario du cas d'utilisation décrit dans le diagramme de séquence.
|
||
|
||
L'agent doit pouvoir compléter les données relatives à l'utilisateur, ce qui signifique que le formulaire doit contenir des champs non remplissables par un utilisateur non authentifié.
|
||
TODO Est-il alors nécessaire de comprendre comment est effectuée la gestion des droits dans wcs ?
|
||
|
||
Reduction du workflow à deux états, c'est suffisant pour ce que nous souhaitons faire.
|
||
|
||
Ajout de champs 'Bureau CC' et 'Téléphone CC' : infos inconnues de l'utilisateur inscrivant son compte invité.
|
||
|
||
Scenario d'utilisation relativement complet pas rapport au diagramme de séquence : passage à l'intégration Gadjo ?
|
||
|
||
TODO LIST pour l'instant
|
||
- Message d'explication et inclusion charte graphique pour le HTTP 403 associé au décorateur @user_not_in_ldap
|
||
- Gadjo dans w.c.s
|
||
- Paramétrage d'un client mail pour la récupération automatique des emails dans ~/Maildir ?
|
||
- Serveur SMTP envoyant des mails à une adresse effective, pas simplement dans ~/Maildir ?
|
||
- Traitement du champ EduPersonPrincipalName (EPPN) tel que défini intialement dans le schéma ?
|
||
- Compte-rendu POC avec captures d'ecran ?
|
||
|
||
2
|
||
bug collectstatic pas fonctionnel dans gadjo
|
||
Definition de STATIC_ROOT dans le fichier settings.py ?
|
||
|
||
|
||
Note de mise en place du POC
|
||
|
||
### Préparation déploiement:
|
||
7 briques majeures:
|
||
- SP
|
||
- IDP
|
||
- Gestion formulaires (WCS)
|
||
- Base de connecteurs (Passerelle)
|
||
- Serveur http (Apache)
|
||
- Annuaire OpenLDAP (slapd)
|
||
- serveur de mail (exim4)
|
||
|
||
Problème à gérer : pour l'instant pas de virtualenv commun aux 4 applications basées Django
|
||
|
||
#### SP
|
||
Importer le sous directory seulement ? Tout le virtualenv ? OUI
|
||
Pas de config https vers authentic, est-ce un problème ?
|
||
Homogénéisation des urls ?
|
||
|
||
Déploiement avec changement de l'URL
|
||
|
||
Pb: pas de fichier setup.py par défaut, il va falloir le créer
|
||
|
||
|
||
#### IDP
|
||
Créer un fichier de peuplement ?
|
||
Export des données en local ?
|
||
|
||
Pb: mauvaise connaissence du format d'archive 'egg' pour les modules pythons
|
||
L'utilitaire authentic2-ctl semble vouloir accéder à un dossier suffixé par l'extension 'egg', laquelle symbolise une format de compression...
|
||
TODO troubleshooting...
|
||
|
||
```
|
||
System check identified no issues (0 silenced).
|
||
Unhandled exception in thread started by <function wrapper at 0x7f038144d848>
|
||
Traceback (most recent call last):
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/utils/autoreload.py", line 229, in wrapper
|
||
fn(*args, **kwargs)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 116, in inner_run
|
||
self.check_migrations()
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 168, in check_migrations
|
||
executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 19, in __init__
|
||
self.loader = MigrationLoader(self.connection)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/db/migrations/loader.py", line 47, in __init__
|
||
self.build_graph()
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/db/migrations/loader.py", line 185, in build_graph
|
||
self.load_disk()
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/db/migrations/loader.py", line 93, in load_disk
|
||
for name in os.listdir(directory):
|
||
OSError: [Errno 20] Not a directory: '/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django_mellon-1.2.29-py2.7.egg/mellon/migrations'
|
||
```
|
||
|
||
Bugfix : suppression du fichier egg, réinstallation de django-mellon à l'aide du pip dans le virtualenv
|
||
|
||
Issue : plusieurs instances de projets différents déployés sur un même host
|
||
TODO Recherche sur la config WSGI dans Apache2
|
||
|
||
Lecture de la doc dans le dossier Debian des sources Authentic
|
||
-> Pas concluant
|
||
|
||
Essayer nginx et gunicorn ? option --config de authentic2-ctl
|
||
|
||
Problème de timeout sur gunicorn
|
||
|
||
Troubleshoot:
|
||
Causes possibles:
|
||
- Appli Django ? Peu problable : fonctionne en local...
|
||
- socket Gunicorn <-> nginx ? La conf a l'air relativement simple
|
||
- mauvaise configuration du serveur nginx ? Le timeout provient du worker gunicorn
|
||
- structuration des sources authentic différente d'un projet django standard :
|
||
* les applications sont situés dans src, et non pas directement à la racine du projet django
|
||
* il n'y a pas de fichier manage.py, mais un script shebang authentic2-ctl
|
||
- la configuration authentic pour gunicorn présume que authentic
|
||
- problème avec le virtualenv ? pourtant le fichier gunicorn.sh laisse pense que la mise en place
|
||
d'un environnement virtuel est prise en compte par gunicorn ,
|
||
- problème de génération et de collecte des fichiers statiques ?
|
||
- le module de gestion des scss est-il installée ?
|
||
- incompatibilité lors du transfert du virtlanev local vers la dev ?
|
||
|
||
Identification des causes:
|
||
* Fichier de log gunicorn ? Log en mode debug et pourtant rien de pertinent n'apparait...
|
||
* Fichiers de log nginx : laisse à penser que la confi nginx est correct: rien de suspect...
|
||
|
||
Update :
|
||
```
|
||
2017/03/08 16:37:12 [error] 14502#0: *19 upstream prematurely closed connection while reading response header from upstream, client: 192.168.44.1, server: condorcet.dev.entrouvert.org, request: "GET / HTTP/1.0", upstream: "fastcgi://127.0.0.1:8000", host: "condorcet.dev.entrouvert.org"
|
||
```
|
||
-> L'erreur semble bel et bien provenir de gunicorn, la connexion est stoppée.
|
||
Revenir a une config Apache et libabache2_mod_wsgi ? l'erreur se posera aussi, non ?
|
||
Apache2 est-il plus souple en terme de front pour une application Django de structure non usuelle (pas de fichier manage.py ?)
|
||
|
||
Le plus logique serait de lire la documentation gunicorn pour comprendre ce qui ne va pas
|
||
Il faut aussi comprendre laquelle des deux installations de gunicorn est la plus adaptée :
|
||
- avec pip dans le virtualenv ?
|
||
- avec apt-get dans l'environnement glogal du conteneur ?
|
||
|
||
Y a-t-il des différences dans la gestion des fichiers statiques par Apache et nginx ?
|
||
Comprendre l'interface Django <-> Apache par WSGI
|
||
peut-être plus simple à comprendre pour une seule appli, par rapport à nginx ?
|
||
|
||
Avec Apache2 et mod_wsgi : 403 forbidden:
|
||
- possibles ? pas de certificats ?
|
||
|
||
TODO : reactiver le mode de debugging ?
|
||
|
||
Problème de cohabitation Apache et nginx
|
||
|
||
Les VirtualHost Apache seuls ne semblent pas adaptables ?
|
||
|
||
Comment faire dans le cas où les projets sont installés à partir des paquets Debian ?
|
||
|
||
Déploiement manuel et configuration des VirtualHost pas évidente...
|
||
|
||
Les deux serveurs écoutent chacun sur des ports TCP différents :
|
||
```
|
||
Proto Recv-Q Send-Q Adresse locale Adresse distante Etat PID/Program name
|
||
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 2973/nginx -g daemo
|
||
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1545/apache2
|
||
```
|
||
|
||
Apache WCS OK :
|
||
```
|
||
wget condorcet.dev.entrouvert.org
|
||
--2017-03-10 15:17:14-- http://condorcet.dev.entrouvert.org/
|
||
Resolving condorcet.dev.entrouvert.org (condorcet.dev.entrouvert.org)... 188.165.196.219
|
||
Connecting to condorcet.dev.entrouvert.org (condorcet.dev.entrouvert.org)|188.165.196.219|:80... connected.
|
||
HTTP request sent, awaiting response... 200 OK
|
||
Length: 561 [text/html]
|
||
Saving to: ‘index.html’
|
||
|
||
index.html 100%[======================================================================================================================>] 561 --.-KB/s in 0s
|
||
|
||
2017-03-10 15:17:14 (101 MB/s) - ‘index.html’ saved [561/561]
|
||
```
|
||
|
||
nginx Authentix nettement moins OK :
|
||
```
|
||
wget condorcet.dev.entrouvert.org:8080
|
||
--2017-03-10 15:17:18-- http://condorcet.dev.entrouvert.org:8080/
|
||
Resolving condorcet.dev.entrouvert.org (condorcet.dev.entrouvert.org)... 188.165.196.219
|
||
Connecting to condorcet.dev.entrouvert.org (condorcet.dev.entrouvert.org)|188.165.196.219|:8080...
|
||
```
|
||
|
||
On essaie alors en local, sur la dev, de générer des logs :
|
||
```
|
||
root@condorcet:~# wget localhost:8080
|
||
--2017-03-10 15:24:11-- http://localhost:8080/
|
||
Résolution de localhost (localhost)… ::1, 127.0.0.1
|
||
Connexion à localhost (localhost)|::1|:8080… échec : Connexion refusée.
|
||
Connexion à localhost (localhost)|127.0.0.1|:8080… connecté.
|
||
requête HTTP transmise, en attente de la réponse… Aucune donnée reçue.
|
||
Nouvel essai.
|
||
|
||
--2017-03-10 15:24:12-- (essai : 2) http://localhost:8080/
|
||
Connexion à localhost (localhost)|127.0.0.1|:8080… connecté.
|
||
requête HTTP transmise, en attente de la réponse… Aucune donnée reçue.
|
||
Nouvel essai.
|
||
|
||
--2017-03-10 15:24:14-- (essai : 3) http://localhost:8080/
|
||
Connexion à localhost (localhost)|127.0.0.1|:8080… connecté.
|
||
requête HTTP transmise, en attente de la réponse… Aucune donnée reçue.
|
||
Nouvel essai.
|
||
|
||
--2017-03-10 15:24:17-- (essai : 4) http://localhost:8080/
|
||
Connexion à localhost (localhost)|127.0.0.1|:8080… connecté.
|
||
requête HTTP transmise, en attente de la réponse… Aucune donnée reçue.
|
||
Nouvel essai.
|
||
|
||
--2017-03-10 15:24:21-- (essai : 5) http://localhost:8080/
|
||
Connexion à localhost (localhost)|127.0.0.1|:8080… connecté.
|
||
requête HTTP transmise, en attente de la réponse… Aucune donnée reçue.
|
||
Nouvel essai.
|
||
```
|
||
|
||
Le serveur renvoie des HTTP 444 :
|
||
```
|
||
root@condorcet:/etc/nginx# cat /var/log/nginx/access.log
|
||
127.0.0.1 - - [10/Mar/2017:15:24:11 +0100] "GET / HTTP/1.1" 444 0 "-" "Wget/1.16 (linux-gnu)"
|
||
127.0.0.1 - - [10/Mar/2017:15:24:12 +0100] "GET / HTTP/1.1" 444 0 "-" "Wget/1.16 (linux-gnu)"
|
||
127.0.0.1 - - [10/Mar/2017:15:24:14 +0100] "GET / HTTP/1.1" 444 0 "-" "Wget/1.16 (linux-gnu)"
|
||
127.0.0.1 - - [10/Mar/2017:15:24:17 +0100] "GET / HTTP/1.1" 444 0 "-" "Wget/1.16 (linux-gnu)"
|
||
127.0.0.1 - - [10/Mar/2017:15:24:21 +0100] "GET / HTTP/1.1" 444 0 "-" "Wget/1.16 (linux-gnu)"
|
||
```
|
||
|
||
Ce qui correspond à la conf de
|
||
/etc/nginx/conf.d/return-444-if-no-host-header.conf
|
||
|
||
Pas de host header
|
||
wsgi cassé ?
|
||
|
||
```
|
||
root@condorcet:~# find / -name authentic2
|
||
/var/log/authentic2
|
||
/var/lib/authentic2
|
||
/var/lib/authentic2/collectstatic/authentic2
|
||
/var/cache/authentic2
|
||
/etc/cron.d/authentic2
|
||
/etc/logrotate.d/authentic2
|
||
/etc/nginx/sites-enabled/authentic2
|
||
/etc/nginx/sites-available/authentic2
|
||
/etc/authentic2
|
||
/etc/init.d/authentic2
|
||
/etc/cron.hourly/authentic2
|
||
/usr/share/authentic2
|
||
/usr/share/doc/authentic2
|
||
/usr/share/dbconfig-common/scripts/authentic2
|
||
/usr/lib/authentic2
|
||
/usr/lib/python2.7/dist-packages/authentic2
|
||
/usr/lib/python2.7/dist-packages/authentic2/manager/templates/authentic2
|
||
/usr/lib/python2.7/dist-packages/authentic2/manager/static/authentic2
|
||
/usr/lib/python2.7/dist-packages/authentic2/templates/authentic2
|
||
/usr/lib/python2.7/dist-packages/authentic2/static/authentic2
|
||
/usr/lib/python2.7/dist-packages/hobo/agent/authentic2
|
||
/run/authentic2
|
||
```
|
||
|
||
Authentic écoute bien en local sur le port 8000
|
||
`tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN 7654/python`
|
||
|
||
```
|
||
ps -aux | grep 7654
|
||
root 4239 0.0 0.0 12628 1076 pts/4 R+ 15:48 0:00 grep 7654
|
||
authent+ 7654 1.5 2.7 253900 56740 pts/2 Sl mars09 21:41 /usr/bin/python /usr/lib/authentic2/manage.py runserver
|
||
```
|
||
|
||
Le code de retour 444 ne semble pas symboliser une erreur côté serveur mais plutôt une incohérence dans la requête du client (champ Host de la requête HTTP laissé vide ?)
|
||
Pourtant le champ HOST est bien rempli dans a requête GET:
|
||
Host: "condorcet.dev.entrouvert.org:8080"
|
||
|
||
```
|
||
root@condorcet:~# wget condorcet.dev.entrouvert.org:8080
|
||
--2017-03-10 16:10:44-- http://condorcet.dev.entrouvert.org:8080/
|
||
Résolution de condorcet.dev.entrouvert.org (condorcet.dev.entrouvert.org)… 192.168.43.32
|
||
Connexion à condorcet.dev.entrouvert.org (condorcet.dev.entrouvert.org)|192.168.43.32|:8080… connecté.
|
||
requête HTTP transmise, en attente de la réponse… 502 Bad Gateway
|
||
2017-03-10 16:10:44 erreur 502 : Bad Gateway.
|
||
```
|
||
|
||
```
|
||
2017/03/10 16:10:44 [error] 4569#0: *2 upstream sent unsupported FastCGI protocol version: 60 while reading response header from upstream, client: 192.168.43.32, server: condorcet.dev.entrouvert.org, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:8000", host: "condorcet.dev.entrouvert.org:8080"
|
||
```
|
||
|
||
Après simplification de la conf:
|
||
```
|
||
># wget condorcet.dev.entrouvert.org:8080
|
||
--2017-03-10 16:15:53-- http://condorcet.dev.entrouvert.org:8080/
|
||
Résolution de condorcet.dev.entrouvert.org (condorcet.dev.entrouvert.org)… 192.168.43.32
|
||
Connexion à condorcet.dev.entrouvert.org (condorcet.dev.entrouvert.org)|192.168.43.32|:8080… connecté.
|
||
requête HTTP transmise, en attente de la réponse… 200 OK
|
||
Taille : non indiqué [text/html]
|
||
Sauvegarde en : « index.html »
|
||
|
||
index.html [ <=> ] 1,89K --.-KB/s ds 0s
|
||
|
||
2017-03-10 16:15:54 (166 MB/s) - « index.html » sauvegardé [1939]
|
||
```
|
||
|
||
Prochaine étape:
|
||
Distant
|
||
D'abord depuis mesclun ?
|
||
|
||
FIX : utilisation de sous domaines
|
||
séparateur '.' ne fonctionne pas, en revanche '-' fonctionne
|
||
(pydns)
|
||
|
||
utilisation de dig :
|
||
```
|
||
# dig condorcet.dev.entrouvert.org
|
||
|
||
; <<>> DiG 9.9.5-9+deb8u10-Debian <<>> condorcet.dev.entrouvert.org
|
||
;; global options: +cmd
|
||
;; Got answer:
|
||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12770
|
||
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
|
||
|
||
;; OPT PSEUDOSECTION:
|
||
; EDNS: version: 0, flags:; udp: 4096
|
||
;; QUESTION SECTION:
|
||
;condorcet.dev.entrouvert.org. IN A
|
||
|
||
;; ANSWER SECTION:
|
||
condorcet.dev.entrouvert.org. 60 IN A 188.165.196.219
|
||
|
||
;; AUTHORITY SECTION:
|
||
dev.entrouvert.org. 228 IN NS ns.dev.entrouvert.org.
|
||
|
||
;; ADDITIONAL SECTION:
|
||
ns.dev.entrouvert.org. 228 IN A 188.165.196.219
|
||
|
||
;; Query time: 6 msec
|
||
;; SERVER: 5.135.221.23#53(5.135.221.23)
|
||
;; WHEN: Fri Mar 10 16:40:26 CET 2017
|
||
;; MSG SIZE rcvd: 106
|
||
|
||
root@condorcet:/var/log/nginx# dig connexion-condorcet.dev.entrouvert.org
|
||
|
||
; <<>> DiG 9.9.5-9+deb8u10-Debian <<>> connexion-condorcet.dev.entrouvert.org
|
||
;; global options: +cmd
|
||
;; Got answer:
|
||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12958
|
||
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2
|
||
|
||
;; OPT PSEUDOSECTION:
|
||
; EDNS: version: 0, flags:; udp: 4096
|
||
;; QUESTION SECTION:
|
||
;connexion-condorcet.dev.entrouvert.org. IN A
|
||
|
||
;; ANSWER SECTION:
|
||
connexion-condorcet.dev.entrouvert.org. 60 IN A 188.165.196.219
|
||
|
||
;; AUTHORITY SECTION:
|
||
dev.entrouvert.org. 204 IN NS ns.dev.entrouvert.org.
|
||
|
||
;; ADDITIONAL SECTION:
|
||
ns.dev.entrouvert.org. 204 IN A 188.165.196.219
|
||
|
||
;; Query time: 8 msec
|
||
;; SERVER: 5.135.221.23#53(5.135.221.23)
|
||
;; WHEN: Fri Mar 10 16:40:50 CET 2017
|
||
;; MSG SIZE rcvd: 116
|
||
```
|
||
|
||
ip addr add dev venet0 192.168.43.33/32
|
||
|
||
Modification de /etc/hosts pour la prise en compte des deux IP:
|
||
```
|
||
192.168.43.32 condorcet.dev.entrouvert.org condorcet
|
||
192.168.43.33 idp-condorcet.dev.entrouvert.org condorcet
|
||
::1 localhost ip6-localhost ip6-loopback
|
||
```
|
||
|
||
Avec netstat on a alors :
|
||
```
|
||
Connexions Internet actives (seulement serveurs)
|
||
Proto Recv-Q Send-Q Adresse locale Adresse distante Etat PID/Program name
|
||
tcp 0 0 192.168.43.33:80 0.0.0.0:* LISTEN 6232/nginx -g daemo
|
||
tcp 0 0 192.168.43.32:80 0.0.0.0:* LISTEN 6075/apache2
|
||
```
|
||
|
||
TODO Puppet et repo git pour la conf ?
|
||
|
||
BLOCKER: installation authentic2 a partir du paquet debian non fonctionnelle, pas de logs
|
||
-> Désinstallation
|
||
WORKAROUND: faire tourner authentic à partir des sources, avec ./authentic2-ctk runfcgi
|
||
|
||
Pb de configuration ?
|
||
Revenir une énième fois à gunicorn ?
|
||
|
||
$ ./authentic2-ctl runfcgi method=threaded host=127.0.0.1 port=8080
|
||
Creation d'un thread
|
||
|
||
TODO quelles différences avec le mode prefork ?
|
||
|
||
Unhandled exception -> Quels logs ?
|
||
|
||
L'exception provient de flup:
|
||
```
|
||
2017/03/14 10:14:26 [error] 18062#0: *7 FastCGI sent in stderr: "Traceback (most recent call last):
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/flup/server/fcgi_base.py", line 558, in run
|
||
protocolStatus, appStatus = self.server.handler(self)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/flup/server/fcgi_base.py", line 1118, in handler
|
||
result = self.application(environ, start_response)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 189, in __call__
|
||
response = self.get_response(request)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 207, in get_response
|
||
return debug.technical_500_response(request, *sys.exc_info(), status_code=400)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/views/debug.py", line 97, in technical_500_response
|
||
html = reporter.get_traceback_html()
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/views/debug.py", line 384, in get_traceback_html
|
||
return t.render(c)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/template/base.py", line 210, in render
|
||
return self._render(context)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/template/base.py", line 202, in _render
|
||
return self.nodelist.render(context)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/template/base.py", line 905, in render
|
||
bit = self.render_node(node, context)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/template/debug.py", line 79, in render_node
|
||
return node.render(context)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/template/defaulttags.py", line 329, in render
|
||
return nodelist.render(context)
|
||
File "/home/pmarillonnet/devel/venv/local/lib/python2.7/site-packages/django/template/base.py", line 905,
|
||
|
||
```
|
||
|
||
=> Retour à gunicorn, voir si ça change quoi que ce soit
|
||
Ok gunicorn
|
||
il faut vieiller à réinstaller le package (/usr/lib/python2.7/dist-packages)
|
||
Installation Authentic fonctionnelle
|
||
|
||
|
||
#### WCS
|
||
Un simple export global devrait suffire
|
||
Pb : WCS configuré avec Apache pour l'instant
|
||
Ici seul nginx est utilisé !
|
||
Mais WCS necessaire en local seulement ? Oui, c'est passerelle qui doit être accessible depuis l'extérieur
|
||
WCS en backend seulement
|
||
|
||
pb: upload de la conf avec lynx
|
||
Ecouter sur le port 80 juste pour l'upload de la conf ?
|
||
Oui, une fois la config faite, on le rebascule, en local seulement, sur 8080
|
||
|
||
2 choix:
|
||
- serveur http embarqué dans wcs ?
|
||
-> Ce n'est pas la solution optimale
|
||
- config scgi DONE
|
||
|
||
Timeout sur l'interrogation de l'annuaire
|
||
TODO
|
||
Dummy git repo
|
||
C'est le décorateur qui timeout
|
||
|
||
|
||
#### Passerelle
|
||
Export du connecteur créé
|
||
|
||
Plus complexe que le l'IdP et le gestionnaire de formulaire
|
||
Cette fois-ci une installation à partir du paquet Debian paraît difficilement réalisable, pour la raison que les sources doivent être patchées afin de pouvoir incorporer le connecteur LDAP.
|
||
Mais le projet présente l'avantage d'un structuration plus 'canonique', ce qui facilite la recherche de documentation générique sur le déploiement des projets Django et de la conf WSGI.
|
||
|
||
On essaie alors de configurer un nouveau VirtualHost Apache avec l'une des adresse privées attribuées à l'interface virtuelle du conteneur
|
||
|
||
```
|
||
$ ip a s │
|
||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN │
|
||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 │
|
||
inet 127.0.0.1/8 scope host lo │
|
||
inet6 ::1/128 scope host │
|
||
valid_lft forever preferred_lft forever │
|
||
2: venet0: <BROADCAST,POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN │
|
||
link/void │
|
||
inet 127.0.0.2/32 scope host venet0 │
|
||
inet 192.168.43.32/32 brd 192.168.43.32 scope global venet0:0 │
|
||
inet 192.168.43.33/32 scope global venet0 │
|
||
inet 192.168.43.34/32 scope global venet0 │
|
||
inet 192.168.43.35/32 scope global venet0 │
|
||
```
|
||
|
||
Première étape : runserver local sur le port 8080
|
||
2e étape : Apache + mod_wsgi
|
||
3e etape (post déploiement) : réécriture plus propre du connecteur, en exploitant les fonctionnalités *endpoints* de Passerelle
|
||
|
||
1. Ok sans virtualenv (c'est ce qui est plus approprié pour une machine en dev)
|
||
2. Utilisation du mode daemon de wsgi pour l'exécution en parallèle de plusieurs backends Django sur un seul environnement python.
|
||
|
||
UPDATE: pas besoin d'exposer l'interface Web de Passerelle
|
||
utilisation backend seulement.
|
||
Conf ok, juste les URLs codées 'en dur' dans les sources, à modifier
|
||
|
||
BLOCKER: Connecteur LDAP plus reconnu par l'appli
|
||
Pourtant les migrations ont été appliquées
|
||
|
||
FIX?: suppression des restes de l'installation globale passerelle (/usr/lib/python2.7/dis-packages/passerelle) avec apt-get remove --purge passerelle python-passerelle
|
||
Non, toujours cette même erreur
|
||
Les sources ne sont-elles pas installées ailleurs ?
|
||
|
||
Pb de conflit avec le virtualenv initial
|
||
Reinstallation de l'appli
|
||
|
||
FIX: ne pas redefinir get_add_url dans le modèle du connecteur hérité de BaseResource, les underscores sont transformés en dashes...
|
||
c'est ldap-dir qui apparait dans les URLs, et non pas ldap_dir
|
||
|
||
|
||
#### Serveur HTTP
|
||
Config SSL/TLS pas utilisée
|
||
Revoir la config wcs, ie la façon dont l'application est repartie entre source, app_dir et data_dir
|
||
|
||
#### Annuaire OpenLDAP
|
||
Retrouver le fichier de peuplement de l'annuaire ? Pas nécessaire, juste besoin de recréer les noeuds intermédiaires de l'arborescence.
|
||
|
||
Installation slapd
|
||
TODO : retrouver les lignes de commande d'interrogation du LDAP
|
||
Fichier usual_ldap_commands
|
||
|
||
ldaputils pour le test en local...
|
||
|
||
Prise en compte du rebond ssh pour le transfert de fichier
|
||
ssh pour le lancement d'une commande sur la machine intermédiair
|
||
|
||
Creation d'un fichier de peuplement minimal
|
||
quelques groupes et une entrée bidon
|
||
|
||
```
|
||
# ldapadd -x -D "cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -w test -p 389 -h `hostname -f` -f /home/pmarillonnet/Documents/
|
||
misc/Example_shrunk.ldif
|
||
adding new entry "dc=org"
|
||
ldap_add: Server is unwilling to perform (53)
|
||
additional info: no global superior knowledge
|
||
|
||
|
||
```
|
||
Ajout OK, avec comme fichier ldif:
|
||
```
|
||
idn: ou=Servers,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
objectClass: organizationalUnit
|
||
objectClass: top
|
||
description: Company Servers
|
||
ou: Servers
|
||
|
||
dn: ou=Groups,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
objectClass: organizationalunit
|
||
objectClass: top
|
||
ou: Groups
|
||
|
||
dn: ou=Managers,ou=groups,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
objectClass: top
|
||
objectClass: organizationalunit
|
||
ou: groups
|
||
description: People who can manage accounting entries
|
||
ou: Managers
|
||
|
||
dn: ou=People,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
objectClass: organizationalunit
|
||
objectClass: top
|
||
ou: People
|
||
|
||
dn: uid=jmorrison,ou=People,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
objectClass: person
|
||
#objectClass: cos
|
||
objectClass: inetOrgPerson
|
||
objectClass: organizationalPerson
|
||
objectClass: posixAccount
|
||
objectClass: top
|
||
uid: jmorrison
|
||
#classOfService: gold
|
||
userpassword: chevron
|
||
facsimiletelephonenumber: +1 408 555 4661
|
||
givenname: Jim
|
||
cn: Jim Morrison
|
||
telephonenumber: +1 408 555 9445
|
||
sn: Morrison
|
||
roomnumber: 2290
|
||
homeDirectory: /home/jmorrison
|
||
mail: jmorrison@example.com
|
||
l: Pere Lachaise
|
||
ou: People
|
||
uidNumber: 1119
|
||
gidNumber: 1000
|
||
|
||
```
|
||
|
||
On suppose que le dn global a été créé lors de la (re)configuration dpkg
|
||
|
||
#### Exim4
|
||
dpkg reconfigure pour obtenir la config souhaitée
|
||
faire une config pour l'envoi de mails vers une adresse réelle ? Dans /home/<user>/Maildir pour l'instant
|
||
|
||
Pb exim4 : les ports ne sont pas ouverts
|
||
Deux solutions
|
||
Workaround en passant tout de même par leucas ?
|
||
Configuration d'un serveur SMTP en local ? Préférable ?
|
||
|
||
Les messages ICMP echo request vers l'extérieur ne passent même pas.
|
||
Ok pb config réseau résolu par redémarrage de la VM
|
||
Déploiement OK
|
||
|
||
### Procédure de déploiement
|
||
- Tarballs -> OK
|
||
- Fonctionnement en local -> En cours
|
||
|
||
### Améliorations envisagables
|
||
Gadjo sur le SP
|
||
Gadjo sur la page finale passerelle
|
||
Adaptation SupAnn 2009
|
||
|
||
### Adaptation au schéma SupAnn 2009
|
||
classes de l'entrée:
|
||
- organization (RFC2798)
|
||
- dcObject (RFC2247)
|
||
- eduOrg
|
||
- supannOrg
|
||
|
||
avec les attributs:
|
||
- o
|
||
- supannEtablissement
|
||
|
||
Nous nous intéresserons ici à l'un des trois branches seulement de cette entrée : ou=People
|
||
|
||
Nous gérons les comptes invités en tant que personne, indépendamment de l'approvisionnement des groupes (`ou=groups`) et des structures (`ou=structures`)
|
||
|
||
Les entrées de la branche des personnes se base sur trois classes : inetOrgPerson en tant que classe structurelle et eduPerson et supannPerson en tant que classes auxiliaires.
|
||
|
||
L'import d'un compte invité dans le méta-annuaire doit tenir compte de l'établissement : l'attribut supannCodeEntite de la personne renvoie au supannCodeEntite de l'établissement et l'attribut supannEtablissement de la personne référence le code UAI.
|
||
|
||
On peut alors établir les différents champs qui seront présents dans le formulaire d'inscription du compte invité :
|
||
- nom
|
||
- prenom
|
||
- adresse email
|
||
- établissement
|
||
- affiliation principale (facultatif)
|
||
- affectation principale (facultatif)
|
||
- corps d'appartenance
|
||
- liste rouge
|
||
|
||
//TODO faut-il collecter aussi les infos concernant la personne invitante ?
|
||
|
||
Les attributs transmis lors du SSO vont servir au préremplissage du formulaire final.
|
||
Attention, certains de ces attributs ne sont pas éditables.
|
||
Au total, il y a en 11 :
|
||
- eduPersonPrincipalName (non éditable)
|
||
- surname
|
||
- givenName
|
||
- mail
|
||
- supannEtablissemnt
|
||
- eduPersonPrimaryAffiliation
|
||
- eduPersonAffiliation
|
||
- supannEntiteAffectationPrincipale
|
||
- supannEntiteAffectation
|
||
- supanEmpCorps
|
||
- supannListeRouge
|
||
|
||
L'absence d'une information obligatoire stoppe la procédure de soumission du formulaire.
|
||
|
||
Il faut maintenant gérer la transmission des attributs depuis l'IdP source.
|
||
Changements à répercuter :
|
||
le SP avec tout le code django-mellon
|
||
WCS lors de la définition des formulaires
|
||
les utilitaires basés python-ldap3 lors de la création de la requête vers le meta-annuaire
|
||
|
||
Bien sur la transmission des attributs dans l'IdP, via l'assertion SAML envoyée, doit tenir compte de l'adoption du schéma SupAnn 2009.
|
||
|
||
TODO comprendre comment est mis en place l'annuaire supann du côté de l'IdP source
|
||
=> Lecture de la doc Authentic2 PSL
|
||
http://doc.entrouvert.org/supann/
|
||
|
||
TODO : serveur LDAP avec inclusion du schéma SupAnn 2009
|
||
outil web de gestion des entrées LDAP -> LdapSaisie
|
||
Un IdP SAML2
|
||
|
||
TODO quelles normes pour la fédération d'identités Renater ?
|
||
|
||
Ici méta-annuaire décrit comme l'utilisation de plusieurs branches au sein du même annuaire, synchronisées vers un annuaire distant.
|
||
|
||
Utilisation de NTP pour la synchro des horloges
|
||
|
||
LdapSaisie : de quel côté l'installer ? sur condorcet ou en local ?
|
||
pb : appli apache php, pas de doc pour nginx
|
||
|
||
Essayer une installation PHP FPM ?
|
||
|
||
On passe cette étape pour l'instant : la configuration et la gestion de l'annuaire SUPANN2009 se fera en ligne de commande, comme pour le LDAP générique.
|
||
|
||
Ici utilisation d'une machine unique, même si en pratique il faudrait installer chaque composant sur des machines séparées... Façon plus propre de déployer une application multi-bloc
|
||
|
||
Le LDAP est déjà fonctionnel, alors comment inclure proprement le schéma supann ?
|
||
Lecture de la doc : installation de authentic2-supann ?
|
||
|
||
Le repo git ne contient que des conf et un script
|
||
La conf nginx est-elle différente de l'install authentic2 classique ?
|
||
Modifier le settings.py de authentic pour la configuration du backend db ?
|
||
|
||
Comment faire remonter les attributs supann dans la politique de transmission SAML d'arguments, dans la GUI Web de authentic2 ?
|
||
TODO adapter le config.py situé dans le dépôt ?
|
||
|
||
Pour l'instant le poc n'est pas en https, il fonctionne sans certificats.
|
||
Faut-il les générer pour que fonctionne la configuration supann ?
|
||
|
||
Récupération du schéme SupAnn 2009 pour OpenLDAP sur le site RENATER.
|
||
Ce n'est pas l'objectif principal pour l'instant : la mise en place du schéma côté annuaire semble plutôt légère, mais c'est le support IdP qui pour l'instant semble poser problème.
|
||
|
||
Y a-t-il forcément besoin d'un backend LDAP pour l'IdP du POC ?
|
||
Cela pose problème : l'installation est locale seulement
|
||
Faire un LDAP avec deux branches ? l'une pour l'annuaire local de l'IdP (côté invité) et l'autre pour le méta-annuaire (côté CC) ?
|
||
|
||
Ce qui est faisable pour l'instant : l'installation d'un OpenLDAP SupAnn pour le méta annuaire
|
||
Ce qu'on pourrait faire par la suite :
|
||
- Cohabitation de deux slapd sur des ports différents ? Préférable
|
||
- Un seul slapd qui gère deux branches différentes : l'une côté client et l'autre côté CC ? Difficile et pas pertinent...
|
||
|
||
1ere étape : installation du schéma
|
||
Cette install se fait par placement d'un fichier ldif dans les répertoires de configuration de slapd.
|
||
Ok, génération d'un LDIF que l'on va passer à ldapadd
|
||
|
||
```
|
||
# slaptest -f ldap_includes.conf -F ldif_output/
|
||
58e24560 /etc/ldap/schema/collective.schema: line 28 attributeType: AttributeType not found: "l"
|
||
slaptest: bad configuration directory!
|
||
```
|
||
|
||
Pb réglé après modification de l'ordre de déclaration des différents schémas.
|
||
On peut alors, après modification de /cn=config/cn=schema/cn={8}misc.ldif telle que décrite dans
|
||
http://www.linuxquestions.org/questions/linux-server-73/how-to-add-a-new-schema-to-openldap-2-4-11-a-700452/
|
||
procéder à un ldapadd du ldif généré
|
||
|
||
```
|
||
ldapadd -x -D "cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -w test -p 389 -h condorcet.dev.entrouvert.org -f /home/pmarillonnet/Documents/misc/ldif_output/cn\=config/cn\=schema/cn\=\{8\}misc.ldif
|
||
```
|
||
|
||
renvoie une erreur 50 (insufficient access)
|
||
et pourtant
|
||
|
||
```
|
||
ldapsearch -D "cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -w test -p 389 -h condorcet.dev.entrouvert.org -b "ou=People,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -s sub "(ObjectClass=*)" * +
|
||
```
|
||
|
||
s'exécute correctement.
|
||
|
||
La conf d'accès à l'administration de l'annuaire ne semble pas se trouver dans son emplacement par défaut
|
||
```
|
||
# grep -nr pw ./
|
||
# grep -nr root ./
|
||
#
|
||
```
|
||
|
||
On peut essayer d'utiliser slapadd en local au lieu de l'utilitaire client ldapadd ?
|
||
|
||
Résolution par ajout d'un mot de passe pour la configuration de l'annuaire
|
||
```
|
||
# slappasswd -h {MD5}
|
||
New password:
|
||
Re-enter new password:
|
||
```
|
||
Ajout d'une ligne olcRootPW: {md5}...
|
||
dans /etc/ldap/slapd.d/cn\=config/olcDatabase\=\{0\}config.ldif
|
||
résout le problème :
|
||
```
|
||
$ ldapadd -x -D "cn=admin,cn=config" -w test -p 389 -h condorcet.dev.entrouvert.org -f /home/pmarillonnet/Documents/misc/ldif_output/cn\=config/cn\=schema/cn\=\{8\}misc.ldif
|
||
adding new entry "cn=misc,cn=schema,cn=config"
|
||
```
|
||
|
||
Pas certain cependant que l'adaptation supann ait été effectuée :
|
||
```
|
||
$ ldapsearch -D "cn=admin,cn=config" -w test -p 389 -h condorcet.dev.entrouvert.org -b "cn=config" -s sub "(ObjectClass=*)" * + | grep -i supann
|
||
```
|
||
ne renvoie rien
|
||
|
||
La commande ldapadd ci-dessus ne semble avoir ajouté qu'une seule entrée (misc)
|
||
|
||
Revenons au fichier LDIF, quelque chose doit manquer
|
||
Une seule entrée en effet, l'opération slaptest s'est mal déroulée
|
||
|
||
Plantage dans la procédure : lire une documentation un peu plus spécifique à SupAnn : il ne s'agirait pas simplement d'ajouter un schéma.
|
||
|
||
On part vers quelque chose d'un peu plus détaillé, par exemple
|
||
http://www.it-sudparis.eu/s2ia/user/procacci/ldap/Ldap_int018.html
|
||
|
||
TODO? eplucher le script perl
|
||
NO: il s'agit simplement d'un script de migration d'un annuaire générique au format supann
|
||
|
||
Maintenant: adaptation de la doc trouvée sur linuxquestions
|
||
le schema manipulé est supann_2009
|
||
on supprime le `{\d*}` comme indiqué dans la doc, ainsi que le dernier paragraphe
|
||
|
||
une erreur survient cependant encore:
|
||
l'entrée que l'on souhaite ajoutée n'est rattaché nulle part dans l'arborescence de l'annuaire
|
||
on change
|
||
cn=supann_2009 pour cn=supann_2009,cn=schema,cn=config
|
||
|
||
L'entrée est ajoutée
|
||
|
||
TODO devient-il alors possible de lui rattacher des entrées de type supannPerson
|
||
|
||
Il faut tout d'abord définir une branche supannPeople ?
|
||
Reprendre et adapter le example.ldif utilisé précédemment
|
||
|
||
Les spécifications issue du document d'analyse ('Analyse v0.4.odt') stipulent que les entrées de la branche doivent appartenir aux trois classes d'objets inetOrgPerson, eduPerson et supannPerson
|
||
|
||
TODO quelles implications de la distrinction entre classe structurelle et classes auxiliaires ?
|
||
|
||
erreur :
|
||
```
|
||
$ ldapadd -x -D "cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -w test -p 389 -h condorcet.dev.entrouvert.org -f ~/Documents/supann/Example_supann.ldif
|
||
adding new entry "ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org"
|
||
ldap_add: Already exists (68)
|
||
```
|
||
|
||
Ok, on a une erreur lors de l'ajout d'une supannPerson
|
||
Réessayons un ldapsearch pour vérifier que supannPeople a bien été ajouté:
|
||
```
|
||
pmarillonnet@condorcet:~$ ldapsearch -D "cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -w test -p 389 -h condorcet.dev.entrouvert.org -b "ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -s sub "(ObjectClass=*)" * +
|
||
# extended LDIF
|
||
#
|
||
# LDAPv3
|
||
# base <ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org> with scope subtree
|
||
# filter: (ObjectClass=*)
|
||
# requesting: debs devel Documents Maildir tmp tmp.txt var +
|
||
#
|
||
|
||
# supannPeople, condorcet.dev.entrouvert.org
|
||
dn: ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
structuralObjectClass: organizationalUnit
|
||
entryUUID: 5ff39d3e-acd4-1036-82c9-7797aedf4f5c
|
||
creatorsName: cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
createTimestamp: 20170403161436Z
|
||
entryCSN: 20170403161436.022060Z#000000#000#000000
|
||
modifiersName: cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
modifyTimestamp: 20170403161436Z
|
||
entryDN: ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
subschemaSubentry: cn=Subschema
|
||
hasSubordinates: FALSE
|
||
|
||
# search result
|
||
search: 2
|
||
result: 0 Success
|
||
|
||
# numResponses: 2
|
||
# numEntries: 1
|
||
|
||
```
|
||
|
||
maintenant : ajout d'une supannPerson
|
||
inetOrgPerson ne définit aucun attribut obligatoire
|
||
|
||
quid de eduPerson et supannPerson ?
|
||
le schema de eduPerson n'est disponible que sur des forums, pas de documentation officielle ?
|
||
|
||
les spéc de Internet2 ne contiennent pas de schéma...
|
||
|
||
https://www.internet2.edu/products-services/trust-identity/eduperson-eduorg/#service-overview
|
||
laisse à croire que l'accès au schéma est disponible sur inscription seulement
|
||
|
||
update: schéma trouvé sur spaces.internet2.edu
|
||
Le schéma est directement au format ldif compatible OpenLDAP
|
||
Il suffit de l'ajouter à l'aide de ldapadd, maintenant que le mot de passe d'administration de l'annuaire a été défini
|
||
|
||
```
|
||
pmarillonnet@condorcet:~/Documents/supann$ ldapadd -x -D "cn=admin,cn=config" -w test -p 389 -h condorcet.dev.entrouvert.org -f ./openLdapEduPerson-201602KH.ldif
|
||
adding new entry "cn=eduPerson,cn=schema,cn=config"
|
||
ldap_add: Undefined attribute type (17)
|
||
additional info: attributeType: attribute type undefined
|
||
```
|
||
|
||
TODO: identifier l'attribut dont le type est indéfini
|
||
commenter ligne par ligne le ldif ?
|
||
ldapmodified maintenant que l'entrée "cn=eduPerson,cn=schema,cn=config" a été ajoutée ?
|
||
|
||
Retrait de l'attribut eduPersonPrincipalNamePrior de la définition du schéma
|
||
|
||
On peut alors essayer d'ajouter une personne appartenant aux trois objectclasses inetOrgPerson, eduPerson, et supannPerson:
|
||
```
|
||
$ ldapadd -x -D "cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -w test -p 389 -h condorcet.dev.entrouvert.org -f ./Example_supann.ldif
|
||
adding new entry "uid=jmarrison,ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org"
|
||
```
|
||
Ok pour la branche People
|
||
|
||
Maintenant: modifier l'IdP pour que le SSO engendre le transfert d'attributs SupAnn dans l'assertion SAML envoyée
|
||
|
||
Lecture de la doc:
|
||
Tentative d'installer d'un authentic compatible SupAnn
|
||
retours à la doc EO pour le projet PSL
|
||
|
||
d'après la doc, l'Idp se connecte en sortie au LDAP ? existe-t-il directement un connecteur LDAP dans authentic ?
|
||
Pourquoi une telle connexion en sortie ?
|
||
L'IdP ne communiquera pas directement avec le méta-annuaire
|
||
django-mellon doit se charger d'aller récupérer les attributs nécessaires au méta-annuaire.
|
||
|
||
Piste envisageable
|
||
Installer dans une VM l'ISO Debian fourni dans la doc et installer l'IDP Authentic2 compatible SupAnn
|
||
=> Déduire, voire exporter partiellement la configuration IDP SupAnn
|
||
|
||
Installation de VirtualBox et mise en place d'une VM IdP SupAnn
|
||
On crée une nouvelle VM avec comme point de boot l'ISO télécharger sur la doc EO
|
||
|
||
Si cela ne fonctionne pas, configuration de l'OS en tant que *domain 0* Xen -> plus lourd que virtualbox
|
||
|
||
Ok pour virtualbox, après installation de la dernière version du noyau et des entêtes
|
||
On procède à l'installation IdP Authentic pour voir comment est géré le backend
|
||
|
||
Rien de concluant avec l'installation IdP
|
||
nouvel essai avec la base installation
|
||
|
||
Rien de concluant, les dépôts ne sont plus à jour, les dépendances sont cassées
|
||
|
||
Comment résoudre le problème ?
|
||
|
||
Pistes de recherches envisageables :
|
||
- IdP SAML SQLite (donc sans backend LDAP)
|
||
- IdP SAML avec backend LDAP SupAnn
|
||
|
||
On privilégie d'abord la première solution
|
||
sur l'IDP, on définit alors de nouveau attributs
|
||
|
||
Dans le cas d'un backend LDAP, les attributs utilisés auraient été directement déduits du schéma utilisé pour le stockage des utilisateurs
|
||
|
||
On crée pour ce faire une nouvelle politique d'options de fournisseur d'identité (SP options policy) prenant en compte les attributs nouvellement créés.
|
||
|
||
TODO
|
||
Création d'un nouvel utilisateur comportant les différents attributs SupAnn
|
||
Déploiement des deux autres branches (groupes et structures) de l'annuaire SupAnn, pour l'instant avec la seule branche People c'est un peu léger
|
||
|
||
répercussions du changement:
|
||
django-mellon côté SP
|
||
utils LDAP côté SP, à deux endroits (python-ldap et ldap3 ?)
|
||
utils LDAP côté passerelle
|
||
formulaire côté WCS
|
||
|
||
on va créer un nouvel utilisateur
|
||
|
||
Dans WCS, il faut aussi créer un nouveau formulaire qui tienne compte des attributs SupAnn
|
||
creation du formulaire traitement_supann
|
||
|
||
BLOCKER: HTTP500
|
||
après merge d'une version à jour des sources
|
||
est-ce l'installation globale dans /usr/lib qui a provoqué l'erreur
|
||
|
||
No module named authentic2.wsgi
|
||
avec les sources locales
|
||
|
||
TODO se renseigner sur l'équivalent du path en python
|
||
|
||
Bad Gateway car le service ne semble pas écouter sur la socket qui lui est attribuée.
|
||
Exploration des logs:
|
||
|
||
```
|
||
# ls
|
||
#
|
||
```
|
||
`$ sudo mv authentic2-2.1.20.1134.g1fda65c.dirty-py2.7.egg/ ../.old`
|
||
|
||
Procédure de rattrapage:
|
||
départ à partir d'un nouveau git clone de l'IDP authentic
|
||
création d'un branche locale pour la récupération des pulls ?
|
||
pb : pas d'update des autres outils jusque là
|
||
applications des changements nécessaires au déploiement ?
|
||
|
||
plusieurs solutions s'offrent à moi :
|
||
- garder une version ancienne de l'IDP authentic (circa 12 mars)
|
||
- mettre à jour tous les outils, au risque de casser le POC
|
||
- ne mettre à jour que authentic, sous risque de péter l'appli
|
||
|
||
`$ git diff 0de162732ac770 480c2374606 > deployment_changes.backup`
|
||
|
||
|
||
```
|
||
pmarillonnet@condorcet:~/devel/authentic$ bash run.sh
|
||
[2017-04-05 14:59:34 +0000] [4453] [INFO] Starting gunicorn 19.6.0
|
||
[2017-04-05 14:59:34 +0000] [4453] [INFO] Listening at: unix:/var/run/authentic2/authentic2.sock (4453)
|
||
[2017-04-05 14:59:34 +0000] [4453] [INFO] Using worker: sync
|
||
[2017-04-05 14:59:34 +0000] [4458] [INFO] Booting worker with pid: 4458
|
||
[2017-04-05 14:59:34 +0000] [4453] [INFO] Shutting down: Master
|
||
[2017-04-05 14:59:34 +0000] [4453] [INFO] Reason: Worker failed to boot.
|
||
```
|
||
|
||
Problème pour la réalisation des migrations :
|
||
./authentic2-ctl ne s'exécute plus correctement
|
||
|
||
```
|
||
pmarillonnet@condorcet:~/devel/authentic.bugged$ ./authentic2-ctl makemigrations
|
||
Traceback (most recent call last):
|
||
File "./authentic2-ctl", line 4, in <module>
|
||
import authentic2.logger
|
||
ImportError: No module named authentic2.logger
|
||
```
|
||
|
||
décalage dans la structure des sources :
|
||
authentic/src/authentic2
|
||
vs
|
||
authentic/authentic2 ?
|
||
|
||
L'IDP fonctionne avec le déploiement à l'aide de
|
||
sudo python setup.py install
|
||
|
||
Retour à la normale, mais persiste encore une erreur de fichiers statiques
|
||
IDP en noir sur fond blanc...
|
||
|
||
```
|
||
pmarillonnet@condorcet:~/devel/authentic.deployed/src$ gunicorn authentic2.wsgi --bind unix:/var/run/authentic2/authentic2.sock
|
||
[2017-04-05 16:00:20 +0000] [6075] [INFO] Starting gunicorn 19.6.0
|
||
[2017-04-05 16:00:20 +0000] [6075] [INFO] Listening at: unix:/var/run/authentic2/authentic2.sock (6075)
|
||
[2017-04-05 16:00:20 +0000] [6075] [INFO] Using worker: sync
|
||
[2017-04-05 16:00:20 +0000] [6080] [INFO] Booting worker with pid: 6080
|
||
[2017-04-05 Wed 16:00:22] - - - WARNING py.warnings.<module>: /home/pmarillonnet/devel/authentic.deployed/src/authentic2_idp_openid/utils.py:8: RemovedInDjango19Warning: django.utils.importlib will be removed in Django 1.9.
|
||
from django.utils.importlib import import_module
|
||
|
||
[2017-04-05 Wed 16:00:22] - 06ce3442 ERROR django.request.handle_uncaught_exception: Internal Server Error: /admin/
|
||
Traceback (most recent call last):
|
||
File "/usr/lib/python2.7/dist-packages/django/core/handlers/base.py", line 108, in get_response
|
||
response = middleware_method(request)
|
||
File "/usr/lib/python2.7/dist-packages/django/middleware/locale.py", line 32, in process_request
|
||
request, check_path=check_path)
|
||
File "/usr/lib/python2.7/dist-packages/django/utils/translation/__init__.py", line 198, in get_language_from_request
|
||
return _trans.get_language_from_request(request, check_path)
|
||
File "/usr/lib/python2.7/dist-packages/django/utils/translation/trans_real.py", line 503, in get_language_from_request
|
||
lang_code = request.session.get(LANGUAGE_SESSION_KEY)
|
||
File "/usr/lib/python2.7/dist-packages/django/contrib/sessions/backends/base.py", line 59, in get
|
||
return self._session.get(key, default)
|
||
File "/usr/lib/python2.7/dist-packages/django/contrib/sessions/backends/base.py", line 181, in _get_session
|
||
self._session_cache = self.load()
|
||
File "/usr/lib/python2.7/dist-packages/django/contrib/sessions/backends/db.py", line 21, in load
|
||
expire_date__gt=timezone.now()
|
||
File "/usr/lib/python2.7/dist-packages/django/db/models/manager.py", line 127, in manager_method
|
||
return getattr(self.get_queryset(), name)(*args, **kwargs)
|
||
File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 328, in get
|
||
num = len(clone)
|
||
File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 144, in __len__
|
||
self._fetch_all()
|
||
File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 965, in _fetch_all
|
||
self._result_cache = list(self.iterator())
|
||
File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 238, in iterator
|
||
results = compiler.execute_sql()
|
||
File "/usr/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 840, in execute_sql
|
||
cursor.execute(sql, params)
|
||
File "/usr/lib/python2.7/dist-packages/django/db/backends/utils.py", line 79, in execute
|
||
return super(CursorDebugWrapper, self).execute(sql, params)
|
||
File "/usr/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
|
||
return self.cursor.execute(sql, params)
|
||
File "/usr/lib/python2.7/dist-packages/django/db/utils.py", line 100, in __exit__
|
||
six.reraise(dj_exc_type, dj_exc_value, traceback)
|
||
File "/usr/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
|
||
return self.cursor.execute(sql, params)
|
||
File "/usr/lib/python2.7/dist-packages/django/db/backends/sqlite3/base.py", line 318, in execute
|
||
return Database.Cursor.execute(self, query, params)
|
||
OperationalError: no such table: django_session
|
||
```
|
||
|
||
Pour l'instant on se contentera de cette installation, sans les fichiers statiques...
|
||
|
||
De nouveau la même erreur apparaît:
|
||
```
|
||
AssertionError at /admin/custom_user/user/add/
|
||
|
||
No exception message supplied
|
||
|
||
Request Method: POST
|
||
Request URL: http://idp-condorcet.dev.entrouvert.org/admin/custom_user/user/add/
|
||
Django Version: 1.8.16
|
||
Exception Type: AssertionError
|
||
Exception Location: /usr/local/lib/python2.7/dist-packages/authentic2-2.1.20.1149.g00bf793-py2.7.egg/authentic2/models.py in set_value, line 205
|
||
Python Executable: /usr/bin/python
|
||
```
|
||
|
||
L'exécution de la commande
|
||
sudo python setup.py clean
|
||
révèle des incohérences de version
|
||
|
||
Cette commande ne recompilerait pas tous les bytecodes pyc après modification de la version d'une des dépendances du projet => découverte d'erreur après nettoyage des bytecodes de l'appli...
|
||
|
||
BLOCKER: mécanismes de migrations éclaté :
|
||
```
|
||
Running migrations:
|
||
Applying authentic2_idp_oidc.0004_auto_20170405_1659... OK
|
||
Traceback (most recent call last):
|
||
File "./authentic2-ctl", line 21, in <module>
|
||
execute_from_command_line(sys.argv[:1] + argv)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/core/management/__init__.py", line 385, in execute_from_command_line
|
||
utility.execute()
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/core/management/__init__.py", line 377, in execute
|
||
self.fetch_command(subcommand).run_from_argv(self.argv)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/core/management/base.py", line 288, in run_from_argv
|
||
self.execute(*args, **options.__dict__)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/core/management/base.py", line 338, in execute
|
||
output = self.handle(*args, **options)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/core/management/commands/migrate.py", line 165, in handle
|
||
emit_post_migrate_signal(created_models, self.verbosity, self.interactive, connection.alias)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/core/management/sql.py", line 268, in emit_post_migrate_signal
|
||
using=db)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/dispatch/dispatcher.py", line 198, in send
|
||
response = receiver(signal=self, sender=sender, **named)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/contrib/contenttypes/management.py", line 39, in update_contenttypes
|
||
for ct in ContentType.objects.using(using).filter(app_label=app_label)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/models/query.py", line 141, in __iter__
|
||
self._fetch_all()
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/models/query.py", line 966, in _fetch_all
|
||
self._result_cache = list(self.iterator())
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/models/query.py", line 265, in iterator
|
||
for row in compiler.results_iter():
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/models/sql/compiler.py", line 701, in results_iter
|
||
for rows in self.execute_sql(MULTI):
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/models/sql/compiler.py", line 787, in execute_sql
|
||
cursor.execute(sql, params)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/backends/utils.py", line 81, in execute
|
||
return super(CursorDebugWrapper, self).execute(sql, params)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/backends/utils.py", line 65, in execute
|
||
return self.cursor.execute(sql, params)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/utils.py", line 94, in __exit__
|
||
six.reraise(dj_exc_type, dj_exc_value, traceback)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/backends/utils.py", line 65, in execute
|
||
return self.cursor.execute(sql, params)
|
||
File "/usr/local/lib/python2.7/dist-packages/Django-1.8.16-py2.7.egg/django/db/backends/sqlite3/base.py", line 485, in execute
|
||
return Database.Cursor.execute(self, query, params)
|
||
django.db.utils.OperationalError: no such column: django_content_type.name
|
||
```
|
||
|
||
TODO:
|
||
résoudre le pb de migrations
|
||
patcher l'erreur sur le assert isinstance
|
||
|
||
pb réglé en installant la version 1.8 de Django plutôt qu'une sous-version précise (1.8.16 posait problème en l'occurrence)
|
||
|
||
Ok le patch sera pour plus tard
|
||
incohérence entre la définition d'un attribut multiple et le moyen de saisie pour cet attribut (possibilité d'ajouter des champs), et le rendu final doit être un tuple, pas une chaîne de caractères
|
||
|
||
retour sur le déploiement:
|
||
installation de l'IDP en mode de développement ? setup.py --dev
|
||
|
||
BLOCKER:ValueError: No JSON object could be decoded
|
||
|
||
erreur provoquée avec l'utilisateur admin
|
||
FIX: création d'un nouvel utilisateur privilégié
|
||
sudo ./authentic2-ctl createsuperuser
|
||
|
||
agent
|
||
|
||
Les attributs SupAnn ne sont pas transmis lors du SSO
|
||
|
||
```
|
||
(Pdb) p dir(UserSAMLIdentifier.objects.last().user)
|
||
['DoesNotExist', 'Meta', 'MultipleObjectsReturned', 'REQUIRED_FIELDS', 'USERNAME_FIELD', '__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', u'__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__', '__weakref__', '_base_manager', '_check_column_name_clashes', '_check_field_name_clashes', '_check_fields', '_check_id_field', '_check_index_together', '_check_local_fields', '_check_long_column_names', '_check_m2m_through_same_relationship', '_check_managers', '_check_model', '_check_ordering', '_check_swappable', '_check_unique_together', '_default_manager', '_deferred', '_do_insert', '_do_update', '_get_FIELD_display', '_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', '_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_save_parents', '_save_table', '_set_pk_val', '_state', 'check', 'check_password', 'clean', 'clean_fields', 'date_error_message', 'date_joined', 'delete', 'email', 'email_user', 'first_name', 'from_db', 'full_clean', 'get_all_permissions', 'get_deferred_fields', 'get_full_name', 'get_group_permissions', 'get_next_by_date_joined', 'get_previous_by_date_joined', 'get_session_auth_hash', 'get_short_name', 'get_username', 'groups', 'has_module_perms', 'has_perm', 'has_perms', 'has_usable_password', 'id', 'is_active', 'is_anonymous', 'is_authenticated', 'is_staff', 'is_superuser', 'last_login', 'last_name', 'logentry_set', 'natural_key', 'objects', 'password', 'pk', 'prepare_database_save', 'refresh_from_db', 'saml_identifiers', 'save', 'save_base', 'serializable_value', 'set_password', 'set_unusable_password', 'unique_error_message', 'user_permissions', 'username', 'validate_unique']
|
||
```
|
||
|
||
Pdb côté mellon
|
||
login.assertion.exportToXml()
|
||
|
||
FieldDoesNotExist at /accounts/mellon/login/
|
||
User has no field named 's_entite_affectation_principale'
|
||
/usr/lib/python2.7/dist-packages/django/db/models/options.py in get_field, line 554
|
||
|
||
Incohérence dans le modèles de données de django_mellon
|
||
le modèle semble cassé :
|
||
```
|
||
tpl '{attributes[s_entite_affectation_principale][0]}'
|
||
|
||
old_value u''
|
||
|
||
model_field <django.db.models.fields.CharField: last_name>
|
||
```
|
||
Pourquoi last_name dans le model_field ?
|
||
Pourtant les migrations du modèle ont été effectuées
|
||
|
||
Pistes de résolutions:
|
||
- débogger le backend mellon ?
|
||
- comprendre le déroulement de la fonction authenticate, pourquoi a-t-elle encore besoin d'aller taper dans le backend mellon
|
||
- en parler avec Benj et Mik !
|
||
- rollback vers un état stable ?
|
||
|
||
|
||
TODO: contourner le filtrage de port ssh chez moi !
|
||
|
||
Retour sur le bug de non transmission des attributs lors du SSO
|
||
En réalité les attributs sont transmis, mais ne peuvent être stockés côté SP par mellon, qui semblent bloqué sur une incohérence du modèle User
|
||
Quelle solution autre que le debugging ?
|
||
|
||
=> Etudier le customizing#extending the user model
|
||
Sur conseil de Josué :
|
||
mellon semble se contenter d'un modèle utilisateur par défaut, qui ne supporte pas l'ajout d'attributs tels que les attributs SupAnn que nous essayons de stocker côté SP
|
||
|
||
|
||
/usr/lib/python2.7/dist-packages/mellon/views.py in authenticate :
|
||
|
||
def authenticate(self, request, login, attributes):
|
||
user = auth.authenticate(saml_attributes=attributes)
|
||
|
||
Bingo :
|
||
class UserSAMLIdentifier(models.Model):
|
||
user = models.ForeignKey(
|
||
verbose_name=_('user'),
|
||
to=settings.AUTH_USER_MODEL,
|
||
related_name='saml_identifiers')
|
||
|
||
|
||
$ python manage.py makemigrations
|
||
SystemCheckError: System check identified some issues:
|
||
|
||
ERRORS:
|
||
saml.SupAnnUser.user_ptr: (fields.E301) Field defines a relation with the model 'auth.User', which has been swapped out.
|
||
HINT: Update the relation to point at 'settings.AUTH_USER_MODEL'.
|
||
|
||
Retour à l'écriture d'un modèle copié sur auth.User ?
|
||
|
||
le UserSAMLIdentifier possède une clé étrangère vers le modèle défini par `AUTH_USER_MODEL`
|
||
|
||
TODO: quelles possibilités d'héritage de ce AUTH_USER_MODEL par défaut (càd django.contrib.auth.models.User) ?
|
||
|
||
Point avec Mik:
|
||
|
||
- Le lien au modèle utilisateur de django-mellon doit se faire par mise en place d'une relation one-to-one
|
||
- S'inspirer du code d'authentic pour la récupération des attributs
|
||
|
||
De façon plus générale, pour l'instant : mauvaise connaissance du besoin cerné par django-mellon de mon côté, il faudrait d'abord que je parvienne à cerner le besoin couvert par mellon.
|
||
|
||
Résolution par relation one-to-one après un petit problème de migrations:
|
||
http://stackoverflow.com/questions/32991965/you-are-trying-to-add-a-non-nullable-field-id-to-contact-info-without-a-defaul
|
||
|
||
ok problème ici:
|
||
pistes:
|
||
Comment sont récupérés les attributs SAML ?
|
||
Lire de code de django-mellon
|
||
+
|
||
Lecture du code d'authentic pour comprendre la transmission des attributs
|
||
|
||
|
||
=> Où ça dans authentic ?
|
||
Attribute aggregator
|
||
|
||
`app_settings.A2_ATTRIBUTE_KINDS` ?
|
||
|
||
|
||
No such column: saml_supannuser.id
|
||
|
||
L'erreur se trouve dans le mapping d'attributs:
|
||
Il se s'agit pas d'un mapping IDP-SP mais plutôt d'un mapping
|
||
mellon.User<->SP.User
|
||
|
||
MELLON_ATTRIBUTE_MAPPING = {
|
||
'first_name': '{attributes[fname_test][0]}',
|
||
'last_name': '{attributes[lname_test][0]}',
|
||
'email' : '{attributes[email_test][0]}',
|
||
'password' : '{attributes[password_test][0]}',
|
||
'ep_principal_name' : '{attributes[ep_principal_name][0]}',
|
||
's_etablissement' : '{attributes[s_etablissement][0]}',
|
||
'ep_primary_affiliation' : '{attributes[ep_primary_affiliation][0]}',
|
||
'ep_affiliation' : '{attributes[ep_affiliation][0]}',
|
||
's_entite_affectation_principale' : '{attributes[s_entite_affectation_principale][0]}',
|
||
's_entite_affectation' : '{attributes[s_entite_affectation][0]}',
|
||
's_emp_corps' : '{attributes[s_emp_corps][0]}',
|
||
's_liste_rouge' : '{attributes[s_liste_rouge][0]}',
|
||
}
|
||
|
||
côté IDP:
|
||
src/authentic2/saml/management/commands/mapping.py
|
||
|
||
```
|
||
#Extracted from version 389 Directory Server du schema
|
||
#SupAnn version 2009.6
|
||
#http://www.cru.fr/_media/documentation/supann/supann_2009.schema.txt
|
||
"supannListeRouge": {
|
||
"oid": "1.3.6.1.4.1.7135.1.2.1.1",
|
||
"display_name": "supannListeRouge",
|
||
"type": "http://www.w3.org/2001/XMLSchema#string",
|
||
"syntax": "1.3.6.1.4.1.1466.115.121.1.7",
|
||
},
|
||
```
|
||
|
||
`
|
||
ERRORS:
|
||
saml.SupAnnUser.user: (fields.E301) Field defines a relation with the model 'auth.User', which has been swapped out.
|
||
HINT: Update the relation to point at 'settings.AUTH_USER_MODEL'.
|
||
`
|
||
|
||
Ajout effectué:
|
||
```
|
||
L'utilisateur a bien ete ajoute a l'annuaire :
|
||
{ "criticality_level": 0, "display_id": "3-8", "display_name": "traitement_supann #3-8", "evolution": [ { "status": "just_submitted", "time": "2017-04-10T15:58:49Z" }, { "time": "2017-04-10T16:00:15Z", "who": { "email": "pmarillonnet@condorcet", "id": "3", "name": "agent" } }, { "status": "finished", "time": "2017-04-10T16:00:20Z" } ], "fields": { "bureau": "foo", "email": "pmarillonnet@entrouvert.com", "ep_affiliation": "u", "ep_primary_affiliation": "student", "ep_principal_name": "pmarillo", "nameid": "pmarilloaa", "nom": "marilloaa", "prenom": "paul", "s_emp_corps": "student", "s_entite_affectation": "u", "s_entite_affectation_principale": "student", "s_etablissement": "studentaaa", "s_liste_rouge": "True", "telephone": "foo", "unit": "foo" }, "id": "traitement_supann/8", "last_update_time": "2017-04-10T16:00:20Z", "receipt_time": "2017-04-10T15:58:49Z", "roles": { "_receiver": [ { "allows_backoffice_access": true, "details": "Recoit les demandes de creation d'un compte invite", "emails": [], "emails_to_members": true, "id": "2", "name": "Destinataire", "slug": "destinataire", "text": "Destinataire" } ], "actions": [], "concerned": [ { "allows_backoffice_access": true, "details": "Recoit les demandes de creation d'un compte invite", "emails": [], "emails_to_members": true, "id": "2", "name": "Destinataire", "slug": "destinataire", "text": "Destinataire" } ] }, "submission": { "backoffice": false, "channel": "web" }, "url": "http://forms-condorcet.dev.entrouvert.org/traitement_supann/8/", "workflow": { "status": { "id": "finished", "name": "Termin\u00e9" } } }
|
||
```
|
||
|
||
On peut alors vérifier à l'aide des ldad utils que l'utilisateur se trouve bien dans l'annuaire SupAnn
|
||
```
|
||
# pmarilloaa, supannPeople, condorcet.dev.entrouvert.org
|
||
dn: uid=pmarilloaa,ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
structuralObjectClass: inetOrgPerson
|
||
entryUUID: d035df7a-b252-1036-8bf7-2f7e2fa64143
|
||
creatorsName: cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
createTimestamp: 20170410160216Z
|
||
entryCSN: 20170410160216.762889Z#000000#000#000000
|
||
modifiersName: cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
modifyTimestamp: 20170410160216Z
|
||
entryDN: uid=pmarilloaa,ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=o
|
||
rg
|
||
subschemaSubentry: cn=Subschema
|
||
hasSubordinates: FALSE
|
||
```
|
||
|
||
TODO: ajout des attributs SupAnn et EduPerson dans la branche de l'annuaire
|
||
|
||
cote connecteur :
|
||
```
|
||
(Pdb) id
|
||
{u'nom': u'marilloaa', u'prenom': u'paul', u's_etablissement': u'studentaaa', u'telephone': u'foo', u's_entite_affectation_principale': u'student', u's_entite_affectation': u'u', u'email': u'pmarillonnet@entrouvert.com', u'unit': u'foo', u'bureau': u'foo', u's_emp_corps': u'student', u'ep_principal_name': u'pmarillo', u'nameid': u'pmarilloaa', u's_liste_rouge': u'True', u'ep_affiliation': u'u', u'ep_primary_affiliation': u'student'}
|
||
```
|
||
|
||
|
||
problème ici : les classes supannPerson et eduPerson ne sont pas ajoutées
|
||
dn: uid=foo,ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
structuralObjectClass: inetOrgPerson
|
||
|
||
|
||
TODO:
|
||
faut-il définir une branche parente eduOrg et 'supannOrg' pour l'ajout d'une entrée comportant les deux classes eduPerson et supannPerson ?
|
||
plusieurs solutions :
|
||
utilisation de ApacheDirectoryServer pour une visualisation plus claire de la structure
|
||
recherche de l'info dans les specs supann ? pas trouvée...
|
||
|
||
ces deux classes ne sont peut-être pas à déclarer de la même façon dans le dictionnaire manipulé par ldap3
|
||
|
||
ldap3 propose-t-il la même interface pour la déclaration d'une classe structurelle et de classes auxiliaires
|
||
|
||
OK bug identifié : eduPerson et supanPerson définie en tant que classes structurelles dans chacun des deux schémas associés
|
||
|
||
Modifier le schéma sans vider l'annuaire ?
|
||
essayer d'abord avec une seule classe parmi les deux ?
|
||
|
||
etapes:
|
||
vider la branche supannPeople (ldapdelete)
|
||
tenter l'ajout d'une première entrée sans eduPerson
|
||
|
||
ldapdelete -D "cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -w test -p 389 -h condorcet.dev.entrouvert.org "uid=jmarrison,ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org"
|
||
|
||
Lecture de la RFC 4512 pour comprendre les différences entre classes structurelles et classes auxiliaires.
|
||
|
||
Il s'agirait d'une question de *DIT content rule* pas précisée pour la classe structurelle de l'entrée ?
|
||
|
||
Allons voir le schéma de inetOrgPerson:
|
||
```
|
||
/etc/ldap/schemas/inetOrgPerson.schema
|
||
|
||
objectclass ( 2.16.840.1.113730.3.2.2
|
||
NAME 'inetOrgPerson'
|
||
DESC 'RFC2798: Internet Organizational Person'
|
||
SUP organizationalPerson
|
||
STRUCTURAL
|
||
MAY (
|
||
audio $ businessCategory $ carLicense $ departmentNumber $
|
||
displayName $ employeeNumber $ employeeType $ givenName $
|
||
homePhone $ homePostalAddress $ initials $ jpegPhoto $
|
||
labeledURI $ mail $ manager $ mobile $ o $ pager $
|
||
photo $ roomNumber $ secretary $ uid $ userCertificate $
|
||
x500uniqueIdentifier $ preferredLanguage $
|
||
userSMIMECertificate $ userPKCS12 )
|
||
)
|
||
```
|
||
alors que supanPerson
|
||
```
|
||
UP top AUXILIARY
|
||
```
|
||
|
||
Ok l'ajout a bien été pris en compte, pour le vérifier il suffit de modifier légèrement la requête, afin d'afficher le contenu de l'entrée et non ses méta-données:
|
||
```
|
||
ldapsearch -D "cn=admin,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -w test -p 389 -h condorcet.dev.entrouvert.org -b "ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org" -s sub "(ObjectClass=*)"
|
||
```
|
||
|
||
Les classes auxiliaires sont bien ajoutées, il suffit alors de rajouter dans le code du connecteur les différents attributs définis dans l'analyse, relevant à la fois des classes supannPerson et eduPerson.
|
||
On ajoute une structure conditionnelle dans le code, pour gérer le champ booléen SupannListeRouge.
|
||
Les attributs de type BooleanMatch dans OpenLDAP prennent les valeurs 'TRUE' ou 'False', tandis que le fichier JSON renvoyé par WCS contient un champ prenant les valeurs True ou False.
|
||
|
||
On remarquera aussi que le champ 'surname' n'est pas supporté par aucune des trois classes auxquelles appartiennent les entrées de l'annuaire supannn.
|
||
On lui préférera donc l'attribut 'sn'.
|
||
|
||
TODO:
|
||
- nettoyage du code DONE
|
||
- fix collectstatic? Plus tard, pas envie de casser le POC pour ça
|
||
- export de la config dans settings ? pas urgent en l'état
|
||
- ecriture des tests ? quels scénarios de tests ?
|
||
- réentrance des fonctions: abandonner le recours multiple à plusieurs lectures de UserSAMLIdentifier
|
||
- gestion du SLO inité par l'IDP ? OUI
|
||
- résolution des erreurs 404 sur les fichiers statiques
|
||
- incorporation d'autres branches supann ?
|
||
- génération d'un certicat, ajouté au navigateur, pour l'établissement d'une connexion https ?
|
||
|
||
SLO initié par l'IDP : pas supporté pour l'instant dans le POC. A-t-on intérêt à le mettre en place ?
|
||
|
||
SLO initié par le SP : comportement anormal, renvoie vers la vue unit alors qu'il faudrait renvoyer vers une nouvelle mire de login
|
||
|
||
Autre comportement anormal : la vue unit est accessible sans authentification => Mettre un décorateur
|
||
=> Mise en place du SLO
|
||
|
||
Page 32/69 de la doc pdf de authentic:
|
||
|
||
Deux façons :SOAP ou Redirect
|
||
Redirect plus rapide à mettre en place, juste une query string à rajouter dans l'url de logout coté sp ?
|
||
|
||
Jetons un oeil aux métadonnées du SP dans l'interface d'admin de l'IDP:
|
||
```
|
||
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://sp-condorcet.dev.entrouvert.org/accounts/mellon/logout/"/>
|
||
```
|
||
|
||
Il reste à aller chercher dans mellon le code de la vue logout
|
||
lecture du fichier views de mellon
|
||
interrogations:
|
||
thin-session de lasso ?
|
||
|
||
```
|
||
(Pdb) request.GET
|
||
<QueryDict: {u'SigAlg': [u'http://www.w3.org/2000/09/xmldsig#rsa-sha1'], u'SAMLResponse': [u'hZJbi8IwEIX/Ssm7ja2ttaEKtRcQ3Jd18WFfJLRBCzVTMlPZn7+xdRcV1n2cy3fmcJIE5bntxBaO0NO7wg40Kufr3GoUw2jJeqMFSGxQaHlWKKgSu/RtK3x3KjoDBBW07A55TUhEZagBzZxNvmSHWRykfriYB1GxKNMyywI/ywMvSONwsUi90K7pH18fYIGgyNIon2dRVHrrfO6VXlCEZewX61no5TML7JVBe2DJ7D2LI/Zqo5GkJtuaetFkGkw8/2MaizASs/iTOblCarSkgToRdYJz7CYV6BpMpcit1cVVmgz0F+veBXPksqqg14T8rNoWNG+HCDlbJdcQxHDWrG5iTf2Pml3gV863ciRrSTLh9zrJ+E47ktTjY5VBrZy9bHv1OnkctsUYZq0M+1vm5lr2dLI+m+rZ7Sh1qCzCN5qU0bLdKWPnhTFgGF+N7u+1n1q/5ePXW30D'], u'Signature': [u'GOOcRJxIwkJQV5l4hJvRtcI/TU5uNwPGNEDsyBL5IJzhKSRiqq7vwvUSerpcCFObjmrTwXlzroFu7z2chfPmoVPb55Y+h/sXlmC7ewpWqtw+kWdUW9xln51jJkW5FgnEmEirKrnXYVhFIsb8xnTJNEkCFfAbi3RP8rSNrzzO1XXmdHFfg819M7/NZWi2kudhok9LCaFt6Scj+7zJJzwkmayf6FZkHb4EqWdBQJLRXfVOhidClESZoSRyzVDzGWqpFMNkqkzSvJ+a1026CzCa/UTFxySf3lCKfELHdrTuKQg+gJi5Ki5oK5Mis2URJA+R0fHVvNA/qbZZATbGwQyLDA==']}>
|
||
```
|
||
La procédure de logout se fait en deux fois:
|
||
récupérer le contexte pour chacun des deux appels à mellon, et déterminer si le comportement est anormal ou non
|
||
|
||
base64.b64decode ne permet pas de décoder le contenu de l'attribut GET['SAMLResponse']
|
||
|
||
mellon logout => lire la doc de mellon concernant ce paramètre (renseigné dans le SP)
|
||
|
||
Ecriture de tests:
|
||
erreur pour l'instant
|
||
|
||
ValueError: Related model 'saml.SupAnnUser' cannot be resolved
|
||
Résolu par migration
|
||
|
||
TODO:
|
||
ajout dans l'annuaire depuis passerelle seulement après authentification
|
||
|
||
### Remarques concernant les tests
|
||
La base de données ne semble pas initialisée
|
||
tox utilise pgsql par défaut ?
|
||
Le déploiement Campus Cordorcet est en sqlite3
|
||
|
||
|
||
différentes solutions pour l'affichage d'un formulaire vide :
|
||
simple flag :pas élégant
|
||
aller remplir UserSAMLIdentifier avec un compte vide, pas très classe, de toute façon il y a une foreign Key
|
||
passage de nom de méthode : overkill ?
|
||
on va commencer avec un flag ?
|
||
Oui pour l'instant
|
||
Revoir le passage d'argument de {% url %} vers une vue
|
||
|
||
Plus simplement, création d'une nouvelle vue en charge de l'afficahe d'un formulaire vide....
|
||
|
||
TODO : nettoyage des UserSAMLIdentifier en base, côté django_mellon
|
||
TODO : refonte du formulaire, selon les attributs désignés dans les spec
|
||
|
||
-> Les champs du formulaire
|
||
Le formulaire présente les champs suivants.
|
||
Invité
|
||
Nom (obligatoire)
|
||
Prénom (obligatoire)
|
||
Adresse de messagerie (obligatoire)
|
||
Établissement d'origine
|
||
Affiliation principale (liste déroulante) (facultatif)
|
||
Affectation principale (déterminer un texte d'aide) (facultatif)
|
||
Corps d'appartenance (Dans le cadre du POC, la liste déroulante de la nomenclature NCORPS sera une liste déroulante construite « à la main »)
|
||
Liste rouge (case à cocher)
|
||
Hôte
|
||
Nom de la personne invitante (obligatoire ?)
|
||
Prénom de la personne invitante (obligatoire ?)
|
||
Établissement invitant (liste de valeurs basée sur ou=structures) (choix unique) (facultatif)
|
||
Unité ou service invitant (liste de valeurs basée sur ou=structures) (choix unique) (facultatif)
|
||
|
||
Le plus simple : modifier un champ à la fois seulement pour limiter la casse potentielle
|
||
|
||
Renommage
|
||
supannListeRouge => Liste Rouge
|
||
Mail OK
|
||
ADMIN_FOR_ALL wcs Ok
|
||
|
||
|
||
Pbatique des affectations et affiliations :
|
||
Choix multiple et désignation
|
||
|
||
TODO : éliminier la redondance du modèle dans {forms,models}.py
|
||
Bug sur la liste déroulante correspondant à l'affectation principale
|
||
Seul le dernier élément est présent.
|
||
|
||
```
|
||
dn: uid=amarilloaa,ou=supannPeople,dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
eduPersonPrimaryAffiliation: []
|
||
cn: aul marilloaa
|
||
objectClass: inetOrgPerson
|
||
objectClass: supannPerson
|
||
objectClass: eduPerson
|
||
supannEntiteAffectationPrincipale: []
|
||
supannEntiteAffectation: u
|
||
supannEmpCorps: student
|
||
eduPersonAffiliation: u
|
||
eduPersonPrincipalName: pmarillo
|
||
sn: marilloaa
|
||
supannEtablissement: studentaaa
|
||
mail: pmarillonnet@entrouvert.com
|
||
givenName: aul
|
||
supannListeRouge: TRUE
|
||
uid: amarilloaa
|
||
```
|
||
|
||
adding new entry "cn=eduorg,cn=schema,cn=config"
|
||
|
||
Ne pas oublier de supprimer les quelques dernières lignes du ldif, à partir de
|
||
structuralObjectClass
|
||
|
||
Le schema supannorg est déjà dans la conf du ldap
|
||
Pas la façon la plus logique de procéder : pourquoi ne pas modifier directement la racine pour qu'elle contienne les deux classes auxiliaires supplémentaires ?
|
||
|
||
```
|
||
# condorcet.dev.entrouvert.org
|
||
dn: dc=condorcet,dc=dev,dc=entrouvert,dc=org
|
||
objectClass: top
|
||
objectClass: dcObject
|
||
objectClass: organization
|
||
objectClass: eduOrg
|
||
objectClass: supannOrg
|
||
o: condorcet.dev.entrouvert.org
|
||
dc: condorcet
|
||
```
|
||
|
||
il devient alors possible d'ajouter les deux branches manquantes pour respecter les spéc fournies dans la version 0.4 du document d'analyse
|
||
|
||
adding new entry "ou=entrouvert,ou=structures,dc=condorcet,dc=dev,dc=entrouvert,dc=org"
|
||
|
||
adding new entry "ou=entitecampuscondorcet,ou=structures,dc=condorcet,dc=dev,dc=entrouvert,dc=org"
|
||
|
||
TODO modifier Groups pour tenir compte des objectclasses edu et supann
|
||
|
||
BIGTODO:
|
||
peuplement test des etablissement et des unites/services pour les deux listes déroulantes (cf page 12 analyse.v0.4)
|
||
|
||
adding new entry "ou=etablissement0,ou=structures,dc=condorcet,dc=dev,dc=entrouvert,dc=org"
|
||
|
||
adding new entry "ou=etablissement1,ou=structures,dc=condorcet,dc=dev,dc=entrouvert,dc=org"
|
||
|
||
adding new entry "ou=etablissement2,ou=structures,dc=condorcet,dc=dev,dc=entrouvert,dc=org"
|
||
|
||
adding new entry "ou=unite0,ou=structures,dc=condorcet,dc=dev,dc=entrouvert,dc=org"
|
||
|
||
TypeError at /
|
||
must be string, not builtin_function_or_method
|
||
|
||
|
||
Entretien Mik
|
||
TODO
|
||
master DONE
|
||
ldap_is_in_directory à changer DONE ldap_contains_user
|
||
UserSAMLIdentifier -> mellon_session
|
||
syslog
|
||
settings concornant django pour la config syslog directe
|
||
|
||
/register
|
||
/sso sélection du sélecteur d'identité
|
||
|
||
verification avec l'eppn des doublons
|
||
Affichage d'une page joli 'vous etes deja'
|
||
Redirect vers une page '/usernone' templateView statique DONE
|
||
|
||
FormValid
|
||
Faire la vérification syntaxique de ce qu'il y a sur les champs
|
||
Check sur l'EPPN en plus du décorateur : modifier le code, ce n'est pas l'EPPN qui est utilisé actuellement en tant qu'identifiant unique DONE
|
||
Si ces deux conditions sont remplies, alors on peut soumettre la demande w.c.s. DONE
|
||
|
||
post s'il n'est pas correct DONE
|
||
renvoyer le formulaire avec les champs invalides, et les autres pré-remplis DONE
|
||
|
||
UnitFormView -> RegistrationFormView Done
|
||
formValid(, form) DONE
|
||
form déjà instancié, déjà crée par défaut par la CBV
|
||
définir les initial quand la CBV
|
||
methode get_initial() DONE
|
||
form_valid DONE
|
||
|
||
dispatch protégée avec le décorateur?
|
||
façon plus élégante : login_required
|
||
décorateur directement dans urls
|
||
not_in_ldap(RegistrationFormView.as_view()) TODO
|
||
|
||
affiliations affectation secondaires dans le SSO mais pas dans l'annuaire
|
||
|
||
pages blanche avec juste un header 'campus condorcet - gestion des comptes invités'
|
||
|
||
ASCII -> Unicode
|
||
|
||
workflow : passer à un seul statut
|
||
|
||
ouverture du port ldap
|
||
role destinataire
|
||
|
||
wcs
|
||
Une nouvelle demande d'inscription vient d'être saisie...
|
||
|
||
envoi un courriel à l'usager
|
||
|
||
clé de signature au web service
|
||
|
||
Soigner un peu les mails
|
||
Bonjour M. ...
|
||
Nous avsons bien reçu votre demande le ... à ...
|
||
form_var_civilite ? necessaire ?
|
||
|
||
viewer LDAP
|
||
enlever le logo entr'ouvert DONE
|
||
|
||
priorité 1 :
|
||
pérenniser les scripts EN COURS : seulement des scripts systemctl de démarrage pour l'instant
|
||
mellon_session DONE
|
||
|
||
priorité 2 : les skins EN COURS
|
||
|
||
priorité 1 :
|
||
pérenniser les scripts EN COURS : seulement des scripts systemctl de démarrage pour l'instant
|
||
mellon_session EN COURS : refactorisation des vues à faire
|
||
|
||
priorité 2 : les skins EN COURS
|
||
aborted : check de l'age des sessions
|
||
42
|
||
43 #import pdb; pdb.set_trace()
|
||
44 #session_string_datetime = self.request.session['mellon_session']['authn_instant']
|
||
45 #session_datetime = datetime.strptime(session_string_datetime[0:19],
|
||
46 # "%Y-%m-%dT%H:%M:%S")
|
||
47
|
||
|
||
Logging:
|
||
https://docs.djangoproject.com/en/1.11/topics/logging/
|
||
|
||
|
||
Maintenant :
|
||
davantage de logs ?
|
||
support utf-8 ?
|
||
|
||
compatibilité supann côté IDP pour minimiser le coût de branchement à une fédération RENATER ?
|
||
|
||
|
||
partie invitation:
|
||
génération d'un code avec rappatriement de l'entrée d'email ?
|
||
préremplissage côté IDP de l'adresse email ?
|
||
Option : utiliser une autre adresse email ?
|
||
TODO voir ce qu'offre authentic pour cela ?
|
||
|
||
Pourquoi ne pas directement utiliser le code de suivi généré par wcs :
|
||
|
||
1ere version, sans fédération :
|
||
génération d'une URL vers le SP avec le numéro de suivi en query string, le SP va récupérer les entrées du formulaire correspondant au code de suivi, et prérempli le formulaire d'inscription avec les trois champs du formulaire d'invitation
|
||
|
||
2e version, avec fédération :
|
||
L'utilisateur dispose de deux options :
|
||
* "Je dispose d'un compte utilisateur sur l'une des fédérations ci-dessous"
|
||
Ici utiliser le WAYF Renater
|
||
MELLON_DISCOVERY_SERVICE_URL = 'https://discovery.renater.fr/renater'
|
||
* "Je crée un compte" : simplement la première version
|
||
|
||
Ok, le plus direct à mettre en place : création d'un compte sans préremplissage autre que ce qui se trouve dans le formulaire d'invitation
|
||
|
||
|
||
Première étape, envoi d'un mail avec le code de suivi, à l'adresse renseignée
|
||
Bonjour
|
||
|
||
2e étape : paramètre supplémentaire optionnel dans la RegistrationFormView, permettant la redirection de l'utilisateur vers un formulaire prérempli
|
||
|
||
TODIG : le code de suivi peut-il être considéré comme un identifiant opaque ?
|
||
Voir comment il est généré dans wcs
|
||
|
||
ok, cf doc
|
||
> Une API existe pour déterminer l'existence d'un code de suivi et, le cas échéant, découvrir la demande associée.
|
||
|
||
$ curl -H "Accept: application/json" \
|
||
https://www.example.net/api/code/QRFPTSLR
|
||
{"url": "http://www.example.net/demarche/23", "err": 0}
|
||
|
||
Maintenant :
|
||
Gestion de plusieurs emails ?
|
||
Invitation à utiliser la fédération ?
|
||
Invitation possible que si l'EPPN se trouve déjà dans l'annuaire ? Oui !
|
||
La vérification se fait après envoi du formulaire, donc dans form_valid
|
||
|
||
TODO:
|
||
pas de préremplissage de l'email, il s'agit de l'adresse d'invitation
|
||
par contre le champ EPPN doit être non éditable
|
||
|
||
Maintenant : l'invitation doit permettre le SSO
|
||
donc regarder les paramètres possibles en query_string vers la vue de login dans
|
||
django mellon
|
||
|
||
TODO
|
||
Possibilités offertes par l'API authentic pour la création d'un utilisateur?
|
||
forger directement une requête post en https avec user/password ? NON, il s'agit des établissements de test
|
||
Commencer à créer l'entrée dès maintenant ? NON, on doit pouvoir laisser le choix à l'utilisateur d'avoir recours à la fédération RENATER
|
||
Créer un utilisateur alors que l'invité a recours à la fédération RENATER revient à créer deux comptes à l'insu de l'utilisateur
|
||
Donc comment faire ?
|
||
Pas de création, juste un préremplissage et on laisse ou non le choix à l'utilisateur de recourir à la fédération RENATER
|
||
|
||
|
||
Maintenant : envoi d'une liste d'emails
|
||
Il y aura autant d'entrée w.c.s que de mails fournis ?
|
||
Oui dans un premier temps, voir ensuite si dans les templates de mail w.c.s on peut envoyer à une liste de participant en bcc ?
|
||
|
||
|
||
DONE
|
||
|
||
ParrainDN :
|
||
Ok il s'agit bien de l'attribut LDAP supannParrainDN
|
||
On va chercher l'EPPN dans la formulaire w.c.s. puis on créé le DN correspondant
|
||
rien à faire côté SP, jusque côté passerelle
|
||
Récuperer la variable hote_identite du formulaire pour créer l'attribut
|
||
supannParrainDN
|
||
|
||
|
||
Problème : lors d'un formulaire libre la personne peut remplir librement l'identité de du référent
|
||
Le référent ne recevra jamais d'email la réponse fournie n'es pas un EPPN valide présent dans le méta-annuaire
|
||
WORKAROUND possible un peu rude : envoyer par défaut un email au référent CC, ou bien vérifier par regex qu'il ne s'agit pas d'une adresse email
|
||
s'il s'agit d'une adresse email, refaire la procédure de recherche des inscrits à l'annuaire avec cette fois-ci un filtre sur l'email
|
||
|
||
BLOCKER : l'ajout dans le LDAP n'est pas effectué
|
||
Regarder les contraintes sur le format des entrées supannParrainDN
|
||
Oui il semblerait bien qu'il y ait un contrôle sur les distinguishedName de l'annuaire
|
||
Dans ce cas il faut un meilleur contrôle d'erreur puisque pour l'instant celle-ci n'est pas détectée
|
||
|
||
FIX: avec un DN valide ça marche !
|
||
Il y bien un contrôle implicite
|
||
|
||
Maintenant : implémentation d'un contrôle d'erreur ?
|
||
A quel moment doit-on vérifier si le référent se trouve dans le méta-annuaire ?
|
||
L'invité doit-il être mis au courant de la présence ou non du référent déclaré dans le méta-annuaire ?
|
||
Peut-on mentionner un référent par son adresse email ?
|
||
Oui, ce serait bien, puisque celle-ci doit de toute façon être retrouvée pour l'envoi du mail de notification au référent
|
||
|
||
Mik:
|
||
on va se servir affectation pour garder une trace de l'établissement d'origine
|
||
Et donc on va le référencer même s'il n'est pas dans l'annuaire
|
||
|
||
En l'état, confusion avec le parrainDN et celui qui va recevoir l'email de notification
|
||
Donc il faut deux champs:
|
||
La personne invitante, càd le parrainDN, et l'agent qui va recevoir l'email de notification
|
||
Finalement très peu de code dans le SP, presque toutes les fonctionnalités requises peuvent être prises en charge par w.c.s.
|
||
|
||
u'supannparraindn': u'pmarillo241'
|
||
|
||
Le champ de traitement w.c.s. est bien rempli, on peut ajouter le DN au ldap
|
||
|
||
Jeu de données pour la seconde démo
|
||
4 Entités : OK
|
||
4 Etablissements : OK
|
||
|
||
Retablissement du push LDAP dans le connecteur passerelle
|
||
OK la procédure d'inscription via invitation fonctionne
|
||
|
||
Connecteur LDAP: BLOCKER
|
||
TypeError: {u'objectClass': [u'organizationalUnit', u'top'], u'ou': [u'people']} is not JSON serializable
|
||
|
||
(Pdb) type(o)
|
||
<class 'ldap3.utils.ciDict.CaseInsensitiveDict'>
|
||
|
||
Solutions ?
|
||
round-trip cast
|
||
dictionnaire de CaseInsensitiveDicts-> str -> dictionnaire de dictionnaires ?
|
||
OK
|
||
|
||
//CURRENT
|
||
|
||
## Tournai
|
||
mail de Benj:
|
||
```
|
||
SSO desktop pour Tournai sur authentic et alfresco
|
||
permettre un SSO qui s'étende à l'accès DAV vers Alfresco.
|
||
|
||
Sur authentic c'est Kerberos qu'il faut utiliser la doc est là:
|
||
|
||
https://dev.entrouvert.org/projects/sysadmin/wiki/Kerberos#Active-Directory
|
||
http://git.entrouvert.org/authentic2-auth-kerberos.git/tree/README
|
||
|
||
générer la keytab en exécutant les commandes setspn et ktpass sur le serveur AD.
|
||
Le fichier keytab ainsi générer devra être copié sur le serveur authentic et
|
||
indiqué à Authentic via la variable d'environnement KRB5_KTNAME.
|
||
|
||
Pour Alfresco je pense que le plus simple est d'activer le mode NTLM
|
||
pass-through (ça n'essaiera que si aucune autre authentification n'a pris la
|
||
main) car ça ne nécessite pas de configuration particulière au niveau de l'AD:
|
||
|
||
http://docs.alfresco.com/5.0/concepts/auth-alfrescontlm-ntlm.html
|
||
|
||
Pour se connecter à la machine alfresco de Tournai voir (Paul tu pourras demander les
|
||
détails à Fred, notamment qu'il ajoute ou fasse ajouter ta clé aux accès vers
|
||
staging.imio.be)[1]:
|
||
|
||
https://dev.entrouvert.org/projects/interne/wiki/Mots_de_passe_utilis%C3%A9s_dans_des_projets_client#Tournai
|
||
|
||
La documentation actuelle de la configuration Alfresco est sur:
|
||
|
||
https://dev.entrouvert.org/projects/tournai/wiki/Param%C3%A9trage_SSO_alfresco
|
||
|
||
Actuellement on a du pass-trough sur une authentification sur un entête
|
||
HTTP (X-Alfresco-Remote-User) sinon on passe en authentification LDAP.
|
||
|
||
Pour se connecter au serveur publik de Tournai:
|
||
|
||
ssh root@staging.imio.be
|
||
|
||
puis
|
||
|
||
docker exec -ti tournaiteleservices_tournaiteleservices_1 bash
|
||
|
||
Paul, selon nos disponibilités n'hésite pas à déranger Fred ou moi.
|
||
|
||
[1]: j'ai cette config dans mon ssh-config
|
||
|
||
Host alfresco-tournai
|
||
HostName 194.78.28.150
|
||
Port 5022
|
||
User root
|
||
ProxyCommand ssh -W %h:%p staging.imio.be
|
||
LocalForward 2080 127.0.0.1:2080
|
||
```
|
||
|
||
Prérequis pour le tuto Achim Grolms :
|
||
A-record, a PTR-record, a CNAME record
|
||
|
||
Lecture RFC Kerberos OK
|
||
|
||
Installation de Alfresco
|
||
dépendances:
|
||
ImageMagick
|
||
|
||
Alfresco OK
|
||
|
||
Installation d'Authentic avec le support Kerberos :
|
||
|
||
Erreur en décrivant la procédire usuelle:
|
||
```
|
||
./authentic2-ctl runserver
|
||
Performing system checks...
|
||
|
||
System check identified no issues (0 silenced).
|
||
Unhandled exception in thread started by <function wrapper at 0x7f6d5fc095f0>
|
||
Traceback (most recent call last):
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/utils/autoreload.py", line 229, in wrapper
|
||
fn(*args, **kwargs)
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/core/management/commands/runserver.py", line 116, in inner_run
|
||
self.check_migrations()
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/core/management/commands/runserver.py", line 168, in check_migrations
|
||
executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/db/migrations/executor.py", line 19, in __init__
|
||
self.loader = MigrationLoader(self.connection)
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/db/migrations/loader.py", line 47, in __init__
|
||
self.build_graph()
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/db/migrations/loader.py", line 185, in build_graph
|
||
self.load_disk()
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/db/migrations/loader.py", line 93, in load_disk
|
||
for name in os.listdir(directory):
|
||
OSError: [Errno 20] Not a directory: '/home/paul/tournai/venv/local/lib/python2.7/site-packages/authentic2_auth_kerberos-1.1.0.5+g198d782-py2.7.egg/authentic2_auth_kerberos/migrations'
|
||
```
|
||
|
||
```
|
||
(venv) paul@spare:~/tournai/apps/authentic$ ./authentic2-ctl runserver
|
||
Performing system checks...
|
||
|
||
System check identified no issues (0 silenced).
|
||
Unhandled exception in thread started by <function wrapper at 0x7fd88fc7d1b8>
|
||
Traceback (most recent call last):
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/utils/autoreload.py", line 229, in wrapper
|
||
fn(*args, **kwargs)
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/core/management/commands/runserver.py", line 116, in inner_run
|
||
self.check_migrations()
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/core/management/commands/runserver.py", line 168, in check_migrations
|
||
executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/db/migrations/executor.py", line 19, in __init__
|
||
self.loader = MigrationLoader(self.connection)
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/db/migrations/loader.py", line 47, in __init__
|
||
self.build_graph()
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/db/migrations/loader.py", line 185, in build_graph
|
||
self.load_disk()
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/Django-1.8.18-py2.7.egg/django/db/migrations/loader.py", line 93, in load_disk
|
||
for name in os.listdir(directory):
|
||
OSError: [Errno 20] Not a directory: '/home/paul/tournai/venv/local/lib/python2.7/site-packages/django_mellon-1.2.29-py2.7.egg/mellon/migrations'
|
||
```
|
||
|
||
après un `python setup.py develop`, puis une application des migrations, authentic fonctionne
|
||
|
||
Installation des paquets
|
||
krb5-config krb5-clients krb5-user
|
||
|
||
DB master key : testdb
|
||
|
||
```
|
||
Now that your realm is set up you may wish to create an administrative
|
||
principal using the addprinc subcommand of the kadmin.local program.
|
||
Then, this principal can be added to /etc/krb5kdc/kadm5.acl so that
|
||
you can use the kadmin program on other computers. Kerberos admin
|
||
principals usually belong to a single user and end in /admin. For
|
||
example, if jruser is a Kerberos administrator, then in addition to
|
||
the normal jruser principal, a jruser/admin principal should be
|
||
created.
|
||
```
|
||
|
||
```
|
||
[domain_realm]
|
||
.mit.edu = ATHENA.MIT.EDU
|
||
mit.edu = ATHENA.MIT.EDU
|
||
.media.mit.edu = MEDIA-LAB.MIT.EDU
|
||
media.mit.edu = MEDIA-LAB.MIT.EDU
|
||
.csail.mit.edu = CSAIL.MIT.EDU
|
||
csail.mit.edu = CSAIL.MIT.EDU
|
||
.whoi.edu = ATHENA.MIT.EDU
|
||
whoi.edu = ATHENA.MIT.EDU
|
||
.stanford.edu = stanford.edu
|
||
.slac.stanford.edu = SLAC.STANFORD.EDU
|
||
.toronto.edu = UTORONTO.CA
|
||
.utoronto.ca = UTORONTO.CA
|
||
|
||
localhost = ENTROUVERT.LAN
|
||
entrouvert.lan = ENTROUVERT.LAN
|
||
.entrouvert.lan = ENTROUVERT.LAN
|
||
|
||
```
|
||
|
||
```
|
||
kadmin.local: listprincs
|
||
K/M@ENTROUVERT.LAN
|
||
kadmin/admin@ENTROUVERT.LAN
|
||
kadmin/changepw@ENTROUVERT.LAN
|
||
kadmin/spare.entrouvert.lan@ENTROUVERT.LAN
|
||
kiprop/spare.entrouvert.lan@ENTROUVERT.LAN
|
||
krbtgt/ENTROUVERT.LAN@ENTROUVERT.LAN
|
||
kadmin.local: quit
|
||
```
|
||
|
||
|
||
```
|
||
kadmin.local: addprinc root/admin
|
||
WARNING: no policy specified for root/admin@ENTROUVERT.LAN; defaulting to no policy
|
||
Enter password for principal "root/admin@ENTROUVERT.LAN":
|
||
Re-enter password for principal "root/admin@ENTROUVERT.LAN":
|
||
Principal "root/admin@ENTROUVERT.LAN" created.
|
||
kadmin.local: quit
|
||
```
|
||
|
||
```
|
||
kadmin: addprinc paul
|
||
WARNING: no policy specified for paul@ENTROUVERT.LAN; defaulting to no policy
|
||
Enter password for principal "paul@ENTROUVERT.LAN":
|
||
Re-enter password for principal "paul@ENTROUVERT.LAN":
|
||
Principal "paul@ENTROUVERT.LAN" created.
|
||
```
|
||
|
||
setspn pour
|
||
set servive principal name
|
||
quel paquet debian ?
|
||
|
||
reprise POC CC
|
||
```
|
||
Souhaitez-vous continuer ? [O/n]
|
||
(Lecture de la base de données... 58576 fichiers et répertoires déjà installés.)
|
||
Suppression de courier-authlib (0.66.1-1+b1) ...
|
||
Suppression de dbconfig-common (1.8.47+nmu3+deb8u1) ...
|
||
Suppression de expect (5.45-6) ...
|
||
Suppression de graphviz (2.38.0-7) ...
|
||
Suppression de libgvc6 (2.38.0-7) ...
|
||
Suppression de libpangocairo-1.0-0:amd64 (1.36.8-3) ...
|
||
Suppression de libpangoft2-1.0-0:amd64 (1.36.8-3) ...
|
||
Suppression de libpango-1.0-0:amd64 (1.36.8-3) ...
|
||
Suppression de fontconfig (2.11.0-6.3+deb8u1) ...
|
||
Suppression de libcairo2:amd64 (1.14.0-2.1+deb8u2) ...
|
||
Suppression de libgvpr2 (2.38.0-7) ...
|
||
Suppression de libcgraph6 (2.38.0-7) ...
|
||
Suppression de libcdt5 (2.38.0-7) ...
|
||
Suppression de libthai0:amd64 (0.1.21-1) ...
|
||
Suppression de libdatrie1:amd64 (0.2.8-1) ...
|
||
Suppression de libgl1-mesa-dri:amd64 (10.3.2-1+deb8u1) ...
|
||
Suppression de libdrm-intel1:amd64 (2.4.58-2) ...
|
||
Suppression de libdrm-nouveau2:amd64 (2.4.58-2) ...
|
||
Suppression de libdrm-radeon1:amd64 (2.4.58-2) ...
|
||
Suppression de x11-utils (7.7+2) ...
|
||
Suppression de libgl1-mesa-glx:amd64 (10.3.2-1+deb8u1) ...
|
||
Suppression de libdrm2:amd64 (2.4.58-2) ...
|
||
Suppression de libelf1:amd64 (0.159-4.2) ...
|
||
Suppression de libfontenc1:amd64 (1:1.1.2-1+b2) ...
|
||
Suppression de libglapi-mesa:amd64 (10.3.2-1+deb8u1) ...
|
||
Suppression de libharfbuzz0b:amd64 (0.9.35-2) ...
|
||
Suppression de libgraphite2-3:amd64 (1.3.6-1~deb8u1) ...
|
||
Suppression de xterm (312-2) ...
|
||
Suppression de libxaw7:amd64 (2:1.0.12-2+b1) ...
|
||
Suppression de libxmu6:amd64 (2:1.1.2-1) ...
|
||
Suppression de libxt6:amd64 (1:1.1.4-1+b1) ...
|
||
Suppression de libjs-leaflet (0.7.3~dfsg-1) ...
|
||
Suppression de libllvm3.5:amd64 (1:3.5-10) ...
|
||
Suppression de libpathplan4 (2.38.0-7) ...
|
||
Suppression de libpciaccess0:amd64 (0.13.2-3+b1) ...
|
||
Suppression de libpixman-1-0:amd64 (0.32.6-3) ...
|
||
Suppression de libsm6:amd64 (2:1.2.2-1+b1) ...
|
||
Suppression de libthai-data (0.1.21-1) ...
|
||
Suppression de python-utidylib (0.2-9) ...
|
||
Suppression de libtidy-0.99-0 (20091223cvs-1.4+deb8u1) ...
|
||
Suppression de tk8.6 (8.6.2-1) ...
|
||
Suppression de libtk8.6:amd64 (8.6.2-1) ...
|
||
Suppression de libtxc-dxtn-s2tc0:amd64 (0~git20131104-1.1) ...
|
||
Suppression de libutempter0 (1.1.5-4) ...
|
||
Suppression de libx11-xcb1:amd64 (2:1.6.2-3) ...
|
||
Suppression de libxcb-dri2-0:amd64 (1.10-3+b1) ...
|
||
Suppression de libxcb-dri3-0:amd64 (1.10-3+b1) ...
|
||
Suppression de libxcb-glx0:amd64 (1.10-3+b1) ...
|
||
Suppression de libxcb-present0:amd64 (1.10-3+b1) ...
|
||
Suppression de libxcb-render0:amd64 (1.10-3+b1) ...
|
||
Suppression de libxcb-shape0:amd64 (1.10-3+b1) ...
|
||
Suppression de libxcb-shm0:amd64 (1.10-3+b1) ...
|
||
Suppression de libxcb-sync1:amd64 (1.10-3+b1) ...
|
||
Suppression de libxcomposite1:amd64 (1:0.4.4-1) ...
|
||
Suppression de libxdamage1:amd64 (1:1.1.4-2+b1) ...
|
||
Suppression de libxdot4 (2.38.0-7) ...
|
||
Suppression de libxxf86vm1:amd64 (1:1.1.3-1+b1) ...
|
||
Suppression de libxxf86dga1:amd64 (2:1.1.4-1+b1) ...
|
||
Suppression de libxfixes3:amd64 (1:5.0.1-2+b2) ...
|
||
Suppression de libxft2:amd64 (2.3.2-1) ...
|
||
Suppression de libxtst6:amd64 (2:1.2.2-1+b1) ...
|
||
Suppression de libxi6:amd64 (2:1.7.4-1+b2) ...
|
||
Suppression de libxinerama1:amd64 (2:1.1.3-1+b1) ...
|
||
Suppression de libxmuu1:amd64 (2:1.1.2-1) ...
|
||
Suppression de libxrandr2:amd64 (2:1.4.2-1+b1) ...
|
||
Suppression de libxrender1:amd64 (1:0.9.8-1+b1) ...
|
||
Suppression de libxshmfence1:amd64 (1.1-4) ...
|
||
Suppression de libxss1:amd64 (1:1.2.2-1) ...
|
||
Suppression de libxv1:amd64 (2:1.0.10-1+b1) ...
|
||
Suppression de python-hobo (0.63-1~eob80+2) ...
|
||
Suppression de python-celery (3.1.13-3) ...
|
||
Suppression de python-kombu (3.0.21-2) ...
|
||
Suppression de python-amqp (1.4.5-2) ...
|
||
Suppression de python-pyexcel-xls (0.2.2-1~eob80+2) ...
|
||
Suppression de python-xlwt (0.7.5+debian1-1) ...
|
||
Suppression de python-antlr (2.7.7+dfsg-6) ...
|
||
Suppression de python-anyjson (0.3.3-1) ...
|
||
Suppression de python-billiard (3.3.0.18-2) ...
|
||
Suppression de python-celery-common (3.1.13-3) ...
|
||
Suppression de python-cffi (1.4.2-2~bpo8+1) ...
|
||
Suppression de python-raven (5.11.1-1~eob80+1) ...
|
||
Suppression de python-contextlib2 (0.4.0-2) ...
|
||
Suppression de python-crypto (2.6.1-5+deb8u1) ...
|
||
Suppression de python-dateutil (2.2-2) ...
|
||
Suppression de python-soappy (0.12.22-1) ...
|
||
Suppression de python-defusedxml (0.4.1-2) ...
|
||
Suppression de python-django-import-export (0.2.7.6.1~eob80+1) ...
|
||
Suppression de python-diff-match-patch (20121119-1) ...
|
||
Suppression de python-django-admin-tools (0.6.0-1~eob80+2) ...
|
||
Suppression de python-django-filters (0.11.0.1-1~eob80+1) ...
|
||
Suppression de python-django-jsonfield (0.9.19.10-1~eob80+1) ...
|
||
Suppression de python-django-model-utils (2.5.2-1~eob80+2) ...
|
||
Suppression de python-django-select2 (4.3.1.6-1~eob80+1) ...
|
||
Suppression de python-django-tables2 (1.0.4.6-1~eob80+1) ...
|
||
Suppression de python-django-tenant-schemas (1.5.2.1.61+g35b4473-1~eob80+1) ...
|
||
Suppression de python-djangorestframework (3.3.2-1~eob80+1) ...
|
||
Suppression de python-dns (2.3.6-3) ...
|
||
Suppression de python-dnspython (1.12.0-1) ...
|
||
Suppression de python-feedparser (5.1.3-3) ...
|
||
Suppression de python-graypy (0.2.11-1) ...
|
||
Suppression de python-qrcode (5.0.1-1) ...
|
||
Suppression de python-imaging (2.6.1-2+deb8u3) ...
|
||
Suppression de python-jwcrypto (0.3.2-2) ...
|
||
Suppression de python-ldaptools (0.14.5+gd32d58a-1~eob80+1) ...
|
||
Suppression de python-ldap (2.4.10-1) ...
|
||
Suppression de python-libxml2 (2.9.1+dfsg1-5+deb8u4) ...
|
||
Suppression de python-magic (1:5.22+15-2+deb8u3) ...
|
||
Suppression de python-mailer (0.7-1) ...
|
||
Suppression de python-markdown (2.5.1-2) ...
|
||
Suppression de python-pyexcel-ods (0.2.1-1~eob80+3) ...
|
||
Suppression de python-odf (1.2.0-2) ...
|
||
Suppression de python-phpserialize (1.3-1~eob80+1) ...
|
||
Suppression de python-pycparser (2.10+dfsg-3) ...
|
||
Suppression de python-ply (3.4-5) ...
|
||
Suppression de python-pyexcel-io (0.2.3-1~eob80+3) ...
|
||
Suppression de python-pyparsing (2.0.3+dfsg1-1) ...
|
||
Suppression de python-scgi (1.13-1.1) ...
|
||
Suppression de python-suds (0.4.1-15) ...
|
||
Suppression de python-tablib (0.9.11-2) ...
|
||
Suppression de python-wstools (0.4.3-2) ...
|
||
Suppression de python-xlrd (0.9.2-1) ...
|
||
Suppression de tcl-expect:amd64 (5.45-6) ...
|
||
Suppression de xbitmaps (1.1.1-2) ...
|
||
Suppression de libice6:amd64 (2:1.0.9-1+b1) ...
|
||
Suppression de libxext6:amd64 (2:1.3.3-1) ...
|
||
Suppression de x11-common (1:7.7+7) ...
|
||
Traitement des actions différées (« triggers ») pour man-db (2.7.0.2-5) ...
|
||
Traitement des actions différées (« triggers ») pour libc-bin (2.19-18+deb8u7) ...
|
||
Traitement des actions différées (« triggers ») pour mime-support (3.58) ...
|
||
Traitement des actions différées (« triggers ») pour python-support (1.0.15) ...
|
||
[master c7e7233] committing changes in /etc after apt run
|
||
Author: Paul Marillonnet <pmarillonnet@entrouvert.com>
|
||
3 files changed, 3 deletions(-)
|
||
delete mode 120000 alternatives/libtxc-dxtn-x86_64-linux-gnu
|
||
delete mode 120000 alternatives/x-terminal-emulator
|
||
delete mode 120000 alternatives/x-terminal-emulator.1.gz
|
||
|
||
```
|
||
|
||
|
||
```
|
||
(venv) paul@spare:~/tournai/apps/authentic$ ./authentic2-ctl findstatic css/gadjo.css
|
||
No matching file found for 'css/gadjo.css'.
|
||
```
|
||
Pourtant l'appli gadjo est installée.
|
||
Le scss est bien là mais pas le css
|
||
Comment générer le second à partir du premier ?
|
||
|
||
Ok gadjo à partir des sources
|
||
|
||
Maintenant : essayer de transmettre les principals Kerberos à Authentic
|
||
|
||
Pour ce faire (cf mail Benj) : une des variables est à paramétrer
|
||
|
||
D'abord, création d'un keytab pour l'utilisateur paul
|
||
```
|
||
$ ktutil
|
||
ktutil: add
|
||
addent add_entry
|
||
ktutil: addent -password -p paul@ENTROUVERT.LAN -k 1 -e rc4-hmac
|
||
Password for paul@ENTROUVERT.LAN:
|
||
ktutil: addent -password -p paul@ENTROUVERT.LAN -k 1 -e aes256-cts
|
||
Password for paul@ENTROUVERT.LAN:
|
||
ktutil: wkt paul.keytab
|
||
ktutil: quit
|
||
```
|
||
|
||
> kinit paul@ENTROUVERT.LAN -k -t paul.keytab; myscript
|
||
|
||
Quelle syntaxe pour le support de l'authentification dans les scripts ?
|
||
|
||
```
|
||
$ klist -k paul.keytab
|
||
Keytab name: FILE:paul.keytab
|
||
KVNO Principal
|
||
---- --------------------------------------------------------------------------
|
||
1 paul@ENTROUVERT.LAN
|
||
1 paul@ENTROUVERT.LAN
|
||
```
|
||
|
||
La création de la keytab sembe s'être bien déroulée
|
||
Voyons ce qu'en dit Authentic
|
||
Ajout de KRB5_KTNAME dans les *settings*
|
||
|
||
|
||
BLOCKER : OpenLDAP à la place de l'AD
|
||
Pas possible de se connecter au serveur publik de Tournai pour comparer l'installation
|
||
|
||
L'annuaire tourne-t-il en backend de Publik ou bien en back-end de Kerberos ?
|
||
|
||
passphrase pour la cle privée RSA : testauth
|
||
|
||
TODO openssl req -new -key server.key -out server.csr
|
||
|
||
TODO vue d'ensemble du support LDAP dans authentic
|
||
voir ce qui se trouve dans authentic2_provisionning_ldap
|
||
|
||
phases :
|
||
- LDAP backend A2
|
||
- LDAP backend KRB
|
||
- Alfresco avec config Kerberos
|
||
dans quelles mesures peut-on substituer la partie spécifique à MS (utilitaires AD, NTLM)
|
||
|
||
backend A2:
|
||
LDAP_AUTH_SETTINGS à remplir
|
||
LDAP_BACKEND : boolean
|
||
possibilité de récupérer un exemple de fichier de conf ?
|
||
|
||
./authentic/doc/auth_ldap.rst
|
||
|
||
installaton de djando_auth_ldap
|
||
|
||
```
|
||
ldapsearch -D "cn=admin,dc=entrouvert,dc=lan" -w test -p 389 -h spare.entrouvert.lan -b "ou=People,dc=entrouvert,dc=lan" -s sub "(ObjectClass=*)" * +
|
||
```
|
||
|
||
Comment s'assurer que la config LDAP est bien fonctionnelle ?
|
||
Les utilisateurs ajoutés dans le group des utilisateurs ne devraient-ils pas apparaître ?
|
||
|
||
Lecture de /src/authentic2/backends/ldap_backend.py
|
||
|
||
le fichier /etc/ssl/certs/ca-certificates.crt, contenant les certificats de la machine, est bien présent.
|
||
|
||
SESSION_LDAP_DATA_KEY à creuser
|
||
|
||
Par ailleurs, il semblerait que les config décrite dans la doc aient été remplacées par un dictionnaire LDAP_AUTH_SETTINGS
|
||
TOD debugger pour voir si ce n'est pas authentic que se charger de remplir le dict
|
||
Pas rempli, LDAP_AUTH_SETTINGS à remplir
|
||
|
||
la documentation n'est pas à jour, les tests par contre le sont :
|
||
|
||
```
|
||
@pytest.mark.django_db
|
||
def test_simple_with_binddn(slapd, settings, client):
|
||
settings.LDAP_AUTH_SETTINGS = [{
|
||
'url': [slapd.ldap_url],
|
||
'binddn': DN,
|
||
'bindpw': PASS,
|
||
'basedn': 'o=orga',
|
||
'use_tls': False,
|
||
}]
|
||
```
|
||
|
||
On dirait qu'un peu de kerberos est mêlé à tout ça
|
||
Est-ce que le lien entre Kerberos et Authentic se fait aussi via l'annuaire ?
|
||
|
||
|
||
Reprise :
|
||
erreurs a2 frontend dans l'interface /manage, alors que /admin fonctionne
|
||
```
|
||
TemplateDoesNotExist at /manage/users/
|
||
django_tables2/table.html
|
||
désinstallation et réinstallation de django_tables2
|
||
seul le .egg était présent dans le venv, et pourtant pip le considérait comme installé
|
||
TODO voir s'il n'y aurait pas une modif à effectuer dans la déclaration des dépendances d'authentic ?
|
||
|
||
incompatibilité django_tables2?
|
||
```
|
||
|
||
```
|
||
File "/home/paul/tournai/venv/local/lib/python2.7/site-packages/django_tables2/columns/base.py", line 249, in from_field
|
||
verbose_name = field.verbose_name
|
||
AttributeError: 'GenericForeignKey' object has no attribute 'verbose_name'
|
||
```
|
||
|
||
Pb : les tests a2_auth_krb echouent
|
||
`E ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the NAME value.`
|
||
|
||
export DB_ENGINE='sqlite3' ne change rien
|
||
NAME pas configuré correctement ?
|
||
Pourtant cet argument est fourni et devrait engendrer la création de la base
|
||
|
||
FIX: django_tables2==1.0*.7*
|
||
|
||
approvisionnement de la base authentic depuis LDAP:
|
||
Benj:
|
||
les comptes sont créés dans authentic dans deux cas:
|
||
au moment du login un compte est créé automatiquement en base authentic
|
||
ou alors lors de l'exécution de la commande sync-ldap-users
|
||
|
||
./authentic2-ctl sync-ldap-users fonctionne, la base authentic est bien provisionnée à partir des entrées ou=People de l'anuaire
|
||
|
||
TODO backend LDAP pour Kerberos
|
||
Via sasl2 ?
|
||
Ou bien par PAM/NSS ?
|
||
Solution 2 parait plus simple pour une installation en local ?
|
||
Quelle utilité des *principals* si les utilisateurs sont fournis par le LDAP ?
|
||
Voir quel scenarion d'approvisionnement est pris en charge ?
|
||
|
||
Installation du paquet krb5-kdc-ldap
|
||
|
||
ldap_kerberos_container_dn
|
||
ldap_kdc_sasl_authcid
|
||
ldap_kdc_sasl_authzid
|
||
ldap_kdc_sasl_mech
|
||
ldap_kdc_sasl_realm
|
||
ldap_kadmind_dn
|
||
ldap_kadmind_sasl_authcid
|
||
ldap_kadmind_sasl_authzid
|
||
ldap_kadmind_sasl_mech
|
||
ldap_kadmind_sasl_realm
|
||
ldap_service_password_file
|
||
ldap_servers
|
||
ldap_conns_per_server
|
||
|
||
On essaie de préciser les trois paramètres nécessaires:
|
||
|
||
ldap_kdc_dn=
|
||
|
||
Erreur sur le fichier de conf du kdc
|
||
```
|
||
# kdb5_ldap_util stashsrvpw "ou=Special Users,dc=entrouvert,dc=lan"
|
||
kdb5_ldap_util: ldap_service_password_file not configured while getting service password filename
|
||
```
|
||
et pourtant si !
|
||
ok mauvaise utilisation de la commande
|
||
|
||
Pourquoi un conteneur à part ?
|
||
Enter DN of Kerberos container: cn=krbcontainer,dc=entrouvert,dc=lan
|
||
|
||
|
||
On peut retrouver à tout moment la config, 'auto-contenue' dans l'annuaire :
|
||
```
|
||
ldapsearch -D "cn=admin,cn=config" -w test -p 389 -h spare.entrouvert.lan -b "cn=config" -s sub "(ObjectClass=*)"
|
||
```
|
||
|
||
divergence entre doc et installation
|
||
olcDatabase{1}hdb vs olcDatabase{1}mdb
|
||
C'est simplement le backend de stockage de la base qui change
|
||
|
||
|
||
Ajout d'un index de base:
|
||
```
|
||
ldapmodify -x -D cn=admin,cn=config -W
|
||
Enter LDAP Password:
|
||
dn: olcDatabase={1}mdb,cn=config
|
||
add: olcDbIndex
|
||
olcDbIndex: krbPrincipalName eq,pres,sub
|
||
modifying entry "olcDatabase={1}mdb,cn=config"
|
||
```
|
||
|
||
quelles différences entre pres et eq ? la doc n'est pas très claire à ce sujet.
|
||
|
||
Erreur lors de la définition des ACL
|
||
```
|
||
# ldapmodify -x -D cn=admin,cn=config -W
|
||
Enter LDAP Password:
|
||
dn: olcDatabase={1}mdb,cn=config
|
||
replace: olcAccess
|
||
olcAccess: to attrs=userPassword,shadowLastChange,krbPrincipalKey by
|
||
dn="cn=admin,dc=entrouvert,dc=lan" write by anonymous auth by self write by * none
|
||
-
|
||
add: olcAccess
|
||
olcAccess: to dn.base="" by * read
|
||
-
|
||
add: olcAccess
|
||
olcAccess: to * by dn="cn=admin,dc=entrouvert,dc=lan" write by * read
|
||
modifying entry "olcDatabase={1}mdb,cn=config"
|
||
ldap_modify: Other (e.g., implementation specific) error (80)
|
||
additional info: <olcAccess> handler exited with 1
|
||
```
|
||
|
||
```
|
||
$ sudo kdb5_ldap_util -D cn=admin,dc=entrouvert,dc=lan create -subtrees dc=entrouvert,dc=lan -r ENTROUVERT.LAN -s -H ldap://spare.entrouvert.lan
|
||
Password for "cn=admin,dc=entrouvert,dc=lan":
|
||
Initializing database for realm 'ENTROUVERT.LAN'
|
||
You will be prompted for the database Master Password.
|
||
It is important that you NOT FORGET this password.
|
||
Enter KDC database master key:
|
||
Re-enter KDC database master key to verify:
|
||
kdb5_ldap_util: Kerberos Container create FAILED: Object class violation while creating realm 'ENTROUVERT.LAN'
|
||
```
|
||
bug dans kdb5_ldap_util ?
|
||
|
||
```
|
||
o# sudo kdb5_ldap_util -D cn=admin,dc=entrouvert,dc=lan stashsrvpw -f /etc/krb5kdc/service.keyfile cn=admin,dc=entrouvert,dc=lan
|
||
Password for "cn=admin,dc=entrouvert,dc=lan":
|
||
Password for "cn=admin,dc=entrouvert,dc=lan":
|
||
Re-enter password for "cn=admin,dc=entrouvert,dc=lan":
|
||
|
||
cat /etc/krb5kdc/service.keyfile
|
||
cn=admin,dc=entrouvert,dc=lan#{HEX}74657374
|
||
```
|
||
|
||
addprinc -x dn="uid=paulo,ou=people,dc=example,dc=com" paulo
|
||
|
||
TODO:
|
||
synthese de la piece en 4 actes expliquant le protocole Kerberos (doc MIT)
|
||
|
||
http://www.openldap.org/lists/openldap-technical/201107/msg00180.html
|
||
Suggestion d'un dev OpenLDAP
|
||
|
||
See:
|
||
|
||
contrib/slapd-modules/smbk5pwd/
|
||
|
||
within the source.
|
||
|
||
Donc il faudrait du Samba en plus ?
|
||
Non : installation d'une machine virtuelle windows server 2012 avec un Active Directory dessus
|
||
|
||
Problème : la VM Windows va-t-elle avoir à la fois les rôles de serveur AD et de poste client ?
|
||
mdp admin :
|
||
t3st4uth!!
|
||
|
||
Directory Service Restore Mode (DSRM) password
|
||
t3st4uth!!
|
||
|
||
|
||
SYSVOL et NTDS
|
||
system volume et NT domain server ?
|
||
|
||
Le script en powershell est
|
||
```
|
||
#
|
||
# Windows PowerShell script for AD DS Deployment
|
||
#
|
||
|
||
Import-Module ADDSDeployment
|
||
Install-ADDSForest `
|
||
-CreateDnsDelegation:$false `
|
||
-DatabasePath "C:\Windows\NTDS" `
|
||
-DomainMode "Win2012R2" `
|
||
-DomainName "entrouvert.local" `
|
||
-DomainNetbiosName "ENTROUVERT" `
|
||
-ForestMode "Win2012R2" `
|
||
-InstallDns:$true `
|
||
-LogPath "C:\Windows\NTDS" `
|
||
-NoRebootOnCompletion:$false `
|
||
-SysvolPath "C:\Windows\SYSVOL" `
|
||
-Force:$true
|
||
```
|
||
|
||
```
|
||
> netdom query fsmo
|
||
Schema master WIN-4HOASL41N0M.entrouvert.local
|
||
Domain naming master WIN-4HOASL41N0M.entrouvert.local
|
||
PDC WIN-4HOASL41N0M.entrouvert.local
|
||
RID pool manager WIN-4HOASL41N0M.entrouvert.local
|
||
Infrastructure master WIN-4HOASL41N0M.entrouvert.local
|
||
The command completed successfully.
|
||
```
|
||
|
||
Maintenant :
|
||
|
||
|
||
=> L'AD tourne sur la VM
|
||
|
||
Maintenant :
|
||
Communication Kerberos et AD ?
|
||
kinit pour récupérer un ticket
|
||
MIT Kerberos ou AD ?
|
||
|
||
le host-only adapter semble fonctionner :
|
||
```
|
||
> ping 192.168.56.1
|
||
Pinging 192.168.56.1 with 32 bytes of data:
|
||
Reply from 192.168.56.1: bytes=32 time<1ms TTL=64
|
||
Reply from 192.168.56.1: bytes=32 time<1ms TTL=64
|
||
Reply from 192.168.56.1: bytes=32 time<1ms TTL=64
|
||
Reply from 192.168.56.1: bytes=32 time<1ms TTL=64
|
||
|
||
Ping statistics for 192.168.56.1:
|
||
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
|
||
Approximate round trip times in milli-seconds:
|
||
Minimum = 0ms, Maximum = 0ms, Average = 0ms
|
||
```
|
||
|
||
Authentic accessible depuis le serveur AD
|
||
pour ce faire : ajout d'un nom de domaine sur l'IP rattachée au host-only adapter côté hôte, par exemple phyhost
|
||
./authentic2-ctl runserver phyhost:8080
|
||
|
||
On va pouvoir récupérer le ticket côté client et utiliser le KDC pour l'authent
|
||
|
||
Ecoute sur le port 80 : c'est sale mais ça marche :
|
||
$ sudo `which python` ./authentic2-ctl runserver phyhost:80
|
||
|
||
```
|
||
> setspn -A HTTP/192.168.56.1 serveuridp
|
||
Checking domain DC=entrouvert,DC=local
|
||
setspn : FindDomainForAccount: Call to DsGetDcNameWithAccountW failed with return value 0x00000525
|
||
At line:1 char:1
|
||
+ setspn -A HTTP/192.168.56.1 serveuridp 2> setspn.txt
|
||
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
+ CategoryInfo : NotSpecified: (FindDomainForAc...alue 0x00000525:String) [], RemoteException
|
||
+ FullyQualifiedErrorId : NativeCommandError
|
||
|
||
Unable to locate account serveuridp
|
||
```
|
||
OK création du compte d'abord...
|
||
|
||
Tools -> Active Directory Users and Computers
|
||
mdp de l'utilisateur
|
||
t3stp!!
|
||
|
||
a2idp@entrouvert.local / t3stauth!!
|
||
|
||
Il faut sans doute créer un compte valide pour les credentials du principal, non ?
|
||
|
||
```
|
||
PS C:\Users\Administrator> ktpass -princ HTTP/192.168.56.1@ENTROUVERT.LOCAL -mapuser a2idp@ENTROUVERT.LOCAL -crypto ALL
|
||
-ptype KRB5_NT_PRINCIPAL -pass t3stauth!! -out c:\idp.keytab
|
||
Targeting domain controller: WIN-4HOASL41N0M.entrouvert.local
|
||
Using legacy password setting method
|
||
Successfully mapped HTTP/192.168.56.1 to a2idp.
|
||
Key created.
|
||
Key created.
|
||
Key created.
|
||
Key created.
|
||
Key created.
|
||
Output keytab to c:\idp.keytab:
|
||
Keytab version: 0x502
|
||
keysize 61 HTTP/192.168.56.1@ENTROUVERT.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 3 etype 0x1 (DES-CBC-CRC) keylength 8 (0x3
|
||
d98dff7a701b0c4)
|
||
keysize 61 HTTP/192.168.56.1@ENTROUVERT.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 3 etype 0x3 (DES-CBC-MD5) keylength 8 (0x3
|
||
d98dff7a701b0c4)
|
||
keysize 69 HTTP/192.168.56.1@ENTROUVERT.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 3 etype 0x17 (RC4-HMAC) keylength 16 (0xaf
|
||
a5a93065041df2e1687d9d9ad1445d)
|
||
keysize 85 HTTP/192.168.56.1@ENTROUVERT.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 3 etype 0x12 (AES256-SHA1) keylength 32 (0
|
||
xeb6c5d4af02c76d6c4104cbc8ab117e04c5a18c865c39df30bec97d50defc72b)
|
||
keysize 69 HTTP/192.168.56.1@ENTROUVERT.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 3 etype 0x11 (AES128-SHA1) keylength 16 (0
|
||
x3902936547e7d0cd4706c38a4a4fc0fb)
|
||
```
|
||
|
||
On copie la keytab côté IdP,
|
||
on la renseigne dans la conf authentic via KRB5_KTNAME
|
||
|
||
Est-ce suffisant ?
|
||
|
||
Installation d'une VM client
|
||
root / admin
|
||
|
||
paul / testp
|
||
|
||
apt-install krb5-user
|
||
default realm configuration : ENTROUVERT@LOCAL
|
||
|
||
client mis dans le host-only adapter
|
||
|
||
Prochaine etape : Se logger à partir du Kerberos
|
||
|
||
installation côté client
|
||
krb5-user
|
||
libpam-krb5
|
||
libpam-ccreds
|
||
auth-client-config ? paquet ubuntu seulement ?
|
||
|
||
récuperation d'un ticket valide pour 10h, comme le montre la commande klist
|
||
|
||
On essaie de se connecter à l'IDP
|
||
sudo `which python` ./authentic2-ctl runserver phyhost:80
|
||
|
||
|
||
$ kinit pmarillonnet@ENTROUVERT.LOCAL
|
||
Password for pmarillonnet@ENTROUVERT.LOCAL:
|
||
|
||
$ klist
|
||
Ticket cache: FILE:/tmp/krb5cc_1003
|
||
Default principal: pmarillonnet@ENTROUVERT.LOCAL
|
||
|
||
Valid starting Expires Service principal
|
||
05/15/2017 15:16:37 05/16/2017 01:16:37 krbtgt/ENTROUVERT.LOCAL@ENTROUVERT.LOCAL
|
||
renew until 05/16/2017 15:16:34
|
||
|
||
|
||
installation de django_kerberos ?
|
||
|
||
BLOCKER :
|
||
TemplateDoesNotExist at /accounts/kerberos/login/
|
||
|
||
django_kerberos/unauthorized.html
|
||
|
||
FIX: reinstallation de django_kerberos
|
||
|
||
|
||
Authentic2 - phyhost
|
||
Homepage
|
||
Access unauthorized please refresh your ticket cache
|
||
|
||
LA RFC est claire à ce sujet:
|
||
The 401 (Unauthorized) response message is used by an origin server
|
||
to challenge the authorization of a user agent.
|
||
|
||
lire les specs de django_kerberos pour comprendre ce qui ne va pas...
|
||
KERBEROS_HOSTNAME
|
||
KERBEROS_BACKEND_CREATE
|
||
KERBEROS_BACKEND_ADMIN_REGEXP
|
||
KERBEROS_SERVICE_PRINCIPAL
|
||
KERBEROS_KEEP_PASSWORD
|
||
à paramétrer
|
||
DONE
|
||
|
||
|
||
https://technet.microsoft.com/en-us/library/cc759550%28v=ws.10%29.aspx
|
||
|
||
Ajout d'une entrée DNS A record pour le serveur IdP
|
||
|
||
On peut alors éditer le /etc/resolv.conf pour l'ajout du DNS tournant sur la VM windows 2012:
|
||
nameserver 192.168.56.101
|
||
|
||
|
||
PS C:\Users\Administrator> ping phyhost.entrouvert.local
|
||
|
||
Pinging phyhost.entrouvert.local [192.168.56.1] with 32 bytes of data:
|
||
Reply from 192.168.56.1: bytes=32 time<1ms TTL=64
|
||
Reply from 192.168.56.1: bytes=32 time<1ms TTL=64
|
||
Reply from 192.168.56.1: bytes=32 time<1ms TTL=64
|
||
Reply from 192.168.56.1: bytes=32 time<1ms TTL=64
|
||
|
||
Ping statistics for 192.168.56.1:
|
||
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
|
||
Approximate round trip times in milli-seconds:
|
||
Minimum = 0ms, Maximum = 0ms, Average = 0ms
|
||
|
||
pb de DNS résolu
|
||
maintenant :
|
||
×Principal pmarillonnet@ENTROUVERT.LOCAL could not be authenticated
|
||
|
||
$ klist
|
||
Ticket cache: FILE:/tmp/krb5cc_1003
|
||
Default principal: pmarillonnet@ENTROUVERT.LOCAL
|
||
|
||
Valid starting Expires Service principal
|
||
05/18/2017 11:01:38 05/18/2017 21:01:38 krbtgt/ENTROUVERT.LOCAL@ENTROUVERT.LOCAL
|
||
renew until 05/19/2017 11:01:35
|
||
05/18/2017 11:05:22 05/18/2017 21:01:38 HTTP/phyhost.entrouvert.local@
|
||
renew until 05/19/2017 11:01:35
|
||
05/18/2017 11:05:22 05/18/2017 21:01:38 HTTP/phyhost.entrouvert.local@ENTROUVERT.LOCAL
|
||
renew until 05/19/2017 11:01:35
|
||
|
||
|
||
essai pour la creation manuelle de l'utilisateur dans la base de l'IDP : ne change rien au problème
|
||
|
||
autre piste : virer complètement la conf dans /etc/hosts
|
||
utiliser le DHCP sur la VM à la place ?
|
||
|
||
$ dig WIN-4HOASL41N0M.entrouvert.local
|
||
|
||
; <<>> DiG 9.10.3-P4-Debian <<>> WIN-4HOASL41N0M.entrouvert.local
|
||
;; global options: +cmd
|
||
;; Got answer:
|
||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54521
|
||
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
|
||
|
||
;; OPT PSEUDOSECTION:
|
||
; EDNS: version: 0, flags:; udp: 4000
|
||
;; QUESTION SECTION:
|
||
;WIN-4HOASL41N0M.entrouvert.local. IN A
|
||
|
||
;; ANSWER SECTION:
|
||
WIN-4HOASL41N0M.entrouvert.local. 3600 IN A 192.168.56.101
|
||
WIN-4HOASL41N0M.entrouvert.local. 3600 IN A 10.0.2.15
|
||
|
||
;; Query time: 0 msec
|
||
;; SERVER: 192.168.56.101#53(192.168.56.101)
|
||
;; WHEN: Thu May 18 17:04:46 CEST 2017
|
||
;; MSG SIZE rcvd: 93
|
||
|
||
et
|
||
|
||
$ dig phyhost.entrouvert.local
|
||
|
||
; <<>> DiG 9.10.3-P4-Debian <<>> phyhost.entrouvert.local
|
||
;; global options: +cmd
|
||
;; Got answer:
|
||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27587
|
||
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
|
||
|
||
;; OPT PSEUDOSECTION:
|
||
; EDNS: version: 0, flags:; udp: 4000
|
||
;; QUESTION SECTION:
|
||
;phyhost.entrouvert.local. IN A
|
||
|
||
;; ANSWER SECTION:
|
||
phyhost.entrouvert.local. 3600 IN A 192.168.56.1
|
||
|
||
;; Query time: 0 msec
|
||
;; SERVER: 192.168.56.101#53(192.168.56.101)
|
||
;; WHEN: Thu May 18 17:12:42 CEST 2017
|
||
;; MSG SIZE rcvd: 69
|
||
|
||
|
||
Feedback benj :
|
||
|
||
Le sso fonctionne, c'est dans le backend de l'Idp que quelque chose ne va pas.
|
||
|
||
=> on dirait une erreur dans le backend de l'IDP
|
||
le ldap a été retiré, c'est pas la peine
|
||
Comment configurer le DJANGO_BACKEND de authentic2-auth-kerberos ?
|
||
|
||
|
||
TODO : début de rédaction de la note DONE
|
||
|
||
Maintenant : déterminer d'où vient cette erreur de homepage utilisateur une fois le SSO effectué
|
||
Ok, fausse alerte, pas de debug, c'est simplement l'option `CREATE_USER` à True qui remplit un utilisateur vide.
|
||
|
||
//CURRENT2
|
||
|
||
## Etude synchro brouillon
|
||
|
||
### Apache Syncope
|
||
blocker : GUI bloquée à
|
||
http://localhost:8080/syncope-console/wicket/bookmarkable/org.apache.syncope.client.console.pages.Realms?5&selectedIndex=1
|
||
|
||
quels logs ?
|
||
Est-ce la config de la base qui n'est pas correcte ?
|
||
Comment débugger un jar ... ?
|
||
|
||
Impossible d'utiliser l'outil pour l'instant, et les logs de tomcat restent assez flous (/var/log/tomcat8/idm.log):
|
||
2017-04-27 10:02:20,886 [] [midPointScheduler_Worker-6] INFO (org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl): HHH000010: On release of batch it still contained JDBC statements
|
||
|
||
Interface de type cronjob pour les reconciliations
|
||
ou plutôt 'at' : possibilité de planifier des taĉhes ponctuelles de réconciliation/synchro
|
||
|
||
TODO: lecture du code si le tuto n'est pas assez précis sur les mécanismes de synchro
|
||
Le connecteur LDAP a été configuré pour aller chercher les posixAccount présents sur l'une des branches de l'annuaire, mais pourtant impossible d'approvisionner syncope.
|
||
|
||
Puisque l'interface frontend semble boguée, peut-être vaut-il mieux utiliser l'API Rest ?
|
||
|
||
Impossible de créer des utilisateurs pour l'instant, mais l'API REST semble toutefois fonctionelle:
|
||
http://localhost:8080/syncope/rest/users
|
||
-> mire de login
|
||
renvoie un fichier XML
|
||
```
|
||
<?xml version="1.0"?>
|
||
<syncope2:pagedResult>
|
||
<page>1</page>
|
||
<result/>
|
||
<size>0</size>
|
||
<totalCount>0</totalCount>
|
||
</syncope2:pagedResult>
|
||
```
|
||
|
||
Ok il faudrait maintenant réussir à faire fonctionner le mécanisme de création d'un utilisateur
|
||
Pistes possibles
|
||
par d'accès en base, les données saisies par l'admin dans l'interface web backoffice ne peuvent être prises en compte
|
||
existe-t-il un mode de débug de la base ?
|
||
|
||
Le code de Syncope laisse à penser que l'ORM est hibernate...
|
||
Et pourtant très peu de références dans le code source :
|
||
```
|
||
$ grep -nri hibernate ./
|
||
Binary file ./.git/objects/pack/pack-e851cb26d72f0bc5c04cbcf88b6fb4514fcf1c1d.pack matches
|
||
./fit/core-reference/src/main/webapp/WEB-INF/jboss-deployment-structure.xml:33: <module name="org.hibernate"/>
|
||
./CHANGES:362: * [SYNCOPE-764] - Replace Hibernate Validator with Apache BVal
|
||
```
|
||
|
||
Pourquoi Jboss alors que toute la doc parle de tomcat ?
|
||
Pas très clair tout ça
|
||
|
||
``` xml
|
||
<?xml version="1.0" encoding="UTF-8"?>
|
||
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
|
||
<deployment>
|
||
<exclude-subsystems>
|
||
<subsystem name="webservices"/>
|
||
<subsystem name="jaxrs"/>
|
||
</exclude-subsystems>
|
||
<dependencies>
|
||
<module name="org.apache.xalan"/>
|
||
</dependencies>
|
||
<exclusions>
|
||
<module name="javax.ws.rs.api"/>
|
||
<module name="org.apache.cxf"/>
|
||
<module name="org.apache.cxf.impl"/>
|
||
<module name="org.hibernate"/>
|
||
<module name="org.slf4j"/>
|
||
<module name="org.slf4j.impl"/>
|
||
<module name="org.apache.log4j"/>
|
||
<module name="org.jboss.log4j.logmanager"/>
|
||
</exclusions>
|
||
</deployment>
|
||
</jboss-deployment-structure>
|
||
```
|
||
dans la section exclusions
|
||
red herring
|
||
|
||
Réessayons de lancer l'appli avec un cronjob de synchronisation
|
||
|
||
On dirait que le chargement des archives java se fait de façon 'lazy' par tomcat : la première initialisation prend plusieurs dizaines de secondes
|
||
|
||
pas seulement un blocage de l'action, même le bouton 'Cancel' ne fonctionne pas
|
||
|
||
défin
|
||
|
||
bug :
|
||
inversion des classes auxiliaires proposées pour la création des entités,
|
||
baseUser pour la création d'un groupe
|
||
vs
|
||
baseGroup pour la création d'un utilisateur
|
||
|
||
FIX : bug frontend de la Web UI seulement
|
||
|
||
Ok la prochaine étape est réellement la synchronisation en tant que telle
|
||
L'interface n'est pas clair du tout, il va falloir aller chercher de la doc
|
||
|
||
Support des workflows dans apache syncope, avec possibilité d'éditer directement le fichier XML
|
||
|
||
``` xml
|
||
"License"); you may not use this file except in compliance
|
||
with the License. You may obtain a copy of the License at
|
||
|
||
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
||
Unless required by applicable law or agreed to in writing,
|
||
software distributed under the License is distributed on an
|
||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||
KIND, either express or implied. See the License for the
|
||
specific language governing permissions and limitations
|
||
under the License.
|
||
-->
|
||
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||
xmlns:activiti="http://activiti.org/bpmn"
|
||
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
|
||
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
|
||
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
|
||
typeLanguage="http://www.w3.org/2001/XMLSchema"
|
||
expressionLanguage="http://www.w3.org/1999/XPath"
|
||
targetNamespace="http://activiti.org/bpmn20">
|
||
|
||
<process id="userWorkflow" name="User Workflow" isExecutable="true">
|
||
<startEvent id="theStart"/>
|
||
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="create"/>
|
||
<serviceTask id="create" name="Create" activiti:expression="#{create.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="flow2" sourceRef="create" targetRef="activate"/>
|
||
<scriptTask id="activate" name="Activate" scriptFormat="groovy" activiti:autoStoreVariables="false">
|
||
<script>execution.setVariable("propagateEnable", Boolean.TRUE);</script>
|
||
</scriptTask>
|
||
<sequenceFlow id="flow3" sourceRef="activate" targetRef="active"/>
|
||
<userTask id="active" name="Active"/>
|
||
<sequenceFlow id="flow8" sourceRef="active" targetRef="activeGw"/>
|
||
<exclusiveGateway id="activeGw"/>
|
||
<sequenceFlow id="active2Update" sourceRef="activeGw" targetRef="update">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 'update'}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<sequenceFlow id="active2Suspend" sourceRef="activeGw" targetRef="suspend">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 'suspend'}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<sequenceFlow id="active2Delete" sourceRef="activeGw" targetRef="delete">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 'delete'}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<sequenceFlow id="active2RequestPasswordReset" sourceRef="activeGw" targetRef="generateToken4PasswordReset">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 'requestPasswordReset'}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<sequenceFlow id="active2ConfirmPasswordReset" sourceRef="activeGw" targetRef="checkToken4ConfirmPasswordReset">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 'confirmPasswordReset'}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<serviceTask id="update" name="Update" activiti:expression="#{update.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="sid-EA22026A-25F0-4ED0-AB6E-9CE9CE74623C" sourceRef="update" targetRef="active"/>
|
||
<serviceTask id="suspend" name="Suspend" activiti:expression="#{suspend.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="flow10" sourceRef="suspend" targetRef="suspended"/>
|
||
<userTask id="suspended" name="Suspended"/>
|
||
<sequenceFlow id="flow11" sourceRef="suspended" targetRef="suspendedGw"/>
|
||
<exclusiveGateway id="suspendedGw"/>
|
||
<sequenceFlow id="suspended2Reactivate" sourceRef="suspendedGw" targetRef="reactivate">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 'reactivate'}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<sequenceFlow id="suspended2Delete" sourceRef="suspendedGw" targetRef="delete">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 'delete'}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<serviceTask id="reactivate" name="Reactivate" activiti:expression="#{reactivate.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="flow12" sourceRef="reactivate" targetRef="active"/>
|
||
|
||
<serviceTask id="generateToken4PasswordReset" name="Generate Token" activiti:expression="#{generateToken.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="sid-7F78CE07-A7A1-467F-BB4B-40FB234AEFF7" sourceRef="generateToken4PasswordReset" targetRef="notify4RequestPasswordReset"/>
|
||
<serviceTask id="notify4RequestPasswordReset" name="Notification" activiti:expression="#{notify.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="sid-CF9ACA40-7750-47C3-A508-7250D24D4F1F" sourceRef="notify4RequestPasswordReset" targetRef="active"/>
|
||
|
||
<serviceTask id="checkToken4ConfirmPasswordReset" name="Check token, remove and update password" activiti:expression="#{passwordReset.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="sid-3E9FE01D-CC60-4A95-B356-CA0DC000FAD6" sourceRef="checkToken4ConfirmPasswordReset" targetRef="notify4ConfirmPasswordReset"/>
|
||
<serviceTask id="notify4ConfirmPasswordReset" name="Notification" activiti:expression="#{notify.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="sid-A37806A7-6B7B-48A2-BB37-DAE640231144" sourceRef="notify4ConfirmPasswordReset" targetRef="active"/>
|
||
|
||
<serviceTask id="delete" name="Delete" activiti:expression="#{delete.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="flow99" sourceRef="delete" targetRef="theEnd"/>
|
||
<!-- Recertification tasks -->
|
||
<userTask id="recertificationRequest" name="Recertification Request" activiti:formKey="recertify">
|
||
<extensionElements>
|
||
<activiti:formProperty id="fullname" name="Identity" type="string" expression="${user.getPlainAttr('fullname').getUniqueValue().getStringValue()}" writable="false"/>
|
||
<activiti:formProperty id="username" name="Username" type="string" expression="${user.username}" writable="false"/>
|
||
<activiti:formProperty id="approve" name="Recertify?" type="boolean" required="true"/>
|
||
<activiti:formProperty id="rejectReason" name="Reason for not recertifying" type="string" variable="rejectReason"/>
|
||
</extensionElements>
|
||
</userTask>
|
||
<serviceTask id="recertify-task" name="Recertify" activiti:expression="#{recertify.execute(execution.processInstanceId)}"/>
|
||
<sequenceFlow id="recert-request-start-flow" sourceRef="activeGw" targetRef="recertificationRequest">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${task == 'request-certify'}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<exclusiveGateway id="recert-condition"/>
|
||
<sequenceFlow id="recert-flow1" sourceRef="recertificationRequest" targetRef="recertify-task"/>
|
||
<sequenceFlow id="recert-flow2" sourceRef="recertify-task" targetRef="recert-condition"/>
|
||
<sequenceFlow id="recert-approved-flow" sourceRef="recert-condition" targetRef="active">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${approve}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<sequenceFlow id="recert-denied-flow" sourceRef="recert-condition" targetRef="suspend">
|
||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${!approve}]]></conditionExpression>
|
||
</sequenceFlow>
|
||
<!-- End Recertification flow -->
|
||
<endEvent id="theEnd"/>
|
||
</process>
|
||
|
||
<bpmndi:BPMNDiagram id="BPMNDiagram_userWorkflow">
|
||
<bpmndi:BPMNPlane bpmnElement="userWorkflow" id="BPMNPlane_userWorkflow">
|
||
<bpmndi:BPMNShape bpmnElement="recertificationRequest" id="BPMNShape_recertificationRequest">
|
||
<omgdc:Bounds height="80.0" width="100.0" x="1370.0" y="375.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="recertify-task" id="BPMNShape_recertify-task">
|
||
<omgdc:Bounds height="80.0" width="100.0" x="1230.0" y="375.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="recert-condition" id="BPMNShape_recert-condition">
|
||
<omgdc:Bounds height="39.99999999999994" width="40.0" x="1178.1817939458806" y="475.4545368832992"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="theStart" id="BPMNShape_theStart">
|
||
<omgdc:Bounds height="30.0" width="30.0" x="540.0" y="525.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="create" id="BPMNShape_create">
|
||
<omgdc:Bounds height="60.00000000000006" width="100.0" x="620.0" y="509.99999999999994"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="active" id="BPMNShape_active">
|
||
<omgdc:Bounds height="60.0" width="100.0" x="1030.0" y="511.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="activeGw" id="BPMNShape_activeGw">
|
||
<omgdc:Bounds height="40.0" width="40.0" x="1400.0" y="520.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="update" id="BPMNShape_update">
|
||
<omgdc:Bounds height="60.0" width="100.0" x="1370.0" y="615.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="suspend" id="BPMNShape_suspend">
|
||
<omgdc:Bounds height="60.0" width="100.0" x="1490.0" y="370.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="suspended" id="BPMNShape_suspended">
|
||
<omgdc:Bounds height="60.0" width="100.0" x="1640.0" y="370.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="suspendedGw" id="BPMNShape_suspendedGw">
|
||
<omgdc:Bounds height="40.0" width="40.0" x="1820.0" y="380.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="reactivate" id="BPMNShape_reactivate">
|
||
<omgdc:Bounds height="60.0" width="100.0" x="1940.0" y="290.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="generateToken4PasswordReset" id="BPMNShape_generateToken4PasswordReset">
|
||
<omgdc:Bounds height="81.0" width="121.0" x="1515.0" y="604.5"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="notify4RequestPasswordReset" id="BPMNShape_notify4RequestPasswordReset">
|
||
<omgdc:Bounds height="81.0" width="121.0" x="1515.0" y="750.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="checkToken4ConfirmPasswordReset" id="BPMNShape_checkToken4ConfirmPasswordReset">
|
||
<omgdc:Bounds height="81.0" width="121.0" x="1725.0" y="664.5"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="notify4ConfirmPasswordReset" id="BPMNShape_notify4ConfirmPasswordReset">
|
||
<omgdc:Bounds height="81.0" width="121.0" x="1725.0" y="810.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="delete" id="BPMNShape_delete">
|
||
<omgdc:Bounds height="60.0" width="100.0" x="1940.0" y="438.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="theEnd" id="BPMNShape_theEnd">
|
||
<omgdc:Bounds height="28.0" width="28.0" x="2080.0" y="451.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNShape bpmnElement="activate" id="BPMNShape_activate">
|
||
<omgdc:Bounds height="80.0" width="100.0" x="828.286878319943" y="500.0"/>
|
||
</bpmndi:BPMNShape>
|
||
<bpmndi:BPMNEdge bpmnElement="recert-approved-flow" id="BPMNEdge_recert-approved-flow">
|
||
<omgdi:waypoint x="1194.0489013105641" y="511.3216442479827"/>
|
||
<omgdi:waypoint x="1194.0489013105641" y="541.0"/>
|
||
<omgdi:waypoint x="1130.0" y="541.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="recert-flow2" id="BPMNEdge_recert-flow2">
|
||
<omgdi:waypoint x="1280.0" y="455.0"/>
|
||
<omgdi:waypoint x="1280.0" y="495.45453688329917"/>
|
||
<omgdi:waypoint x="1218.1817939458806" y="495.45453688329917"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="recert-flow1" id="BPMNEdge_recert-flow1">
|
||
<omgdi:waypoint x="1370.0" y="415.0"/>
|
||
<omgdi:waypoint x="1330.0" y="415.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="recert-denied-flow" id="BPMNEdge_recert-denied-flow">
|
||
<omgdi:waypoint x="1198.1817939458806" y="475.4545368832992"/>
|
||
<omgdi:waypoint x="1198.1817939458806" y="313.6363529725508"/>
|
||
<omgdi:waypoint x="1540.0" y="313.6363529725508"/>
|
||
<omgdi:waypoint x="1540.0" y="370.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12">
|
||
<omgdi:waypoint x="1990.0" y="290.0"/>
|
||
<omgdi:waypoint x="1990.0" y="261.0"/>
|
||
<omgdi:waypoint x="1080.0" y="261.0"/>
|
||
<omgdi:waypoint x="1080.0" y="511.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11">
|
||
<omgdi:waypoint x="1740.0" y="400.0"/>
|
||
<omgdi:waypoint x="1820.0" y="400.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">
|
||
<omgdi:waypoint x="1590.0" y="400.0"/>
|
||
<omgdi:waypoint x="1640.0" y="400.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="active2Suspend" id="BPMNEdge_active2Suspend">
|
||
<omgdi:waypoint x="1440.0" y="540.0"/>
|
||
<omgdi:waypoint x="1540.0" y="540.0"/>
|
||
<omgdi:waypoint x="1540.0" y="430.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="sid-A37806A7-6B7B-48A2-BB37-DAE640231144" id="BPMNEdge_sid-A37806A7-6B7B-48A2-BB37-DAE640231144">
|
||
<omgdi:waypoint x="1725.0" y="850.4571226080794"/>
|
||
<omgdi:waypoint x="1080.0" y="850.0"/>
|
||
<omgdi:waypoint x="1080.0" y="571.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="suspended2Delete" id="BPMNEdge_suspended2Delete">
|
||
<omgdi:waypoint x="1860.0" y="400.0"/>
|
||
<omgdi:waypoint x="1990.0" y="400.0"/>
|
||
<omgdi:waypoint x="1990.0" y="438.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="active2RequestPasswordReset" id="BPMNEdge_active2RequestPasswordReset">
|
||
<omgdi:waypoint x="1440.0" y="540.0"/>
|
||
<omgdi:waypoint x="1575.0" y="540.0"/>
|
||
<omgdi:waypoint x="1575.307142857143" y="604.5"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="active2Delete" id="BPMNEdge_active2Delete">
|
||
<omgdi:waypoint x="1440.0" y="540.0"/>
|
||
<omgdi:waypoint x="1990.0" y="540.0"/>
|
||
<omgdi:waypoint x="1990.0" y="498.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
|
||
<omgdi:waypoint x="720.0" y="540.0"/>
|
||
<omgdi:waypoint x="828.286878319943" y="540.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="sid-3E9FE01D-CC60-4A95-B356-CA0DC000FAD6" id="BPMNEdge_sid-3E9FE01D-CC60-4A95-B356-CA0DC000FAD6">
|
||
<omgdi:waypoint x="1785.5" y="745.5"/>
|
||
<omgdi:waypoint x="1785.5" y="810.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="sid-7F78CE07-A7A1-467F-BB4B-40FB234AEFF7" id="BPMNEdge_sid-7F78CE07-A7A1-467F-BB4B-40FB234AEFF7">
|
||
<omgdi:waypoint x="1575.5" y="685.5"/>
|
||
<omgdi:waypoint x="1575.5" y="750.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="sid-EA22026A-25F0-4ED0-AB6E-9CE9CE74623C" id="BPMNEdge_sid-EA22026A-25F0-4ED0-AB6E-9CE9CE74623C">
|
||
<omgdi:waypoint x="1370.0" y="645.0"/>
|
||
<omgdi:waypoint x="1080.0" y="645.0"/>
|
||
<omgdi:waypoint x="1080.0" y="571.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
|
||
<omgdi:waypoint x="570.0" y="540.0"/>
|
||
<omgdi:waypoint x="620.0" y="540.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="active2ConfirmPasswordReset" id="BPMNEdge_active2ConfirmPasswordReset">
|
||
<omgdi:waypoint x="1440.0" y="540.0"/>
|
||
<omgdi:waypoint x="1785.0" y="540.0"/>
|
||
<omgdi:waypoint x="1785.3772727272726" y="664.5"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
|
||
<omgdi:waypoint x="928.286878319943" y="540.2478767845322"/>
|
||
<omgdi:waypoint x="1030.0" y="540.7521232154678"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="sid-CF9ACA40-7750-47C3-A508-7250D24D4F1F" id="BPMNEdge_sid-CF9ACA40-7750-47C3-A508-7250D24D4F1F">
|
||
<omgdi:waypoint x="1515.0" y="790.4389505549949"/>
|
||
<omgdi:waypoint x="1080.0" y="790.0"/>
|
||
<omgdi:waypoint x="1080.0" y="571.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="suspended2Reactivate" id="BPMNEdge_suspended2Reactivate">
|
||
<omgdi:waypoint x="1860.0" y="400.0"/>
|
||
<omgdi:waypoint x="1902.0" y="400.0"/>
|
||
<omgdi:waypoint x="1902.0" y="320.0"/>
|
||
<omgdi:waypoint x="1940.0" y="320.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="flow99" id="BPMNEdge_flow99">
|
||
<omgdi:waypoint x="2040.0" y="466.5576923076923"/>
|
||
<omgdi:waypoint x="2080.005821071606" y="465.40367823831906"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
|
||
<omgdi:waypoint x="1130.0" y="540.8529411764706"/>
|
||
<omgdi:waypoint x="1400.058651026393" y="540.0586510263929"/>
|
||
</bpmndi:BPMNEdge>
|
||
<bpmndi:BPMNEdge bpmnElement="active2Update" id="BPMNEdge_active2Update">
|
||
<omgdi:waypoint x="1420.0" y="560.0"/>
|
||
<omgdi:waypoint x="1420.0" y="615.0"/>
|
||
</bpmndi:BPMNEdge>
|
||
</bpmndi:BPMNPlane>
|
||
</bpmndi:BPMNDiagram>
|
||
</definitions>
|
||
```
|
||
|
||
Utilisation du namespace XML BPMN (Business Process Model Notation)
|
||
|
||
### ForgeRock
|
||
Creuser les revendications de www.timeforafork.com -> les licenses des outils ForgeRock auraient changé
|
||
|
||
### LSC
|
||
|
||
$ ./lsc-sample --run
|
||
Running "/home/paul/devel/lsc-2.1.3/sample/hsqldb/bin/./../../../bin/lsc" --config "/home/paul/devel/lsc-2.1.3/sample/hsqldb/bin/./../etc" --synchronize all --clean all
|
||
May 02 17:55:37 - INFO - Logging configuration successfully loaded from /home/paul/devel/lsc-2.1.3/sample/hsqldb/bin/./../etc/logback.xml
|
||
May 02 17:55:37 - INFO - LSC configuration successfully loaded from /home/paul/devel/lsc-2.1.3/sample/hsqldb/bin/./../etc/
|
||
May 02 17:55:37 - INFO - Connecting to LDAP server ldap://localhost:33389/dc=lsc-project,dc=org as cn=Directory Manager
|
||
May 02 17:55:37 - ERROR - Error opening the LDAP connection to the destination! (javax.naming.CommunicationException: localhost:33389 [Root exception is java.net.ConnectException: Connection refused (Connection refused)])
|
||
May 02 17:55:37 - ERROR - org.lsc.exception.LscConfigurationException: Configuration exception: javax.naming.CommunicationException: localhost:33389 [Root exception is java.net.ConnectException: Connection refused (Connection refused)]
|
||
|
||
Pourquoi d'autres commandes fonctionnent ?
|
||
Options de débug ?
|
||
|
||
Pour l'instant, HSQLDB n'est pas installé
|
||
|
||
java -jar sqltool.jar
|
||
|
||
On peut lancer une GUI d'administration de la base par
|
||
|
||
java -cp ../lib/hsqldb.jar org.hsqldb.util.DatabaseManagerSwing
|
||
|
||
ou
|
||
|
||
java -cp ../lib/hsqldb.jar org.hsqldb.util.DatabaseManager
|
||
|
||
(Swing obsolete)
|
||
|
||
type de stockage
|
||
mem, file, res
|
||
|
||
la lib ne semble pas nécessaire à l'utilisation de LSC
|
||
|
||
chercher ailleurs l'origine du 'Connection refused'
|
||
|
||
Essai avec un serveur postgres:
|
||
Etape 1) Installation PostgreSQL JDBC servcer : aller chercher le JAR et le déployer
|
||
|
||
tcpip_socket = true in the postgresql.conf file.
|
||
|
||
C'est parti : première connexion à un annuaire LDAP :
|
||
|
||
<lsc>
|
||
<connections>
|
||
<ldapConnection>
|
||
<name>ldap-dst-conn</name>
|
||
<url>ldap://spare.entrouvert.lan:389/dc=entrouvert,dc=lan</url>
|
||
<username>cn=admin</username>
|
||
<password>test</password>
|
||
<authentication>SIMPLE</authentication>
|
||
<referral>IGNORE</referral>
|
||
<derefAliases>NEVER</derefAliases>
|
||
<version>VERSION_3</version>
|
||
<pageSize>-1</pageSize>
|
||
<factory>com.sun.jndi.ldap.LdapCtxFactory</factory>
|
||
<tlsActivated>false</tlsActivated>
|
||
</ldapConnection>
|
||
</connections>
|
||
</lsc>
|
||
|
||
TODO écriture d'un JavaBean pour la prise en charge des tâches de synchro ?
|
||
SimpleBean, OrderedValuesBean ?
|
||
|
||
|
||
Qu'est-ce qui est déjà mis à disposition de l'utilisateur ?
|
||
Mécanisme de paramétrage de tâches pour la synchro
|
||
|
||
cleanHook pour l'opération de nettoyage
|
||
syncHook pour l'opération de synchro
|
||
|
||
Il faut par ailleurs définir une ou plusieurs règles de synchro
|
||
|
||
lsc>tasks>task>propertiesBasedSyncOptions
|
||
Par exemple, possibilité d'imposer des conditions à remplir pour que la sycnhronisation ait lieu :
|
||
<conditions>
|
||
<create>1 > 0</create>
|
||
<update>srcBean.getDatasetFirstValueById
|
||
('updateTimeStamp') > dstBean.getDatasetFirstValueById('updateTimeStamp')</update>
|
||
<delete>false</delete>
|
||
<changeId>false</changeId>
|
||
</conditions>
|
||
|
||
Fonctionnalité d'audit, au format CSV ou LDIF (? pour garder les logs dans le LDAP ?)
|
||
|
||
Fonctionnalité de chiffrement
|
||
keyfile
|
||
AES 128 par défaut
|
||
|
||
Notion intéressante d'appender pour les logs
|
||
Utilisation de logback, serveur de logs en Java
|
||
|
||
§ Script
|
||
langages JS ou Groovy
|
||
|
||
modes synchrones, asynchrones ou de nettoyage
|
||
|
||
création d'un script initd
|
||
pidfile
|
||
JMX (Java Management Extensions)
|
||
|
||
Création d'une 'sandbox' sur virtualbox pour s'amuser un peu avec LSC ?
|
||
OK
|
||
Installation de LSC et de slapd
|
||
Synchro de plusieurs branches entre elles
|
||
|
||
Ok VM en place avec serveur ssh
|
||
|
||
Déploiement d'un nginx/gunicorn pour l'IDP sur la sandbox
|
||
Maintenant : déployer deux implémentations différentes de LDAP ?
|
||
L'une avec OpenLDAP et l'autre ApacheDS ?
|
||
Ecriture d'un petit script de sychro avec le daemon lsc ?
|
||
|
||
```
|
||
ldapsearch -D "cn=admin,dc=eosandbox,dc=amok" -w test -p 389 -h localhost -b "dc=eosandbox,dc=amok" -s sub "(ObjectClass=*)" * +
|
||
```
|
||
|
||
Maintenant, essayons
|
||
'Synchronize from CSV to LDAP directory'
|
||
|
||
6192 [main] ERROR org.lsc.opendj.LdapServer - org.opends.server.util.LDIFException: Entry dc=lsc-project,dc=org read from LDIF starting at line 1 is not valid because it violates the server's schema configuration: Entry dc=lsc-project,dc=org violates the Directory Server schema configuration because it does not include a structural objectclass. All entries must contain a structural objectclass
|
||
|
||
Voir si le serveur LDAP tourne en dépit de l'erreur ?
|
||
Sinon aller chercher dans le script le LDIF et corriger l'erreur ?
|
||
|
||
Ok on relance le serveur, et on essaie avec les credentials:
|
||
URL: ldap://localhost:33389/
|
||
Base DN: dc=lsc-project,dc=org
|
||
Bind DN: cn=Directory Manager
|
||
Password: secret
|
||
|
||
$ bin/lsc-sample --show
|
||
ID UID ENDOFVALIDITY SN CN GIVENNAME MAIL O ADDRESS TELEPHONENUMBER CARLICENSE
|
||
-- ------------- ------------- ----------- ---------------------------- --------------- --------------------------- --------- --------------------------------------- -------------------- -------------
|
||
1 j.clarke 31/12/2015 Clarke Clarke, Jonathan Jonathan jonathan@philipoux.net Normation [null] +33 (0)1 83 62 26 96 BHU772|DED899
|
||
2 r.schermesser 31/12/2015 Schermesser Schermesser, Remy-Christophe Remy-Christophe remy@schermesser.com Octo [null] [null] [null]
|
||
3 t.chemineau 31/12/2015 Chemineau Chemineau, Thomas Thomas thomas@aepik.net AFNOR [null] [null] [null]
|
||
4 s.bahloul 31/12/2015 Bahloul Bahloul, Sebastien Sebastien sebastien.bahloul@gmail.com Dictao 156 av. de Malakof, 75116 PARIS, France [null] [null]
|
||
5 c.oudot 31/12/2015 Oudot Oudot, Clement Clement clem.oudot@gmail.com Linagora [null] 33(0)810251251 [null]
|
||
6 r.ouazana 31/12/2015 Ouazana Ouazana, Raphael Raphael rouazana@linagora.com Linagora [null] 33(0)810251251 [null]
|
||
7 d.coutadeur 31/12/2015 Coutadeur Coutadeur, David David dcoutadeur@linagora.com Linagora [null] 33(0)810251251 [null]
|
||
8 e.pereira 31/12/2015 Pereira Pereira, Esteban Esteban epereira@linagora.com Linagora [null] 33(0)810251251 [null]
|
||
|
||
Fetched 8 rows.
|
||
|
||
|
||
Mais l'appli plante
|
||
l'entrée
|
||
`tcp6 0 0 :::33389 :::* LISTEN 17557/java`
|
||
termine bel et bien
|
||
|
||
|
||
Ok: le LDIF doit être modifié
|
||
On ajoute 'objectClass: organization' dans la définition de l'entrée racine (fichier test.ldif)
|
||
|
||
Ok ça tourne maintenant
|
||
Reessayons
|
||
|
||
|
||
L'une des particularités de LDAP : la configuration est auto-contenue
|
||
OpenDJ semble aussi stocker dans l'annuaire les règles à appliquer sur les
|
||
requêtes :
|
||
1155 dn: cn=Directory String First Component Equality Matching Rule,cn=Matching Rules,cn=config
|
||
1156 objectClass: top
|
||
1157 objectClass: ds-cfg-matching-rule
|
||
1158 objectClass: ds-cfg-equality-matching-rule
|
||
1159 cn: Directory String First Component Equality Matching Rule
|
||
1160 ds-cfg-java-class: org.opends.server.schema.DirectoryStringFirstComponentEqualityMatchingRuleFactory
|
||
1161 ds-cfg-enabled: true
|
||
|
||
|
||
```
|
||
$ ldapsearch -D "cn=Directory Manager" -w secret -p 33389 -h localhost -b "dc=lsc-projet,dc=org" -s sub "(ObjectClass=*)"
|
||
# extended LDIF
|
||
#
|
||
# LDAPv3
|
||
# base <dc=lsc-projet,dc=org> with scope subtree
|
||
# filter: (ObjectClass=*)
|
||
# requesting: ALL
|
||
#
|
||
|
||
# search result
|
||
search: 2
|
||
result: 32 No such object
|
||
text: The entry dc=lsc-projet,dc=org specified as the search base does not exis
|
||
t in the Directory Server
|
||
|
||
# numResponses: 1
|
||
```
|
||
|
||
lsc-sample --run pour lancer la synchro
|
||
|
||
OK
|
||
l'exemple de test fonctionne en trois étapes :
|
||
Première phase : $ bin/lsc-sample --import sample.csv
|
||
la création d'une base de données relationnelle contenant une
|
||
table remplie à partir d'un fichier csv.
|
||
Le SGBDR utilisé ici est HSQLDB
|
||
Le fichier csv présente une première ligne permettant le nommage des attributs
|
||
dans la base.
|
||
|
||
Seconde phase : $ bin/lsc-sample --start-ldap-server
|
||
Lancement du server LDAPv3 (implémentation OpenDJ)
|
||
Le serveur ne contient pour l'instant aucune données
|
||
|
||
Troisième phase : $ bin/lsc-sample --run
|
||
Réconciliation des données entre la base de données relationnelle et l'annuaire
|
||
LDAP.
|
||
Pour comprendre comment est effectuée cette synchronisation, il faut étudier
|
||
le fichier de synchronisation fourni avec l'exemple.
|
||
Il s'agit du fichier lsc.xml
|
||
La configuration commence par une liste des différentes connexions que LSC doit
|
||
prendre en charge.
|
||
Ici, logiquement, seule deux connexions sont assurées par LSC:
|
||
|
||
```
|
||
<ldapConnection>
|
||
<name>dst-ldap</name>
|
||
<url>ldap://localhost:33389/dc=lsc-project,dc=org</url>
|
||
<username>cn=Directory Manager</username>
|
||
<password>secret</password>
|
||
<authentication>SIMPLE</authentication>
|
||
<referral>IGNORE</referral>
|
||
<derefAliases>NEVER</derefAliases>
|
||
<version>VERSION_3</version>
|
||
<pageSize>-1</pageSize>
|
||
<factory>com.sun.jndi.ldap.LdapCtxFactory</factory>
|
||
<tlsActivated>false</tlsActivated>
|
||
<saslMutualAuthentication>false</saslMutualAuthentication>
|
||
</ldapConnection>
|
||
```
|
||
On constate qu'il s'agit des principaux paramètres à fournir lors d'une tentative de connexion à un serveur LDAPv3.
|
||
Pas d'authentification mutuelle, pas de chiffrement TLS.
|
||
L'option factory pour la déclaration du module de gestion des contextes de connexion.
|
||
Pas de déréférencement des alias.
|
||
Protocole, hôte, port et DN de base précisés en une seule ligne:
|
||
ldap://localhost:33389/dc=lsc-project,dc=org
|
||
|
||
Côté base de données, une configuration plus succincte permet l'établissement de la connexion.
|
||
<databaseConnection>
|
||
<name>src-jdbc</name>
|
||
<url>jdbc:hsqldb:file:/tmp/lsc/hsqldb/lsc</url>
|
||
<username>sa</username>
|
||
<password></password>
|
||
<driver>org.hsqldb.jdbcDriver</driver>
|
||
</databaseConnection>
|
||
Pas de mot de passe requis
|
||
|
||
La partie suivante est plus intéressante, il s'agit des règles de synchronisation.
|
||
LSC peut prendre en charge plusieurs tâches de synchronisation à la fois, bien qu'une seule tâche est définie dans cet exemple.
|
||
Une fois la tâche nommée (MySyncTask), le chemin vers la classe Java en charge de l'opération de synchronisation est déclaré.
|
||
TODO: explication du code source du JavaBean
|
||
S'en suivent la déclaration des différentes méthodes pour la partie 'base source' de la synchronisation.
|
||
|
||
Côté cible, une fois déclaré le DN d'approvisionnement des entrées de la base, on peut définir la liste des attributs synchronisés.
|
||
Parmis eux doivent se trouver un ou plusieur attributs pivots, c'est-à-dire, un ou des attributs qui vont servir à LSC pour effectuer la correspondance entre les entrées de chacun de référentiels synchronisés.
|
||
L'ensemble de ces attributs pivot sert ainsi d'identifiant pour retrouver une même entité dans plusieurs référentiels.
|
||
//Pb: LSC permet-il des mécanismes de détection et de propagation des modifications de ces attributs pivots.
|
||
Jusque là il semble être clair que c'est l'unicité des attributs pivots à travers les différentes bases qui permet de détecter et propager les modifications sur les attributs secondaires, non pivots.
|
||
|
||
propertiesBasedSyncOptions définit la façon dont sera créé le DN d'une entrée LDAP à partir de l'adresse email dans la base de données relationnelle.
|
||
|
||
//CURRENT3
|
||
|
||
## Explications techniques Mik
|
||
|
||
Se concentrer sur l'étude de synchro et d'approvisionnement en tant que telle
|
||
La partie de mapping entre un événement déclenché et l'action WCS à effectuer mérite réflexions.
|
||
|
||
Dans quelle mesure le connecteur pourra être générique ?
|
||
Les mêmes règles ne s'appliqueront-elles pas à tous les connecteurs ?
|
||
|
||
Le connecteur est en fait utilisé en écriture seulement : il sert à des fins d'approvisionnement et de synchronisation
|
||
|
||
Pour la lecture, un simple script ou outil de polling sera utilisé
|
||
|
||
Une des problématiques centrales à cette étude est la façon d'éviter les boucles/effets de bords provoqués par les changements en cascade sur les différents référentiels. Une modification effectuée par le système d'approvisionnement et de synchro ne doit pas être confondue avec une modification externe, nécessitant une éventuelle synchro avec d'autre référentiels
|
||
|
||
Plusieurs solutions s'offrent à nous pour remédier à ce problème :
|
||
- garder une historique des actions (timestamp/horodatage) dans WCS pour ne pas les faire remonter lors du polling
|
||
Cette solution nécessite une synchronisation de l'horloge des différentes briques logicielles de l'infra
|
||
- utiliser un marqueur/flag du type `performedByWCS` pour chacunes des actions appliquées à un référentiel
|
||
Le système de polling ne concernera que les actions ne portant pas le marqueur
|
||
|
||
=> TODO aller chercher un ou plusieurs scenario de processus en entreprise justifiant un outil de synchro
|
||
Dans une deuxième phase, il faudra étudier ce qui serait déjà possible avec les outils EO tels quel
|
||
|
||
Recherche de scenarii de recours à la synchronisation :
|
||
- documentation Alfresco
|
||
- PapercutNG
|
||
- LSC
|
||
Pb : pas assez générique, pas d'expression des besoins de synchro
|
||
|
||
Lecture RFC4533 : LDAP Content Synchronization Operation
|
||
Considérations justifiant une spéc du mécanisme de synchro avec LDAP :
|
||
- pbatique de la convergence : comment s'assurer que les référentiels vont converger vers un état stable, sans données incohérentes
|
||
Différents problèmes se posent avec les solutions déjà existantes :
|
||
* le niveau de convergence souhaité ne peut être atteint
|
||
* l'impossibilité d'une convergence reste indétectable
|
||
* soit les hypothèses préalables à la synchro sont trop contraignantes
|
||
* nécessite le stockage d'un historique des changements côté serveur
|
||
* est à l'origine d'une quantité excessive d'informations échangées entre client et serveur
|
||
|
||
LDAP Sync simplement basé sur l'état actuel des serveurs, pas besoin d'un historique pour la reconstitution des modifications sur un des référentiels.
|
||
|
||
Cette RFC préconise aussi une optimisation en termes de quantité d'information nécessaire pour mener à bien la synchronisation.
|
||
|
||
Deux modes pour la détection des changements :
|
||
- le *polling mode* : caractère ponctuel, granulaire de l'écoute
|
||
Le serveur fournit un champ Sync State Control
|
||
- le mode *listening for changes* (refreshAndPersist)
|
||
|
||
Operation selon un mode client-serveur ?
|
||
TODO explication archi
|
||
+ explication des deux modes de connexion
|
||
|
||
**Usages possibles :**
|
||
- application de type 'pages blanches' qui souhaitent synchronisation une sous-partie (un DIT partiel, pour *Directory Information Tree*) d'un annuaire plus global.
|
||
- Moteur de méta-données récoltées par opérations de synchro sur des référentiels
|
||
- Service de proxy-cache nécessitant la synchronisation pour construction du cache
|
||
- Simple process esclave/maître pour la réplication cachée d'un DIT partiel (*DIT fragment*). Alternative à X.500 DISP (Directory
|
||
|
||
### Elements entrant en jeu pour l'opération de synchronisation
|
||
- syncUUID (codé sur 128 bits)
|
||
- syncCookie
|
||
- Sync Request Control
|
||
- Sync State Control
|
||
- Sync Done Control
|
||
- Sync Information Message
|
||
- Sync Result Code
|
||
TODO explication fonctionnelle ou technique ? En quoi cela peut-il aider à la phase 2 de l'étude ?
|
||
|
||
### Synchronisation des contenus
|
||
TODO
|
||
Déclenchement de l'opération de synchronisation:
|
||
Le serveur reçoit un message de type SearchRequest contenant un Search Request Control (cf plus haut TODO)
|
||
|
||
La détection d'une session déjà existante se fait par vérification de la présence d'un cookie dans la SearchRequest.
|
||
|
||
==========
|
||
|
||
//EN COURS
|
||
TODO
|
||
Plan
|
||
Schémas
|
||
Mise au propre
|
||
Puis retour au travail technique
|
||
|
||
Découper en deux
|
||
Description de l'existant
|
||
Décrire fonctionnellement ce que l'on souhaite faire au niveau de la synchro Schémas du même type que ce qu'on a fait avec le campus condorcet (Diagramme de séquence, de flux : (RH, AD, téléphonie, méta-annuaire, outil de synchro, agent => 6 lignes)
|
||
Puis on parlera des pbatiques techniques
|
||
|
||
=> Découpage en trois
|
||
|
||
|
||
Plan : partie 3 : "cas d'usages " - pbatique du stage, répondre à un besoin"""
|
||
Commencer par une partie cas d'usage => aspect fonctionnel
|
||
Etat de l'art : étude des différents techno
|
||
Préliminaires de la GI
|
||
= synthèse d'une page maxi sur les différents aspects, renvoyer vers les annexes pour les études détaillées
|
||
|
||
Partie 4 ajoutée Etat de l'art de la GI
|
||
Etat de l'art sur la snchro et l'approvisionnement
|
||
|
||
Partie 5 Prise en main des technos
|
||
DJango
|
||
wcs passerelle
|
||
les API rest
|
||
|
||
Partie 6 : Mise en oeuvre et realisations
|
||
Chap 1 démonstrateur avec LSC
|
||
Chap 2 développement spécifique cas campus condorcet, gestion des comptes invités
|
||
chap 3 analyse de la couverture du besoin par les outils entr'ouvert
|
||
architecture cible
|
||
développements nécessaires
|
||
|
||
Synthèse technique (deux pages)
|
||
|
||
Conclusion (plus sur l'aspect stage)
|
||
|
||
Annnexes
|
||
acronymes
|
||
bibliographie (titre, source, date, auteurs)
|
||
extrait de code source (il faut que ce soit pertinent, ou URLs vers un dépot public)
|
||
diagramme et schémas ? Non dans les corps de chap
|
||
|
||
### Exemple "haut-niveau"
|
||
//TODO doc commerciale des concurrents
|
||
Cas d'usage pour la doc fonctionnelle
|
||
A titre comparatif, la doc openidm est pas assez 'haut niveau'
|
||
|
||
Retour documentation midPoint :
|
||
page 26: exemple complet IDM avec cas de synchro sur plusieurs bases d'identités
|
||
creation
|
||
modif avec répercussions dans les différentes bases
|
||
suppression
|
||
changement des droits
|
||
|
||
L'exemple, bien que non retenu pour l'étude expérimentale, présente certains point intéressants, méritants d'être détaillés ici :
|
||
|
||
**Phase 1 :**
|
||
La procédure de synchro est effectuée par ajout d'une entrée dans le référentiel des ressources humaines. Cet ajout résulte de l'embauche d'une nouvelle employée.
|
||
Le système est en charge de la génération d'attributs pour d'autres référentiels : la création d'un identifiant unique global est effectuée à partir du nom d'utilisateur local à la base RH.
|
||
A la création de l'identifiant est associé l'ajout d'une entrée dans la base du gestionnaire d'identités (IDM).
|
||
A ensuite lieu la récupération de l'identifiant organisationnel tel que renseigné lors de la création de l'entrée RH. Le gestionnaire d'identité peut ensuite déduire du service dans lequel se trouve la nouvelle employée.
|
||
Il est aussi en charge de l'association des privilèges/droits associés au rôle du service auquel appartient maintenant l'employée. Ces rôles sont déduits du service qu'a rejoint l'employée. L'annuaire du service est un Active Directory (AD).
|
||
L'ajout du compte est aussi accompagné de la création d'une boîte mail pour l'employée.
|
||
|
||
//Notion de groupes et de listes à étudier -> pour les mails seulement ?
|
||
Finalement, la procédure est complétée par la création d'une entrée dans le CRM, en accord avec la politiques de permissions associées au rôle obtenu par l'employée.
|
||
|
||
**Phase 2 :**
|
||
Dans cette phase, il est précisé que le gestionnaire d'identités peut effectuer une quelconque modification de privilèges indépendamment des rôles auxquels appartient un compte. Cette modification des privilèges résulte en la création d'un statut spécial, ne pouvant plus être défini comme la somme des rôles auxquels l'employée appartient.
|
||
On retrouve une fois de plus la notion de workflow pour le mécanisme de gestion des identités : la montée en privilège n'est effectuée qu'une fois les approbations du manager et du responsable technique obtenues.
|
||
De façon plus générale, l'aboutissement d'une demande de modifications de droits d'accèss nécessite l'action d'un opérateur (humain). Il s'agira ici d'un supérieur hiérarchique, lequel pourra accepter ou refuser la demande.
|
||
|
||
**Phase 3 :**
|
||
Nous partons ici du cas d'un changement de nom de l'employée. Ce changement a des répercussions, de façon automatique et en cascade, sur les différents référentiels locaux à chaque service ou à chaque application.
|
||
Par exemple, un changement de nom résulte logiquement en la création d'un nouvel alias d'adresse email. Cette création sera accompagnée de l'envoi d'un message de notification à l'employée concernant l'ajout de l'alias.
|
||
|
||
**Phase 4 :**
|
||
L'expiration du mot de passe du compte utilisateur est aussi un mécanisme pouvant être pris en charge par le gestionnaire d'identité. Après choix d'un nouveau mot de passe par l'employée, le gestionnaire d'identité est en charge d'appliquer les modifications dans toutes les bases.
|
||
Nous remarquons toutefois qu'à aucun moment on parle de SSO dans le cadre de cet exemple.
|
||
|
||
**Phase 5 :**
|
||
Nous pouvons maintenant nous intéresser à des cas particuliers survenant dans le domaine de la gestion des identités numériques. Les besoins en sécurité dans le système d'informations requièrent la détection d'incohérences dans l'attribution des droits. Cette détection, pour l'exemple donné dans le document //REF// est mise en place à la suite de soupçons concernant un vol de données.
|
||
Entre alors en compte la notion de traçabilité, en tant que possibilité d'identifier l'employé ayant attribué des droits excessifs à son subordonné à l'origine du vol de données.
|
||
Le système de gestion des permissions doit ainsi être en mesure de répondre aux question suivantes :
|
||
* Qui a attribué les droits ?
|
||
* A quelle date ces droits ont-ils été données ?
|
||
* Quelles actions ont été effectuées ensuite ?
|
||
|
||
La désactivation des droits est ensuite effectuée à l'aide du gestionnaire d'identités de façon centralisée, et est répercutée sur l'ensemble des référentiels d'identités.
|
||
|
||
**Phase 6 :**
|
||
Nous passons maintenant au cas de la suppression de l'un des deux comptes, et de la diminution des droits associés à l'autre compte. Encore une fois des contraintes de synchronisation sont nécessaires pour assurer la cohérence des référentiels d'identités entre eux. Il ne faut pas, par exemple, que le rétablissement d'une sauvegarde, sur un référentiel local, et antérieure à la modification, ait pour conséquence d'annuler la suppression du compte banni.
|
||
|
||
**Phase 7 :**
|
||
Il convient maintenant de décrire la procédure de mise en place d'une politique de sécurité, et ceci concernant en particulier la détection des droits incohérents, des comptes obsolètes ou n'ayant pas de propriétaire clairement identifié. Les besoins de sécurité impliquent la mise d'un processus de détection _périodique_ de ces incohérences.
|
||
//TODO essayer d'obtenir une estimation du temps nécessaire pour une telle détection, avec des paramètres standard ?
|
||
|
||
**Phase 8 :**
|
||
Ce mécanisme de sécurité aboutit à la création d'une politique de recertification des droits de employés par chacun de leurs managers. Pour chaque employé, les droits activés jusqu'à présent doivent être validés à nouveau par un des responsables de l'employé (habilité à octroyer les droits en question).
|
||
|
||
**Conclusion :**
|
||
Cet exemple met en scène différents concepts et processus pertinents dans le cadre de l'étude réalisée pour ce stage, notamment l'utilisation de *workflows*, et la synchronisation et l'approvisionnement à divers étapes du cycle de vie des données d'identités
|
||
L'étape suivante consistera à identifier les contraintes techniques nécessaire au déploiement de telles fonctionnalités de gestion des identités, et de déterminer les éventuelles modifications nécessaires aux outils EO pour la mise en place d'un tel scenario.
|
||
|
||
### Détails techniques GI
|
||
Un des concepts récurrents dans la gestion des identités est le RBAC (pour *Role-Based Access Control*). Ce terme est né des mécanismes souhaitant remédier aux inconvénients d'un contrôle d'accès par permissions simples.
|
||
Dans un modèle régi par une politique de sécurité de type RBAC, on n'attribue pas des permissions aux utilisateurs, seulement des rôles.
|
||
Une sécurisation des accès par RBAC présente deux principaux avantages :
|
||
- il est nettement plus simple de manipuler des privilèges en termes de *rôles*, cette granularité reflète naturellement la séparation des responsabilités au sein d'une organisation (au sens où les permissions sont rarement données individuellement, mais sont plutôt associées au poste occupé par chaque individu).
|
||
- ce modèle RBAC permet la factorisation des permissions à travers les rôles : c'est plus maintenable qu'un éclatement des permissions sur chaque utilisateur.
|
||
|
||
Nous précisons toutefois que des alternatives au modèle RBAC existent, l'une d'elle étant ABAC (*Attribute-Based Access Control*).
|
||
Ce mécanisme manipule un ensemble d'attributs permettant de générer à la volée les permissions ?
|
||
Les auteurs du document //REF// affirment toutefois qu'un contrôle de type ABAC n'est pas adapté dans le cadre d'un SI comportant un gestionnaire d'identités.
|
||
|
||
# Planification du stage
|
||
La planification du stage est réalisée à l'aide d'un ensemble de diagrammes de Gantt :
|
||
Ils sont au total au nombre de quatre, c'est-à-dire les diagrammes :
|
||
- prévisionnel, _i.e._ réalisé au début du stage
|
||
- réel. C'est celui qui est maintenu à jour tout au long du projet
|
||
- prévisionnel mi-parcours, réalisé à la moitié de la durée du projet
|
||
- final. C'est planning réel une fois le projet réalisé.
|
||
|
||
# Ecriture d'un connecteur Passerelle
|
||
La création d'un nouveau connecteur doit d'abord être précédée d'une phase de lecture du code de Passerelle, afin de comprendre la structuration des connecteurs fournis par l'application.
|
||
|
||
Choix d'un connecteur à dériver pour l'écriture du connecteur LDAP
|
||
|
||
Update :
|
||
L'outil Passerelle est pensé pour faciliter le développement de nouveaux connecteurs.
|
||
Seule l'écriture du fichier models.py est nécessaire. Il suffit de préciser les *endpoints* mis à disposition par le connecteur, et passerele se charge du code 'logique' (non métier) du connecteur.
|
||
|
||
# Mise au point technique
|
||
## Python
|
||
### Packing et unpacking
|
||
### Coding style
|
||
* keywork `linebreaks`
|
||
* `cleaned_data` pour les formulaires
|
||
* surcharge de `__unicode__` et `__str__` pour la description textuelle des données et objets Django.
|
||
|
||
"A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is the most important." (PEP8)
|
||
|
||
### Lecture du code source Authentic
|
||
|
||
### Sessions et pseudo-terminaux
|
||
#### tmux
|
||
Pb: bugs
|
||
#### screen
|
||
Possibilité de détacher les sessions
|
||
Plus puissant que tmux mais plus difficile d'utilisation
|
||
|
||
## Virtualisation
|
||
### Avantages
|
||
TODO Securité, portabilité, 'scalabilité' etc
|
||
### OpenVZ
|
||
Techno utilisée pour la virtualisation des serveurs sur la plateforme de développement (hébergée chez OVH)
|
||
OpenVZ implémenté sa propre version du noyau (on parle de noyau 'patché'), lui-même basé sur le noyau RHEL
|
||
Notion de VPS (*Virtual Private Server*) ou de VE (*Virtual Environment*)
|
||
Identification des conteneurs par attribution d'un VEID
|
||
VE IDentifier
|
||
|
||
Notion de "conteneurisation" : hôte et invités partagent un même noyau
|
||
|
||
Gestion des conteneurs par CLI (*Command-Line Interface*)
|
||
Utilitaire `vzctl {start, create, stop, exec, enter, set} <params>`
|
||
|
||
Bâti sur LXC ? cgroups ?
|
||
|
||
Création d'un conteneur suivant la technique de template cache :
|
||
Il s'agit d'un patron de système d'exploitation, nécessaire au déploiemend'un nouveau conteneur
|
||
|
||
TODO
|
||
OS template metadata
|
||
|
||
TODO en quoi cela diffère-t-il des 'recipes' Docker et Rocket ?
|
||
|
||
### Packaging
|
||
Cette section couvrira la méthode de packaging utilisée chez EO: création de paquets Debian pour les projets Django développés par l'équipe
|
||
l'outil utilisé pour la création de ces paquets .deb (cf deb.entrouvert.org) est dpkg-deb
|
||
Il a recours à l'utilitaire fakeroot (pourquoi ?)
|
||
|
||
Pour chaque projet, les scripts et metadonnées nécessaires à la création du paquet sont situées dans le fichier /debian
|
||
|
||
Les sources des projets EO fournissent aussi des exemples de fichier de configuration pour les services associées (Apache, nginx, gunicorn, systemd, postgresql) //TODO a verifier
|
||
|
||
#### Structure d'un paquet Debian
|
||
Le fichier *control* rassemble les méta-données du paquet
|
||
|
||
Scripts preinst, poistinst, prerm, postrm
|
||
|
||
commande dpkg-deb --build
|
||
|
||
|
||
## Linux screen
|
||
Abstraction des shells en session ssh, avec possibilité de séparer la fenêtre active en plusieurs shell, de détacher les screen de la session, afin de pouvoir les récupérer lors de la prochaine connexion.
|
||
|
||
## Connecteurs
|
||
### ConnId
|
||
Javadoc at http://connid.tirasa.net/apidocs/1.4/index.html
|
||
TODIG ?
|
||
|
||
## Puppet
|
||
Il s'agit d'un outil de gestion de config logicielle, utilisé pour l'automatisation du déploiement des serveurs.
|
||
Reprend les principes du contrôle de version du code pour l'adapter à la config serveur
|
||
Voir comment EO l'utilise pour le déploiement de ses serveurs de dev et de prod
|
||
|
||
## GnuPG (Privacy Guard)
|
||
|
||
Implémentation GNU de PGP (Pretty Good Privacy)
|
||
|
||
Lecture de la RFC : points remarquables :
|
||
```
|
||
compression has the added side effect that some types of
|
||
attacks can be thwarted by the fact that slightly altered, compressed
|
||
data rarely uncompresses without severe errors. This is hardly
|
||
rigorous, but it is operationally useful.
|
||
```
|
||
|
||
Radix-64 ~ ASCII Armor
|
||
|
||
Le chiffrement mais surtout la signature : fonctionnalité clé de GnuPG
|
||
|
||
Fonctionnalités de conversion S2K
|
||
(String to Key)
|
||
|
||
TODO Paramétrer la signature des messages avec GnuPG
|
||
La notion de fiabilité de la clé est définie par le nombre de certifications par des tiers.
|
||
|
||
|
||
|
||
## Config client VoIP
|
||
TODO
|
||
|
||
# Sources
|
||
https://shibboleth.net/
|
||
## Lues
|
||
## A lire
|
||
https://docs.djangoproject.com/fr/1.10/topics/settings/
|
||
http://support.novell.com/techcenter/articles/ana20011101.html
|
||
http://www.journaldunet.com/developpeur/xml/analyse/la-federation-d-identite-au-travers-de-saml.shtml
|
||
https://www.ietf.org/rfc/rfc4512.txt
|
||
https://docs.djangoproject.com/en/1.10/howto/custom-template-tags/#thread-safety-considerations
|
||
http://syncope.apache.org/docs/reference-guide.html
|
||
https://en.wikipedia.org/wiki/ALFA_%28XACML%29
|
||
https://en.wikipedia.org/wiki/List_of_LDAP_software
|
||
|
||
# Annexes
|
||
## Assertion SAML d'authentification (SAMLResponse IdP -> SP)
|
||
`<?xml version="1.0"?>`
|
||
`<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_CD4CC621A02FDE6054649B69E6DBCC41" InResponseTo="_A79D6A8E4A93A92D65EE570ECA571BDB" Version="2.0" IssueInstant="2017-02-15T14:14:04Z" Destination="http://localhost:8008/accounts/mellon/login/" Consent="urn:oasis:names:tc:SAML:2.0:consent:prior">`
|
||
` <saml:Issuer>http://localhost:8000/idp/saml2/metadata</saml:Issuer>`
|
||
` <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">\n<SignedInfo>\n<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>\n<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>\n<Reference URI="#_CD4CC621A02FDE6054649B69E6DBCC41">\n<Transforms>\n<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>\n<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>\n</Transforms>\n<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>\n<DigestValue>ozqrnvN5HCJ8jxnPK8oT8U/+sHk=</DigestValue>\n</Reference>\n</SignedInfo>\n<SignatureValue>Ccne2rcykuXTgGW8QSNCANcliOvvl854uyiwPXGTGYbKfDNrFq87HNmDDizLslDY\nZVETw6TdVRi6vKlHebW0uWO9F4XRy7o4qEGiIEhLLGe1MIz+PWKqd1G1FcoQcEVG\nojZioS1BfWxcySZrU/OXftIsW929wYeXV+FsHauihGolAp5tnf+e0es5Gk2kuawy\nLBSEoWtriXRVMpEDfl1BHM61Y1uzkpmeA221e07WLDLr/KuAf4PS0px7l8YUEDz4\nA87GHekQ8ar2OiS+9unJ9DhZ+qFzLeddb6IdxHqUfWkdmAdajGffAyvfefEcm5wp\njE2b6cQPv0xh530CEFRXUw==</SignatureValue>\n<KeyInfo>\n<X509Data>\n<X509Certificate>MIIDIzCCAgugAwIBAgIJANUBoick1pDpMA0GCSqGSIb3DQEBBQUAMBUxEzARBgNV\nBAoTCkVudHJvdXZlcnQwHhcNMTAxMjE0MTUzMzAyWhcNMTEwMTEzMTUzMzAyWjAV\nMRMwEQYDVQQKEwpFbnRyb3V2ZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAvxFkfPdndlGgQPDZgFGXbrNAc/79PULZBuNdWFHDD9P5hNhZn9Kqm4Cp\n06Pe/A6u+g5wLnYvbZQcFCgfQAEzziJtb3J55OOlB7iMEI/T2AX2WzrUH8QT8NGh\nABONKU2Gg4XiyeXNhH5R7zdHlUwcWq3ZwNbtbY0TVc+n665EbrfV/59xihSqsoFr\nkmBLH0CoepUXtAzA7WDYn8AzusIuMx3n8844pJwgxhTB7Gjuboptlz9Hri8JRdXi\nVT9OS9Wt69ubcNoM6zuKASmtm48UuGnhj8v6XwvbjKZrL9kA+xf8ziazZfvvw/VG\nTm+IVFYB7d1x457jY5zjjXJvNysoowIDAQABo3YwdDAdBgNVHQ4EFgQUeF8ePnu0\nfcAK50iBQDgAhHkOu8kwRQYDVR0jBD4wPIAUeF8ePnu0fcAK50iBQDgAhHkOu8mh\nGaQXMBUxEzARBgNVBAoTCkVudHJvdXZlcnSCCQDVAaInJNaQ6TAMBgNVHRMEBTAD\nAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAy8l3GhUtpPHx0FxzbRHVaaUSgMwYKGPhE\nIdGhqekKUJIx8et4xpEMFBl5XQjBNq/mp5vO3SPb2h2PVSks7xWnG3cvEkqJSOeo\nfEEhkqnM45b2MH1S5uxp4i8UilPG6kmQiXU2rEUBdRk9xnRWos7epVivTSIv1Ncp\nlG6l41SXp6YgIb2ToT+rOKdIGIQuGDlzeR88fDxWEU0vEujZv/v1PE1YOV0xKjTT\nJumlBc6IViKhJeo1wiBBrVRIIkKKevHKQzteK8pWm9CYWculxT26TZ4VWzGbo06j\no2zbumirrLLqnt1gmBDvDvlOwC/zAAyL4chbz66eQHTiIYZZvYgy</X509Certificate>\n</X509Data>\n</KeyInfo>\n</Signature>`
|
||
` <samlp:Status>`
|
||
` <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>`
|
||
` </samlp:Status>`
|
||
` <saml:Assertion Version="2.0" ID="_A86605DF1F9D51A8BD5EFB5F9B02A712" IssueInstant="2017-02-15T14:14:10Z">`
|
||
` <saml:Issuer>http://localhost:8000/idp/saml2/metadata</saml:Issuer>`
|
||
` <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">\n<SignedInfo>\n<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>\n<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>\n<Reference URI="#_A86605DF1F9D51A8BD5EFB5F9B02A712">\n<Transforms>\n<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>\n<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>\n</Transforms>\n<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>\n<DigestValue>F9UyV7kkrdL45HhZmIG+qR8hqE8=</DigestValue>\n</Reference>\n</SignedInfo>\n<SignatureValue>cmFamTX6vzK0evsehNv8U7Mjz1JXdz60ZGpzEuner+xEdB8I4rISzWZBLmLQYMiU\n8IlCZYvOeaeHIwf/xStowUZy+dfjzYKMmN5OD9z9ifD5Kr6rNNS9a0Tsmu55HUvv\nD83CkGS2c8HsdpWTR3Og7ED2lVT6rsXTx+VgTJ1mzl0ONVKPSnTp8x09VgHbMFXh\nLq5Pg+5im+G0jJIcpVN3VesVzLdfP6w3CjJz5f+aMllfvRdYYSad0vyXlLUx59Al\nAsIeqFTFq3uKsVHH4yd/JZoFwrhFE4Q6Ve9UeTRw9qR+y6M+fd/cJTcvFzHjKo2A\nTEt9QYM4RpfPPy4conjGqg==</SignatureValue>\n<KeyInfo>\n<X509Data>\n<X509Certificate>MIIDIzCCAgugAwIBAgIJANUBoick1pDpMA0GCSqGSIb3DQEBBQUAMBUxEzARBgNV\nBAoTCkVudHJvdXZlcnQwHhcNMTAxMjE0MTUzMzAyWhcNMTEwMTEzMTUzMzAyWjAV\nMRMwEQYDVQQKEwpFbnRyb3V2ZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAvxFkfPdndlGgQPDZgFGXbrNAc/79PULZBuNdWFHDD9P5hNhZn9Kqm4Cp\n06Pe/A6u+g5wLnYvbZQcFCgfQAEzziJtb3J55OOlB7iMEI/T2AX2WzrUH8QT8NGh\nABONKU2Gg4XiyeXNhH5R7zdHlUwcWq3ZwNbtbY0TVc+n665EbrfV/59xihSqsoFr\nkmBLH0CoepUXtAzA7WDYn8AzusIuMx3n8844pJwgxhTB7Gjuboptlz9Hri8JRdXi\nVT9OS9Wt69ubcNoM6zuKASmtm48UuGnhj8v6XwvbjKZrL9kA+xf8ziazZfvvw/VG\nTm+IVFYB7d1x457jY5zjjXJvNysoowIDAQABo3YwdDAdBgNVHQ4EFgQUeF8ePnu0\nfcAK50iBQDgAhHkOu8kwRQYDVR0jBD4wPIAUeF8ePnu0fcAK50iBQDgAhHkOu8mh\nGaQXMBUxEzARBgNVBAoTCkVudHJvdXZlcnSCCQDVAaInJNaQ6TAMBgNVHRMEBTAD\nAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAy8l3GhUtpPHx0FxzbRHVaaUSgMwYKGPhE\nIdGhqekKUJIx8et4xpEMFBl5XQjBNq/mp5vO3SPb2h2PVSks7xWnG3cvEkqJSOeo\nfEEhkqnM45b2MH1S5uxp4i8UilPG6kmQiXU2rEUBdRk9xnRWos7epVivTSIv1Ncp\nlG6l41SXp6YgIb2ToT+rOKdIGIQuGDlzeR88fDxWEU0vEujZv/v1PE1YOV0xKjTT\nJumlBc6IViKhJeo1wiBBrVRIIkKKevHKQzteK8pWm9CYWculxT26TZ4VWzGbo06j\no2zbumirrLLqnt1gmBDvDvlOwC/zAAyL4chbz66eQHTiIYZZvYgy</X509Certificate>\n</X509Data>\n</KeyInfo>\n</Signature>`
|
||
` <saml:Subject>`
|
||
` <saml:NameID NameQualifier="http://localhost:8000/idp/saml2/metadata">_1E83322C6A38FF13CF515D299647E04E</saml:NameID>`
|
||
` <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">`
|
||
` <saml:SubjectConfirmationData NotOnOrAfter="2017-02-15T14:15:10.325204Z" Recipient="http://localhost:8008/accounts/mellon/login/" InResponseTo="_A79D6A8E4A93A92D65EE570ECA571BDB"/>`
|
||
` </saml:SubjectConfirmation>`
|
||
` </saml:Subject>`
|
||
` <saml:Conditions NotBefore="2017-02-15T14:13:10.325204Z" NotOnOrAfter="2017-02-15T14:15:10.325204Z">`
|
||
` <saml:AudienceRestriction>`
|
||
` <saml:Audience>http://localhost:8008/accounts/mellon/metadata/</saml:Audience>`
|
||
` </saml:AudienceRestriction>`
|
||
` </saml:Conditions>`
|
||
` <saml:AuthnStatement AuthnInstant="2017-02-15T14:14:10.325204Z" SessionIndex="_A86605DF1F9D51A8BD5EFB5F9B02A712" SessionNotOnOrAfter="2017-03-01T14:14:10Z">`
|
||
` <saml:AuthnContext>`
|
||
` <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>`
|
||
` </saml:AuthnContext>`
|
||
` </saml:AuthnStatement>`
|
||
` <saml:AttributeStatement>`
|
||
` <saml:Attribute Name="id_test" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" FriendlyName="Test ID">`
|
||
` <saml:AttributeValue>2</saml:AttributeValue>`
|
||
` </saml:Attribute>`
|
||
` <saml:Attribute Name="lname_test" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" FriendlyName="Test Last Name">`
|
||
` <saml:AttributeValue>Marillonnet</saml:AttributeValue>`
|
||
` </saml:Attribute>`
|
||
` <saml:Attribute Name="fname_test" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" FriendlyName="Test First Name">`
|
||
` <saml:AttributeValue>Paul</saml:AttributeValue>`
|
||
` </saml:Attribute>`
|
||
` </saml:AttributeStatement>`
|
||
` </saml:Assertion>`
|
||
`</samlp:Response>`
|
||
|
||
## Diagramme de séquence conceptuel du POC
|
||
TODO
|
||
## Diagramme de séquence technique du POC
|
||
TODO
|
||
## Architecture fonctionnelle du POC
|
||
TODO
|
||
## Architecture logicielle du POC
|
||
TODO
|
||
|
||
# Prises de notes vidéos
|
||
## Workshop: Identity standards OIDC
|
||
### OAuth
|
||
TODO
|
||
### OpenID Connect
|
||
Notion de Authentication Context
|
||
4 degrés de sécurité ?
|
||
acr : notion de risque, de seuil de risque de acceptable
|
||
amr : TODO
|
||
|
||
Réauthentification forcée
|
||
Durée de la vie la session pour une machine
|
||
|
||
Lier seuil de risque et activité liée à l'authentification (1:14)
|
||
Même contraintes et problèmes qu'avec SAML2
|
||
|
||
Requête d'autorisation dynamique (1:15)
|
||
|
||
|
||
JSON Web Tokens (RFC7519) -> Introduit la notion de confirmation (utilisateur ?)
|
||
JWS RFC7515 JSON Web Signature
|
||
JWE RFC7516 JSON Web Encryption
|
||
|
||
NAPPS
|
||
PKCE ('pixy')
|
||
AC/DC
|
||
|
||
Archi en 3 parties:
|
||
Client
|
||
Resource server
|
||
Authorization Server
|
||
|
||
Pour le scenario de livraison d'un jeton (token)
|
||
|
||
Cf Google Access Tokens
|
||
Nécessite de PKCE pour remédier à ce type d'attaque dans les applis natives frauduleuses
|
||
|
||
IOS9: Mutual authentication ?
|
||
Access aux cookies partagés dans le navigateur pour le SSO
|
||
Sans agent natif de jetons (Native tokan agent)
|
||
|
||
ACDC est un type de JSON Web Token //TODIG
|
||
code verifier (hash)
|
||
code challenge (salt ?) Génération d'un nombre aléatoire
|
||
|
||
RT & AT
|
||
Access Token
|
||
Replay Token ? Resource Token ? Revocation token ?
|
||
TLS Token Auth
|
||
{SaaS, Enterprise} Authentication Server
|
||
|
||
concepts clé :
|
||
- NAPPS
|
||
Token agent directement sur le terminal client
|
||
- PKCE
|
||
- Authorization Cross Domain Code (ACDC)
|
||
|
||
### SAML
|
||
1.0
|
||
1.1
|
||
2.0 -> 2005
|
||
|
||
XML
|
||
SAOP
|
||
XML Signature
|
||
|
||
techno pre OIC et OAuth
|
||
|
||
les spécifications de la RFC sont ambigües
|
||
variations lors de l'implémentation
|
||
|
||
Quelles implémentations ?
|
||
8 documents différents forment la totalité de l'implémentation
|
||
Fonctionnalités optionnelles peuvent être imposées par les bindings SAML
|
||
|
||
SAOP, XML : mastodontes
|
||
|
||
Problèmes sémantiques de XML : pas interopérable
|
||
|
||
binding le plus populaire: SAML Redirect & POST
|
||
Facile à implémenter, et à déployer
|
||
Chiffrement des messages SAML optionnel seulement
|
||
|
||
SAML Artifact
|
||
en deux étapes
|
||
envoi d'une référence sur un premier canal
|
||
le message passe sur un second canal
|
||
plus difficile à déployer
|
||
apparence de la sécurité seulement ?
|
||
authentification du second canal devient nécessaire
|
||
déplacement du problème ?
|
||
|
||
SSO:
|
||
initié par l'IDP ou par le SP
|
||
|
||
Si initié par l'IDP
|
||
URL, visitée par le SP, qui génère une assertion SAML
|
||
|
||
initié par le SP
|
||
Pb de la découverte du fournisseur d'identité
|
||
|
||
Signed Authent request
|
||
pbatique de l'échange des certificats, sans retarder le sso
|
||
|
||
DoS potentiel vers le fournisseur de service
|
||
2 sessions : d'application
|
||
+ une session pour l'IDP
|
||
|
||
Profils
|
||
d'implémentation
|
||
de déploiement (contenu dans le profil précédent)
|
||
|
||
SAML2Int
|
||
|
||
Notion avancées :
|
||
Découverte de fournisseur d'identité
|
||
laisser le choix parmi une liste d'IDP à l'utilisateur
|
||
|
||
NASCAR Screen
|
||
|
||
wayf-less URLs
|
||
|
||
ECP
|
||
Enhanced Client or Proxy
|
||
|
||
SLO plus difficile que SSO
|
||
Comment garantir le SLO ? l'ACK du SP quant au SLO ?
|
||
Faille de sécurité potentielle si échec du SLO
|
||
Best practice : ne pas implémenter SLO
|
||
Pas le même problème avec le SSO : s'il échoue ce n'est pas grave du point de vue de la sécurité
|
||
|
||
La fermeture du navigateur Web détruit les cookies de session
|
||
|
||
Confiance entre IDPs et SPs
|
||
Quelle politique de sécurité de l'IDP auquel le SP fait confiance ?
|
||
Vice versa : comment s'assurer, du point de vue de l'IDP, que le SP ne fait pas n'importe quoi avec les infos d'identité envoyées ?
|
||
|
||
Aller voir les spec de l'échange de métadonnées
|
||
Origine des métadonnées à vérifier
|
||
utilisation l'option d'expiration de la période de validité des métadonnéesn
|
||
|
||
Signature XML : d'abord le décodage du fichier XML => DOS
|
||
|
||
Echecs de SAML:
|
||
simpleSAML php demo cert : à fuir
|
||
|
||
wrapping attack
|
||
|
||
Au contraire
|
||
Cross domain sso très utilisé //TODIG
|
||
|
||
TODO
|
||
téléchargement des deux autres vidéos DONE
|
||
|
||
Faire une synthèse des deux
|