Skip to content
Snippets Groups Projects
Commit 3496cf5d authored by EL HAJJIOUI Nabil's avatar EL HAJJIOUI Nabil Committed by bbenarbia
Browse files

Initial dat

parent 697398c1
No related branches found
No related tags found
No related merge requests found
Showing
with 1506 additions and 0 deletions
######################
# STS
######################
**/.apt_generated
**/.classpath
**/.factorypath
**/.project
**/.settings
**/.springBeans
######################
# IntelliJ IDEA
######################
.idea/
**/.idea
**/*.iws
**/*.iml
**/*.ipr
######################
# NetBeans
######################
**/nbproject/private/
**/build/
**/nbbuild/
**/dist/
**/nbdist/
**/.nb-gradle/
nb-configuration.xml
######################
# Node
######################
**/node/
**/node_tmp/
**/node_modules/
**/npm-debug.log.*
**/.awcache/*
######################
# SASS
######################
**/.sass-cache/
######################
# Eclipse
######################
**/*.pydevproject
**/.project
**/.metadata
**/tmp/
**/tmp/**/*
**/*.tmp
**/*.bak
**/*.swp
**/*~.nib
**/local.properties
**/.classpath
**/.settings/
**/.loadpath
**/.factorypath
**/src/main/resources/rebel.xml
**/*.pmd
**/*.pmd*
**/*.checkstyle
# External tool builders
**/.externalToolBuilders/**
# Locally stored "Eclipse launch configurations"
**/*.launch
# CDT-specific
**/.cproject
# PDT-specific
**/.buildpath
######################
# Visual Studio Code
######################
**/.vscode/
######################
# Maven
######################
**/target/
!**/.mvn/wrapper/maven-wrapper.jar
**/log/
**/target/
pom.xml.releaseBackup
pom.xml.versionsBackup
maven-eclipse.xml
######################
# Gradle
######################
**/.gradle/
**/build/
######################
# Package Files
######################
**/*.jar
**/*.war
**/*.ear
**/*.db
**/*.rpm
**/*.deb
######################
# Windows
######################
# Windows image file caches
**/Thumbs.db
# Folder config file
**/Desktop.ini
######################
# Mac OSX
######################
**/.DS_Store
**/.svn
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
######################
# Directories
######################
**/bin/
/deploy/
######################
# Logs
######################
*.log*
######################
# Others
######################
*.class
*.*~
*~
.merge_file*
######################
# Gradle Wrapper
######################
!gradle/wrapper/gradle-wrapper.jar
######################
# ESLint
######################
.eslintcache
/common/nb-configuration.xml
######################
# Ansible
######################
*.retry
######################
# Editor files:
######################
.ideas/*
######################
# python compiled code :
######################
*.pyc
######################
# Dolphin explorateur file
######################
.directory
####################
# Vagrant
###################
deployment/.vagrant
.vagrant/
*.box
######
# CAS
######
**/overlays/
######
# Camel
**/tmp/
/deployment/playbooks/pki/tempcerts/
##################
# Angular Common #
##################
ui/angular-commons/*.tgz
##################
# Deloyment tmp #
##################
/deployment/tmp/
##########################################
# Deployment Local deployement keystores #
##########################################
# Created vitam client stores
deployment/playbooks/pki/vitam/client-external/*.p12
deployment/playbooks/pki/vitam/client-external/*.jks
# Created dlab pki truststore
deployment/playbooks/pki/certs/*/*.jks
# Created dlab pki vitam truststore
deployment/playbooks/pki/certs/*/*.p12
# Imported dlab app truststore
deployment/playbooks/templates/dlab/conf/*/*.jks
# Imported dlab app vitam truststore
deployment/playbooks/templates/dlab/conf/*/*.p12
_build/*
site/*
\ No newline at end of file
# dat_vitamui
Dat Vitamui with markdown.
Command to build PDF as output:
`./sources/gen_pdf.sh ./docs/dat_vitamui/index.md vitamui.pdf`
\ No newline at end of file
docs/DAT/docs/assets/images/material.png

1.24 MiB

docs/DAT/docs/assets/images/securisationProd.png

20 KiB

Dossier d'architecture technique VITAM UI
#########################################
Cette section décrit le dossier d'architecture technique de la solution logicielle :term:`VITAMUI`.
.. toctree::
:maxdepth: 4
:glob:
*/*/*
## Applications Web
Les applications Web constituent les IHM de la solution. Elles sont accessibles depuis le portail de la solution. L'authentification d'un utilisateur dans une application cliente se fait par l'intermédiaire de l'IAM CAS. Une application cliente est constituée de 2 parties.
* Interface utilisateur Front (IHM WEB) qui donne accès aux fonctionnalités via un navigateur
* Interface utilisateur Back (Service BackOffice) qui gère la communication avec CAS et les accès aux API externes
Une double authentification est nécessaire pour qu’un utilisateur puissent accéder aux API externes :
* Le service UI Back de l’application cliente doit posséder un certificat reconnu par la solution
* L’utilisateur de l’application cliente doit être authentifié dans la solution (par CAS) et posséder un token valide
Les applications de base :
* portal : application portail donnant accès aux applications
* identity : application pour gérer les organisations, utilisateurs, profils, etc.
# Architecture
La solution VITAMUI popose des applications web accessibles depuis un portail. La solution VITAMUI est constitué de différents modules :
* Socle IAM CAS pour la gestion des identités et des accès
* Socle VITAM pour la gestion des archives
* Services d'infrastructure
* Annuaire de service
* Gestion des logs centralisée
* Applications web pour les utilisateurs
* portail
* gestion des organisations, utilisateurs, profils, etc.
* Services API externes
* service de gestion des organisations, des utilisateurs, etc.
* service CAS
* Services API internes
* service des gestion des organisations, des utilisateurs, etc.
* service de gestion de la sécurité
Schéma de l’architecture fonctionnelle VITAMUI:
![Architecture fonctionnelle](../images/dat_archi_generale.png)
# Journalisation
## Introduction
La journalisation des événements VITAMUI a pour objectifs :
* Conservation de la valeur probante : être en capacité de prouver toute opération effectuée sur toute unité archivistique ou tout objet qui lui est associé.
* La sécurité d’un SAE doit être systémique, c’est-à-dire reposer sur un faisceau d’éléments redondants dont la modification simultanée et cohérente est impossible, ou plus exactement non réalisable en pratique.
* Les journaux constituent un élément central de cette sécurité systémique
Utilisation des journaux vitam NF Z42-013
![Journalisation](../images/journalisation_architecture.png)
## Événement
### Vitam
* Un événement = Un master (maître) et ensemble de sous-événements (esclaves)
* Master : événement initial
* les champs sont contrôlés par VITAM
* Marque le début de la transaction au sens VITAM
* L’heure de l’événement et mise par VITAM (cohérence des journeaux)
* slave : note un sous événement réalisé suite à l’action principale
* possède les mêmes champs que l’événement Master mais VITAM ne procède à aucun contrôle
* l’heure de l’êvénement est à l’appréciation du client
* Fin de la transaction : le dernier sous événement doit posséder le même champs “eventType” que l’événement Master pour finir la transaction.
### VITAMUI
* Maître et esclave => Un event VITAMUI cf : fr.gouv.vitamui.commons.logbook.domain.event
* Un appel REST => Une ou plusieurs opération métier => ensemble d’events => le premier sera le maître et les suivants esclaves
* Stocker dans le tenant des éléments de preuves du client
![Journalisation](../images/journalisation_transaction.png)
## Application dans VITAMUI
### Modèle
|Propriétés | valeurs |
|-----------------|:-------------------------------------------------:|
|EventTypeProc |EXTERNAL_LOGBOOK |
|EventType | Nom du type d'événement (EXT_VITAMUI_CREATE_USER) |
|obIdReq | Nom de la collection Mongo (USERS) |
|obId |Identifiant métier de l’objet |
|evDetData |Contient les informations importantes (modification avant/après contenu du nouvelle objet) outcome : OK, KO (Pour le master -> OK, pour les sous-events le champ est libre) |
|evIdAppSession |applicationIdExt:requestId:applicationName:userIdentifier:superUserIdentifier:customerIdentifier |
|evIdReq |X-Request-Id |
## Création
* L’ensemble des modifications de la base de données se font dans une unique transaction.
* Centralisation de la création des traces dans chaque module (IamLogbookService, ArchiveLogbookService, FlowLogbookService) (Responsable de la cohérence de la génération d’un event à partir d’un objet métier
* Chaque objet de notre modèle de données possède un converter associé (Capable de convertir un objet en json et qui sera mis dans le evDetData de l’event)
## Sauvegarde
* Réalisation par les tâches asynchrones (Cf : SendEventToVitamTasks.java et DeleteSynchronizedEventsTasks.java)
* Les événements sont regroupés par rapport à leur X-Request-Id et triés par ordre chronologique croissant.
* Le premier événements du groupe devient le Master et les autres des sous-events.
* Le premier est recopier a la fin des sous-events afin de fermer la “transaction au sens VITAM)
* Envoit vers vitam (La reponse vitam et la date d'envoi sont toujours stocké) :
* Succès -> Les events sont conservés X jours et sont marqué au status “SUCCESS”
* Erreur -> Les events sont marqués au statut “ERROR” et un retry sera effectué dans X heure.
# Modèle de données
## Liste des bases
iam
security
cas
## Base IAM
##### Collections
customers
events
groups
owners
profiles
providers
subrogations
tenants
tokens
users
* _Collection Customer_
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| identifier | String | minimum = 1, maximum = 12 | |
| code | String | minimum = 6, maximum = 20 | |
| companyName | String | maximum = 250 | |
| language | String | Non null, valeurs = [FRENCH,ENGLISH]| |
| passwordRevocationDelay | Integer | Non null | exprimé en jour |
| otp | Enum | Non null, valeurs = [OPTIONAL,DISABLED,MANDATORY] | |
| emailDomains | List<_String_> | Non null, Non vide | |
| defaultEmailDomain | String | Non null | |
| address | Address | Non null | |
| name | String | maximum = 100 | |
| subrogeable | boolean | default=false | |
| readonly | boolean | default=false | |
| graphicIdentity | GraphicIdentity | | |
* GraphicIdentity (Embarqué)
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| hasCustomGraphicIdentity | boolean | | |
| logoDataBase64 | String | | |
| themeColors | Map<String, String> | | |
* _Collection Tenants_
Le tenant correspond à un container (ie. espace de travail) logique.
Chaque tenant est unique dans le système et appartient à un seul et unique client.
Un client peut posséder plusieurs tenants.
Un client ne doit jamais pouvoir accéder au tenant d’un autre client.
Les tenants VITAMUI correspondent aux tenants VITAM.
Toutes les requêtes HTTP dans VITAMUI doivent renseigner le tenant dans le header.
Dans VITAMUI, le tenant permet de vérifier les autorisations applicatives (certificat et contexte) et utilisateurs (profils).
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| customerId | String | Non null, Clé Étrangère | |
| identifier | Integer | Non null | correspond au tenant vitam |
| ownerId | String | Non null, Clé Étrangère| |
| name | String | maximum = 100 | exprimé en jour |
| proof | Boolean | | identifie le tenant de preuve |
| readonly | Boolean | | |
| ingestContractHoldingIdentifier | String | Non null | contrat d’entrée pour l’arbre |
| accessContractHoldingIdentifier | String | Non null | contrat d’accès pour l’arbre |
| itemIngestContractIdentifier | String | Non null | contrat d’entrée pour les bordereaux |
| accessContractLogbookIdentifier | String | Non null | contrat d’accès pour le logbook |
| enabled | Boolean | Non null | |
* _Collection Owner_
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| identifier | String | minimum = 1, maximum = 12 | |
| customerId | String | Clé Étrangère | Clé Étrangère |
| name | String | maximum = 100| |
| code | String | minimum = 6, maximum = 20 | |
| companyName | String | maximum = 250 | |
| address | Address | | embedded |
| readonly | Boolean | | |
* Address (Embarqué)
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| street | String | maximum = 250 | |
| zipCode | String | maximum = 10 | |
| city | String | maximum = 100 | |
| country | String | maximum = 50| |
* _Collection Identity Provider_
L’identity provider L’IDP est soit externe (Total, Teamdlab, etc.) soit interne.
L’IDP interne est CAS lui même et les utilisateurs sont alors gérés uniquement dans l’annuaire CAS de VITAMUI.
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| customerId | String | Clé Étrangère | |
| identifier | String | minimum = 1, maximum = 12 | |
| name | String | maximum = 100| |
| technicalName | String | | |
| internal | Boolean | default=true| |
| patterns | List<_String_> | minimum = 1| |
| enabled | Boolean | default=true| |
| keystoreBase64 | String | | |
| keystorePassword | String | | Mot de passe |
| privateKeyPassword | String | | Mot de passe |
| idpMetadata | String | | XML |
| spMetadata | String | | XML |
| maximumAuthenticationLifetime | Integer | | |
| readonly | Boolean | | |
* _Collection User_
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| customerId | String | Clé Étrangère | |
| enabled | boolean | default = true | |
| status | Enum | default = ENABLED, BLOCKED, ANONYM, DISABLED | |
| type | Enum | NOMINATIVE, GENERIC | |
| password | String | maximum = 100 | Mot de passe |
| oldPasswords | List<_String_> | | |
| identifier | String | minimum = 1, maximum = 12 | |
| email | String | email, Unique | |
| firstname | String | maximum = 50 | |
| lastname | String | maximum = 50 | |
| language | String | Non null, valeurs = [FRENCH,ENGLISH] | |
| phone | String | phone number | |
| mobile | String | mobile phone number | |
| otp | Boolean | default = false | |
| groupId | String | Not null | |
| subrogeable | Boolean | | |
| lastConnection | OffsetDateTime | | |
| nbFailedAttempts | int | | |
| readonly | boolean | default=false | |
| level | String | Not null | |
| passwordExpirationDate | OffsetDateTime | | |
| address | Address | | |
* _Collection Groups_
Le groupe de profil définit un ensemble de profils.
Un groupe de profil ne peut contenir qu’un seul profil par “app:tenant”. Par exemple : “profil(app1:tenant1), profil(app1:tenant2), profil(app2:tenant1)” est autorisé.
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| identifier | String | minimum = 1, maximum = 12 | |
| customerId | String | Non Null, Clé Étrangère | |
| name | String | maximum = 100 | |
| description | String | maximum = 250 | |
| profileIds | List<_String_> | clé étrangére | les profils |
| level | String | maximum = 250 | |
| readonly | Boolean | | |
| enabled | Boolean | | |
* _Collection Profils_
Le profil définit les permissions (rôles) données à un utilisateur et l’accès à une application (applicationName), généralement une IHM qui regroupe un ensemble de fonctionnalités selon une logique métier et appelant des API backoffice.
Un profil appartient à une groupe (de profils). Il ne peut y avoir qu’un seule et unique profile par tenant, applicationName dans un groupe.
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| identifier | String | minimum = 1, maximum = 12 | |
| tenantIdentifier | Integer | | |
| name | String | maximum = 100 | |
| enabled | boolean | default=true | |
| description | String | maximum = 250 |
| applicationName | String | maximum = 250 | |
| roles | List<_Role_> | | rôle Spring |
| readonly | Boolean | | |
| level | String | maximum = 250 | |
| externalParamId | String | | |
* _Collection subrogations_
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| status | Enum | CREATED, ACCEPTED | |
| date | Date | | |
| surrogate | String | email, minimum = 4, maximum = 100 | celui qui est subrogé |
| superUser | String | email, minimum = 4, maximum = 100 | celui qui subroge |
| surrogateCustomerId | String | not null | |
| superUserCustomerId | String | not null | |
* _Collection tokens_
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | | |
| updatedDate | Date | not null | |
| refId | String | not null | |
| surrogation | Boolean | | |
* _Collection Events_
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| tenantIdentifier | Integer | not null | |
| accessContractLogbookIdentifier | String | not null | |
| evParentId | String | | |
| evIdProc | String | | |
| evType | String | not null | |
| evTypeProc | Enum | EXTERNAL_LOGBOOK |
| outcome | Enum | UNKNOWN, STARTED, ALREADY_EXECUTED, OK, WARNING, KO, FATAL | |
| outMessg | String | not null | |
| outDetail | String | not null | |
| evIdReq | String | not null | |
| evDateTime | String | not null | |
| obId | String | not null | |
| obIdReq | String | not null | |
| evDetData | String | not null | |
| evIdAppSession | String | not null | |
| creationDate | Long | not null | |
| status | Enum | CREATED, SUCCESS, ERROR | |
| vitamResponse | String | | |
| synchronizedVitamDate | OffsetDateTime | | |
## Base security
* _Collection Context_
Le contexte applicatif permet d’attribuer à une application cliente selon son certificat X509 transmis lors de la connexion https les droits d’accès (rôles) à différents services.
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| fullAccess | Boolean | default = false | |
| name | String | not null | |
| tenants | List<_Integer_> | Not Null, List de Clé Étrangère | Liste des tenants autorisés |
| roleNames | List<_String_> | Not Null | Liste des rôles autorisés |
* _Collection Certificate_
La collection certificat permet de stocker les certificats correspondant à un contexte.
Le certificat est transmis par l’application client lors de la connexion SSL.
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| contextId | String | Not Null | |
| serialNumber | String | Not Null | Numéro de série du certificat |
| subjectDN | String | Not Null | Identifiant unique (Distinguished Name) du certificat |
| issuerDN | String | Not Null | Identifiant unique (Distinguished Name) de l’autorité de certification |
| data | String | Not Null | Certificat en base64 |
* _Collection CustomSequence_
La collection sequence permet de stocker les différentes séquences utilisés.
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| name | String | Not Null | Nom de la séquence |
| sequence | int | | Valeur courante |
## Base Cas
Cette base est initialisée à la création de l'environnement. Elle est uniquement utilisée par CAS en lecture seule.
| Nom | Type | Contrainte(s) | Remarque(s) |
| -------- | -------- | ------ | ------ |
| _id | String | Clé Primaire | |
| serviceId | String | Not Null | url du service web |
| name | String | | nom du service |
| logoutType | String | | |
| logoutUrl | String | | url de logout |
| attributeReleasePolicy | | | Stratégie des attributs |
## Profils et rôles
### Groupe de profils
Un groupe de profils contient (entre autres) les informations suivantes :
* liste de profils
* niveau
Un groupe de profils est rattaché à un utilisateur, lui-même rattaché à une organisation. Un groupe de profil peut contenir des profils avec des tenants différents. Pour un tenant donné, un groupe de profil ne peut contenir qu'un seul profil d'une même APP.
### Profils
Le profil contient (entre autres) les informations suivantes :
* tenant
* liste de rôles
* niveau
* APP
Un profil contient un seul et unique tenant.
L'APP permet d'autoriser l'affichage d'une application dans le portail. Le fait de pouvoir afficher l'application dans le portail ne préjuge pas des droits qui sont nécessaires au bon fonctionnement de l'application.
Un profil est modifiable uniquement par un utilisateur possédant un rôle autorisant la modification de profil et qui possède un niveau supérieur à celui du niveau du profil concerné.
Un profil ne peut être rattaché qu'à un groupe de profils de même niveau.
Dans une instance VITAMUI partagée, il convient de limiter les droits des administrateurs d'une organisation afin qu’ils ne puissent pas réaliser certains actions sur des ressources sensibles. (ie. customer, idp, tenant, etc.). Les profils créés à l’initialisation d’une nouvelle organisation ne doivent donc jamais comporter certains rôles (gestion des organisations, idp, tenants, etc. ) afin d'interdire à l'administrateur d'une organisation d'utiliser ou de créer de nouveaux profils avec ces rôles pour réaliser des opérations multi-tenants.
Généralement l'adminitrateur de l'instance possède tous les droits (et donc tous les rôles).
### Rôles
Le crôle constitue la granularité la plus fine dans le système de gestion des droits. Un rôle donne des droits d’accès à des endpoints (API) correspondants à des services. Un rôle peut être affecté à un ou plusieurs profils. Dans l'implémentation VITAMUI, l’accès à un endpoint est contrôlé par l’annotation @Secured. Il existe des rôles (dénommés sous-rôles) qui donnent accès à des fonctions protégées du service. Ces “sous-rôles” sont généralement contrôlés dans le corps de la méthode par le contexte de sécurité.
@Secured(ROLE_CREATE_XXX)
public MyDto create(final @Valid @RequestBody MyDto dto) {
if ( SecurityContext.hasRole(ROLE_CREATE_XXX_YYY) {
setProperty(...)
}
else {
return HTTP.403 ;.
}
}
Dans l'exemple ci-dessus :
* ROLE_CREATE_XXX est un rôle qui donne accès au service create
* ROLE_CREATE_XXX_YYY est un sous-rôle, utilisé dans le corps de la méthode, qui donne accès à une fonctionnalité spécifique de la méthode.
### Niveaux
Dans une organisation, la gestion des utilisateurs, des profils et groupe de profils repose sur le principe de la filière unidirectionnelle d'autorité étendue. Elle donne autorité au manageur sur les ressources d'une entité. Plusieurs manageurs peuvent avoir autorité sur une même entité. Un manageur n’a jamais autorité sur l'entité à laquelle il appartient. Il existe cependant un manageur administrateur qui a autorité sur toutes les ressources de toutes les entités.
Schéma de l’arbre de niveaux :
![Arbre des niveaux](../images/dat_level.png)
* Une entité dispose d'un niveau représenté par une chaine de caractère
* Une ressource est un objet (user, group, profile, etc.) appartenant à une entité
* Le manageur est un utilisateur qui a autorité sur des entités et leurs ressources associées
Ex. niveau : "World.France.DSI.Infra"
* World : entité racine - le niveau est vide (ou zéro). Le manageur World a autorité sur toutes les entités de l'arbre (dont lui-même)
* France : entité enfant de World - La manageur France a autorité sur les entités DSI et Infra
* DSI : entité enfant de France - La manageur DSI a autorité sur l'entité Infra
* Infra : entité enfant de DSI - La manageur Infra n'a autorité sur rien
Un utilisateur :
* manageur d'une ressource possède un niveau supérieur à celui de la ressource
* peut lister, modifier & supprimer une ressource dont il est le manageur
* peut créer une ressource dans une entité dont il est le manageur
* ne peut pas effectuer une action sur une ressource dont il n'est pas manageur
* ne peut pas effectuer des actions s’il ne dispose pas des rôles associés à ces actions
* ne peut pas affecter à un profil des rôles dont il ne dispose pas (cf. gestion des profils)
Un utilisateur avec un niveau vide (administrateur) :
* peut uniquement effectuer les actions associées aux rôles qu'il possède
* peut créer un profil ou un groupe de profils de niveau vide (admin)
* peut modifier ses ressources
* ne peut pas ajouter à un profil un rôle dont il ne dispose pas
Un administrateur d'une organisation possède donc des droits limités aux rôles qui ont été affectés à l'initialisation du système. Il ne peut pas par exemple créer une nouvelle organisation, si ce rôle ne lui pas été donné à l'origine. D'autre part, les droits de l'administrateur restent également limités par les droits associés à ceux du contexte de sécurité de l'application qu'il utilise.
* un profil ou un groupe de profils ne peuvent être supprimés que s'ils ne sont plus utilisés
* un profil avec un niveau ne peut être rattaché qu’à un groupe de un même niveau.
### Matrice des droits
Les tableaux ci-dessous indiquent les droits d'un utilisateur en fonction du niveau de la ressource cible.
* Matrice des droits d'un utilisateur de niveau N pour réaliser des actions sur un utilisateur de niveau cible N+1, N, N-1 :
|Niveau cible | N+1 | N | N-1 |
|---------------|:----------:|:---------:|:---------:|
|Créer | Non | Non | Oui |
|Modifier | Non | Non | Oui |
|Lire | Non | Oui (1) | Oui |
|Supprimer | Non | Non | Oui (2) |
Oui(1) : oui mais uniquement s'il s'agit de lui-même
Oui(2) : en théorie, car il est n'est pas possible de supprimer un utilisateur
* Matrice des droits d'un utilisateur de niveau N pour réaliser des actions sur un profil de niveau cible N+1, N, N-1 :
|Niveau cible | N+1 | N | N-1 |
|---------------|:----------:|:---------:|:---------:|
|Créer | Non | Non | Oui |
|Modifier | Non | Non | Oui |
|Lire | Non | Oui (1) | Oui |
|Attribuer | Non | Non | Oui |
|Supprimer | Non | Non | Oui |
Oui(1) : oui mais uniquement si le profil est présent dans son groupe de profils
Lors de la modification du niveau du profil. Il faut vérifier qu’il n’est associé à aucun groupe.
L'utilisateur ne peut affecter à un profil que les rôles et un tenant qu'il possède
* Matrice des droits d'un utilisateur de niveau N pour réaliser des actions sur un groupe de profils de niveau cible N+1, N, N-1 :
|Niveau cible | N+1 | N | N-1 |
|---------------|:----------:|:---------:|:---------:|
|Créer | Non | Non | Oui |
|Modifier | Non | Non | Oui |
|Lire | Non | Oui (1) | Oui |
|Attribuer | Non | Non | Oui |
|Supprimer | Non | Non | Oui |
Oui(1) : oui mais uniquement s'il s'agit de son groupe
Lors de la modification du niveau d'un groupe. Il faut vérifier qu’il n’a pas de profils
* Matrice des droits d'un administrateur de niveau racine (niveau vide) pour réaliser des actions sur une ressource de niveau cible N+1, N, N-1 :
|Niveau cible | N+1 | N | N-1 |
|---------------|:--------:|:---------:|:---------:|
|Créer | - | Oui | Oui |
|Modifier | - | Oui | Oui |
|Lire | - | Oui | Oui |
|Attribuer | - | Oui | Oui |
|Supprimer | - | Oui | Oui |
Un administrateur ne peut pas affecter à un profil des rôles qui ne sont pas autorisés dans son organisation.
### Sécurisation des ressources
#### Vérification générale
Le processus de sécurisation des ressources est systématique et identique quelque soit l’utilisateur appelant la ressource. Ce processus, implémenté dans Spring Security, est essentiel car il permet de s’assurer qu’un utilisateur ne sorte jamais de son tenant. Ce processus de sécurisation est réalisé sur les accès aux ressources des services externals.
Les étapes du processus de sécurisation sont les suivantes :
1. récupérer l’utilisateur associé au token utilisateur fourni dans le header
2. vérifier que l'organisation de l’utilisateur possède le tenant fourni dans le header
3. vérifier que l’utilisateur possède un profil avec le tenant fourni dans le header
4. trouver le contexte applicatif par rapport au certificat x509 fourni dans la requête
5. vérifier que le contexte applicatif autorise le tenant fourni dans le header
6. créer un contexte de sécurité utilisateur qui correspond au tenant fourni dans le header et à l’intersection des rôles des profils de l’utilisateur et ceux du contexte applicatif
7. vérifier que les rôles du contexte de sécurité de l’utilisateur autorisent l’utilisateur authentifié à appeler la ressource
Si la ressource n'est pas accessible, une erreur 403 est retournée
#### Vérification des sous-rôles
Cette étape correspond à la vérification des sous-rôles dans le service appelé. Un sous-rôle donne accès à une fonction ou à un périmètre spécifique du service.
Exemple : Un utilisateur RH a le droit de modifier un autre utilisateur sauf son email (qui est sécurisé).
* L’utilisateur RH possède donc un rôle UPDATE_USER qui lui donne accès à l’API et au service de mise à jour globale des utilisateurs
* L’utilisateur RH ne possède pas le rôle UPDATE_USER_EMAIL qui permettrait de modifier l’email
La vérification du rôle UPDATE_USER_EMAIL est réalisée dans le service de mise à jour de l’utilisateur.
#### Vérification du tenant
En règle générale, le tenant concerné par la requête est vérifié par le processus de vérification générale. Il existe néanmoins des cas où le tenant est fourni en paramètre ou dans le corps de la requête.
Dans ce cas, les étapes de sécurisation sont les suivantes :
* vérifier la validité du tenant dans le contexte de sécurité
* Si le tenant n’est pas valide, il faut éventuellement vérifier si l’utilisateur a le droit de réaliser une opération multi-tenant. Cette dernière vérification est implémentée grâce aux rôle et sous-rôles (cf. gestion des customer, des idp, des tenants, des profils, etc).
* Si le tenant n'est pas valide, une erreur 403 est retournée
Cette implémentation permet ainsi de réaliser simplement des opérations multi-tenant en définissant des rôles appropriés. La solution VITAMUI fournit des services multi-tenant pour gérer les organisations, les fournisseurs d'identité, etc. Il est fondamental de limiter autant que possible l'utilisation de rôles muli-tenants. Il est en outre recommandé de borner l'usage des rôles multi-tenant à une zone protégée de l'infrastructure.
L'ensemble des rôles autorisés dans une organisation sont définis à la création de cette organisation.
## Service d'archivage
Le service d'archivage se base sur le socle logiciel VITAM a pour fonction de gérer l'archivage des documents. Il apporte une forte garantie de sécurité et de disponibilité pour les archives.
Ses principales caractéristiques sont :
* Fonctions d’archivage : versement, recherches, consultation, administration , structurations arborescentes, référentiels…
* Accès aux unités d’archives via un service de requêtage performant
* Garantie de la valeur probante par le respect des normes en vigueur, par la traçabilité des opérations et du cycle de vie des objets et leur journalisation sécurisée
* Sécurité et la robustesse : la gestion applicative du stockage permet une réplication des données, métadonnées, index et journaux sur plusieurs sites et plusieurs offres contrôlées. L’architecture interne du stockage assure la capacité de reconstruire le système à partir d’une seule offre, en une fois ou au fil de l’eau
* La possibilité d’une utilisation mutualisée grâce à la gestion multi-tenant des archives
* Offres de stockage multiple
* Capacité à absorber de fortes volumétries de données
La documentation de la solution VITAM est disponible [ici](http://www.programmevitam.fr/).
This diff is collapsed.
## Services externes
Les services externes exposent des API REST publiques accessibles en HTTPS. Ces services constituent une porte d'accès aux services internes et assurent principalement un rôle de sécurisation des ressources internes.
La connexion d'une application cliente à un service externe nécessite le partage de certificats X509 client et serveur dans le cadre d'un processus d'authentification mutuel (Machine To Machine/M2M). Dans la solution VITAMUI, les certificats des clients sont associés à un contexte de sécurité stocké dans une collection MongoDb gérée par le service security_internal. D'autre part, les utilisateurs clients sont identifiés et authentifiés dans les services externes par le token fourni par CAS et transmis dans les headers des requêtes REST en HTTPS.
Le service externe a pour responsabilité de sécuriser les accès en effectuant les différentes étapes de vérifications des droits (générale, tenant, rôles, groupes, etc.) et de déterminer les droits résultants du client à l'origine de la requête, en réalisant l'intersection des droits applicatifs, définis dans le contexte de sécurité, avec les droits issus des profils de l'utilisateur. Le service externe s'assure ensuite que le client possède bien les droits pour accéder à la ressource demandée.
Les services externes s'auto-déclarent au démarrage dans l'annuaire de service Consul.
Les services disposent d'API REST pour suivre leur état et leur activité. Ces API ne sont pas accessibles publiquement.
* API Status pour connaitre la disponibilité du service (utilisé par Consul)
* API Health (basée sur SpringBoot) pour suivre l'activité
Les services génèrent les logs techniques dans la solution de log centralisée basée sur ELK.
### Service identity-external
* Description : service externe pour la gestion des organisations, utilisateurs, profils, etc.
* Contraintes
* API swagger
### Service cas-external
* Description : service d’authentification nécessaire et accessible uniquement par l'IAM CAS
* Contraintes
* API swagger
## Services d’infrastructure
La solution utilise plusieurs services d'infrastructures :
* l'annuaire de service. basé sur l'outil Consul, il permet de localiser les services actifs dans l'infrastructure
* le service de gestion des logs rsyslog. Il permet de collecter, gérer et de transporter les logs
* l'outil de centralisation et de recherche des logs ELK (Elasticsearch / Logstash / Kibana)
Les services d'infrastructures sont basés et mutualisés avec VITAM. Vous pouvez donc vous référer aux documentations VITAM pour avoir un détail précis du fonctionnement de ces services :
* [Doc VITAM : Chaîne de log - rsyslog / ELK ](http://www.programmevitam.fr/ressources/DocCourante/html/exploitation/composants/elasticsearch_log/_toc.html)
* [Doc VITAM : Annuaire de service consul](http://www.programmevitam.fr/ressources/DocCourante/html/exploitation/composants/consul/_toc.html)
## Services internes
Les services internes offrent des API REST accessibles en HTTPS uniquement depuis les services externes ou internes. Les API de ces services ne sont donc pas exposées publiquement. Les services internes implémentent les fonctionnalités de base de la solution ainsi que les fonctionnalités métiers. En fonction des besoins, les services internes peuvent être amenés à journaliser des évènements dans le logbook des opérations du socle VITAM.
Les utilisateurs sont identifiés dans les services internes grâce au token transmis dans les headers des requêtes HTTPS. L'utililisation du protocole HTTPS permet de chiffrer les tokens et les informations sensibles qui sont transportées dans les requêtes. Les services internes peut éventuellement vérifier les droits d'accès de l'utilisateur avant d'accéder aux ressources.
Les services internes s'auto-déclarent au démarrage dans l'annuaire de service Consul.
Les services disposent d'API REST pour suivre leur état et leur activité.
* API Status pour connaitre la disponibilité du service (utilisé par Consul)
* API Health (basée sur SpringBoot) pour suivre l'activité du service
Les services génèrent les logs techniques dans la solution de log centralisée basée sur ELK.
### Service identity-internal
* Description : service d’administration des clients, des utilisateurs et des profils, portail
* Contraintes
* API swagger
* Modèle de données
### Service security-internal
* Description : service de gestion de la sécurité applicative
* Contraintes
* API swagger
* Modèle de données
\ No newline at end of file
## Sessions applicatives
### Liste des sessions
Il existe 4 sessions définies dans la solution VITAMUI :
* la session applicative Web (cookie JSESSIONID)
* la session des services API (token X-AUTH-TOKEN)
* la session applicative CAS (cookie JSESSIONID / Domaine CAS)
* la session de l'IDP SAML utilisé pour la délégation d'authentification
### Séquence de création des sessions
La séquence de création des sessions est liée à l'utisation du protocole CAS et à l'intégration des services API.
Dans le processus de connexion, la création des sessions s'effectue dans l'ordre suivant :
1. création par l'application Web du cookie JSESSIONID
2. création de la session SAML (dans le cas d'une délégation d'authentification)
3. création dans CAS du cookie TGC
4. création par CAS dans l'API VITAMUI du token API
Schéma des sessions applicatives
![Sessions Applicatives](../images/dat_session_1.png)
### Session applicative Web
La session applicative est portée par le cookie JSESSIONID créée dans l'application Web. Le cookie expire à l'issue du délai d'inactivité et sa durée de vie est réinitialisée à chaque utilisation. [A vérifier]
Lorsque la session expire, le cookie est automatiquement recréé par l'application WEB et le client redirigé par un code HTTP 302 vers le service CAS.
Si la session CAS (cookie TGC) a expiré, l’utilisateur doit se reloguer et les sessions CAS (TGC), services API (Token), et si nécessaire SAML, sont recréées. En revanche, si la session CAS est valide, l'utilisateur n’a pas besoin de se reloguer et est directement redirigé sur l’application Web. Dans ce dernier cas, la session des services est conservée et le token n'est pas recréé.
### Session des services API
La session des services API est porté par un token. Le token permet l'identification des utilisateurs dans les services API (external et internal) de VITAMUI. Le token expire à l'issue du délai d'inactivité et sa durée de vie est réinitialisée à chaque utilisation.
Lors du processus d'authentification, le resolver de CAS extrait l’identité de l'utilisateur (de la réponse SAML en cas de délégation d'authentification) et appelle le service Identity de VITAMUI pour créer un token conservé dans la base mongoDB.
Le token est fourni aux applications web, mais n'est pas visible dans le navigateur web du client car il est conservé dans la session applicative (JSESSIONID) de l'utilisateur. Dans chaque requête vers les services, le header X-Auth-Token est positionné avec la valeur du token. Avant d'accpter la requête, le service contrôle l'existence du header précédent et vérifie que le token est toujours valide.
Lorsque le token a expiré, les services API génèrent une erreur 401 transmis aux applications web. Lors de la réception d'une erreur 401, l'application web invalide la session applicative (JSESSIONID) concernée, puis effectue une redirection vers le logout CAS (afin de détruire le TGC et la session SAML). L'utilisateur doit obligatoirement se reconnecter pour utiliser à nouveau l'application.
### Session CAS
La session CAS est portée par un cookie Ticket-Granting Cookie ou TGC. Le TGC est le cookie de session transmis par le serveur CAS au navigateur du client lors de la phase de login. Ce cookie ne peut être lu ou écrit que par le serveur CAS, sur canal sécurisé (HTTPS). Lors du processus d'authentification, le resolver de CAS extrait l’identité de l'utilisateur (de la réponse SAML en cas de délégation), crée le cookie TGC et un ticket dans l’URL puis stocke ces informations dans le cache HazelCast.
[A vérifier]
En cas de délégation d'authentification, si la session CAS a expiré (TGC invalide)
* l'utilisateur doit se reconnecter si la session SAML a expiré
* sinon CAS recrée automatiquement le TGC et le token
Sans délégation d'authentification, l'utilisateur doit se reconnecter systématiquement pour que CAS puisse recréer le TGC et le token.
### Session des IDP
La session de l’IDP (Identiy Provider) est propre à chaque IDP SAML. Il existe néanmoins un délai maximum dans CAS pour accepter la délégation d'authentification d'un IDP SAML.
L'utilisateur doit obligatoirement se reconnecter si la session SAML a expiré.
### Expiration et cloture des sessions
Il existe deux politiques d'expiration possibles :
* expiration de session par délai d'inactivité : la session expire si aucune action n'est faite (par l'utilisateur) au bout du délai d'inactivité (session Token)
* expiration de session par délai maximum : la session expire au bout du délai maximum depuis la date de création, quelque soit les actions faites par l'utilisateur (Sessions Applicatives & CAS)
A l’expiration de la session CAS, toutes les sessions applicatives sont supprimées. [Quid du token ?] Les sessions applicatives sont détruites via une redirection dans le navigateur. [A Préciser le fonctionnement via le navigateur vs certificats]
Le logout d'une application web invalide la session applicative concernée, puis effectue une redirection vers le logout CAS afin de détruire la session CAS (destruction du TGC), la session API (destruction du token) et la session SAML. [à confirmer]
A près un logout ou l'utilisateur doit obligatoirement se reconnecter pour utiliser à nouveau l'application.
### Paramétrages des sessions
Toutes ces valeurs sont paramétrables dans l’instance de la solution.
Compte principal : [à confirmer]
* la session applicative JSESSIONID : 15 minutes (délai d'inactivité) :
* la session du token : 165 minutes (délai maximum) :
* la session CAS TGC : 170 minutes (délai maximum) :
* délai maximum dans CAS pour accepter la délégation d’authentification : 14 jours (délai maximum)
Dans le cas de la subrogation, on a : [à confirmer]
* la session applicative JSESSIONID : 15 minutes (délai d'inactivité) :
* la session du token : 165 minutes (délai maximum) :
* la session CAS TGC : 170 minutes (délai maximum) :
* délai maximum dans CAS pour accepter la délégation d’authentification : 14 jours (délai maximum)
# Gestion du système
## Chaîne de déploiement
* Les composants de la solution VITAM UI sont installés et configurés par un outil de déploiement automatique (ansible) dans des systèmes d’exploitation cibles (VM, container..).
* La procédure d’installation et de configuration se fait à travers un ensemble de scripts dont le source code est stocké dans le repository GIT.
* L’outil de déploiement (yum) utilise exclusivement les dépôts de packages pour installer les softs, afin de se décharger des étapes d’installation des dépendances et la gestion de conflit de fichiers.
Schéma du processus de déploiement
![Pocessus de déploiment](../images/dat_chaine_deploiement.png)
### Packaging
Les packages VITAMUI sont disponibles au format RPM (CentOS).
Chaque package respecte les principes suivants :
* Nom des packages : vitamui<id> du package
* Version du package : Numéro de “release” du projet
* Les dossiers (ainsi que les droits associés) compris dans les packages respectent les principes dictés dans la section dédiée aux utilisateurs, dossiers et droits.
* Les fichiers de configuration sont gérés par l’outil de déploiement de manière externe aux packages et ne sont pas inclus dans les packages.
Les composants de la solution VITAMUI sont tous disponibles sous forme de packages natif aux distributions supportées (rpm pour CentOS 7). Ceci inclut notamment :
* L’usage des pré-requis (au sens Require ou Depends) nativement inclus dans la distribution concernée
* L’arborescence des répertoires OS de la distribution concernée
* L’usage du système de démarrage systemd.
Les packages ne contiennent pas de pré/post action d’arrêt/démarrage/redémarrage de services. La gestion de démarrage des services et leur démarrage (a minima initial) est de la responsabilité de l’outillage de déploiement.
Les fichiers de configuration ne sont pas gérés dans les packages RPM. Par conséquent, ils n’apparaissent pas dans le résultat de commandes telles que rpm -ql. Les fichiers de configuration sont instanciés par l’outil de déploiement. Pour éviter la génération de fichier .rpmnew ou .rpmsave, il n’est pas utilisé la directive %config.
Les limitations associés au format de packaging choisi sont :
* L’instanciation d’une seule instance d’un même moteur par machine (il n’est ainsi pas possible d’installer 2 moteurs d’exécution sur le même OS) ;
* La redondance de certains contenus dans les packages (ex: les librairies Java sont embarquées dans les packages, et non tirées dans les dépendances de package)
### Dépôts
L’installation de VITAMUI s’appuie sur des dépôts Nexus et dans le Repository RPM; ou tout autre repository mis en oeuvr suite au build. Il est également possible de déployer VitamUI en générant des dépôts locaux sur les machines cibles.
### Principes de déploiement
Les principes généraux de déploiement sont les suivants :
* Les packages d’installation (rpm) sont identiques pour tous les environnements. Seule leur configuration change.
* La configuration des services est externalisée et gérée par l’outillage de déploiement.
* Le déploiement est décrit intégralement dans un fichier de définition du déploiement. En dehors des pré-requis, le déploiement initial est automatisé en totalité (sauf exception).
* Les services sont configurés par défaut pour permettre leur colocalisation (dans le sens de la colocalisation de deux instances de deux moteurs différents) (ex: dossiers d’installation / de fonctionnement différents, ports d’écoute différents, ...).
* Le déploiement s’effectue à partir d’un point central. Les commandes passées sur chaque serveur à partir de ce point central utilisent le protocole SSH.
Les service de déploiement fourni permet le déploiement de la solution VITAMUI.
* Gestion des binaires d’installations (version, intégrité)
* Gestion des éléments de configuration spécifiques à chaque plate-forme
* Pilotage de l’installation des services sur les éléments d’infrastructure (VM/containers) de manière cohérente
Données gérées :
* Configuration technique du système VITAMUI
* Certificats x509 : le moteur de déploiement et de configuration doit posséder la référence des certificats techniques déployés sur la plate-forme (car il doit entre autres assurer la cohérence de ces certificats entre les différentes instances des composants VITAMUI déployés)
## Cloisonnement
TODO
## Logs techniques
La gestion des logs techniques dans VITAMUI est similaire à celle de VITAM. Pour une description complète du fonctionnement des logs et d'ELK, il est possible de se référer à la documentation VITAM.
* [Doc VITAM : Chaîne de log - rsyslog / ELK ](http://www.programmevitam.fr/ressources/DocCourante/html/exploitation/composants/elasticsearch_log/_toc.html)
## Supervision
TODO
## Métriques
TODO
## Sauvegarde
TODO
## PRA
TODO
docs/DAT/docs/dat_vitamui/images/dat_archi_cas.png

229 KiB

docs/DAT/docs/dat_vitamui/images/dat_archi_fonctionnelle.png

123 KiB

<mxfile host="Electron" modified="2020-05-01T08:51:40.938Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.0.3 Chrome/80.0.3987.163 Electron/8.2.1 Safari/537.36" etag="loaPhsthV6b94jbNY6RY" version="13.0.3" type="device"><diagram id="wIKiT4tXNhHy29AJVhV5" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment