Signaux partagés (SSF)
Sur cette page
Quand un utilisateur est désactivé ou supprimé, TOSIAM ferme ses sessions et révoque ses jetons (voir Révocation à la désactivation). Une application qui garde sa propre session, ou qui valide les jetons par leur seule signature, n’en sait rien : elle accepte l’utilisateur jusqu’à l’expiration.
À partir de la version 3.38.0, TOSIAM peut la prévenir. Il est émetteur du Shared Signals Framework (SSF 1.0) : il pousse à chaque application abonnée, le récepteur, un jeton d’événement de sécurité signé (SET, RFC 8417), ou le lui garde jusqu’à ce qu’elle le relève.
| Changement | Événements | Canaux |
|---|---|---|
| Utilisateur désactivé | RISC account-disabled et CAEP session-revoked | Tous |
| Utilisateur supprimé | RISC account-purged et CAEP session-revoked | Tous |
| Utilisateur réactivé | RISC account-enabled | Écriture par TOSIAM seulement |
| Clé d’accès supprimée par l’utilisateur ou un administrateur | CAEP credential-change | Console, API, libre-service |
Une désactivation ou une suppression est signalée quel que soit le canal du changement : console, API REST, ssoadm, TOSIDM ou écriture directe dans l’annuaire (voir ce qui déclenche la révocation). Une réactivation n’est connue que si TOSIAM l’écrit lui-même : rien ne garde l’état précédent d’un compte réactivé dans l’annuaire. Les clés d’accès d’un utilisateur supprimé ne donnent pas de credential-change : sa suppression est déjà signalée.
1. Le récepteur#
Un récepteur est un client OAuth2 du royaume. Il gère son flux d’événements avec un jeton d’accès :
- obtenu pour lui-même, par le grant
client_credentials: un jeton délivré pour un utilisateur est refusé ; - portant la portée
ssf.manage, à ajouter aux portées du client.
Un récepteur a un flux. Il ne voit ni ne modifie celui d’un autre récepteur.
curl -s -u crm:secret -d grant_type=client_credentials -d scope=ssf.manage \
https://am.example.com/tosiam/oauth2/ventes/access_token2. Découverte#
La configuration de l’émetteur est publiée à côté de celle d’OpenID Connect, sans authentification :
GET /tosiam/oauth2/<royaume>/.well-known/ssf-configuration{
"spec_version": "1_0",
"issuer": "https://am.example.com/tosiam/oauth2/ventes",
"jwks_uri": "https://am.example.com/tosiam/oauth2/ventes/connect/jwk_uri",
"delivery_methods_supported": ["urn:ietf:rfc:8935", "urn:ietf:rfc:8936"],
"configuration_endpoint": "https://am.example.com/tosiam/oauth2/ventes/ssf/stream",
"status_endpoint": "https://am.example.com/tosiam/oauth2/ventes/ssf/status",
"verification_endpoint": "https://am.example.com/tosiam/oauth2/ventes/ssf/verify",
"add_subject_endpoint": "https://am.example.com/tosiam/oauth2/ventes/ssf/subjects/add",
"remove_subject_endpoint": "https://am.example.com/tosiam/oauth2/ventes/ssf/subjects/remove",
"authorization_schemes": [{"spec_urn": "urn:ietf:rfc:6749"}],
"default_subjects": "ALL"
}Par défaut, un flux porte sur tous les utilisateurs du royaume (default_subjects: ALL). Un récepteur peut le restreindre (voir Sujets).
3. Gérer son flux#
| Requête | Rôle |
|---|---|
POST /ssf/stream | Créer le flux. Répond 409 si le récepteur en a déjà un. |
GET /ssf/stream | Lister les flux du récepteur (zéro ou un). Avec ?stream_id=, lire le flux. |
PATCH /ssf/stream | Changer les champs donnés. |
PUT /ssf/stream | Remplacer les réglages : un champ absent reprend sa valeur par défaut. |
DELETE /ssf/stream?stream_id= | Supprimer le flux et les événements en attente. |
GET /ssf/status?stream_id=, POST /ssf/status | Lire ou changer le statut. |
POST /ssf/verify | Demander un événement de vérification. |
POST /ssf/subjects/add, POST /ssf/subjects/remove | Ajouter ou retirer un sujet. |
POST /ssf/poll | Relever les événements d’un flux en relève. |
Création :
curl -s -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
https://am.example.com/tosiam/oauth2/ventes/ssf/stream -d '{
"delivery": {
"method": "urn:ietf:rfc:8935",
"endpoint_url": "https://crm.example.com/ssf/events",
"authorization_header": "Bearer jeton-du-crm"
},
"events_requested": [
"https://schemas.openid.net/secevent/risc/event-type/account-disabled",
"https://schemas.openid.net/secevent/risc/event-type/account-purged",
"https://schemas.openid.net/secevent/caep/event-type/session-revoked"
],
"description": "CRM"
}'delivery: poussée (urn:ietf:rfc:8935) ou relève (urn:ietf:rfc:8936).- Pour une poussée, l’
endpoint_urldoit être enhttps, sans utilisateur ni fragment. L’authorization_headerest envoyé tel quel à chaque poussée. Il est gardé chiffré et n’est jamais renvoyé. - Pour une relève, le récepteur ne donne pas d’
endpoint_url: la réponse lui donne celui de TOSIAM,/ssf/poll. - Changer de méthode déplace les événements en attente vers la nouvelle.
- Pour une poussée, l’
events_requested: sans ce champ, tous les événements pris en charge sont livrés. La réponse donneevents_delivered, les événements demandés que TOSIAM prend en charge.default_subjects:ALL(par défaut) ouNONE. SSF 1.0 définit ce champ pour l’émetteur entier ; TOSIAM laisse chaque récepteur le choisir pour son flux.
Sujets#
Un flux ALL porte sur tous les utilisateurs du royaume, sauf ceux que le récepteur a retirés. Un flux NONE ne porte sur aucun, sauf ceux qu’il a ajoutés.
curl -s -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
https://am.example.com/tosiam/oauth2/ventes/ssf/subjects/add -d '{
"stream_id": "8c1f...",
"subject": {"format": "iss_sub", "iss": "https://am.example.com/tosiam/oauth2/ventes", "sub": "jdupont"}
}'- Le sujet est au format
iss_sub, avec l’issuer du flux et lesubque le récepteur connaît, pairwise compris. Les autres formats sont refusés (400). - Un flux liste 1 000 sujets au plus.
- Changer
default_subjectsabandonne les sujets ajoutés ou retirés : ils voudraient dire le contraire.
La spécification OpenAPI de ces points est publiée sous le nom ssf, comme celle d’OpenID Connect.
4. Les événements#
Chaque événement est un JWT de type secevent+jwt, signé par les clés OAuth2 du royaume, celles du jwks_uri : le récepteur le vérifie comme un id_token. Un royaume qui signe ses jetons par secret partagé (HS256) signe ses événements en RS256.
{
"iss": "https://am.example.com/tosiam/oauth2/ventes",
"jti": "3c3c4f0e-8a6b-4f2d-9f43-0d8f1b3a2c11",
"iat": 1761696000,
"aud": ["crm"],
"txn": "b7c1d2e3-0f45-4a6b-8c9d-0e1f2a3b4c5d",
"sub_id": {
"format": "iss_sub",
"iss": "https://am.example.com/tosiam/oauth2/ventes",
"sub": "jdupont"
},
"events": {
"https://schemas.openid.net/secevent/caep/event-type/session-revoked": {
"event_timestamp": 1761696000,
"initiating_entity": "admin",
"reason_admin": {"en": "The account was disabled"}
}
}
}sub_id: lesubque le client connaît, celui de ses id_tokens. Il est pairwise si le client le demande.txn: commun aux événements d’un même changement. Quand TOSIAM a écrit le changement, c’est la transaction de la requête, qu’on retrouve dans l’audit.initiating_entity:adminquand le changement a été écrit par TOSIAM (console, API, ssoadm),systemquand il a été appris de l’annuaire (TOSIDM, écriture directe).account-disabled,account-enabledetaccount-purgedne portent pas de champ.credential-changeportecredential_type(fido2-platform, oufido2-roamingquand le rattachement de la clé n’est pas connu),change_type(delete),friendly_nameetfido2_aaguidquand ils sont connus,initiating_entity(userouadmin) etevent_timestamp.
Une désactivation ou une suppression est signalée une seule fois pour tout le site : chaque serveur reçoit la notification de l’annuaire, et un seul d’entre eux émet, élu par une réservation dans le Core Token Store. Le serveur qui a écrit le changement passe en premier, car il en connaît l’auteur et la transaction : les autres attendent 5 secondes avant de tenter leur chance. Un changement fait hors de TOSIAM est donc signalé environ 5 secondes après sa notification. Quand TOSIAM apprend seulement qu’un utilisateur déjà inactif a été modifié, il ne le signale de nouveau qu’au bout d’un jour. Une réactivation par TOSIAM lève cette retenue : une nouvelle désactivation est signalée aussitôt. Une réactivation et une suppression de clé d’accès ne sont connues que du serveur qui les écrit, qui les signale seul.
5. Livraison#
Les événements attendent dans le Core Token Store : n’importe quel serveur du site les livre, même si celui qui les a émis s’arrête.
POST https://crm.example.com/ssf/events
Content-Type: application/secevent+jwt
Accept: application/json
Authorization: Bearer jeton-du-crm
eyJ0eXAiOiJzZWNldmVudCtqd3QiLCJraWQiOi...| Réponse du récepteur | Suite |
|---|---|
| 2xx (202 attendu) | Livré, supprimé de la file |
| 400, 413, 415 | Refusé : abandonné |
| Autre réponse, ou récepteur injoignable | Nouvel essai après 2 s, puis un délai doublé à chaque essai, au plus 5 min ; abandon après 10 essais |
Un événement non livré au bout de 24 heures est abandonné. Les redirections ne sont pas suivies.
Relève#
Un flux en relève (RFC 8936) garde ses événements jusqu’à ce que le récepteur les acquitte :
curl -s -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
https://am.example.com/tosiam/oauth2/ventes/ssf/poll -d '{
"ack": ["3c3c4f0e-8a6b-4f2d-9f43-0d8f1b3a2c11"],
"maxEvents": 10,
"returnImmediately": false
}'{
"sets": {"5d1e...": "eyJ0eXAiOiJzZWNldmVudCtqd3QiLCJraWQiOi..."},
"moreAvailable": false
}ack: lesjtides événements reçus, supprimés de la file.setErrs: ceux que le récepteur refuse, parjti, supprimés aussi et tracés dans les journaux.maxEvents: 20 par défaut, 100 au plus. Les événements sont rendus du plus ancien au plus récent, et rendus de nouveau tant qu’ils ne sont pas acquittés.- Sans
returnImmediately, la requête attend un événement jusqu’à 5 secondes. - Un flux en pause ne rend rien. Un événement non relevé au bout de 24 heures est abandonné.
Vérification et statut#
- Vérification :
POST /ssf/verifyavec{"stream_id": "...", "state": "..."}. TOSIAM pousse un événementverificationqui renvoie lestate, au sujet du flux lui-même ({"format": "opaque", "id": "<stream_id>"}). - Statut :
POST /ssf/statusavec{"stream_id": "...", "status": "paused"}.
| Statut | Effet |
|---|---|
enabled | Les événements sont livrés. |
paused | Les événements sont gardés, et livrés dans la minute qui suit la réactivation, s’ils ont moins de 24 heures. |
disabled | Les événements sont abandonnés, y compris ceux en attente. |
6. Réglage et suivi#
| Propriété serveur | Valeur par défaut | Rôle |
|---|---|---|
org.tst.tosiam.ssf.allowInsecureEndpoints | false | Accepte un endpoint_url en http. Réservée aux tests. |
Sans flux dans un royaume, une révocation n’ajoute aucune écriture au Core Token Store.
Les journaux sont écrits par la catégorie OAuth2Provider :
SSF stream 8c1f... of crm created in the realm /ventes
2 SSF event(s) of jdupont emitted, txn b7c1d2e3-...
SSF event 3c3c4f0e-... delivered to crm
SSF event 3c3c4f0e-... not delivered to crm, attempt 1: ConnectException: ...
SSF event 3c3c4f0e-... for crm given up after 10 attempt(s): 503 ...7. Limites de cette version#
account-enabledn’est émis que pour une réactivation écrite par TOSIAM.credential-changen’est émis que pour les clés d’accès, pas pour les appareils OATH ou push, ni pour le mot de passe.session-revokedn’est émis qu’à la désactivation ou à la suppression d’un utilisateur, pas à une déconnexion ordinaire.- Les sujets sont au seul format
iss_sub.
Mis à jour le