Objectif de cette note : rappeler à l'éditeur d'un portail métier les standards SSO et plus précisément les impératifs pour se raccorder à un portail Publik. Ce texte pourra être inclus avec profit par les collectivités directement dans leur CCTP afin qu'il s'impose à l'éditeur métier.
Entr'ouvert ne fournit pas de base d'assistance à l'intégration ou à la spécification fonctionnelle d'un SSO. Si souhaité, cette assistance nécessitera un contrat de prestation auprès de la collectivité ou de l'éditeur/intégrateur du portail de l'éditeur métier.
Les spécifications désignées DOIVENT être respectées à la lettre, le nommage des attributs ("claim") et des scopes peut, par contre, être adapté.
Des implémentations de référence du protocole OpenID Connect pour différents langages et cadriciels sont disponibles sur https://openid.net/developers/libraries/
Le portail métier et ses éventuels web-services DOIVENT absolument être diffusés via le protocole HTTPS://
.
redirect_uris
post_logout_redirect_uris
frontchannel_logout_uri
Attention : si les URLs de redirection ont des domaines différents et l'UUID n'est pas utilisé comme identifiant, penser à définir une URL de secteur.
L'administrateur de la plateforme Publik transmettra à l'intégrateur du portail métier :client_id
client_secret
authorization_endpoint_url
(en général IDP_URL/idp/oidc/authorize/
)token_endpoint_url
(en général IDP_URL/idp/oidc/token/
)userinfo_endpoint_url
(en général IDP_URL/idp/oidc/user_info/
)IDP_URL/.well-known/openid-configuration
)Toutes les opérations de connexion ou déconnexion se font via des appels au fournisseur d'identité de la plateforme Publik de la collectivité, on désignera son URL par IDP_URL
.
Une authentification unique débutera comme suit :
1. déclenchement de l'authentification sur le portail (appui sur un bouton, appel à une URL particulière, protection de toutes les pages du portail, c'est un point d'implémentation qui relève de l'éditeur du portail métier)
IDP_URL/idp/oidc/authorize/?client_id=...&...&redirect_uri=...&state=...&...
client_id
: identifie le portail métier auprès du fournisseur d'identité, la valeur de ce champ sera fournit par l'administrateur de la plateforme Publikredirect_uri
: URL sur laquelle l'usager sera re-dirigé après authentification, elle devra être déclarée auprès de l'administrateur de la plateforme Publik (plusieurs sont possibles, mais pas de wildcard)state
: paramètre opaque retourné au retour sur le portail métier si le SSO échoue ou réussi, il permet au portail de maintenir un état entre la requête de SSO et sa réponse (par exemple URL de retour précise sur le portail, sachant que l'URL de retour au SSO ne peut pas varier énormément)3. le fournisseur d'identité de la plateforme Publik procède à l'authentification de l'usager, s'il n'est pas déjà authentifié, puis s'il n'a pas encore donné son autorisation lui présente un formulaire lui demandant de confirmer sa volonté de s'authentifier auprès du portail en fournissant un certain nombre d'attributs.
4. le fournisseur d'identité Publik redirige le navigateur de l'utilisateur sur l'URL de retour (ou de callback) déclaré par le portail métier par exemple,
https://portail-metier.collectivite.fr/oidc/callback/?code=xxx&state=yyy
5. le portail métier à la réception de cette requête doit :
5.1. éventuellement utiliser le paramètre state
pour retrouver un état conservé (URL de retour sur le portail, identifiant métier de la personne demandé préalablement, jeton transmis par mail ou SMS permettant l'appairage, etc...) en session
5.2. appeler le web-service token
(IDP_URL/ipd/oidc/token/
) du fournisseur d'identité en s'authentifiant avec son client_id
et son client_secret
(fourni lui aussi par l'administrateur de la plateforme Publik) permettant d'échanger code
contre un access_token
; l'access token est un jeton qui permettra d'appeler le web-service fournissant les informations sur l'utilisateur. Le web-service token
fournit aussi le sub
ou identifiant unique de l'utilisateur, c'est cet identifiant qui sert de clé à la liaison entre Publik et le portail-métier. Enfin, le web-service token
fournit deux valeurs iss
(identifiant de l'émetteur) et sid
(identifiant de la session) qui doivent être enregistrés dans la session créée sur le portail métier, en vue d'assurer la mécanique de déconnexion (voir plus bas).
5.3. appeler le web-service user-info
(IDP_URL/idp/oidc/user_info/
) pour obtenir les attributs de l'utilisateur qui lui sont autorisés.
sub
est connu
sub
est connu, il connecte l'usager à son compte ou un de ses comptes (voir plus haut)sub
est inconnu, il doit lancer un processus d'appairage ou de création de compte, nécessitant des interaction ou pas avec l'utilisateur (cette partie est entièrement à la charge de l'éditeur métier)Voir http://openid.net/specs/openid-connect-frontchannel-1_0.html#RPLogout
La plateforme Publik procédera à une re-direction sur l'URL frontchannel_logout_uri
via une iframe
invisible, le portail métier devra procéder à la déconnexion de la session en cours sur toute requête à cette URL et faire en sorte qu'elle ne puisse jamais être mise en cache par le navigateur.
Deux paramètres sont envoyés dans la query-string de l'URL frontchannel_logout_uri
: iss
et sid
. Ce sont ceux qui ont été reçus lors de l'appel au web-service token au début de la création de la session (voir plus haut). Ces deux paramètres permettent de retrouver la session en jeu sur le portail métier, et de la détruire afin d'assurer la déconnexion.
Note : il convient de régler les entêtes de sécurité de l'URL pour que celle-ci soit utilisable dans une iframe
. Notamment il ne faut pas renvoyer d'entête de restriction X-Frame-Options
, ni de limitation via Content-Security-Policy
.
Voir https://openid.net/specs/openid-connect-rpinitiated-1_0.html
Le portail-métier devra rediriger le navigateur de l'utilisateur sur l'URL IDP_URL/idp/oidc/logout/
, il pourra passer une URL de retour via le paramètre post_logout_redirect_uri
. Cette URL devra être préalablement déclarée auprès de l'administrateur Publik.
Publik propose un point d'entrée unique pour la gestion de la relation usager, à ce titre il est important que Publik puisse centraliser toutes les informations importantes des portails métiers tiers. Pour cela nous proposons la possibilité d'appeler des web-services portés par les portails métiers en vue d'afficher des informations dans les pages du portail citoyen de Publik.
{
"err": 0,
"data": {}
}
err
contiendra 0
si tout s'est bien passé, sinon 1
ou une chaîne de caractère indiquant le type de l'erreur,data
contiendra les données en sortie du web-service dans un dictionnaire JSON{
"err": "code-erreur-xxx",
"err_desc": "",
}
err
contiendra un code erreur (éventuellement 1
si rien de plus précis n'est décidé)err_desc
contiendra un texte décrivant l'erreur.sub
mis en place via le SSO, ce sub pourra être passé soit dans le contenu JSON (POST en JSON, {"sub": "xxx"}
), soit comme paramètre d'URL (https://portail/web-service/factures/?sub=xxxx
)Publik étant spécialisé dans la mise en place de télé-services, il y a un formalisme particulier à adopter pour faire remonter des demandes dans le portail Publik.
Ce téléservice devra répondre sur un GET et prendre en entrée le sub
comme paramètre de l'URL (le chemin de l'URL n'est pas imposé). La réponse devra avoir la forme exacte suivante :
GET /api/demandes/?sub=xxx
{
"err": 0,
"data": [
{
"datetime": "2018-03-04 12:34:32",
"name": "Demande de carte de stationnement",
"status": "En attente d'information",
"form_number": "1234",
"form_status_is_endpoint": false,
"url": "https://portail-metier/demandes/1234/",
"draft": false
}
]
}
Champ | Type | Obligatoire | Description |
datetime | string, la date au format ISO8601 YYYY-MM-DD HH:MM:SS | Oui | la date de création de la demande |
name | string | Oui | le nom du type de demande |
form_number | string | Oui | l'identifiant de la demande (numéro ou autre) |
url | string | Oui | lien profond vers la demande, si une URL par demande n'est pas disponible le portail métier peut se contenter de renvoyer l'URL d'une page affichant toutes les demandes en cours |
status | string | Oui | le statut actuel de la demande, "Nouvelle", "En cours", "En attente d'information", à définir par le portail mais la chaîne doit être présentable directement à l'usager, ce ne doit pas être un code |
form_status_is_endpoint | booléen | Non | vrai si le statut de la demande indique qu'elle est terminée |
draft | booléen | Non | vrai si la demande est un brouillon |
Publik contient nativement un système de remontée et paiement de factures, pour permettre une intégration des factures exposées par un portail métier tiers, il y a là aussi un formalisme particulier à respecter.
Le portail métier DOIT fournir un web-services porté par une URL de base que nous nommerons BASE_URL
, de la forme BASE_URL/invoices/
, le dernier élément du chemin est obligatoire.
Ce téléservice devra répondre sur un GET et prendre en entrée le sub
comme paramètre de l'URL (le chemin de l'URL n'est pas imposé). La réponse devra avoir la forme exacte suivante :
GET /api/invoices/?sub=xxx
{
"err": 0,
"data": [
{
"id": "939456",
"label": "restauration août 2015",
"amount": "37.26",
"total_amount": "37.26",
"created": "2015-08-01",
"pay_limit_date": "2015-09-29",
"paid": false,
"no_online_payment_reason": "litigation",
"payment_url": "https://portail-metier/factures/934395/pay/",
"pdf_url": "https//portail-metier/factures/934395/pdf/F20180192.pdf",
... (autres informations si le logiciel backend en donne)
},
]
}
Champ | Type | Obligatoire | Description |
id |
string, libre | Oui | identifiant interne au portail métier de la facture, uniquement pour debug |
amount |
string, décimal | Oui | montant du reste à payer, nombre décimal formaté avec un point décimal et non une virgule décimale (à l'anglaise) |
total_amount |
string, décimal | Oui | montant total de la facture, format identique à amount |
created |
string, date ISO | Oui | date de création de la facture, format ISO8601 YYYY-MM-DD |
pay_limit_date |
string, date ISO | Oui | date limite de paiement de la facture, date exlue (i.e. à partir de cette date le paiement n'est plus possible), format ISO8601 YYYY-MM-DD |
payment_url |
string, URL | Non | l'URL pour payer la facture si celle-ci est payable en ligne |
pdf_url |
string, URL | Non | l'URL vers le PDF de la facture si celle-ci est téléchargeable |
non_online_payment_reason |
sttring, enum | Non | si payment_url est absent, la raison éventuelle de la non-possibilité de paiement en ligne (contestation, prélèvement, délai dépassé), voir plus loin les valeurs possibles |
no_online_payement_reason
sont :
Valeur | Description |
litigation |
la facture pose un problème |
autobilling |
la facture est payée par prélèvement automatique |
past_due_date |
il n'est plus possible de payer cette facture en ligne car un délai est dépassé |
sub
data
contiendra une liste de données qui seront transformés en HTML, chaque donnée est décrite par un dictionnaire et possède un type, ex:{
"type": "block",
"label": "Mes informations familles",
"content": [...],
"edit_url": "https://portail-metier/ma-famille/",
}
Type | Description |
block |
un bloc composé d'autres éléments, permet de grouper |
text |
un paragraphe, peut contenir un texte simple, pré-formaté ou formaté en HTML, en utilisant uniquement les balises autorisés dans un noeud <p> du HTML (balises inline, <em/> , <i/> , <b/> ), ainsi qu'un lien d'édition (pictogramme stylo dans le coin haut-droit du contenu) |
table |
un tableau, contenant des lignes qui contiennent soit des entête header soit des cellules de contenu text |
label
qui ajoutera un titre avec le bon niveau d'imbrication avant le contenu,id
et class
(respectivement une chaîne et une liste de chaînes) permettant de donner des valeurs pour les attributs HTML correspondant, simplifiant l'application d'une feuille de style.Exemple de présentation d'un profil famille venant d'un portail famille :
{
"err": 0,
"data": {
"type": "block",
"label": "Ma famille",
"edit_url": "https://portail-famille/ma-famille/edit/",
"content": [
{
"type": "text",
"id": "adresse",
"label": "Adresse",
"pre": true,
"content": "1 rue du calvaire\nXX100 MAVILLE"
},
{
"type": "text",
"id": "parent1",
"class": "parent",
"label": "Premier parent",
"html": true,
"content": "Jean-Michel <b>DUPOND</b>, né le 12 décembre 1964 à Marseille",
},
{
"type": "text",
"id": "parent2",
"class": "parent",
"label": "Second parent",
"html": true,
"content": "Régine <b>DUPOND</b>, né MARTIN le 12 décembre 1964 à Lyon"
}
{
"type": "block",
"label": "Enfants",
"content": [
{
"type": "text",
"content": "Kévin DUPOND, 5 ans, né le 22 mars 2013",
}
]
}
]
}
}
Le but de ce formalisme est de laisser à la fois un peu de liberté au portail métier sur les contenus et aussi la liberté pour Publik d'appliquer des feuilles de style aux contenus.
Coté Publik, ces contenus seront présentés via des cellules JSON (cellule associant un web-service JSON avec un template).
1 technologie équivalente https://github.com/portabletext/portabletext
Voir https://doc-publik.entrouvert.com/dev/echanges-logiciel-de-demandes-metier/ en sachant que l'information « sub » peut être envoyée dans la demande si elle doit être reliée à un compte dans le logiciel cible.