Version | Auteur | Remarque | |
0.1 | bdauvergne | Première version, manque la définition du format pour la description des comptes et des erreurs | 15122016 |
0.2 | mates | Ajout paramètres pour l'envoi de mail à la création | 08032017 |
0.3 | bdauvergne | Mise à jour pour conformité avec la liste des attributs du compte | 21032017 |
0.4 | bdauvergne, mates | URLs, ex modified__gte, envoi email à la création, forcer changement de mot de passe, test existence en masse | 26062017 |
0.5 | jkouka, mates | Correction valeurs attributs gender, utilisation des alias d'attributs, ajouts appels suppression fédération FC et envvoi jeton réinit mot de passe | 10072017 |
0.6 | bdauvergne, mates | Ajout du service de modification d'une adresse de messagerie | 31082017 |
0.7 | mates | Ajout des attributs FranceConnect | 01092017 |
0.8 | mates | Contrôle sur les attributs | 10102017 |
0.9 | mates | Précisions sur la pagination | 16022018 |
0.10 | bdauvergne | Première ébauche API validation des comptes | 05032018 |
0.11 | bdauvergne, mates | Version initiale API validation des comptes | 14032018 |
0.12 | mates | Corrections mineures sur API validation des comptes | 23042018 |
0.13 | mates | Corrections sur les urls, corrections mineures diverses | 24042018 |
0.14 | bdauvergne | Ajout code schema-error pour API de validation des identités | 25042018 |
0.15 | bdauvergne | Ajout paramètre page pour le code d'erreur justificatifs-bad-format pour l'API de validation des identités | 25042018 |
0.16 | bdauvergne | Ajout remarque sur le WS de test des comptes en masse | 02072018 |
0.17 | mates | Publication sur projet Authentic | 30072018 |
Il s'agit d'un travail en cours. Certaines des fonctionnalités présentées peuvent ne pas être encore disponibles dans authentic mais uniquement dans authentic2-cut.
Cette API offre la possibilité de créer, lire, modifier et rechercher et supprimer (CRUD) des utilisateurs.
HTTP obligatoire
REST/JSON
L'authentification se fait via un login et un mot de passe en utilisant le mode d'authentification HTTP Basic.
En utilisant la fonctionnalité des rôles affectés aux utilisateurs techniques il est possible d'autoriser ou non les différentes actions: créer, modifier, rechercher, supprimer.
La valeur d'un champs de téléphone peut débuter par un '+'. Elle ne doit ensuite contenir que des chiffres, maximum 20.
Les champs nom et prénoms de naissance sont limités à 64 caractères.
Les autres champs sont limités à 256 caractères.
URL | Méthode | Contenu | Paramètres |
/api/users/ |
GET | document JSON | voir plus loin |
Nom | Sémantique | Valeurs permises | Exemple |
ordering | Permet de passer le nom d'un champ par lequel les réponses seront ordonnées, préfixé par - l'ordre est inversé, ex.: ordering=last_name |
[-]date_joined , [-]modified , [-]first_name , [-]last_name |
|
first_name |
recherche exacte sur le prénom pour une valeur exacte | ||
first_name__iexact |
recherche exacte sur le prénom pour une valeur exacte en ignorant la casse | ||
first_name__icontains |
recherche exacte sur le prénom pour une sous chaîne en ignorant la casse | ||
first_name__gte |
recherche sur le prénom supérieure ou égale à la valeur | ||
first_name__lte |
recherche sur le prénom inférieure ou égale à la valeur | ||
first_name__gt |
recherche sur le prénom supérieure à la valeur | ||
first_name__lt |
recherche sur le prénom inférieure à la valeur | ||
last_name + __iexact , __icontains , __gte , __lte , __gt , __lt |
idem que pour le prénom mais avec le nom | ||
modified__gte |
recherche sur la date de dernière modification supérieure ou égale à la valeur | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS | curl -X GET -u partenaire:geronimo https://connexion-grandlyon.dev.entrouvert.org/api/users/?modified__gte=2017-03-28T00:00:00 |
modified__lte |
recherche sur la date de dernière modification inférieure ou égale à la valeur | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS | |
modified__gt |
recherche sur la date de dernière modification supérieure à la valeur | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS | |
modified__lt |
recherche sur la date de dernière modification inférieure à la valeur | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS | |
email |
recherche sur le courriel exact | ||
email__iexact |
recherche sur le courriel exact en ignorant la casse |
Le document retour est un objet/dictionnaire JSON, les résultats sont toujours paginés, chaque page a une taille de 100, le lien vers la page suivante est dans la propriété next
et celui vers la page précédente
dans la propriété previous
. La propriété results
contient la liste des résultats.
Les résultats contiennent les propriétés suivantes:
Propriété | Description | Format |
sub | identifiant | chaîne hexadécimal |
first_name | prénom | chaîne quelconque |
given_name | idem (alias) | idem |
last_name | nom | chaîne quelconque |
family_name | idem (alias) | idem |
courriel | courriel | |
gender | genre de la personne | male ou female |
birthdate | date de naissance | format ISO8601: YYYY-MM-DD |
birthplace | lieu de naissance | chaîne quelconque |
birthplace_insee | code INSEE du lieu de naissance | code INSEE (https://www.insee.fr/fr/information/2114819) |
birthcountry | pays de naissance | chaîne quelconque |
birthcountry_insee | code INSEE du pays de naissance | code INSEE (https://www.insee.fr/fr/information/2028273) |
birthdepartment | nom du département de naissance | chaîne quelconque |
preferred_givenname | prénom préféré | chaîne quelconque |
preferred_username | nom préféré | chaîne quelconque |
comment | commentaire | chaîne quelconque |
title | civilité | "Monsieur" ou "Madame" |
address_number | adresse: numéro de voie | chaîne quelconque |
address_street | adresse: type et nom de la voie | chaîne quelconque |
address_complement | adresse: complément d'adresse | chaîne quelconque |
address_zipcode | adresse: code postal | chaîne quelconque |
address_city | adresse: nom de la ville | chaîne quelconque |
address_country | adresse: pays | chaîne quelconque |
address_fc | attribut address fournie par FranceConnect | Object JSON tel que défini dans les spécifications OpenIDConnect 1.0 |
home_phone | téléphone fixe personnel | Peut commencer par un '+'. Ne contient ensuite que des chiffres, maximum 20. |
home_mobile_phone | téléphone fixe personnel | Peut commencer par un '+'. Ne contient ensuite que des chiffres, maximum 20. |
professional_phone | téléphone fixe professionnel | Peut commencer par un '+'. Ne contient ensuite que des chiffres, maximum 20. |
professional_mobile_phone | téléphone fixe professionnel | Peut commencer par un '+'. Ne contient ensuite que des chiffres, maximum 20. |
phone_number_fc | attribut phone fourni par FranceConnect | chaîne quelconque |
modified | date dernière mofification | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS |
validated | statut de validation du compte | booléen |
validation_date | date de validation du compte | format ISO8601: YYYY-MM-DD |
validation_context | contexte de validation | énumération: "FC" ou "online" ou "office" |
GET /api/users/ HTTP/1.1 Authorization: Basic xxx 200 Ok Content-Type: application/json Content-Length: xxxx { "next": "https://cresson.entrouvert.org/api/users/?cursor=XYZ", "previous": null, "results": [ { "address_city": "", "address_complement": "", "address_country": "", "address_fc": { "country": "France", "formatted": "26 rue Desaix, 75015 Paris", "locality": "Paris", "postal_code": "75015", "region": "Ile-de-France", "street_address": "26 rue Desaix" }, "address_number": "", "address_street": "", "address_zipcode": "", "birthcountry": "FRANCE", "birthcountry_insee": "99100", "birthdate": "1981-06-23", "birthdepartment": "", "birthplace": "GIF-SUR-YVETTE", "birthplace_insee": "91272", "comment": null, "creation_domain": null, "creation_mode": null, "creation_partner": null, "date_joined": "2017-07-25T08:41:40.998793Z", "email": "eric.mercier@france.fr", "email_verified": true, "family_name": "Mercier", "first_name": "Eric", "gender": "male", "given_name": "Eric", "home_mobile_phone": "", "home_phone": "", "is_active": true, "last_name": "Mercier", "modified": "2017-08-31T15:16:29.690864Z", "phone_number_fc": null, "preferred_givenname": "", "preferred_username": null, "professional_mobile_phone": "", "professional_phone": "", "sub": "YTIBAQB9-fZcwZKt7k28P_towGlszsW0uDvxq5hd_zQOJhGBJ1qP3FYajF-JUY6ug_Ekw8k", "title": "Monsieur", "validated": "True", "validation_context": "FC", "validation_date": "2017-08-31" }, ... ] }
Code | Signification | Contenu |
400 | Le format de la requête est invalide (paramètre interdit ou avec une valeur invalide) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action |
La réponse d'un cas passant contient au maximum 100 comptes. Si le résultat est supérieur à 100 comptes, le résultat se découpe en plusieurs pages et la réponse à la requête initiale ne contient que les 100 premiers comptes de la liste. Il faut ensuite parcourir les pages suivantes en interrogeant l'url spécifiée dans le champs next
de la réponse et cela jusqu'à ce que le champs next
soit à null
.
Par exemple :
GET /api/users/ HTTP/1.1 Authorization: Basic xxx 200 Ok Content-Type: application/json Content-Length: xxxx { "next": "https://moncompte.grandlyon.com/api/users/?cursor=XYZ", "previous": null, "results": [ { ...
Le champs next
indique qu'il y a une autre page de résultat que l'on obtient par la requête :
GET /api/users/?cursor=XYZ HTTP/1.1 Authorization: Basic xxx 200 Ok Content-Type: application/json Content-Length: xxxx { "next": null, "previous": "https://moncompte.grandlyon.com/api/users/?cursor=ABC", "results": [ { ...
URL | Méthode | Contenu | Paramètres |
/api/users/ | POST | document JSON décrivant le compte à créer (à spécifier) | non |
Le document en entrée est un object/dictionnaire JSON avec les propriétés suivantes:
Propriété | Description | Valeur requise | Valeur permise |
first_name | prénom | oui | chaîne quelconque |
last_name | nom | oui | chaîne quelconque |
courriel | non | courriel | |
gender | genre de la personne | non | entier: 1 = homme, 2 = femme |
birthdate | date de naissance | non | format ISO8601: YYYY-MM-DD |
birthplace | lieu de naissance | non | chaîne quelconque |
birthplace_insee | code INSEE du lieu de naissance | non | code INSEE (https://www.insee.fr/fr/information/2114819) |
birthcountry | pays de naissance | non | chaîne quelconque |
birthcountry_insee | code INSEE du pays de naissance | non | code INSEE (https://www.insee.fr/fr/information/2028273) |
birthdepartment | nom du département de naissance | non | chaîne quelconque |
preferred_givenname | prénom préféré | non | chaîne quelconque |
preferred_username | nom préféré | non | chaîne quelconque |
comment | commentaire | non | chaîne quelconque |
title | civilité | non | "Monsieur" ou "Madame" |
address_number | adresse: numéro de voie | non | chaîne quelconque |
address_street | adresse: type et nom de la voie | non | chaîne quelconque |
address_complement | adresse: complément d'adresse | non | chaîne quelconque |
address_zipcode | adresse: code postal | non | chaîne quelconque |
address_city | adresse: nom de la ville | non | chaîne quelconque |
address_country | adresse: pays | non | chaîne quelconque |
home_phone | téléphone fixe personnel | non | Peut commencer par un '+'. Ne contient ensuite que des chiffres, maximum 20. |
home_mobile_phone | téléphone fixe personnel | non | Peut commencer par un '+'. Ne contient ensuite que des chiffres, maximum 20. |
professional_phone | téléphone fixe professionnel | non | Peut commencer par un '+'. Ne contient ensuite que des chiffres, maximum 20. |
professional_mobile_phone | téléphone fixe professionnel | non | Peut commencer par un '+'. Ne contient ensuite que des chiffres, maximum 20. |
send_registration_email | Envoyer un email à la création de compte terminer l'enregistrement. | non | "True" |
send_registration_email_next_url | Adresse sur laquelle rediriger l'utilisateur après l'enregistrement. | URL valide |
Les valeurs null
ne sont pas autorisées.
La validité INSEE des champs birthplace, birthplace_insee, birthcountry et birthcountry_insee, ainsi que la cohérence entre birthplace et birthplace_insee et entre birthcountry et birthcountry_insee, est à la charge du client.
POST /api/users/ HTTP/1.1 Content-Type: application/json Authorization: Basic xxxx Content-Length: xxx { "email": "john.doe@example.com", "first_name": "John", "last_name": "Doe", "gender": 1, "email": "john.doe@example.com", "birthdate": "1981-06-01", "birthplace": "Marseille", "birthcountry": "France", "preferred_username": "john", "address_city": "New-York", "send_registration_email": "True", "send_registration_email_next_url": "http://www.entrouvert.com" }
201 Created Content-Type: application/json Content-Length: xxx { "sub": "8e7f200b4bb447fa8a91cd03c0f0ade3", "first_name": "john", "given_name": "john", "last_name": "doe", "family_name": "doe", "email": "john.doe@entrouvert.com", "modified": "2017-03-20T13:16:44.991343Z", "birthplace_insee": null, "gender": "1", "birthcountry_insee": null, "title": null, "birthdate": "1981-06-01", "birthplace": "Marseille", "birthcountry": "France", "preferred_username": "john "preferred_givenname": null, "address_number": null, "address_street": null, "address_complement": null, "address_zipcode": null, "address_city": "New-York", "address_country": null, "birthdepartment": null, "comment": null, "validated": null, "validation_date": null, "validation_context": null, "home_phone": null, "home_mobile_phone": null, "professional_phone": null, "professional_mobile_phone": null }
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action |
HTTP/1.1 400 BAD REQUEST Content-Type: application/json Content-Length: xxxx { "errors": { "last_name": [ "Ce champ est obligatoire." ] }, "result": 0 }
get_or_create
ou update_or_create
à l'URL pour indiquer les champs concernés. Ces deux champs sont exclusifs (on ne peut pas utiliser get_or_create
et update_or_create
en même temps). Les différents comportements dépendent du résultat de la recherche :
get_or_create
, l'utilisateur est retourné avec un code 200 Ok
au lieu de 201 Created
mais aucune modification ne lui est apporté, les données postées sont ignorées,update_or_create
, l'utilisateur est mis à jour avec les données postées puis retourné avec un code 200 Ok
,Exemple (email dans l'URL doit être écrit littéralement, il ne faut pas indiquer un courriel ou une variable)
POST /api/users/?get_or_create=email HTTP/1.1 Content-Type: application/json Authorization: Basic xxxx Content-Length: xxx
{
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe",
"gender": 1,
"email": "john.doe@example.com",
"birthdate": "1981-06-01",
"birthplace": "Marseille",
"birthcountry": "France",
"preferred_username": "john",
"address_city": "New-York",
"send_registration_email": "True",
"send_registration_email_next_url": "http://www.entrouvert.com"
}
200 Ok Content-Type: application/json
{
"sub": "8e7f200b4bb447fa8a91cd03c0f0ade3",
"first_name": "john",
"given_name": "john",
"last_name": "doe",
"family_name": "doe",
"email": "john.doe@examle.com",
"modified": "2017-03-20T13:16:44.991343Z",
}
Exemple avec clé multiple :
POST /api/users/?update_or_create=first_name&update_or_create=last_name HTTP/1.1 Content-Type: application/json Authorization: Basic xxxx Content-Length: xxx
{
"email": "john.doe2@example.net",
"first_name": "john",
"last_name": "doe",
}
200 Ok Content-Type: application/json
{
"sub": "8e7f200b4bb447fa8a91cd03c0f0ade3",
"first_name": "John",
"given_name": "Doe",
"last_name": "doe",
"family_name": "doe",
"email": "john.doe2@examle.com",
"modified": "2017-03-20T13:16:44.991343Z",
}
URL | Méthode | Contenu | Paramètres |
/api/users/<id_compte>/ | GET | document JSON décrivant le compte lu | non |
GET /api/users/<id_compte>/ HTTP/1.1 Authorization: Basic xxxx
Code | Signification | Contenu |
200 | Un document JSON décrivant le compte |
200 Ok Content-Type: application/json Content-Length: xxxx { "sub": "8e7f200b4bb447fa8a91cd03c0f0ade3", "first_name": "john", "given_name": "john", "last_name": "doe", "family_name": "doe", "email": "john.doe@example.com", "modified": "2017-03-20T13:16:44.991343Z", "birthplace_insee": null, "gender": "1", "birthcountry_insee": null, "title": null, "birthdate": "1981-06-01", "birthplace": "Marseille", "birthcountry": "France", "preferred_username": "ben", "preferred_givenname": null, "address_number": null, "address_street": null, "address_complement": null, "address_zipcode": null, "address_city": "New-York", "address_country": null, "birthdepartment": null, "comment": null, "validated": null, "validation_date": null, "validation_context": null, "home_phone": null, "home_mobile_phone": null, "professional_phone": null, "professional_mobile_phone": null }
Les propriétés sans valeur sont à null
.
Code | Signification | Contenu |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id compte donné n'existe pas |
voir plus haut
URL | Méthode | Contenu | Paramètres |
/api/users/<id_compte>/ | PUT | document JSON décrivant le compte | non |
/api/users/<id_compte>/ | PATCH | document JSON décrivant le compte | non |
PATCH /api/users/<id_compte>/ HTTP/1.1 Content-Type: application/json Authorization: Basic xxxx Content-Length: xxx { "validated": "True", "validation_date": "2016-11-23", "validation_context": "FC" }
L'action PUT nécessite que first_name
et last_name
(obligatoires) soient dans le document JSON. S'ils ne sont pas renseignés, une erreur 400 est retournée.
La validité INSEE des champs birthplace, birthplace_insee, birthcountry et birthcountry_insee, ainsi que la cohérence entre birthplace et birthplace_insee et entre birthcountry et birthcountry_insee, est à la charge du client.
Attention : gender, family_name et given_name sont des alias des attributs title, last_name et firstname, avec gender où Madame est traduit en female et Monsieur en male. Lorsque l'on souhaite modifier ces attributs, cela doit porter sur les attributs title, last_name et firstname et non sur gender, family_name et given_name.
Attention : l'attribut email n'est pas modifiable par ce service. Sa modification nécessite l'utilisation d'un "service dédié au changement d'email":#Envoyer-un-jeton-pour-modifier-lemail
Code | Signification | Contenu |
200 | Ok | Un document JSON décrivant le compte modifié |
200 Ok Content-Type: application/json Content-Length: xxx { "sub": "8e7f200b4bb447fa8a91cd03c0f0ade3", "first_name": "john", "given_name": "john", "last_name": "doe", "family_name": "doe", "email": "john.doe@example.com", "modified": "2017-03-20T13:16:44.991343Z", "birthplace_insee": null, "gender": "1", "birthcountry_insee": null, "title": null, "birthdate": "1981-06-01", "birthplace": "Marseille", "birthcountry": "France", "preferred_username": "ben", "preferred_givenname": null, "address_number": null, "address_street": null, "address_complement": null, "address_zipcode": null, "address_city": "New-York", "address_country": null, "birthdepartment": null, "comment": null, "validated": "True", "validation_date": null, "validation_context": null, "home_phone": null, "home_mobile_phone": null, "professional_phone": null, "professional_mobile_phone": null }
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id compte donné n'existe pas |
HTTP/1.1 400 BAD REQUEST Content-Type: application/json Content-Length: xxxx { "errors": { "last_name": [ "Ce champ est obligatoire." ] }, "result": 0 }
URL | Méthode | Contenu | Paramètres |
/api/users/<id_compte>/ | DELETE | aucun | non |
DELETE /api/users/<id_compte>/ HTTP/1.1 Authorization: Basic xxx
Code | Signification | Contenu |
204 | Ok | aucun |
204 No content
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id compte donné n'existe pas | JSON d'erreur |
URL | Méthode | Contenu | Paramètres |
/api/users/<id_compte>/force-password-reset/ | POST | aucun | non |
POST /api/users/<id_compte>/force-password-reset/ HTTP/1.1 Authorization: Basic xxx
Code | Signification | Contenu |
204 | Ok | aucun |
204 No content
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id compte donné n'existe pas | JSON d'erreur |
Ce web-service doit être utilisé pour la propagation des suppressions de compte. L'appel peut-être fait soit au moment de la détection d'une collision (compte nouveau arrivant avec un email existant), avec envoi du sub du compte existant, soit en masse régulièrement, avec envoi en plusieurs fois (par paquet de 100) de la totalité des subs connus.
URL | Méthode | Contenu | Paramètres |
/api/users/synchronization/ | POST | Document JSON contenant la liste des ID compte à tester | non |
POST /api/users/synchronization/ HTTP/1.1 Authorization: Basic xxx Content-Type: application/json Content-Length: xxxx { "known_uuids":["e46d46ebcb1d4d6bac4571159b542389", "1234567890"], }
200 Ok Content-Type: application/json Content-Length: xxxx { "unknown_uuids":["1234567890"], "result":1 }
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action |
400 BadRequest Content-Type: application/json Content-Length: xxxx { "detail":"JSON parse error - Expecting ',' delimiter: line 1 column 53 (char 52)" }
URL | Méthode | Contenu | Paramètres |
/api/users/<id_compte>/fc-unlink/ | DELETE | aucun | non |
DELETE /api/users/<id_compte>/fc-unlink/ HTTP/1.1 Authorization: Basic xxx
Code | Signification | Contenu |
204 | Ok | aucun |
204 No content
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id compte donné n'existe pas | JSON d'erreur |
URL | Méthode | Contenu | Paramètres |
/api/users/<id_compte>/password-reset/ | POST | aucun | non |
POST /api/users/<id_compte>/password-reset/ HTTP/1.1 Authorization: Basic xxx
Code | Signification | Contenu |
204 | Ok | aucun |
204 No content
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id compte donné n'existe pas | JSON d'erreur |
500 | L'utilisateur identifié par l'id compte n'a pas de couriel | JSON d'erreur |
URL | Méthode | Contenu | Paramètres |
/api/users/<id_compte>/email/ | POST | aucun | non |
POST /api/users/<id_compte>/email/ HTTP/1.1 Authorization: Basic xxx {"email": "nouvelemail@example.com"}
Code | Signification | Contenu |
204 | Ok | aucun |
200 No content Content-Type: application/json {"result": 1}
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id compte donné n'existe pas | JSON d'erreur |
Pour éviter les problématiques de validation des pièces jointes, seul le format JPEG est autorisé au niveau de l'API portée par le compte. Charge aux clients de l'API de convertir d'autres formats en JPEG.
URL | Méthode | Contenu | Paramètres |
/api/users/<id_compte>/validate/ | POST | application/json | non |
POST /api/users/<id_compte>/validate/ HTTP/1.1 Authorization: Basic xxx Content-Type: application/json
Le champ external_id
représente l'identifiant de la demande dans le SI du demandeur, il permet d'empêcher les doublons. Le couple (id_compte
, external_id
) doit être unique, sinon la création de la demande est rejetée.
{ "justificatifs": [{ "b64_content": "..." }], "external_id": "XYZ1234" }
Le champs justificatifs
est une liste de dictionnaire contenant une unique clé b64_content
. Chaque dictionnaire représente une page du justificatif, jusqu'à 2. Chaque page doit peser moins de 300Ko, sinon la demande est rejetée, et doit être un fichier JPEG encodé en base64 dans une chaîne JSON.
Code | Signification | Contenu |
201 | Created | application/json |
201 Created Content-Type: application/json { "result": 1, "status": "received", "sub": "xyz1234543534535", "external_id": "32423424324", "id": 123 }
À noter qu'il est interdit de créer plusieurs demandes pour un même external_id
pour un partenaire donné mais que plusieurs demandes pour un même id_compte
(même usager) peuvent être créée. C'est au partenaire de décider dans son système s'il autorise cela.
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
404 | L'id compte donné n'existe pas | |
401 | L'authentification a échoué | |
403 | Permission non accordée d'effectuer l'action | |
413 | Entity too large | la requête dépasse la limite dur du serveur web (disons 5x la limite par justificatif) |
400 Bad Request Content-Type: application/json { "result": 0, "errors": [ { 'code': 'justificatifs-bad-format', 'page': 0, 'accepted': ['image/jpeg'], }, { 'code': 'justificatifs-too-big', 'page': 0, 'max-size': '300000', } { 'code': 'already-exists', } ] }Liste des codes d'erreur
Code | Paramètres | Signification |
justificatifs-bad-format | page: l'index du justificatif qui pose problème, accepted: la liste des types MIME acceptés | une des pièces jointes n'est pas dans un des formats autorisés |
justificatifs-too-big | page: l'index du justificatif qui pose problème, max-size: la taille maximum acceptée | une des pièces jointes dépasse la taille autorisée |
already-exists | Aucun | la demande a déjà été créé |
schema-error | field: le champ JSON concerné sub-errors: une liste de chaîne expliquant l'erreur ou un dictionnaire si l'erreur est dans un sous-champ (ici uniquement b64_content) | le format du document JSON envoyé ne correspond pas à ce qui est attendu. Ce code signale une erreur dans le code appelant qui ne respecte pas le format du document JSON attendu. |
La liste est paginée (comme pour le listing des compte), par groupe de 100. L'ordre est l'ordre croissant de la date de création. Voir cette "section":#Pagination-des-r%C3%A9sultats pour l'utilisation de la pagination.
Les demandes traitées ayant plus d'un mois sont purgées.
URL | Méthode | Contenu | Paramètres |
/api/validate/ | GET | non | voir plus loin |
/api/users/<id_compte>/validate/ | GET | non | voir plus loin |
La version avec l'id_compte
ne liste que les demandes concernant cet ID compte.
Nom | Sémantique | Valeurs permises | Exemple |
validated__gt | Liste les demandes validées, acceptées ("status": "accepted" ) ou refusées ("status": "refused" ) après la date indiquée. Ne s'applique que sur /api/validate/. |
date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SSZ |
Code | Signification | Contenu |
200 | OK | application/json |
200 OK Content-Type: application/json { "next": null, "previous": null, "result": 1, "results": [ { "created": "2018-04-24T06:49:37.371577Z", "external_id": "7", "id": 9, "reason": "", "status": "received", "sub": "YTIBAQCbZndVIpit-Eog-Y-33sFBf9hTbHYa4YVxDfqW6kwmJWo3_5glGQtGbzQI7FajXtw", "validated": null }, ... { "created": "2018-04-23T17:03:16.791785Z", "external_id": "4", "id": 6, "reason": "", "status": "accepted", "sub": "YTIBAQCbZndVIpit-Eog-Y-33sFBf9hTbHYa4YVxDfqW6kwmJWo3_5glGQtGbzQI7FajXtw", "validated": "2018-04-23T17:06:52.623275Z" }, { "created": "2018-04-23T17:01:46.458133Z", "external_id": "3", "id": 5, "reason": "underaged", "status": "refused", "sub": "YTIBAQCbZndVIpit-Eog-Y-33sFBf9hTbHYa4YVxDfqW6kwmJWo3_5glGQtGbzQI7FajXtw", "validated": "2018-04-23T17:04:52.121961Z" }, { "created": "2018-04-23T16:59:24.773830Z", "external_id": "2", "id": 4, "reason": "unreadable", "status": "refused", "sub": "YTIBAQCbZndVIpit-Eog-Y-33sFBf9hTbHYa4YVxDfqW6kwmJWo3_5glGQtGbzQI7FajXtw", "validated": "2018-04-23T17:01:02.989202Z" }, { "created": "2018-04-23T16:44:24.223940Z", "external_id": "1", "id": 3, "reason": "invalid", "status": "refused", "sub": "YTIBAQCbZndVIpit-Eog-Y-33sFBf9hTbHYa4YVxDfqW6kwmJWo3_5glGQtGbzQI7FajXtw", "validated": "2018-04-23T16:57:50.874902Z" }, ... ] }Le champ
status
peut contenir trois valeurs différentes :
received
pour les nouvelles demande non encore traitées,accepted
pour les demandes acceptées,refused
pour les demandes refusées, la raison se trouvant dans le champ reason
qui est une chaîne de texte.reason
est un code parmi les valeurs suivantes :
Valeur | Signification |
unreadable | L'agent n'est pas parvenu à lire la ou les pièces jointes. |
invalid | La pièce jointe ne correspond pas à une pièce jointe acceptable (à déterminer dans la convention de partenariat et pas dans du code) ou elle n'est pas complète ou elle est périmée. |
underaged | L'usager est mineur. |
Lorsqu'une demande passe du statut "received"
à "accepted"
ou "refused"
, la date de la transition est conservée dans le champs validated
. Le fait de filtrer à l'aide de validated__gt
ne renvoie que des demandes validées ("status": "accepted"
ou "status": "refused"
), donc dont le champs validated
n'est pas null
.
Code | Signification | Contenu |
401 | L'authentification a échoué | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id compte donné n'existe pas |
Cette API offre la possibilité de créer, lire, modifier et rechercher et supprimer (CRUD) des utilisateurs dans l'annuaire du Utilisateur.
HTTP obligatoire
REST/JSON
L'authentification se fait via un login et un mot de passe en utilisant le mode d'authentification HTTP Basic.
En utilisant la fonctionnalité des rôles affectés aux utilisateurs techniques il est possible d'autoriser ou non les différentes actions: créer, modifier, rechercher, supprimer.
URL | Méthode | Contenu | Paramètres |
/api/users/ |
GET | document JSON | voir plus loin |
Nom | Sémantique | Valeurs permises | Exemple |
ordering | Permet de passer le nom d'un champ par lequel les réponses seront ordonnées, préfixé par - l'ordre est inversé, ex.: ordering=last_name |
[-]date_joined , [-]modified , [-]first_name , [-]last_name |
|
first_name |
recherche exacte sur le prénom pour une valeur exacte | ||
first_name__iexact |
recherche exacte sur le prénom pour une valeur exacte en ignorant la casse | ||
first_name__icontains |
recherche exacte sur le prénom pour une sous chaîne en ignorant la casse | ||
first_name__gte |
recherche sur le prénom supérieure ou égale à la valeur | ||
first_name__lte |
recherche sur le prénom inférieure ou égale à la valeur | ||
first_name__gt |
recherche sur le prénom supérieure à la valeur | ||
first_name__lt |
recherche sur le prénom inférieure à la valeur | ||
last_name + __iexact , __icontains , __gte , __lte , __gt , __lt |
idem que pour le prénom mais avec le nom | ||
modified__gte |
recherche sur la date de dernière modification supérieure ou égale à la valeur | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS | curl -X GET -u partenaire:geronimo https://connexion-demo.dev.entrouvert.org/api/users/?modified__gte=2017-03-28T00:00:00 |
modified__lte |
recherche sur la date de dernière modification inférieure ou égale à la valeur | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS | |
modified__gt |
recherche sur la date de dernière modification supérieure à la valeur | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS | |
modified__lt |
recherche sur la date de dernière modification inférieure à la valeur | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS | |
email |
recherche sur le courriel exact | ||
email__iexact |
recherche sur le courriel exact en ignorant la casse |
Le document retour est un objet/dictionnaire JSON, les résultats sont toujours paginés, chaque page a une taille de 100, le lien vers la page suivante est dans la propriété next
et celui vers la page précédente
dans la propriété previous
. La propriété results
contient la liste des résultats.
Les résultats contiennent les propriétés suivantes:
Propriété | Description | Format |
uuid | identifiant unique | |
username | nom d'utilisateur | chaine quelconque |
password | mot de passe chiffré | |
date_joined | date d'inscription | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS |
courriel | courriel | |
email_verified | booléen | |
first_name | prénom | chaîne quelconque |
last_name | nom | chaîne quelconque |
is_active | booléen | |
is_staff | booléen | |
is_admin | booléen | |
date_joined | date de dernière connexion | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS |
modified | date de dernière modification | date et heure au format ISO-8601: YYYY-MM-DDTHH:MM:SS |
ou | Collectivité de l'utilisateur | chaine quelconaue |
GET /api/users/ HTTP/1.1 Authorization: Basic xxx 200 OK Coneent-Type: application/json Content-Length: xxxx { "next": null, "previous": null, "results": [ { "date_joined": "2017-08-21T14:28:00Z", "email": "john.doe@example.com", "email_verified": false, "first_name": "John Kevin Eric", "id": 4, "is_active": true, "is_staff": false, "is_superuser": false, "last_login": null, "last_name": "Doe", "modified": "2017-08-21T14:47:34.102909Z", "ou": "default", "password": "pbkdf2_sha256$20000$crynWolm1hVD$SpcKEw0W6HNjDdex6RcKrGPB5N5eBwjCRT+KaFWFATA=", "username": "jdoe", "uuid": "73e62dc8de25486e901753d127309eef" } ] }
Code | Signification | Contenu |
400 | Le format de la requête est invalide (paramètre interdit ou avec une valeur invalide) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action |
URL | Méthode | Contenu | Paramètres |
/api/users/ | POST | document JSON décrivant le Utilisateur à créer (à spécifier) | non |
Le document en entrée est un object/dictionnaire JSON avec les propriétés suivantes:
Propriété | Description | Valeur requise | Valeur permise |
username | nom d'utilisateur | non | chaine quelconque |
password | mot de passe | non | chaine quelconque |
first_name | prénom | oui | chaîne quelconque |
last_name | nom | oui | chaîne quelconque |
courriel | non | courriel |
Les valeurs null
ne sont pas autorisées.
POST /api/users/ HTTP/1.1 Content-Type: application/json Authorization: Basic xxxx Content-Length: xxx { "email": "john.doe@example.com", "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "username": "jdoe", "password": "toto" }
201 Created Content-Type: application/json Content-Length: xxx { "date_joined": "2017-08-21T14:28:00.194032Z", "email": "", "email_verified": false, "first_name": "John", "id": 4, "is_active": true, "is_staff": false, "is_superuser": false, "last_login": null, "last_name": "Doe", "modified": "2017-08-21T14:28:00.470957Z", "ou": "default", "password": "pbkdf2_sha256$20000$crynWolm1hVD$SpcKEw0W6HNjDdex6RcKrGPB5N5eBwjCRT+KaFWFATA=", "username": "jdoe", "uuid": "73e62dc8de25486e901753d127309eef" }
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action |
HTTP/1.1 400 BAD REQUEST Content-Type: application/json Content-Length: xxxx { "errors": { "last_name": [ "Ce champ est obligatoire." ] }, "result": 0 }
URL | Méthode | Contenu | Paramètres |
/api/users/<uuid>/ | GET | document JSON décrivant le Utilisateur lu | non |
GET /api/users/<uuid>/ HTTP/1.1 Authorization: Basic xxxx
Code | Signification | Contenu |
200 | Un document JSON décrivant le Utilisateur |
200 Ok Content-Type: application/json Content-Length: xxxx { "date_joined": "2017-08-21T14:28:00Z", "email": "john.doe@example.com", "email_verified": false, "first_name": "John", "id": 4, "is_active": true, "is_staff": false, "is_superuser": false, "last_login": null, "last_name": "Doe", "modified": "2017-08-21T14:34:15.669381Z", "ou": "default", "password": "pbkdf2_sha256$20000$crynWolm1hVD$SpcKEw0W6HNjDdex6RcKrGPB5N5eBwjCRT+KaFWFATA=", "username": "jdoe", "uuid": "73e62dc8de25486e901753d127309eef" }
Les propriétés sans valeur sont à null
.
Code | Signification | Contenu |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id Utilisateur donné n'existe pas |
voir plus haut
URL | Méthode | Contenu | Paramètres |
/api/users/<uuid>/ | PUT | document JSON décrivant le Utilisateur | non |
/api/users/<uuid>/ | PATCH | document JSON décrivant le Utilisateur | non |
PATCH /api/users/<uuid>/ HTTP/1.1 Content-Type: application/json Authorization: Basic xxxx Content-Length: xxx { "first_name": "John Kevin" }
L'action PUT nécessite que first_name
et last_name
(obligatoires) soient dans le document JSON. S'ils ne sont pas renseignés, une erreur 400 est retournée.
Code | Signification | Contenu |
200 | Ok | Un document JSON décrivant le Utilisateur modifié |
200 Ok Content-Type: application/json Content-Length: xxx { "date_joined": "2017-08-21T14:28:00Z", "email": "john.doe@example.com", "email_verified": false, "first_name": "John Kevin", "id": 4, "is_active": true, "is_staff": false, "is_superuser": false, "last_login": null, "last_name": "Doe", "modified": "2017-08-21T14:34:15.669381Z", "ou": "default", "password": "pbkdf2_sha256$20000$crynWolm1hVD$SpcKEw0W6HNjDdex6RcKrGPB5N5eBwjCRT+KaFWFATA=", "username": "jdoe", "uuid": "73e62dc8de25486e901753d127309eef" }
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id Utilisateur donné n'existe pas |
HTTP/1.1 400 BAD REQUEST Content-Type: application/json Content-Length: xxxx { "errors": { "last_name": [ "Ce champ est obligatoire." ] }, "result": 0 }
URL | Méthode | Contenu | Paramètres |
/api/users/<uuid>/ | DELETE | aucun | non |
DELETE /api/users/<uuid>/ HTTP/1.1 Authorization: Basic xxx
Code | Signification | Contenu |
204 | Ok | aucun |
204 No content
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id Utilisateur donné n'existe pas | JSON d'erreur |
URL | Méthode | Contenu | Paramètres |
/api/users/<uuid>/force-password-reset/ | POST | aucun | non |
POST /api/users/<uuid>/force-password-reset/ HTTP/1.1 Authorization: Basic xxx
Code | Signification | Contenu |
204 | Ok | aucun |
204 No content
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id Utilisateur donné n'existe pas | JSON d'erreur |
URL | Méthode | Contenu | Paramètres |
/api/users/synchronization/ | POST | Document JSON contenant la liste des ID Utilisateur à tester | non |
POST /api/users/synchronization/ HTTP/1.1 Authorization: Basic xxx Content-Type: application/json Content-Length: xxxx { "known_uuids":["73e62dc8de25486e901753d127309eef", "1234567890"], }
200 Ok Content-Type: application/json Content-Length: xxxx { "unknown_uuids":["1234567890"], "result":1 }
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquan les erreurs rencontrées | |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action |
400 BadRequest Content-Type: application/json Content-Length: xxxx { "detail":"JSON parse error - Expecting ',' delimiter: line 1 column 53 (char 52)" }
URL | Méthode | Contenu | Paramètres |
/api/users/<uuid>/password-reset/ | POST | aucun | non |
POST /api/users/<uuid>/password-reset/ HTTP/1.1 Authorization: Basic xxx
Code | Signification | Contenu |
204 | Ok | aucun |
204 No content
Code | Signification | Contenu |
400 | Le format de la requête est invalide (JSON mal formaté, attribut manquant, etc..) | Un document JSON décrivant les erreurs rencontrées |
401 | L'authentification a échouée | |
403 | Permission non accordée d'effectuer l'action | |
404 | L'id Utilisateur donné n'existe pas | JSON d'erreur |
500 | L'utilisateur identifié par l'id Utilisateur n'a pas de couriel | JSON d'erreur |
This page describe a new attribute engine for authentic having simpler articutaled concepts and being more powerful.
It's largely based on a reading of Shibboleth IdPAddAttribute wiki page but with a larger setting than an only SAML 1.0 / SAML 2.0 compliant identity provider.
There are 3 functional concepts: the attribute sources, the attribute engine and the attribute encoders.
wanted_attributes
attribute describe later in get_attributes()
method of the attribute engine)Each source is responsible to finding its configuration, there is no global definition of how the configuration should look like, where it is stored, etc... Available attribute source types are found using the list of installed applications by looking for a contained module named attribute_backend
containing a class named AttributeBackend
, i.e. if the saml
application want to define an attribute source there should be file named saml/attribute_backend.py
which contains a classe named AttributeBackend
.
get_instances(ctx)
Return a list of (source, instance) for this source. It's used by the attribute engine to list all attribute source instances.
get_dependencies(instance, ctx)
Return the list of attributes this instance requires. It's used by the attribute engine to order the attribute source instances before running them.
get_attribute_names(instance, ctx)
Return the list of attribute names produced by this instance.
get_attributes(instance, ctx)
Return a dictionnary of the attributes produced for this instance given the context ctx
.
A singleton object, there is one instance for the global application. The default implementation is found using the A2_ATTRIBUTE_ENGINE
which should be a Python class path. A default one is provided.
It calls every sources and returns the aggregated list of defined attributes, defined does not mean that the attributes are available. For example if you have two ldap sources ldap1
and ldap2
against which people can be authenticated. If an user is authenticated against the ldap1
sources, the attributes from ldap1
will be defined and available (not all of them as an LDAP search can return a partial response), but the attributes from ldap2
will be defined but not available at all.
It is responsible for calling every sources in order to aggregate attributes. The ctx
argument is used to initialize the ctx
argument passed to the first source called. Each source instance decides each time to produce or not some attributes, i.e if its dependencies have not produced the needed attributes, it can decide to do nothing. The engine is authorized to cache the list of instances between calls and the topological sort done based on the dependencies attributes. If a cyclical dependency is found an exception is raised. Each source is called only one time. If you want a source to be run again (if there is an implicit cyclical dependency), then call get_attributes()
again.
Some attribute names have special meaning:
wanted_attributes
:session
:request.session
object, if available.request
:request
object, if available.user
:request.user
object, if available.identifer.last_call
with a timestamp, to determine previous call and freshness.request.session.pop('attributes', {})
then overwrite it with the return value, which would permit to use the engine in other contexts than a Django HTTP request.They are objects linked to attribute recipients, usually service providers in the Authentic2 setting. They define which and how attributes should be transmitted. They can be defined through the setting file or ORM models, this is undefined. Their interface is also undefined as it depends upon the identity provider calling them. They are not really part of the attribute engine but clients of it. Each identity provider backend is responsible for calling them. They are the clients of the attribute engine interfaces, and are here only to see how the attribute engine interfaces will be used.
saml:Attribute
element, i.e a Name
, NameFormat
and FriendlyName
mapping.py
file.user_info
rest endpointStill missing is a way to limit use of the service for specific endpoints and to control use of the proxying ticket by services.
The configuration page is on /admin/settings/cas.
/sms/
).SMS_SENDER
et SMS_URL
dans la configuration du tenant.{ "A2_ACCEPT_PHONE_AUTHENTICATION": true }
Dans le répértoire du tenant
openssl req -x509 -sha256 -newkey rsa:2048 -nodes -keyout publik-sp.key -out publik-sp.crt -batch -subj '/CN=connexion.demarches.ville.fr' -days 3652
Pour Authentic multitenant, copier les fichiers générés dans le répértoire du tenant:
cp sp-saml.key /var/lib/authentic2-multitenant/tenants/<connexion.demarches.ville.fr>/ cp sp-saml.crt /var/lib/authentic2-multitenant/tenants/<connexion.demarches.ville.fr>/
Télécharger le fichier des métadonnées, ou si pas accessible directement via HTTP, le demander au client.
Pour Authentic multitenant copier le fichier dans le répértoire du tenant:
cp idp-metadata.xml /var/lib/authentic2-multitenant/tenants/<connexion.demarches.ville.fr>/
Pour Authentic multitenant créer le fichier settings.json
dans le répértoire /var/lib/authentic2-multitenant/tenants/<connexion.demarches.ville.fr>/
avec le contenu suivant:
{ "A2_AUTH_SAML_ENABLE": true, "MELLON_PUBLIC_KEYS": ["/var/lib/authentic2-multitenant/tenants/<connexion.demarches.ville.fr>/publik-sp.crt"], "MELLON_PRIVATE_KEY": "/var/lib/authentic2-multitenant/tenants/<connexion.demarches.ville.fr>/publik-sp.key", "MELLON_PROVISION": true, "MELLON_IDENTITY_PROVIDERS": [ { "A2_ATTRIBUTE_MAPPING": [ { "attribute": "email", "mandatory": true, "saml_attribute": "email" }, { "attribute": "last_name", "mandatory": false, "saml_attribute": "last_name" }, { "attribute": "first_name", "mandatory": false, "saml_attribute": "first_name" }, { "action": "toggle-role", <= si besoin d'affecter un rôle aux comptes en provenance du fournisseur "role": { "name": "Agent" } } ], "SLUG": "my-idp", "LOOKUP_BY_ATTRIBUTES": [ { "user_field": "email", "saml_attribute": "email" } ], "METADATA": "/var/lib/authentic2-multitenant/tenants/<connexion.demarches.ville.fr>/idp-metadata.xml" ou bien "METADATA_URL": "https://annuaire.ville.fr/.../metadata.xml", } ] }
Dans le cas ou le fournisseur d'identité est un serveur ADFS, les noms des attributs usagers peuvent être des URIs: exemple
https://connexion.demarches.ville.fr/accounts/saml/metadata/
-----BEGIN CERTIFICATE-----et après la dernière ligne
-----END CERTIFICATE-----
<EntityDescriptor entityID="google.com" xmlns="urn:oasis:names:tc:SAML:2.0:metadata"> <SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat> <AssertionConsumerService index="1" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.google.com/a/YOURDOMAIN.COM/acs" /> </SPSSODescriptor> </EntityDescriptor>
$ apt install python-jwcrypto $ python Python 2.7.8 (default, Oct 18 2014, 12:50:18) [GCC 4.9.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from jwcrypto import jwk >>> k = jwk.JWK.generate(kty='RSA', size=2048) >>> s = jwk.JWKSet() >>> s['keys'].add(k) >>> s.export() '{"keys":[{"d":"Y9GJV37oeFlqz2vuZZDsBVfu4u6YLGbMR7ONhedvn3YTMvFxzmeSwjHd2pdoY05TBjgNbDk6QaCKVtqRrHsbbrmYN_6aRIoZk9KiZqLPvnrRUbe0_lLaozJxZjPa4urb8-vsq_Y040DhUEiBog0xjq2RDg7qtcpi5nf0NRNhXbEm2dzIutH22e8WDoUMma8b64NeZgciSmvdu24UUG_eoAt7fsy8xfL81nxA6qk0mWFrjyCpvxmjEotuCBQ79JLzStWeiKkBx80mokNnMTD3bZm-coJRXEPTcKzmtG_NTmNGi1_IZwZslr5cB6F3cyMIsA1y4mYgYu46JNVvUlwIYQ","dp":"OSokOYunlOqOFxOXuMNfdxTyxi2itS5dW2M4S0PBzwlfOU-fD7JWft94sRTOXCP65No_vmw-V2AHnRRj-GgcHdjyIgHkMV4bgtgUkV7HtAmsC_VAdYwnEWOfeaq-izl34DRUt-qN_m6HzNVziC2JtiPum2ifFuS2vrvO4FTPMgE","dq":"QwnEqx3W1MOa5dRhboSwPu4_J5vgwqofjeKrQD1OmEjeowwzJmj5aYiRysZW6IzV5L7XpW081EdxDXI6ddBGWRq-QFlpF9hGxGYQ9qmmohz_ZcVuw5qUdoF113tUA_9aPujG3LPV7S9Jt-R1piN8b7HGUkz_DSVMLzgArlQ4F8k","e":"AQAB","kty":"RSA","n":"yDIt_sOfAY7h5kcyQLimct2R-4PF5K6Fb90xtEAQmZiXzfW2LzhUX4Uow-XLU_shMrAwixAqc-P8A_Sg-IpCHqvcEaIt0tylGThaguN6e6kJxgTU22Oqx4QBCgejm9xMW9kNf15OvudBiuxn5vveR8VFts_pWU-wCNwBw1AHx67E6dszP0C2G7ZN_7v9AI3f3fTj9S1AGzaJHX5bu9aSRFkmVk-K_VBOyovJYYXb3rhFoy16fJWGsxSTLHD9LS_OvpN3_EIj82ziTB2pEAhMAN4uuB8QmhYvevBin96TbECNMCuIbxenbZYyn1FslXWn29-UA03f8-jau5PubcyEDQ","p":"-Rh3WQ2i3ona_U4kKMR_XGYF6JXwQJAcfUlSfkx6VBI3mmW5uXzWWj8KFgRZEklhGoEq57GCyPWiRARgFOdLRHGQzJidvZaNFqpWw96oFP5eDaOdmLmtthr59l6kUqfQgUwRF_QeHEOlgQrmXBG7-j2hNt0L-YdQIHO0OUEU0Fk","q":"zb67UTECBXKtRfrDoyOvxOc1g7FcUSwGI15Qc_VXIG8ktRtJtj-6ZsnHymO3MXYE3L0ucjxmivj9ow6yVvj6C9uMLmo8AUNhzzF6_FCgHTMERu7pNeRU5ArLMMJA-A5dcMyLCPnGCVFKxhMCEbVeAMs0DfJA6CW1Gk4E61GfOtU","qi":"d4R9BfJKsnOA3ZHpTXtn7mR0uvxPK-mGiYVVLmk0Ko7OSCQxjzYscfle8L3d0iwTPXVVVhazT5ZUN-jOEzmtJ4XQxnfgYqdfxgAXIwducaoz4aptW3GOWcwK9sK_q89IdV3HRQdeJhwUG4IJINBtC7QYvwE9FNhWvC9DsB5VAEo"}]}' >>>
Recopier la chaîne contenant le document JSON dans le fichier /etc/authentic2/config.py
ou le settings.json
du tenant, comme ceci:
A2_IDP_OIDC_JWKSET = {"keys":[{"d":"Y9GJV37oeFlqz2vuZZDsBVfu4u6YLGbMR7ONhedvn3YTMvFxzmeSwjHd2pdoY05TBjgNbDk6QaCKVtqRrHsbbrmYN_6aRIoZk9KiZqLPvnrRUbe0_lLaozJxZjPa4urb8-vsq_Y040DhUEiBog0xjq2RDg7qtcpi5nf0NRNhXbEm2dzIutH22e8WDoUMma8b64NeZgciSmvdu24UUG_eoAt7fsy8xfL81nxA6qk0mWFrjyCpvxmjEotuCBQ79JLzStWeiKkBx80mokNnMTD3bZm-coJRXEPTcKzmtG_NTmNGi1_IZwZslr5cB6F3cyMIsA1y4mYgYu46JNVvUlwIYQ","dp":"OSokOYunlOqOFxOXuMNfdxTyxi2itS5dW2M4S0PBzwlfOU-fD7JWft94sRTOXCP65No_vmw-V2AHnRRj-GgcHdjyIgHkMV4bgtgUkV7HtAmsC_VAdYwnEWOfeaq-izl34DRUt-qN_m6HzNVziC2JtiPum2ifFuS2vrvO4FTPMgE","dq":"QwnEqx3W1MOa5dRhboSwPu4_J5vgwqofjeKrQD1OmEjeowwzJmj5aYiRysZW6IzV5L7XpW081EdxDXI6ddBGWRq-QFlpF9hGxGYQ9qmmohz_ZcVuw5qUdoF113tUA_9aPujG3LPV7S9Jt-R1piN8b7HGUkz_DSVMLzgArlQ4F8k","e":"AQAB","kty":"RSA","n":"yDIt_sOfAY7h5kcyQLimct2R-4PF5K6Fb90xtEAQmZiXzfW2LzhUX4Uow-XLU_shMrAwixAqc-P8A_Sg-IpCHqvcEaIt0tylGThaguN6e6kJxgTU22Oqx4QBCgejm9xMW9kNf15OvudBiuxn5vveR8VFts_pWU-wCNwBw1AHx67E6dszP0C2G7ZN_7v9AI3f3fTj9S1AGzaJHX5bu9aSRFkmVk-K_VBOyovJYYXb3rhFoy16fJWGsxSTLHD9LS_OvpN3_EIj82ziTB2pEAhMAN4uuB8QmhYvevBin96TbECNMCuIbxenbZYyn1FslXWn29-UA03f8-jau5PubcyEDQ","p":"-Rh3WQ2i3ona_U4kKMR_XGYF6JXwQJAcfUlSfkx6VBI3mmW5uXzWWj8KFgRZEklhGoEq57GCyPWiRARgFOdLRHGQzJidvZaNFqpWw96oFP5eDaOdmLmtthr59l6kUqfQgUwRF_QeHEOlgQrmXBG7-j2hNt0L-YdQIHO0OUEU0Fk","q":"zb67UTECBXKtRfrDoyOvxOc1g7FcUSwGI15Qc_VXIG8ktRtJtj-6ZsnHymO3MXYE3L0ucjxmivj9ow6yVvj6C9uMLmo8AUNhzzF6_FCgHTMERu7pNeRU5ArLMMJA-A5dcMyLCPnGCVFKxhMCEbVeAMs0DfJA6CW1Gk4E61GfOtU","qi":"d4R9BfJKsnOA3ZHpTXtn7mR0uvxPK-mGiYVVLmk0Ko7OSCQxjzYscfle8L3d0iwTPXVVVhazT5ZUN-jOEzmtJ4XQxnfgYqdfxgAXIwducaoz4aptW3GOWcwK9sK_q89IdV3HRQdeJhwUG4IJINBtC7QYvwE9FNhWvC9DsB5VAEo"}]}
http://idp/admin/authentic2_idp_oidc/oidcclient/
Ajouter un oidc client
redirect_uri
de la requête d'authentification aucune variation n'est permise (même dans la query string), la norme exige que cette URL utilise HTTPS, mais authentic ne force pas ce comportementclient_secret
de chaque service.Politique des identifiants \ Mode de consentement | Par RP | Par OU |
rien de spécial | rien de spécial | |
uuid | rien de spécial | rien de spécial |
pairwise irreversible | hash de l'uuid + (domaine de l'unique redirect_uri ou domaine de l'identifiant de secteur ) | hash de l'uuid + slug de l'OU |
pairwise reversible | chiffrement AES de l'uuid par settings.SECRET_KEY salé avec (domaine de l'unique redirect_uri ou domaine de l'identifiant de secteur ) |
chiffrement AES de l'uuid par settings.SECRET_KEY salé avec le slug de l'OU |
Entr'ouvert fournit des prestations pour le raccordement à MSP
Pour les collectivités territoriales ou les organismes publics proposant des services en ligne nécessitant une authentification des utilisateurs, l'authentification unique apporte une grande simplification pour des utilisateurs qui possèdent de plus en plus d'identifiants. Une possibilité est d'utiliser l'un des nombreux fournisseurs d'identités privés sur Internet - Google et Facebook entre autres - une autre est de s'appuyer sur une acteur public incontournable.
Depuis 2009, le portail Internet des administrations françaises propose en Mon-Service-Public.fr - MSP - un service d'authentification unique à destination des collectivités et administrations françaises basé sur les normes ID-FF 1.2 et SAML 2.0 issues du projet Liberty Alliance, et maintenant OAUTH 2.0. Le raccordement d'un service à Mon-Service-Public.fr passe par un accord de raccordement pris avec la Direction de l'information légale et administrative - DILA - en charge du projet MSP et de l'implémentation des normes SAML 2.0 et OAUTH 2.0 dans le service.
Entr'ouvert propose concernant le projet d'un raccordement à MSP des prestations complètes de maîtrise d'ouvrage :
et de maîtrise d'œuvre :
mais aussi de formation :
Notre expérience particulière sur ce sujet est exemplaire:
Via une prestation de service (service hébergé par Entr'ouvert)
Entr'ouvert propose aussi un service d'authentification externe hébergé :
Ce service peut lui même être raccordé par simple configuration à MSP pour une mise en place en un clic. Nous pouvons ensuite convertir cette authentification vers un protocole d'authentification plus simple et déjà employé par votre application :
Si vous choisissiez cette solution pour vos authentifications, nous pouvons dans un même projet fournir en plus de l'authentification MSP d'autres types d'authentifications tels que celles fournies par des acteurs majeurs d'internet tel que Google ou Facebook, ou via des protocoles standardisés tel qu'OpenID 2.0 utilisé par exemple par Google.
Porte-document
Notre expertise ne se limite pas qu'à l'authentification nous pouvons aussi vous aider dans l'utilisations des fonctionnalités suivantes de la plateforme MSP :
Nous proposons ces fonctionnalités soit dans une prestation sur mesure mais aussi via notre service mandataire dans le cas d'une prestation de service, ce qui simplifie grandement leur utilisation. En effet dans le cas de l'utilisation de notre mandataire pour les interactions avec MSP nous pouvons convertir un protocole REST très simple vers les protocoles aux noms barbares utilisés par MSP, tel qu'ID-WSF 1.0.
Entr'ouvert fournit des prestations pour le raccordement à MSP
hex(sha1(username+entity_id+django_secret_key))
.hex(sha1(NameID+django_session_key))
. Lasso is automatically generating a session index when the service provider has a logout endpoint, a session should be generated using the deterministic algorimth (after the call to lasso_login_build_assertion
) only if Lasso has also set one.saml.common.load_session
and saml.common.save_session
. Session index should only be saved if there is one.A versatile identity management server.
Originally focused on the SAML protocols, Authentic has evolved to become a trully multiprocol Identity provider : LDAP, SAML 2.0, OpenID, CAS, SSL... are all supported (to different extends). And it keeps evolving to integrate the most used standards.
Additionally it has several extra features; for example it can act as a proxy identity provider, redirecting requests from service providers to other identity providers; or help in forwardig identity attributes to service providers managing attribute namespaces.
The underlying components are quite fast and Authentic doesn't slow things down. There are no hard measure yet but a quick benchmark using autobench yielded more than 300 requests per second on a simple laptop.
Authentic implements SAML 2.0 through the use of Lasso, which has been certified as conformant to SAML 2.0 in december 2006.
from source
from debian packages
from git repository (Browse)
Administration guide (PDF version)
Authentic's developpers and users hangs on the mailing list authentic@listes.entrouvert.com
You want to use but it does not work as you would like; you found a bug; you have a remark submit your remark or your bug ! Developers will work on it !
On imagine une application PHP qui désire obtenir des utilisateurs depuis le fournisseur OAuth2 d'Authentic2.
L'application est disponible sur https://application.example.net
Authenitc2 est installé sur https://idp.example.net
Source : https://github.com/adoy/PHP-OAuth2/
... ou n'importe quel autre nom, avec ce code :
<?php require('Client.php'); require('GrantType/IGrantType.php'); require('GrantType/AuthorizationCode.php'); const REDIRECT_URI = 'https://application.example.net/oauth2.php'; // URL définitive à transmettre à Entr'ouvert const AUTHORIZATION_ENDPOINT = 'https://idp.example.net/idp/oauth2/authorize/'; const TOKEN_ENDPOINT = 'https://idp.example.net/idp/oauth2/access_token/'; const USER_INFO = 'https://idp.example.net/idp/oauth2/user-info/'; const CLIENT_ID = 'xxxxxxxxx'; // à demander à Entr'ouvert const CLIENT_SECRET = 'yyyyyyyyyyyyyyyyyyyy'; // à demander à Entr'ouvert $client = new OAuth2\Client(CLIENT_ID, CLIENT_SECRET); if (!isset($_GET['code'])) { $auth_url = $client->getAuthenticationUrl(AUTHORIZATION_ENDPOINT, REDIRECT_URI); header('Location: ' . $auth_url); die('Redirect'); } else { $params = array('code' => $_GET['code'], 'redirect_uri' => REDIRECT_URI); $response = $client->getAccessToken(TOKEN_ENDPOINT, 'authorization_code', $params); $info = $response['result']; $client->setAccessToken($info['access_token']); $response = $client->fetch(USER_INFO); $compte_citoyen = $response['result']; // ... et ici se placera la construction ou la mise à jour de l'utilisateur // local, puis de la session, etc... dépendant de l'application. var_dump($compte_citoyen); // debug... } ?>
Par exemple ici https://application.example.net/oauth2.php, et placez bien cette valeur dans la variable REDIRECT_URI du code PHP.
Ces "CLIENT_ID" et "CLIENT_SECRET" devront être copiés dans le code PHP.
Vous devez être envoyé sur l'IdP : logez-vous et vous reviendrez sur l'application avec un compte.
Q = "id=" + urlencode(_I_) + email=" + urlencode(_C_) + "¬OnOrAfter=" + urlencode(iso8601(now + _dN_)) _L_ = _U_ + "?" + Q + "&signature=" + base64(hmac-sha1(_S_, Q))
Durant toute la période now - now+dN, l'application pourra se servir de l'adresse C sans problème.
Authentic aims at being a multiplexer of a maximum of authentication and security protocols, in order to improve interoperability between free softwares and ease identity management for little organizations. KISS is our moto.
Authentic vise à établir des passerelles entre un maximum de technologies d'authentification et de sécurité pour améliorer l'interopérabilité entre logiciels libre et facilité la gestion des identités dans les petites organisations. KISS est notre mot d'ordre.