Permissions et droits des objets sécurisés

Ce document présente le modèle de sécurité objet du serveur : les objets sécurisés, les permissions, les masques de flags, les autorisations et refus, les groupes, les partages internes et les permissions fournies lors de l’installation.

1. Vue d’ensemble

Le système répond à la question suivante :

Un utilisateur donné possède-t-il une permission donnée sur un objet métier donné ?

Il relie quatre notions.

Notion Classe principale Rôle
Bénéficiaire DomainSecurityObject Utilisateur, groupe ou autre principal de sécurité auquel un droit peut être attribué.
Cible SecurizedObject Référence de sécurité vers l’objet métier protégé.
Permission Permission Action testable pour un type d’objet, représentée par un masque de bits.
Droit Right Association entre un bénéficiaire et une cible, avec un masque autorisé et un masque refusé.

Un droit peut donc se lire ainsi :

Le groupe Operators reçoit les flags autorisés 0x13 et les flags refusés 0x04 sur l’équipement 42.

Le serveur ne se contente pas de chercher un droit directement porté par l’utilisateur. Il tient aussi compte de ses appartenances aux groupes, y compris les groupes imbriqués. Un refus applicable est évalué avant les autorisations.

2. Le principe de SecurizedObject

2.1 Une référence de sécurité, pas l’objet métier

SecurizedObject est une entrée légère du modèle de sécurité qui désigne une cible avec deux valeurs :

Propriété Signification
Identifier Identifiant de l’instance métier.
ObjectType Identifiant stable de son type, généralement une valeur de ImmersiveObjectType.

La clé réelle est le couple (Identifier, ObjectType). Par exemple :

Objet métier ObjectType Identifier Cible de sécurité
Carte 48 Map, soit 15 48 (48, 15)
Scope de supervision 48 SupervisionScope, soit 48 48 (48, 48)

Le nombre 48 peut donc être simultanément un identifiant d’instance et un identifiant de type. Il faut toujours afficher et transmettre ces deux informations séparément.

Pour plus d'information consultez le Catalogue des ImmersiveObjectType.

2.2 Relation avec l’objet métier

Le SecurizedObject ne contient ni le nom, ni la description, ni les propriétés métier. C'est un pointeur vers un objet sécurisé qui est hébergé ailleurs. SecurizedObject porte uniquement la collection des Right applicables à la cible. L’objet métier reste dans sa propre base.

Cette séparation permet au moteur de sécurité de protéger plusieurs familles d’objets sans dépendre de leurs classes concrètes.

2.3 Quand un type est-il considéré comme sécurisé ?

Le calcul central regroupe les Permission par SecurizedObjectTypeLorsqu’aucune permission n’existe pour un type, le système de sécurité considère que ce type ne nécessite pas de filtrage par droits. Les objets de ce type sont donc accessibles sans limitations et contrôles de sécurité.

Lorsqu’au moins une permission est configurée, le type entre dans le calcul de sécurité qui évalue les permissions de chaque cible requise en termes d'autorisations et d'interdictions en regard du bénéficiaire.

3. Le principe d’une permission

Une Permission décrit une action connue pour un type d’objet. Elle ne donne aucun accès à elle seule. Elle fournit le vocabulaire utilisé par les Right et par les contrôleurs.

Propriété Rôle
Identifier Identifiant de la permission dans son type d’objet. La clé EF complète est (Identifier, SecurizedObjectType).
SecurizedObjectType Type d’objet auquel la permission s’applique. Une permission de carte ne doit pas être utilisée sur un équipement.
Name Nom affiché et utilisé pour comprendre l’action.
Description Explication fonctionnelle de la permission.
Flag Masque qui doit être présent dans AuthorizedFlags pour accorder la permission.
DeniedFlag Masque recherché dans DeniedFlags. Lorsqu’il est absent, le serveur utilise Flag.

Le nom et la description d’une permission existante peuvent évoluer. Son Flag et son DeniedFlag sont volontairement immuables dans l’administration courante.

4. Comprendre les flags

4.1 Un masque de bits

Un flag est un entier dont chaque bit représente une capacité élémentaire. L’opérateur binaire OU, écrit |, combine plusieurs valeurs.

Expression Décimal Hexadécimal Bits positionnés
1 1 0x1 bit 0
0x3 3 0x3 bits 0 et 1
1 | 5 5 0x5 bits 0 et 2
0x3 | 65 67 0x43 bits 0, 1 et 6

Le testeur de la modale de permissions accepte ces quatre formes.

4.2 Test d’une permission autorisée

Une permission est autorisée lorsque tous les bits de son Flag sont présents dans AuthorizedFlags :

(authorizedFlags & permission.Flag) == permission.Flag

Exemples avec les permissions de carte :

AuthorizedFlags du bénéficiaire Permission testée Flag requis Résultat
0x3 See Map 0x3 Autorisée.
0x3 Modify Map 0x5 Refusée : le bit 0x4 manque.
0x43 See Map 0x3 Autorisée.
0x43 Edit All 0x40 Autorisée.
0x43 Modify Map 0x5 Refusée : le bit 0x4 manque.

4.3 Flags simples et flags composites

Les valeurs du catalogue ne sont pas toutes des puissances de deux indépendantes. Plusieurs permissions utilisent un masque composite qui inclut un socle de lecture :

  • 3, soit 1 | 2 ;
  • 5, soit 1 | 4 ;
  • 11, soit 1 | 2 | 8 ;
  • 19, soit 1 | 2 | 16 ;
  • 35, soit 1 | 2 | 32.

Ainsi, autoriser See Map avec le masque 3 autorise aussi le test de Read Map avec le masque 1. En revanche, Modify Map avec le masque 5 n’inclut pas le bit 2 de See Map.

Exemple

Comment lire cette image

Un nombre binaire est écrit uniquement avec des 0 et des 1 :

  • 0 signifie que la capacité de la colonne est désactivée ;
  • 1 signifie que la capacité de la colonne est activée.

En partant de la droite, chaque colonne vaut le double de la précédente :

Position binaire 128 64 32 16 8 4 2 1
Valeur lorsque le bit est actif 128 64 32 16 8 4 2 1

Pour connaître la valeur décimale, il suffit d’additionner les colonnes contenant 1.

Exemple détaillé : pourquoi 35 vaut 100011

Le nombre 35 active les colonnes 32, 2 et 1 :

Valeur de la colonne 128 64 32 16 8 4 2 1
Bit de 35 0 0 1 0 0 0 1 1

On obtient donc :

35 = 32 + 2 + 1
35 = 00100011 en binaire

Le même calcul peut être présenté comme un assemblage de flags simples avec l’opérateur | :

32  = 00100000
 2  = 00000010
 1  = 00000001
----------------  OU binaire
35  = 00100011

L’opérateur | conserve donc chaque bit actif rencontré. Il ne concatène pas les nombres : il fabrique un masque contenant toutes les capacités sélectionnées.

Lecture des autres lignes

Décimal Décomposition Écriture binaire sur 8 bits
3 2 + 1 00000011
5 4 + 1 00000101
11 8 + 2 + 1 00001011
19 16 + 2 + 1 00010011
35 32 + 2 + 1 00100011

Par exemple, tester la permission 35 revient à vérifier que les droits contiennent bien les bits 32, 2 et 1 :

(droits & 35) == 35

Si un seul de ces trois bits manque, la permission 35 n’est pas accordée.

Les valeurs 32, 2 et 1 correspondent à trois permissions, alors 35 les active toutes.

Certaines permissions, incluses de base dans Immersive, couvrent tous les bits de poids faibles nécessaires pour cibler l'ensemble des permissions.

Masque Valeur Utilisation courante
0xF 15 Workspace, Folder et SupervisionScope. Il couvre les quatre bits de poids faible.
0xFFFFFF 16777215 Map, WorldView et Equipment. Il couvre les vingt-quatre bits de poids faible.

FullControl n’est pas un mot-clé spécial du moteur. C’est une permission ordinaire dont le masque contient les capacités prévues pour le type. Si une future permission utilise un bit extérieur au masque FullControl, elle ne sera pas automatiquement incluse.

5. AuthorizedFlags, DeniedFlags et priorité du refus

5.1 Contenu d’un Right

Un Right associe un bénéficiaire à une cible :

Propriété Signification
DomainSecurityObjectIdentifier Utilisateur ou groupe bénéficiaire.
SecurizedObjectIdentifier Identifiant de l’instance protégée.
SecurizedObjectType Type de l’instance protégée.
AuthorizedFlags Masque des capacités accordées.
DeniedFlags Masque des capacités explicitement refusées.

Plusieurs permissions sont regroupées dans un même droit avec l’opérateur |.

right.AuthorizedFlags = existingAuthorizedFlags | permission.Flag;
right.DeniedFlags = existingDeniedFlags | deniedFlag;

Une valeur absente est traitée comme 0.

5.2 Rôle de DeniedFlag

Pour tester un refus, le serveur utilise :

int deniedFlag = permission.DeniedFlag ?? permission.Flag;
bool denied = (deniedFlags & deniedFlag) == deniedFlag;

Sur les cartes, les permissions composites possèdent généralement un DeniedFlag élémentaire. Par exemple, Modify Map demande Flag = 5, soit les bits 1 + 4, mais se refuse avec DeniedFlag = 4. Le bit commun de lecture n’a donc pas besoin d’être répété dans le masque de refus.

5.3 Ordre de décision

Le calcul central suit l’ordre suivant :

  1. Cerebrate est autorisé sans autre calcul.
  2. Le serveur résout la cible par son identifiant et son type.
  3. Il cherche un refus applicable directement à l’utilisateur ou à l’un de ses groupes.
  4. Si un refus est trouvé, le résultat est immédiatement refusé.
  5. En l’absence de refus, il cherche une autorisation directe ou héritée d’un groupe.
  6. Un partage interne actif peut ajouter une autorisation, mais jamais contourner un refus explicite.
  7. En l’absence d’autorisation explicite, le résultat est refusé par défaut.

L’administration empêche également d’enregistrer, dans une même mutation, une permission simultanément autorisée et refusée. Les flags négatifs et les bits inconnus pour le type d’objet sont rejetés.

6. Droits directs, groupes, droits automatiques et partages

6.1 Droit direct

Le DomainSecurityObjectIdentifier d’un Right peut désigner directement un utilisateur. Le droit ne bénéficie alors qu’à cet utilisateur.

6.2 Droit attribué à un groupe

Le DomainSecurityObjectIdentifier d’un Right peut aussi être un groupe. Le système de sécurité parcourt les appartenances récursivement : un utilisateur membre d’un groupe lui-même membre d’un autre groupe hérite des droits du groupe parent. Les identifiants déjà visités sont mémorisés afin d’éviter une boucle infinie en présence d’un cycle de groupes.

6.3 Droit automatique

Une règle de droit automatique ne constitue pas une seconde mécanique d’autorisation. Lors de la création ou de la régularisation d’un objet, elle résout son bénéficiaire puis crée ou complète un Right ordinaire.

Les variables actuellement prévues dans les distinguished names sont :

  • {CurrentUserDistinguishedName} ;
  • {SubDomainName} ;
  • {SubDomainDistinguishedName}.

Une règle d’autorisation ajoute le Flag de sa permission à AuthorizedFlags. Une règle de refus ajoute son DeniedFlag, ou son Flag à défaut, à DeniedFlags.

6.4 Partage interne

Un partage visant un utilisateur ou un groupe interne peut ajouter les flags qu’il porte au calcul central lorsqu’il est actif, non révoqué, commencé et non expiré.

Le partage ne permet pas :

  • de contourner un refus explicite ;
  • d’administrer à son tour les droits de l’objet ;
  • d’introduire un masque qui n’existe pas dans le catalogue du type.

Les liens de partage externes ne participent pas au calcul d’autorisation d’un utilisateur authentifié.

7. Permissions métier fournies de base

Cette section décrit les permissions persistées par les migrations d’installation. Les libellés présentés par une instance peuvent ensuite être modifiés dans /Security/Configuration.

7.1 Cartes — Map, type 15

Permission de base Flag autorisé Flag de refus Rôle
Read Map 1 / 0x1 1 Lire les propriétés de la carte.
See Map 3 / 0x3 2 / 0x2 Voir le contenu de la carte.
Modify Map 5 / 0x5 4 / 0x4 Modifier les propriétés de la carte.
Edit Topography 11 / 0xB 8 / 0x8 Modifier la topographie.
Edit Points of interest 19 / 0x13 16 / 0x10 Gérer les points d’intérêt.
Edit equipments 35 / 0x23 32 / 0x20 Gérer les équipements placés sur la carte.
Edit All 64 / 0x40 64 / 0x40 Gérer globalement le contenu associé à la carte.
Full control on map 16777215 / 0xFFFFFF même masque Contrôle total sur les capacités comprises dans les vingt-quatre premiers bits.

7.2 Vues monde — WorldView, type 25

Permission de base Flag autorisé Flag de refus Rôle
Read WorldView 1 / 0x1 1 Lire les propriétés de la vue monde.
See WorldView 3 / 0x3 2 / 0x2 Voir le contenu de la vue monde.
Modify WorldView 5 / 0x5 4 / 0x4 Modifier ses propriétés.
Edit WorldView 11 / 0xB 8 / 0x8 Modifier le contenu associé à la vue monde.
Full control on WorldView 16777215 / 0xFFFFFF même masque Contrôle total.

7.3 Équipements — Equipment, type 18

Permission de base Flag autorisé Flag de refus Rôle
Read Equipment 1 / 0x1 1 Lire les propriétés de l’équipement.
See Equipment instances 3 / 0x3 2 / 0x2 Voir les instances de l’équipement.
Modify Equipment 5 / 0x5 4 / 0x4 Modifier les propriétés de l’équipement.
Edit Equipment instances 11 / 0xB 8 / 0x8 Modifier les instances.
ControlInstanceHandles 19 / 0x13 16 / 0x10 Modifier les valeurs des handles des instances.
Full control on Equipment 16777215 / 0xFFFFFF même masque Contrôle total.

7.4 Workspaces — Workspace, type 37

Permission de base Flag autorisé Flag de refus Rôle
See Workspace 1 / 0x1 même masque Rendre le workspace visible.
Read Workspace 3 / 0x3 même masque Lire le workspace.
Modify Workspace 5 / 0x5 même masque Modifier le workspace.
Execute Workspace 11 / 0xB même masque Exécuter le workspace.
Full control on Workspace 15 / 0xF même masque Contrôle total du workspace.

7.5 Dossiers — Folder, type 38

Permission de base Flag autorisé Flag de refus Rôle
See folder 1 / 0x1 même masque Voir le dossier.
See folder content 3 / 0x3 même masque Consulter son contenu.
Modify folder 5 / 0x5 même masque Modifier le nom et les propriétés du dossier.
Modify folder content 11 / 0xB même masque Ajouter ou modifier son contenu.
Full control on folder 15 / 0xF même masque Lire, modifier, alimenter et supprimer le dossier.

7.6 Scopes de supervision — SupervisionScope, type 48

Permission de base Flag autorisé Flag de refus Rôle
See supervision scope 1 / 0x1 même masque Voir le scope de supervision.
Read supervision scope 3 / 0x3 même masque Lire son contenu.
Modify supervision scope 7 / 0x7 même masque Modifier le scope.
Oversee supervision scope 11 / 0xB même masque Superviser les éléments rattachés au scope.
Full control on supervision scope 15 / 0xF même masque Contrôle total.

7.7 OrganizationalUnit, type 12

Permission Flag Rôle décrit par le seed
Read 1 Lire les propriétés et les membres.
Modify 3 Modifier les propriétés ou métadonnées.
Manage 5 Ajouter ou retirer des membres.
FullControl 16777215 / 0xFFFFFF Contrôle total.

8. Exemple complet de calcul

Considérons la carte Identifier = 42, donc la cible (42, Map).

  • Le groupe MapEditors possède AuthorizedFlags = 0x5 : ses membres ont Read Map et Modify Map.
  • Le groupe MapViewers possède AuthorizedFlags = 0x3 : ses membres ont Read Map et See Map.
  • Le groupe RestrictedMaps possède DeniedFlags = 0x4 : ses membres se voient refuser Modify Map, dont le DeniedFlag vaut 4.
  • Alice appartient aux trois groupes.

Résultat :

Permission testée Résultat Explication
Read Map Autorisée Les groupes MapEditors et MapViewers contiennent le flag requis 1.
See Map Autorisée MapViewers contient le masque autorisé 3 et aucun refus 2 ne s’applique.
Modify Map Refusée MapEditors autorise le masque 5, mais RestrictedMaps refuse le bit 4. Le refus est prioritaire.
Edit Topography Refusée par défaut Aucun droit applicable ne contient le masque autorisé 11.

9. Règles à retenir

  • Une Permission décrit une action ; un Right l’accorde ou la refuse sur une cible.
  • Un SecurizedObject est identifié par le couple type et identifiant.
  • Les flags se combinent avec | et se testent avec &.
  • Une permission composite exige tous les bits de son Flag.
  • DeniedFlag peut être différent de Flag pour isoler le bit réellement refusé.
  • Tout refus direct ou hérité gagne sur les autorisations.
  • Sans autorisation applicable, l’accès est refusé.
  • Les groupes imbriqués transmettent les droits.
  • Les droits automatiques produisent des Right ordinaires.
  • Un partage interne peut ajouter un accès, jamais neutraliser un refus.
  • Le masque d’une permission existante ne doit pas être modifié après utilisation.