Façade d'API et Sécurité
- Tutorial
Ce document présente les points d'entrée de RestFrontage pour authentifier un client, consulter ou modifier la sécurité, filtrer les objets OData et utiliser les outils Razor.
Pour le modèle conceptuel et les règles de décision, consulter Présentation de la sécurité dans Immersive.
Authentification d'un client API
Obtenir un jeton
POST {{baseUrl}}/api/Security/User/Authenticate
Content-Type: application/json
{
"AccountName": "utilisateur",
"Password": "mot-de-passe"
}
Alias accepté : POST /api/Security/Users/Authenticate.
Réponse simplifiée :
{
"Domain": "DC=Immersive, DC=GraphicStream, DC=fr",
"Token": "eyJ...",
"AuthenticatedUser": {
"Identifier": 123,
"DistinguishedNameValue": "AN=utilisateur, OU=Users, ..."
}
}
Le client transmet ensuite :
Authorization: Bearer {{token}}
Les identifiants et le mot de passe doivent être envoyés uniquement en HTTPS.
Cycle du jeton
| Verbe et route | Fonction |
|---|---|
POST /api/Security/Token/Renew |
Renouveler un jeton valide |
GET ou POST /api/Security/Token/Validate |
Vérifier que le pipeline accepte le jeton |
GET ou POST /api/Security/Whoami |
Obtenir le nom de l'identité courante |
Endpoints principaux de sécurité
Toutes les routes ci-dessous ont le préfixe /api/Security.
Contrôle et administration des droits
| Verbe et route | Usage | État recommandé |
|---|---|---|
GET /Users/{askerId}/Rights/{flags}/SecurizedObjects/{type}/{objectId} |
Tester un masque sur un objet | Historique ; n'intègre pas les partages |
GET /Rights?securedObjectIdentifier=...&securedObjectTypeIdentifier=... |
Lire les droits explicites d'un objet | Utilisable pour l'administration |
POST /Rights |
Appliquer une collection de droits via ISecurityAdministrationService |
Point d'écriture recommandé |
DELETE /Rights?rightIdentifiers=... |
Supprimer des droits par identifiant | Historique ; à migrer vers la façade centrale |
GET /Permissions |
Lire les permissions configurées | Recommandé pour construire une interface sans flags codés en dur |
Exemple d'application d'un droit :
POST {{baseUrl}}/api/Security/Rights
Authorization: Bearer {{token}}
Content-Type: application/json
[
{
"Identifier": 0,
"DomainSecurityObjectIdentifier": 145,
"SecurizedObjectIdentifier": 902,
"SecurizedObjectType": 15,
"AuthorizedFlags": 3,
"DeniedFlags": 0
}
]
Règles de POST /Rights :
- l'acteur est toujours lu depuis le contexte authentifié ;
- Cerebrate et les administrateurs racine peuvent administrer tous les droits ;
- sinon l'acteur et les bénéficiaires doivent appartenir à l'organisation courante ;
- un bénéficiaire
BuiltInest protégé ; - l'acteur doit pouvoir administrer chaque objet cible ;
- les flags doivent correspondre aux permissions configurées ;
AuthorizedFlags = 0etDeniedFlags = 0supprime le droit correspondant ;- plusieurs requêtes visant le même triplet sont normalisées avant l'écriture.
Réponses d'erreur :
400: données ou flags invalides ;401: absence d'identité authentifiée ;403: acteur non autorisé ou mauvaise organisation ;409: incohérence ou conflit de données, par exemple anciens droits dupliqués.
Partages
| Verbe et route | Usage |
|---|---|
POST /SharedAccess |
Créer un partage dont AccessLinkIdentifier référence une TinyUrl existante |
POST /SharedAccess/Aggregate |
Créer explicitement un agrégat et préciser la TinyUrl au niveau racine |
POST /SharedAccess/{grantIdentifier}/Revoke |
Révoquer le partage sans supprimer la TinyUrl |
Exemple de partage interne pendant une semaine :
POST {{baseUrl}}/api/Security/SharedAccess/Aggregate
Authorization: Bearer {{token}}
Content-Type: application/json
{
"TinyUrlIdentifier": "equipment-902-share",
"Grant": {
"BeneficiaryDomainSecurityObjectIdentifier": 245,
"ExternalRecipientEmail": null,
"ValidFromUtc": "2026-08-18T10:00:00Z",
"ExpiresAtUtc": "2026-08-25T10:00:00Z",
"Rights": [
{
"SecurizedObjectIdentifier": 902,
"SecurizedObjectType": 18,
"AuthorizedFlags": 1
},
{
"SecurizedObjectIdentifier": 84,
"SecurizedObjectType": 15,
"AuthorizedFlags": 1
},
{
"SecurizedObjectIdentifier": 31,
"SecurizedObjectType": 48,
"AuthorizedFlags": 1
}
]
}
}
Pour un destinataire externe, renseigner ExternalRecipientEmail et laisser BeneficiaryDomainSecurityObjectIdentifier à null. Exactement un des deux champs doit être défini.
Réponse simplifiée :
{
"grantIdentifier": 12,
"publicIdentifier": "...",
"externalAccessToken": "retourné uniquement pour un partage externe",
"tinyUrlIdentifier": "equipment-902-share",
"tinyUrlPath": "/?TU=equipment-902-share",
"externalAccessPath": "/Shared?token=...&tinyUrl=equipment-902-share"
}
Le serveur ne déduit aucune dépendance. Beholder, Forge ou le Player doit envoyer la liste complète des objets nécessaires à l'ouverture de la cible.
Il n'existe pas encore de route REST dédiée à la liste des partages. Cette liste est actuellement consommée par la partial Razor via GetSharedAccessGrantsAsync.
Appel minimal de la modale de partage :
/Security/Modals/SharedAccess
?SecurizedObjectIdentifier={identifier}
&SecurizedObjectType={type}
&TinyUrlIdentifier={tinyUrlExistante}
Annuaire
La façade expose aussi les familles suivantes :
| Famille | Routes principales |
|---|---|
| Résolution | GET /DomainObjects/{dnOuId}, POST /Discover |
| Navigation | GET /DomainObjects/{dn}/Members, GET /Explorer/{dn}/Search/{criteria} |
| Appartenances | GET, POST, PUT, DELETE /DomainObjects/{dn}/Membership |
| Membres de groupe | PUT, POST, DELETE /Groups/{dn}/Members |
| Hiérarchie | GET /DomainObjects/{dn}/GroupMembershipHierarchy |
| Champs extensibles | GET, PUT, POST /DomainObjects/{dn}/Fields |
| Utilisateurs | POST /Users, PUT /Users, PATCH /Users({id}), DELETE /Users/{id} |
| Groupes | POST /Groups, PUT /Groups, PATCH /Groups({id}), DELETE /Groups/{id} |
| OU | POST /OrganizationalUnits, PUT /OrganizationalUnits, PATCH /OrganizationalUnits({id}), DELETE /OrganizationalUnits/{id} |
| Reconstruction d'organisation | POST /OrganizationalUnits/{id}/SubDomain/Rebuild |
Ces routes d'annuaire sont en partie historiques et ne passent pas toutes par ISecurityAdministrationService. Toute nouvelle mutation doit utiliser la façade transversale ou étendre celle-ci.
OData sécurisé
ODataCrudController<TEntity> applique la sécurité seulement si le type Immersive possède des permissions configurées.
Pour un type sécurisé :
GETfiltre leIQueryableavant l'application des options OData ;GET(key)et les navigations vérifient la visibilité du parent ;PUTetPATCHexigent la permission de modification du contrôleur ;DELETEexige la permission de suppression du contrôleur ;POSTexige Cerebrate, un administrateur racine ou le groupeAdministratorsdu sous-domaine cible ;- après création, les droits automatiques sont appliqués par la façade d'administration.
| Entity set | Type | Lecture | Modification | Suppression |
|---|---|---|---|---|
/odata/Maps |
15 |
ReadMap |
ModifyMap |
FullControlMap |
/odata/Equipments |
18 |
ReadEquipment |
ModifyEquipment |
FullControlEquipment |
/odata/Workspaces |
37 |
ReadWorkspace |
ModifyWorkspace |
FullControlWorkspace |
/odata/SupervisionScopes |
48 |
ReadSupervisionScope |
ModifySupervisionScope |
FullControlSupervisionScope |
Exemple :
GET {{baseUrl}}/odata/SupervisionScopes?$filter=Name eq 'Yvetot'&$select=Identifier,Name
Authorization: Bearer {{token}}
Accept: application/json
Le filtre de sécurité et le filtre OData sont composés puis exécutés par la base métier. Le contrôleur ne doit pas télécharger toute la collection avant de filtrer.
Pages utiles du RestFrontage
Entrées principales
| Chemin | Fonction | Accès |
|---|---|---|
/Security |
Tableau de bord du domaine courant | Utilisateur authentifié |
/Security/Explorer |
Parcourir les OU, utilisateurs, groupes et devices | Utilisateur authentifié |
/Security/UsersAndGroups |
Rechercher et administrer utilisateurs et groupes | Utilisateur authentifié ; mutations contrôlées par leurs handlers |
/Security/RightsTester |
Expliquer un droit effectif | Utilisateur authentifié et organisation courante |
/Security/Tools |
Audits et réparations de sécurité | Cerebrate uniquement |
Testeur de droits
Le testeur permet de choisir :
- un utilisateur ou un groupe ;
- un type d'objet reconnu ;
- un objet appartenant à l'organisation courante ;
- une permission configurée pour ce type.
Il produit un AuditAccess qui détaille les chemins d'appartenance ayant autorisé ou interdit l'accès. Le catalogue détecte les types à partir des DbSet<TEntity> dont l'entité implémente IIdentifiedObject et possède un ImmersiveObjectAttribute.
Limites actuelles : sélection plafonnée à 5 000 objets par type et absence des partages internes dans le rapport.
Outils Cerebrate
La page /Security/Tools est accessible uniquement par Cerebrate. Elle ne doit pas servir d'interface d'administration courante.
Unicité des droits
L'outil affiche :
- le nombre de droits ;
- les groupes dupliqués ;
- la présence de l'index unique SQL.
Le nettoyage manuel actuel conserve la ligne la plus récente du groupe choisi. La migration 20260815_EnforceUniqueRights suit une stratégie plus conservatrice : elle fusionne d'abord tous les flags autorisés et interdits avant de supprimer les anciennes lignes.
Structure des organisations
L'audit vérifie pour chaque organisation :
- les OU
Groups,UsersetDevices; - les groupes
Administrators,UsersetSharers; - l'utilisateur
{Organisation}_Admin; - les appartenances standard ;
- les groupes conventionnels de permission déjà reconnus.
La réparation appelle EnsureSubDomainDefaultsAsync et préserve les données existantes.
Droits automatiques
L'audit compare les droits attendus et enregistrés pour :
- les cartes ;
- les équipements ;
- les workspaces ;
- les scopes de supervision.
Il peut réparer un objet ou une sélection. La réparation ajoute seulement les flags automatiques manquants.
Points de vigilance et durcissements à prévoir
Priorité haute
GET /api/Security/ResetDomainporte actuellement[AllowAnonymous]. Même s'il ne modifie pas les droits, il provoque un rechargement et une invalidation globale ; il doit être protégé ou déplacé vers la console de récupération.DELETE /api/Security/Rightssupprime directement dansSecurityModelsans passer par l'autorisation deISecurityAdministrationService. Il doit être remplacé parPOST /Rightsavec des flags à zéro ou par une méthode centrale dédiée.- Les partages internes ne sont pas encore consultés par
ObjectSecurityService. Ils sont persistés mais ne donnent pas encore accès dans OData. - Le test historique
HaveRightet le testeur Razor utilisentSecurityUtilsdirectement et ne voient pas les partages.
Priorité de cohérence
- Centraliser progressivement les mutations d'utilisateurs, groupes, OU et appartenances.
- Ajouter une route authentifiée de sélection d'organisation adaptée aux clients Bearer stateless, ou inclure un contexte d'organisation contrôlé dans le contrat API.
- Exposer une route de liste des partages si les clients WebGL doivent administrer les partages sans partial Razor.
- Étendre l'audit des droits automatiques lorsque de nouveaux types sont branchés au pipeline.
- Retirer à terme les alias historiques après migration des clients.
Ajouter un nouveau type sécurisé
Pour étendre la façade sans créer un service par type :
- déclarer le type dans
ImmersiveObjectType; - appliquer
ImmersiveObjectAttributesur l'entité ; - enregistrer ses
Permissiondans le domaine et l'instantanéObjectsToPermissions; - dériver le contrôleur d'
ODataCrudController<TEntity>; - fournir
ReadPermission,UpdatePermissionetDeletePermission; - injecter les services transversaux existants ;
- garantir que
ISubDomainServicepeut retrouver l'organisation de l'entité ; - ajouter son
RightsDefaultPatternsi nécessaire ; - ajouter le type à l'audit des droits automatiques ;
- tester lecture, création, modification, suppression, interdiction, Cerebrate et multi-instance.
Fichiers de référence
| Sujet | Fichier |
|---|---|
| Contrôleur REST | Controllers/SecurityController.cs |
| Contrôleur de session/organisation | Controllers/SessionController.cs |
| Pipeline JWT | Commons/Immersive.RestFrontage.Components/Security/TokenParserMiddleware.cs, TokenCheckMiddleware.cs |
| Contrôleur OData générique | corporate/Commons/GraphicStream.Server.Components/Controllers/ODataCrudController.cs |
| Catalogue du testeur | Security/SecurizedObjectCatalog.cs |
| Testeur | Pages/Security/RightsTester.cshtml.cs |
| Outils | Pages/Security/Tools |
| Modale de partage | Pages/Security/Modals/SharedAccess.cshtml et .cshtml.cs |
| Page externe | Pages/Shared/Index.cshtml et .cshtml.cs |