IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Utiliser le modèle ADOX avec Visual Basic


précédentsommairesuivant

XII. Gestion des utilisateurs

La gestion des utilisateurs comprend en fait de façon imbriquée deux thèmes que sont les droits d'accès et la propriété. Quasiment tous les SGBD disposent d'un système limitant l'accès aux données ainsi qu'à la structure de la base. Avec ADOX on retrouve ces concepts dans les objets User et Group.

XII-A. Cas particulier d'Access

Les concepts que nous allons voir plus loin fonctionnent pour de nombreux SGBD, mais Access gère la sécurité utilisateur par l'utilisation d'un fichier externe. Ceci présente des avantages et des inconvénients, mais je ne vais pas démarrer une polémique ici.

Si j'aborde ce point, c'est pour une particularité d'Access. Pour garantir l'unicité de chaque utilisateur ou groupe, le fichier de sécurité Access utilise un identifiant Unique nommé SID qui est généré à l'aide du nom de l'utilisateur (ou du groupe) et d'une chaîne nommée PID. Un même nom avec un même PID génère toujours le même SID ce qui permet de reconstruire le fichier de sécurité si besoin est.

Si cette possibilité existe avec DAO, ADO ne permet pas de fournir un PID explicite ce qui rend le fichier impossible à reconstruire en cas de problème. Certes des sauvegardes fréquentes doivent pouvoir éviter ce problème, mais c'était une perte de souplesse importante.

De même, normalement un utilisateur hérite implicitement des droits d'accès du groupe, mais cela n'est pas le cas avec ADO 2.7 et inférieur. Il faut alors coder explicitement les droits du groupe et de l'utilisateur.

Comme Access gère sa sécurité par un fichier externe, il est fortement conseillé de spécifier ce fichier dans la connexion du catalogue avec la Property (« Jet OLEDB:System database ») et éventuellement la création d'un nouveau fichier avec la Property (Jet OLEDB:Create System Database)

Si vous spécifiez un fichier de sécurité incorrecte, vous n'aurez pas d'erreur lors de l'ouverture du catalogue. L'erreur surviendra lors de l'appel d'un objet lié à la sécurité. De plus vous obtiendrez une erreur 3251 « L'opération demandée par l'application n'est pas prise en charge par le fournisseur » ce qui ne vous aidera pas beaucoup à voir l'erreur.

XII-B. Propriétés et droits

Voilà deux notions importantes, corrélatives et pourtant différentes dans leur conception.

XII-B-1. Propriétaire

Chaque objet a toujours un propriétaire. À l'origine, c'est le créateur de l'objet qui est le propriétaire.

Le propriétaire d'un objet garde le droit d'accès total (modification, suppression, droits) sur l'objet. Le propriétaire d'un objet peut être un utilisateur ou un groupe. La base de données est un objet un peu particulier puisque seul un utilisateur (et non un groupe) peut en être propriétaire.

Le problème de la gestion de la propriété est important à gérer si les utilisateurs ont le droit de créer des objets. Si vous souhaitez qu'ils gardent tous les droits sur les objets qu'ils ont créés, il n'y a rien à faire, mais sinon vous devez gérer le transfert de la propriété.

Faites toujours très attention à cette notion de propriétaire, elle peut permettre des accès que vous ne souhaiteriez pas si vous n'y prenez pas garde.

XII-B-2. Administrateur

Habituellement, l'administrateur ou les membres du groupe administrateur sont les seuls à avoir tous les droits sur une base de données, y compris celui de modifier les droits d'accès des autres. De par ce fait, on essaye toujours de limiter le nombre d'administrateurs. Pour ce faire, il faut donc mettre au point une stratégie de droits pour que chaque groupe ait les droits nécessaires et suffisants à un bon fonctionnement. L'avantage dans ce cas d'une approche par programme est la possibilité d'utiliser une connexion ayant les droits administrateurs pour permettre aux utilisateurs de faire des actions (prévues) que leurs droits ne leurs permettraient pas de faire normalement.

XII-B-2-a. Access

Même si cela est transparent, la sécurité d'Access est toujours activée. Il existe un compte « Administrateur » possédant tous les droits et n'ayant pas de mot de passe. Pour activer la sécurité sur Access on procède en général de la manière suivante :

  • On donne un mot de passe à l'utilisateur « Administrateur ».
  • On crée un nouveau compte d'administrateur, avec un autre nom de préférence (« Admin » par exemple) auquel on donne tous les droits et propriétés
  • On supprime le compte « Administrateur » du groupe « Administrateurs ». Il n'est en effet pas possible de supprimer les Groupes et Utilisateurs par défaut.

La dernière étape n'est pas indispensable, par contre la première l'est, car sans cela, n'importe qui ayant Access sur son poste pourra ouvrir votre base de données.

XII-B-3. Utilisateurs et groupes

C'est une notion classique de la sécurité des SGBD. Un groupe représente l'ensemble des utilisateurs possédant les mêmes droits. Un utilisateur représente en général une personne.

Chaque utilisateur appartient au minimum au groupe des utilisateurs, mais il peut appartenir à plusieurs groupes.

Un utilisateur hérite toujours des droits du(des) groupe(s) dont il dépend, mais peut avoir des droits modifiés par rapport à celui-ci. Attention, en cas de contradiction entre les droits du groupe et ceux de l'utilisateur, c'est toujours la condition la moins restrictive qui l'emporte.

Pour simplifier la gestion des droits, on définit habituellement les groupes puis les utilisateurs.

Lorsqu'un groupe est propriétaire, chaque utilisateur du groupe est également propriétaire.

L'héritage des droits d'un groupe est paramétrable.

XII-B-4. Héritage des objets

Les droits d'un groupe / utilisateur se définissent normalement pour chaque objet.

Pour une base de données contenant de multiples objets, vous voyez immédiatement le code que cela peut engendrer. Il est possible de propager les droits d'un objet à tous les objets que celui-ci contient. Une solution consiste donc à donner des restrictions standards à l'objet base de données puis à adapter au cas par cas sur les objets. Attention, cette méthode n'est pas réversible, elle n'est donc pas sans risque. Cet héritage n'est jamais transverse, mais il est possible de définir des droits pour une catégorie générique d'objet.

XII-C. Objet Group

En soi un objet Group n'est pas très complexe. Il ne possède que la collection Users qui représente les utilisateurs membres du groupe, une propriété Name qui est son nom et deux méthodes. C'est celles-ci que nous allons voir en détail.

XII-C-1. SetPermissions

Attribue les permissions sur un objet pour un groupe ou un utilisateur. De la forme

Group.SetPermissions Name, ObjectType, Action, Rights [, Inherit] [, ObjectTypeId]

Il s'agit là d'une méthode. Contrairement à la valorisation des propriétés ADOX qui se fait avant l'ajout de l'objet à la collection, on applique les méthodes à l'objet seulement après son ajout à la collection.

Passons en revue ces paramètres, mais notez bien qu'ils s'appliquent aussi bien au groupe qu'à l'utilisateur. Les différences seront vues dans l'étude de l'objet User.

ObjectType

Le paramètre ObjectType peut prendre une des valeurs suivantes :

Constante

Valeur

Description

adPermObjProviderSpecific

-1

Définit un objet spécifique du fournisseur.. Une erreur se produira si le paramètre ObjectTypeId n'est pas fourni

adPermObjTable

1

Objet Table.

adPermObjColumn

2

objet Column

adPermObjDatabase

3

L'objet est la base de données

adPermObjProcedure

4

Objet Procedure.

AdPermObjView

5

Objet View

On retrouve la tous les objets du modèle plus l'objet Database. La valeur adPermObjProviderSpecific permet d'utiliser des objets spécifiques au fournisseur, par exemple pour Access les états ou les formulaires.

Name

Donne le nom de l'objet cible, si vous ne précisez pas ce nom vous devez passer NULL, mais vous aurez une erreur si vous omettez le paramètre. Dans ce cas, les droits seront attribués à tous les nouveaux objets de même type contenu dans le catalogue (catégorie générique).

Pour l'objet database, vous devez donner une chaîne vide ("") au paramètre Name. Voir dans l'exemple plus loin.

Action

Ce paramètre est combiné avec le paramètre Rights. Il peut prendre les valeurs suivantes :

Constante

Valeur

Description

adAccessGrant

1

Le groupe aura au moins les autorisations demandées.

adAccessSet

2

Le groupe aura exactement les autorisations demandées

adAccessDeny

3

Le groupe n'aura pas les autorisations demandées.

adAccessRevoke

4

Tous les droits d'accès explicites que possède le groupe seront annulés.

Détaillons ces valeurs, car elles dépendent fortement de la stratégie choisie ainsi que de la gestion de l'existant.

Lorsque l'on considère un utilisateur, on entend par droits (autorisations) explicites, les droits qui appartiennent à celui-ci et par droits implicites les droits de son groupe. Pour un groupe, tous les droits sont explicites.

adAccessRevoke retire donc tous les droits du groupe, il n'est pas utile de renseigner le paramètre Rights (évidemment). Le fait de retirer les droits d'un groupe ne retire pas les droits d'un utilisateur appartenant au groupe lorsqu'ils sont différents de ceux du groupe.

adAccessDeny enlève tous les droits définis dans le paramètre Rights.

adAccessSet est la valeur que l'on utilise en général lors de la création du fichier de sécurité. Les droits définis dans le paramètre Rights seront exactement les droits donnés, ceux existant précédemment seront remplacés ou modifiés.

AdAccessGrant est la valeur pour la modification de droits. Au lieu de redéfinir toute la liste des droits on précise le droit que l'on souhaite modifier, les autres droits ne seront pas redéfinis.

Rights

Valeur de type Long représentant un masque binaire des droits pouvant être une ou plusieurs des valeurs suivantes. Certaines de ces valeurs sont exclusives (adRightFull par exemple) :

Constante

Valeur

Description

adRightCreate

16384 (&H4000)

Le groupe à l'autorisation de créer des objets de ce type

adRightDelete

65536 (&H10000)

Le groupe a l'autorisation de supprimer des données de l'objet

adRightDrop

256 (&H100)

Le groupe a l'autorisation de supprimer l'objet

adRightExclusive

512 (&H200)

Le groupe a l'autorisation d'accéder de façon exclusive à l'objet

adRightExecute

536870912 (&H20000000)

Le groupe a l'autorisation d'exécuter l'objet.(macro Access par exemple)

adRightFull

268435456 (&H10000000)

Le groupe a toutes les autorisations concernant l'objet

adRightInsert

32768 (&H8000)

Le groupe a l'autorisation d'insérer des données dans l'objet.

adRightMaximumAllowed

33554432 (&H2000000)

Le groupe a le maximum d'autorisations spécifiques autorisées par le fournisseur.

adRightNone

0

Le groupe n'a aucune autorisation concernant l'objet.

adRightRead

-2147483648 (&H80000000)

Le groupe a l'autorisation de lire l'objet

adRightReadDesign

1024 (&H400)

Le groupe a l'autorisation de lire la définition de l'objet

adRightReadPermissions

131072 (&H20000)

Le groupe a l'autorisation de lire les autorisations de l'objet

adRightReference

8192 (&H2000)

Le groupe a l'autorisation de référencer l'objet

adRightUpdate

1073741824 (&H40000000)

Le groupe a l'autorisation de modifier des données dans l'objet.

adRightWithGrant

4096 (&H1000)

Le groupe a l'autorisation d'accorder des autorisations concernant l'objet

adRightWriteDesign

2048 (&H800)

Le groupe a l'autorisation de modifier la structure de l'objet

adRightWriteOwner

524288 (&H80000)

Le groupe a l'autorisation de modifier le propriétaire de l'objet

adRightWritePermissions

262144 (&H40000)

Le groupe a l'autorisation de modifier des autorisations spécifiques de l'objet.

Comme il s'agit de masque binaire, on compose les droits avec l'opérateur « OR ».

Une erreur fréquente consiste à considérer l'attribution des droits par programmation comme fonctionnant à l'identique de l'assistant sécurité. Celui-ci crée implicitement des droits lorsque l'on attribue certains droits à l'utilisateur (par exemple l'autorisation « modifier les données » donne automatiquement l'autorisation « lire les données »). Il n'en est pas de même par programmation. Vous devez définir de façon cohérente et explicite les droits sous peine de bloquer vos utilisateurs.

Une autre erreur consiste à utiliser un droit qui n'existe pas pour l'objet considéré. Ainsi j'ai déjà vu donner le droit adRightExecute sur des procédures, sûrement parce que l'on dit exécuter une requête, alors que c'est le droit adRightRead qu'il faut utiliser.

Inherit

Paramètre optionnel qui détermine comment les objets contenus dans l'objet cible hériteront des autorisations. Les valeurs peuvent être :

Constante

Valeur

Description

adInheritNone

0

Valeur par défaut. Pas d'héritage.

adInheritObjects

1

Les objets non-conteneurs héritent des autorisations.

adInheritContainers

2

Les objets conteneurs héritent des autorisations.

adInheritBoth

3

Tous les objets héritent des autorisations.

adInheritNoPropagate

4

Les objets n'ayant pas déjà hérité d'autorisations hériteront.

L'héritage a parfois des résultats surprenants avec ADOX, je vous conseille donc de ne pas en abuser. Toutefois on peut toujours déterminer une configuration type par groupe et la donner à la base de données avec un héritage, afin que les objets contenus héritent des autorisations. Je ne vous conseille pas d'utiliser cette technique.

ObjectTypeId

Ce paramètre est obligatoire avec le type adPermObjProviderSpecific. Cela permet d'accéder à certains objets contenus dans le SGBD. Il faut passer comme valeur le GUID de l'objet. Par exemple pour Access les GUID suivants permettent de définir des autorisations pour les formulaires, états et macro

Object

GUID

Form

{c49c842e-9dcb-11d1-9f0a-00c04fc2c2e0}

Report

{c49c8430-9dcb-11d1-9f0a-00c04fc2c2e0}

Macro

{c49c842f-9dcb-11d1-9f0a-00c04fc2c2e0}

XII-C-2. GetPermissions

Permet de lire les autorisations d'accès d'un objet. Ce n'est pas toujours très simple à interpréter par programmation, aussi je vous conseille plutôt de supprimer puis de recréer les autorisations.

De la forme

ReturnValue = Group.GetPermissions(Name, ObjectType [, ObjectTypeId])

Ou ReturnValue est une valeur de type Long représentant le masque binaire. Pour tester si une autorisation existe dans le masque utiliser l'opérateur AND

La fonction suivante permet d'afficher les droits dans la fenêtre d'exécution.

 
Sélectionnez
Private Sub EcrisDroit(Droits As Long)

    If Droits And adRightCreate Then Debug.Print "Création"
    If Droits And adRightDelete Then Debug.Print "Effacement"
    If Droits And adRightDrop Then Debug.Print "Suppression"
    If Droits And adRightExclusive Then Debug.Print "Exclusif"
    If Droits And adRightExecute Then Debug.Print "Exécution"
    If Droits And adRightInsert Then Debug.Print "Insertion"
    If Droits And adRightRead Then Debug.Print "Lecture D"
    If Droits And adRightReadDesign Then Debug.Print "Lecture S"
    If Droits And adRightReadPermissions Then Debug.Print "LirePermission"
    If Droits And adRightReference Then Debug.Print "Reference"
    If Droits And adRightUpdate Then Debug.Print "Modification"
    If Droits And adRightWithGrant Then Debug.Print "ModifPermission"
    If Droits And adRightWriteDesign Then Debug.Print "Modif Structure"
    If Droits And adRightWriteOwner Then Debug.Print "Modif Prop"
End Sub

Avec un appel de procédure comme :

 
Sélectionnez
temp = MonGrou.GetPermissions("tblAnomalie", adPermObjTable)
Call EcrisDroit(temp)

XII-D. Objet User

Cet objet ressemble fortement à l'objet Group dans sa programmation. Il possède une méthode de plus.

XII-D-1. ChangePassword

Permet de modifier le mot de passe d'un utilisateur.

User.ChangePassword OldPassword, NewPassword

Là pas besoin d'explication si ce n'est qu'un des paramètres peut être la chaîne vide ""

XII-D-2. GetPermissions et SetPermissions

S'utilise comme pour l'objet Group.

Comme je l'ai déjà dit, un utilisateur membre d'un groupe peut avoir des autorisations différentes de celles du groupe. Pour des raisons de maintenance, cette situation est toutefois à proscrire. N'oubliez pas que sur un mélange de propriétés utilisateur / groupe c'est toujours l'autorisation la moins restrictive qui l'emporte.

XII-D-3. Properties

Les objets User et Group ont une collection properties.

XII-E. Exemple

Dans l'exemple suivant, nous allons sécuriser une base de données, créer deux groupes et deux utilisateurs.

En phase de création de base, commencer toujours par gérer la sécurité comme vous allez le voir c'est beaucoup plus simple.

 
Sélectionnez
Dim Catalogue As ADOX.Catalog, MonGrou As ADOX.Group, strconn As String
    Set Catalogue = New ADOX.Catalog
    strconn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" &
"D:\User\jmarc\tutorial\ADOX\Test\NouvBase1.mdb" & ";Jet OLEDB:System
    database = D:\User\jmarc\tutorial\ADOX\system.mdw;User Id=Admin; Password="
    Catalogue.Create strconn
    Catalogue.Users("Admin").ChangePassword "", "password"
    Catalogue.Groups.Append "Utilisateurs"
    Set MonGrou = Catalogue.Groups("Utilisateurs")
    With MonGrou
        .SetPermissions "", adPermObjDatabase, adAccessSet, adRightRead,adInheritNone
        .SetPermissions Null, adPermObjTable, adAccessSet, adRightInsert Or adRightRead Or adRightUpdate, adInheritNone
        .SetPermissions Null, adPermObjProcedure, adAccessSet, adRightRead Or adRightReadDesign, adInheritNone
        .SetPermissions Null, adPermObjView, adAccessSet, adRightRead Or adRightReadDesign, adInheritNone
    End With
    Catalogue.Groups.Append "Consultants"
    Set MonGrou = Catalogue.Groups("Consultants")
    With MonGrou
        .SetPermissions "", adPermObjDatabase, adAccessSet, adRightNone,adInheritNone
        .SetPermissions Null, adPermObjTable, adAccessSet, adRightNone,adInheritNone
        .SetPermissions Null, adPermObjProcedure, adAccessSet, adRightNone,adInheritNone
        .SetPermissions Null, adPermObjView, adAccessSet, adRightRead,adInheritNone
    End With
    Catalogue.Users.Append "Emile", ""
    Catalogue.Users("Emile").ChangePassword "", "xtf22re"
    Catalogue.Groups("Utilisateurs").Users.Append "Emile"
    With Catalogue.Users("Emile")
        .SetPermissions "", adPermObjDatabase, adAccessSet, adRightRead,adInheritNone
        .SetPermissions Null, adPermObjTable, adAccessSet, adRightInsert Or adRightRead Or adRightUpdate, adInheritNone
        .SetPermissions Null, adPermObjProcedure, adAccessSet, adRightRead Or adRightReadDesign, adInheritNone
        .SetPermissions Null, adPermObjView, adAccessSet, adRightRead Or adRightReadDesign, adInheritNone
    End With
    Catalogue.Users.Append "Leon", ""
    Catalogue.Users("Leon").ChangePassword "", "pwed58t"
    Catalogue.Groups("Consultants").Users.Append "Leon"
    With Catalogue.Users("Leon")
        .SetPermissions "", adPermObjDatabase, adAccessSet, adRightNone, adInheritNone
        .SetPermissions Null, adPermObjTable, adAccessSet, adRightNone, adInheritNone
        .SetPermissions Null, adPermObjProcedure, adAccessSet, adRightNone,    adInheritNone
        .SetPermissions Null, adPermObjView, adAccessSet, adRightRead, adInheritNone
    End With

Comme nous le voyons, la première étape après la création est de changer le mot de passe de l'administrateur afin d'activer la sécurité.

Je crée ensuite deux groupes dont je définis les droits puis deux utilisateurs (1 par groupe). Notez que je redéfinis les mêmes droits puisque ADO avec Access ne génère pas l'héritage implicite des droits du groupe.

Dans ce cas, je n'ai encore créé aucun objet dans ma table. Ceci me permet d'utiliser des catégories génériques pour l'attribution des droits (utilisation de Null pour le paramètre Name).

Vous remarquerez enfin que j'utilise SetPermissions après l'ajout de l'objet à sa collection

XII-F. Techniques de sécurisation

Il est bien évident que gérer la sécurité par le code n'est pas une sinécure, aussi on essaye toujours de passer par les assistants ad hoc des SGBD plutôt que de se lancer dans un code aventureux.

Dans le cas d'Access, il est beaucoup plus parlant de gérer les sécurités depuis Access. Si toutefois vous devez utiliser le code, vous gagnerez en efficacité et en simplicité à suivre le modèle DAO pour gérer la sécurité, du moins tant que Microsoft n'aura pas sorti une version ADO faisant cela efficacement.

Nous allons partir du principe dans cette partie que l'emploi du code avec ADO est indispensable.

Grosso modo il n'existe que deux cas, soit vous allez modifier des groupes, des utilisateurs ou des autorisations existantes soit il vous faut tout créer.

XII-F-1. Modification

Si la sécurité est déjà bien gérée, il ne s'agit que d'ajouter des utilisateurs et de bien gérer les droits d'accès ou de propriété. La technique consiste toujours à créer un utilisateur dans un groupe existant, afin de ne pas avoir à gérer tous ses droits objet par objet. Lors de la modification d'autorisations, il est souvent plus simple de détruire les anciennes, puis de réattribuer les autorisations. Cherchez toujours à donner la propriété des nouveaux objets à l'administrateur ou alors créez un utilisateur fantôme, appelé par exemple « Code », qui possède les autorisations nécessaires à tous vos accès par le code.

Si la sécurité est mal gérée, détruisez tout et repartez du début.

Le code suivant vous donne un exemple de la réattribution de la propriété des tables.

 
Sélectionnez
Private Sub Command9_Click()

Dim cnn1 As ADODB.Connection
Dim Catalogue As ADOX.Catalog, MaTable As ADOX.Table
    
    Set Catalogue = New ADOX.Catalog
    Set cnn1 = New ADODB.Connection
    With cnn1
        .Provider = "Microsoft.Jet.OLEDB.4.0;"
        .ConnectionTimeout = 30
        .CursorLocation = adUseClient
        .IsolationLevel = adXactChaos
        .Mode = adModeShareExclusive
        .Properties("Jet OLEDB:System database") = "D:\User\jmarc\tutorial\ADOX\system.mdw"
        .Open "Data Source=D:\User\jmarc\tutorial\ADOX\Test\NouvBase1.mdb ;User Id=Admin; Password=password"
    End With
    Catalogue.ActiveConnection = cnn1
    For Each MaTable In Catalogue.Tables
        If StrComp(Catalogue.GetObjectOwner(MaTable.Name, adPermObjTable), "admin", vbTextCompare) <> 0 And StrComp(Catalogue.GetObjectOwner(MaTable.Name, adPermObjTable), "engine", vbTextCompare) &lt;> 0 Then
            Catalogue.SetObjectOwner MaTable.Name, adPermObjTable, "Admin"
        End If
    Next

End Sub

Comme vous le voyez dans le test, n'essayez pas de prendre la propriété des tables dont le propriétaire est « engine » (information de schéma du moteur Jet) vous déclencheriez une erreur.

XII-F-2. Création

Lors de la création de la base, je vous conseille vivement de créer la sécurité en premier. Vous pouvez dès lors utiliser des objets génériques et définir vos droits assez rapidement. Il vaut toujours mieux avoir un groupe de trop que l'on supprime à la fin, plutôt que de se rendre compte qu'il en manque un.

Définissez votre système de sécurité avant de coder. Par le code il vaut mieux multiplier les groupes que les utilisateurs.

XII-F-3. Une autre solution : le DDL

À partir d'Access 2000, vous pouvez contourner les faiblesses de ADO pour la création des utilisateurs et des groupes en utilisant le DDL. Sachez que celui vous permet de gérer les PID.

Un objet Command peut être utilisé avec une requête de type :

CREATE USER Nom MotDePasse PID

Mais nous sortons là du cadre de cet article

XII-G. Conclusion sur la sécurité

Comme nous l'avons vu, gérer la sécurité par le code n'est souvent pas un bon choix. Cela reste possible à faire dans certains cas particuliers, mais le code est relativement lourd et dur à corriger. Privilégiez toujours la solution des assistants tant que cela est possible.

Bien que je n'ai pas abordé cela, vous aurez une erreur si l'utilisateur qui se connecte n'a pas les droits d'écriture de structure et tente d'ouvrir le catalogue.

Ce catalogue peut être partiel en fonction des droits définis.


précédentsommairesuivant

Copyright © 2003 bidou. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.