Aller au contenu principal
Version: Cible · roadmap

Identité

Qui parle à la station ? Une room commence anonyme. Elle peut ensuite être identifiée par une donnée que la personne donne, puis authentifiée quand un fournisseur prouve que cette donnée est bien la sienne. Les permissions et les politiques lisent le résultat ; elles ne savent pas comment il a été obtenu.

Déclaré, vérifié​

Une donnée d'identité porte un nom que la station choisit — phone, email, customer_id… — et une valeur. Elle a l'un de deux niveaux.

déclaré — la room est identifiéevérifié — la personne est authentifiée
vient deun champ de formulaire marqué identifies: true : la personne l'a tapéun fournisseur qui l'a prouvé : un code reçu, une connexion SSO, le login du tenant
prouverien sur la personnequ'elle contrôle ce numéro, cet e-mail, ce compte
vaut pourcette room seulementla personne : la room lui appartient
donnela donnée n'est plus redemandée, et part au tenant avec le submiten plus : ses autres rooms, son historique, et submitted_by: owner
retrouve d'autres roomsjamaisoui, pour elle seule

Un numéro tapé ne retrouve jamais rien : n'importe qui peut taper le numéro d'un autre, et cela ne doit montrer ni ses commandes ni son adresse. Le retrouver d'une room à l'autre demande la même donnée vérifiée.

Identifier une room : identifies: true​

Un champ de formulaire identifie la room ; la donnée porte le nom du champ.

skills:
- name: takeDeliveryOption
select:
guards:
- form:
phone: {type: phone, required: true, identifies: true}
address: {type: text}

La room garde le numéro au niveau déclaré : les formulaires suivants de la room ne le demandent plus — Core y répond —, et il part au submit. Le modèle sait que la room a un téléphone, jamais lequel. Deux champs qui déclarent le même nom avec des types différents sont refusés au chargement.

Vérifier : les fournisseurs​

La station déclare les fournisseurs qu'elle accepte, dans station.identity.providers. Chacun est un mécanisme que Convoy prépare : on le configure, on ne le code pas. Chacun dit la donnée qu'il vérifie (verifies:).

mécanismeprouvese configure avec
otpla personne reçoit les codes envoyés à cette donnée (un téléphone, un e-mail)verifies, puis via: tenant (les opérations send et check du tenant, dans ses apis) ou via: convoy (le service que Convoy opère, channel: sms ou email)
oidcla personne s'est connectée chez un fournisseur d'identité : Okta, Auth0, Keycloak, Entra ID, Google…verifies (le claim qui nomme la personne), issuer, client_id_env, scopes, attributes
assertionle site du tenant a déjà connecté la personneverifies (l'identifiant client du tenant), secret_env, attributes, login_url (sa page de connexion, pour une demande d'authentification)

La version actuelle a déjà otp avec via: tenant : voir Auth.

attributes dit quels autres champs du fournisseur les règles peuvent lire, et sous quel nom : {roles: groups, teams: teams, manager: manager} pour un annuaire.

station:
identity:
providers:
sms: {mechanism: otp, verifies: phone, via: tenant, send: sendOtp, check: checkOtp}
salaries: {mechanism: oidc, verifies: email, issuer: "https://acme.okta.com",
client_id_env: OKTA_CLIENT_ID, attributes: {roles: groups, teams: teams, manager: manager}}
compte: {mechanism: assertion, verifies: customer_id, secret_env: SHOP_IDENTITY_SECRET,
attributes: {addresses: addresses}}

Au chargement, une configuration qui ne peut pas marcher est refusée : via: tenant avec des opérations que le tenant ne déclare pas, un oidc sans client_id_env, un auth: qui nomme un fournisseur absent.

Convoy ne garde jamais un secret de la personne : pas de mot de passe, pas de code, pas de page de connexion à lui. Il garde le résultat — telle donnée est vérifiée, par tel fournisseur, à telle heure.

Chaque portail dit comment il prouve qui parle​

Un portail nomme le fournisseur qu'il propose, ou anonymous :

agent:
portals:
web:
widget: {identity: {auth: compte}} # sur le site du tenant, sa connexion suffit
pwa: {identity: {auth: sms}} # hors du site, un code par SMS
teams: {app: commandes, identity: {auth: salaries}}

Le portail est décrit dans L'agent et ses portails. Quand une skill exige une preuve, c'est ce fournisseur que Core propose : voir Demander l'authentification.

Ce que les règles lisent : identity​

Les profils, les permissions et les politiques lisent un objet identity. Il donne des noms et des attributs, jamais les valeurs des données d'identité : une règle teste qu'un téléphone est vérifié, pas quel numéro c'est.

champsensvient de
identity.typeperson ou agentla porte
identity.authenticatedau moins une donnée vérifiéeles fournisseurs
identity.verifiedles noms des données vérifiées : 'phone' in identity.verifiedles fournisseurs
identity.declaredles noms des données déclarées dans cette roomles formulaires
identity.providerle fournisseur qui a vérifiéles fournisseurs
identity.<attribut>roles, teams, manager, addresses…les attributes du fournisseur
identity.org, identity.station, identity.roles, identity.limitspour un agent : son organisation, la station qui appelle, les rôles et les limites posés sur sa sous-identitéla sous-identité déléguée
profiles:
anonyme: {when: "identity.authenticated == false"}
client: {when: "'phone' in identity.verified"}
manager: {when: "'support-manager' in identity.roles"}

La room et son propriétaire​

Quand une donnée est vérifiée, la room est réclamée : elle appartient désormais à cette personne, son propriétaire (owner). Ses autres rooms lui sont rendues, à elle seule.

submitted_by: [{who: owner}] exige ce propriétaire vérifié au submit. Sans cette règle, un humain dans la room soumet, même anonyme : le clic du client. Avec elle, détenir le code de la room ne suffit plus — il faut recevoir le code, ou être connecté. Voir Le submit.

Recommandé pour toute station qui passe des commandes ou des demandes chez le marchand. Sans connexion, rien ne distingue la cliente sur un autre appareil d'un inconnu qui tient le code : les deux peuvent finaliser. Si la station sait connecter mais n'exige pas submitted_by: owner, la sélection invite le client à se connecter avant de finaliser, sans l'y obliger.

Les données d'identité, protégées​

  • La valeur est gardée parce que le tenant en a besoin dans son submit, et pour rien d'autre.
  • Les recherches passent par une empreinte (HMAC, une clé par tenant, le tenant compris dans l'empreinte) : aucun index ne contient un numéro en clair. Le provisioner dérive la clé de chaque tenant de celle du déploiement ; changer celle-ci déconnecte tout le monde.
  • Elle suit la durée de vie de la room ; l'effacement demandé par le propriétaire l'efface.

Trois exemples​

Simple — la room identifiée par un numéro, sans preuve. Le tenant reçoit le numéro au submit, la room s'en souvient ; les submits restent anonymes.

skills:
- name: takeDeliveryOption
select:
guards:
- form:
phone: {type: phone, required: true, identifies: true}

Moyen — le numéro vérifié par un code, et seul le propriétaire soumet.

station:
identity:
providers:
sms: {mechanism: otp, verifies: phone, via: tenant, send: sendOtp, check: checkOtp}

skills:
- name: takeDeliveryOption
select:
guards:
- form:
phone: {type: phone, required: true, identifies: true}

agent:
portals:
web:
widget: {identity: {auth: sms}}

playbooks:
- name: commande
submit_guard:
submitted_by: [{who: owner}]

Avancé — une voie par portail. Le client connecté sur le site est vérifié sans rien taper ; hors du site, il reçoit un code ; un salarié passe par le SSO de l'entreprise, qui donne ses rôles.

station:
identity:
providers:
sms: {mechanism: otp, verifies: phone, via: convoy, channel: sms}
compte: {mechanism: assertion, verifies: customer_id, secret_env: SHOP_IDENTITY_SECRET}
salaries: {mechanism: oidc, verifies: email, issuer: "https://login.microsoftonline.com/acme/v2.0",
client_id_env: ENTRA_CLIENT_ID, attributes: {roles: groups}}

agent:
portals:
web:
widget: {identity: {auth: compte}}
pwa: {identity: {auth: sms}}
teams: {app: commandes-internes, identity: {auth: salaries}}

profiles:
acheteur: {when: "'purchasing' in identity.roles"}

playbooks:
- name: commande
submit_guard:
submitted_by: [{who: owner}]