Gestion itinérante de droits, la méthode du trousseau de clés

Par Pascal Cambier

Download

Téléchargez le classeur Excel de calcul des trousseaux et la base .mdb d'exemple.
Lisez Lisez-moi.txt
Fichier ZIP de 61 Ko

Préliminaires

Si cette méthode a d’abord été pensée pour une application Access (dans presque toutes ses versions), elle peut être adaptée en Excel, en VB et en d’autres langages.
Elle nécessite des prérequis et/ou une volonté d'approndir par une recherche personnelle sur le Web.
Google peut être votre ami.

Liminaires

Dans une application multi utilisateurs, les droits ne sont pas nécessairement identiques pour tout le monde.
Certains utilisateurs ont accès à des fonctionnalités mais pas à d’autres et vice-versa.
« Dupont » peut éditer certaines données que « Durand » ne peut que consulter, et en partie seulement. Ce dernier peut aussi éditer d’autres données que le premier ne pourra consulter, etc.

La gestion de sécurité intégrée d’Access ne répond pas à ces besoins.

Mauvaise idée

Écrire dans des tables qui peut faire quoi, ou quoi peut être fait par qui n’est pas une sinécure, est source d’erreurs et est lourd à gérer lors de la venue d’un nouvel utilisateur, par exemple.

La bonne idée…

… est, lors d’un login, de munir l’utilisateur d’un trousseau de clés (en fait un entier long) lui permettant d’accéder ou pas aux fonctionnalités barrées par une porte.
Il faut comprendre que c’est la clef qui ouvre et pas l’utilisateur. Cela permet de cloisonner par clé et non pas par utilisateur et donc d’avoir une programmation souple : il suffit d’indiquer la clé pour chaque action.

Attention !

Pour que cette protection soit efficace, l’utilisateur ne doit pas pouvoir la contourner.
L’application doit donc être aboutie pour pouvoir être exécutée en mode RUNTIME.

Introduction

La clé sera un donc un nombre de type entier long, soit 32 bits signés et donc 31 utilisables (le 32ème bit servant au signe).
Pour plus d’informations sur le binaire et l’algèbre de Boole allez voir cette petite introduction http://www.cambier.eu/pascal/notes/initiation/ini02.html
Etc.
Pour calculer le trousseau des clés une et seize, il suffit de sommer 65536 et 2, soit 65538 dont la représentation binaire est : 00000000000000010000000000000010.
Bien entendu, vous pouvez avoir plusieurs portes avec la même clé.
Si vous n’avez pas assez de 31 clés, vous pouvez munir vos utilisateurs d’un deuxième trousseau. Vous avez alors trois possibilités :
  1. C’est le trousseau 1 OR le trousseau 2, soit 31 + 31 clés.
  2. C’est le trousseau 1 ET le trousseau 2, soit 31 x 31 clés. (une porte du trousseau 1 donne sur des portes du trousseau 2)
  3. Un mix des deux ci-dessus, toujours pour 961 clés, et si ce n’est toujours pas assez, un 3ème trousseau pour 29.791 clés ;-)

Préparation des trousseaux

Un classeur Excel va vous faciliter le travail. Il suffit d’énumérer les différentes actions / fonctionnalités, en n’oubliant pas qu’il peut y avoir plusieurs portes avec la même clé. Puis les différents utilisateurs et enfin mettre un « 1 » en regard des uns et des autres, là où il le faut !
Classeur Excel "Trousseaux.xls"
Download.

Mise en œuvre, fonctionnalités de base

  1. Il faut donc une table reprenant les caractéristiques des utilisateurs.
  2. Un formulaire de login
  3. Une fonction qui teste si la clé demandée est dans le trousseau

Table des utilisateurs

Table des utilisateur (mode création)

Table des utilisateurs, mode View

Formulaire de LOGIN

Dans un module standard

Option Compare Database
Option Explicit

'variables globales
Public sGlb_User_Id As String
Public lGLb_User_Trousseau As Long
Public sGlb_User_Nom As String
Public sTitre As String

Frm_901_Login

Formulaire de Login (Frm_901_Login)

Option Compare Database
Option Explicit

Private Sub Cmd_Commencer_Click()
    Dim Rst As ADODB.Recordset
    Set Rst = New ADODB.Recordset
    Dim CN As ADODB.Connection
    Set CN = CurrentProject.Connection
    Dim sSql As String
    Dim sCrit As String
    Dim sPass As String
   
    Rst.Open "Tbl_L_Users", CN, adOpenStatic, adLockOptimistic
   
    'user ID
    If IsNull(Txt_user_id) Then
        MsgBox "Veuillez choisir un identificateur", vbCritical + vbOKOnly
        Txt_user_id.SetFocus
        GoTo SubExit
    End If
   
    If IsNull(Txt_pass) Then
        MsgBox "Veuillez taper un mot de passe", vbCritical + vbOKOnly
        Txt_pass.SetFocus
        GoTo SubExit
    End If
   
    sCrit = "[user_id] = '" & Txt_user_id & "'"
   
    Rst.Find sCrit
    If Rst.EOF Then
        MsgBox "Identificateur ou mot de passe incorrect", vbCritical + vbOKOnly, sTitre
        Txt_user_id.SetFocus
        GoTo SubExit
    End If

    'mot de passe
    sPass = Rst("user_pass")
    If sPass <> Txt_pass Or IsNull(sPass) Then
        MsgBox "Identificateur ou mot de passe incorrect", vbCritical + vbOKOnly, sTitre
        Txt_user_id.SetFocus
        GoTo SubExit
    End If
   
    If Not IsNull(Txt_N1) Or Not IsNull(Txt_N2) Then 'nouveau mot de passe
        If Txt_N1 = Txt_N2 Then 'Okay
            Rst("user_pass") = Txt_N2
            Rst.Update
            sPass = Txt_N2
        Else
            MsgBox "Les deux lignes du nouveau mot de passe ne sont pas identiques", vbCritical + vbOKOnly, sTitre
            Me.Txt_N1.SetFocus
            GoTo SubExit
        End If
    End If
   
    If LCase$(sPass) = LCase$(sGlb_User_Id) Then
        MsgBox "Le mot de passe ne peut pas être vos initiales.  Obligation de changer.  Merci.", vbCritical + vbOKOnly, sTitre
        Me.Txt_N1.SetFocus
        GoTo SubExit
    End If
   
    'TROUSSEAU
    sGlb_User_Id = Txt_user_id
    sGlb_User_Nom = Rst("user_nom")
    lGLb_User_Trousseau = Rst("user_trousseau")
        Rst.Close
    Set Rst = Nothing
    Set CN = Nothing
    DoCmd.Close acForm, Me.Name, acSaveYes
    Exit Sub
SubExit:
    Rst.Close
    Set Rst = Nothing
    Set CN = Nothing
End Sub

Private Sub CmdAnnuler_Click()
    On Error GoTo Err_CmdAnnuler_Click
    DoCmd.Close
Exit_CmdAnnuler_Click:
    Application.Quit acQuitSaveAll  'Annuler = quitter l'application
    Exit Sub
Err_CmdAnnuler_Click:
    MsgBox Err.Description
    Resume Exit_CmdAnnuler_Click
End Sub

Private Sub Form_Load()
'initialise la variable globale avec le titre / nom de l'application
    sTitre = "°Trousseaux°"
End Sub

Private Sub Txt_N2_LostFocus()
    Me.Cmd_Commencer.SetFocus
End Sub


Les fonctions à utiliser

Public Function PositionBit(Nombre As Long, Position As Byte) As Boolean
    'Regarde dans Nombre si le bit à la position est à 1
    PositionBit = (Nombre And 2 ^ Position) <> 0
End Function

Public Function IsCle(Cle As Byte) As Boolean
    'Vérifie si la clef est bien dans le trousseau "lGLb_User_Trousseau", _
    Variable publique initialisé lors du Login
    Dim Okay As Boolean
    Okay = False
    If IsLogin Then
        Okay = PositionBit(lGLb_User_Trousseau, Cle)
    End If
    If Not Okay Then
        MsgBox "Désolé, vous n'avez pas les droits nécessaires pour accéder à cette fonctionnalité", , sTitre
    End If
    IsCle = Okay
End Function

Public Function IsLogin() As Boolean
    If IsNull(sGlb_User_Id) Or sGlb_User_Id = "" Then
        'pas logué.  ouvre le formulaire de login en dialogue. _
        Dans le login on ne peut que s'identifier ou quitter l'application
        DoCmd.OpenForm "Frm_901_login", acNormal, , , , acDialog
    End If
    IsLogin = True
End Function


Mise en œuvre, le menu général

Le menu général existe depuis longtemps en Access, certainement au moins depuis la version 97. Il est très facile à mettre en œuvre et à modifier. Le code a une syntaxe un peu vieillotte, mais rien ne vous empêche de le moderniser.

Créer le menu général

2000 à 2003

Menu général 2000 à 2003

2007

Dans le menu outils (ou le ruban outils de bases de données), chercher le menu général (ou Switchboard Manager)
Menu général 2007
Yes !
Création du menu général

Menu général créé

Formulaire "Menu Général"
Un formulaire « Menu général » a été créé.
Table "Switchboard Items"
Une table « Switchboard Items » a été créée.
Ajoutez un champ « Cle » comme ci-dessus.
Modification de la table "SwitchBoard Items"
Mettez à jour la colonne « Cle ». Notez que vous pouvez modifier le contenu de la table sans passer par l’assistant. Par exemple, j’ai moi-même modifié l’emplacement (ItemNumber) des « retour au menu général » en 8, dernière position possible.
Modifiez le code du menu général comme suit :

Private Function HandleButtonClick(intBtn As Integer)
.
.
.
    ' If no item matches, report the error and exit the function.
    If (rs.EOF) Then
        MsgBox "Une erreur s'est produite lors de la lecture de la table d'élément du Menu général."
        rs.Close
        Set rs = Nothing
        Set con = Nothing
        Exit Function
    End If

    '---------- Trousseau de clé
    If Not IsCle(rs("Cle")) Then Exit Function
    '----------- fin de trousseau

    Select Case rs![Command]

        ' Go to another switchboard.
    Case conCmdGotoSwitchboard
.
.
.

Essayez !

Login en action

Accès à une fonctionnalité

Pas accès à une autre fonctionnalité

 La touche finale : le verrouillage

Contrôler le démarrage

D’abord, faire en sorte que le menu général soit affiché automatiquement au démarrage.

2007

contrôle du démarrage en v 2007

2000 à 2003





Runtime

Utilisez le mode Runtime, ou mieux, carrément le runtime, disponible à l’adresse http://www.microsoft.com/downloads/details.aspx?FamilyID=d9ae78d9-9dc6-4b38-9fa6-2c745a175aed&displaylang=fr
Pour le mode runtime, utilisez la ligne de commande (dans un .bat)

C:\Program Files\Microsoft Office\OfficeXX\MSACCESS.EXE /runtime X:\dossier\dataBase.mdb

OfficeXX est 10, 11 ou 12 pour respectivement XP, 2003 et 2007

Vous pouvez aussi utiliser un script VBS.  Par exemple :

option explicit
Dim Fso
Dim WshShell
Dim Dossier_Local
Dim Nom_Base
Dim Nom_Complet
Dossier_Local = "x:\dossier"
Nom_Base = "database.mdb"
Set Fso = CreateObject("Scripting.FileSystemObject")Set WshShell = WScript.CreateObject("WScript.Shell")
Nom_Complet = CHR(34) & "C:\Program Files\Microsoft Office\OfficeXX\MSACCESS.EXE"
Nom_Complet = Nom_Complet & chr(34) & " /runtime " & Fso.BuildPath(Dossier_Local,Nom_Base)
WshShell.Run Nom_Complet
, 3

Désactiver la touche Shift (Maj)

Beaucoup de personnes savent que l’on peut inhiber les options de démarrage d’une application en maintenant la touche shift appuyée durant son démarrage. Le code suivant désactive la touche Shift
Attention, il faut que le code soit au moins exécuté une fois pour que cela fonctionne (sa simple présence ne suffit pas).
 
Public Sub Shift_Desactive()
    On Error GoTo errProperty
    Dim dbDAO As DAO.Database
    Dim prtDAO As DAO.Property
    Set dbDAO = CurrentDb()
    dbDAO.Properties("AllowByPassKey") = False
okProperty:
    'ferme les objets proprement
    Set prtDAO = Nothing
    dbDAO.Close
    Set dbDAO = Nothing
    Exit Sub
errProperty:
    'à la première utilisation, il faut créer la propriété !
    Set prtDAO = dbDAO.CreateProperty("AllowByPassKey", 1, False)
    dbDAO.Properties.Append prtDAO
    Resume okProperty
End Sub


Modifiez le code du menu général comme suit pour exécuter le code au démarrage de l’application.

Private Sub Form_Open(Cancel As Integer)
' Minimize the database window and initialize the form.
    ' Move to the switchboard page that is marked as the default.
    Me.Filter = "[ItemNumber] = 0 AND [Argument] = 'Par défaut' "
    Me.FilterOn = True
    '----- Début Trousseau
    Shift_Desactive 'désactive la touche SHIFT
    '----- Fin trousseau
End Su
b

Le code suivant réactive la touche shift. Et bien oui, il y a une parade :-(

Public Sub Shift_Reactive()
    Dim dbDAO As DAO.Database
    Dim prtDAO As DAO.Property
    Set dbDAO = DBEngine.OpenDatabase("X:\Dossier\base")
    dbDAO.Properties("AllowBypassKey") = True
    MsgBox dbDAO.Name & " est de nouveau accessible."
    Set prtDAO = Nothing
    dbDAO.Close
    Set dbDAO = Nothing
End Sub

Contrôler l’accès en mode « Non Runtime »

Si l’utilisateur a Access complet, il peut accéder directement à la base sans passer par le script ou batch de démarrage.
Un petit formulaire et un peu de code va résoudre le problème.

Mot de passe Non Runtime...

Option Compare Database
Option Explicit
Private Sub Cmd_Annuler_Click()
    Application.Quit
End Sub
Private Sub Cmd_Ok_Click()
    If Me.TxtInput <> "password" Then Application.Quit
    DoCmd.Close
End Sub


Comme vous pouvez le voir, le mot de passe est en clair dans le code. Ce n’est pas trop grave parce que la dernière étape sera de rendre le code inaccessible.
Modifiez une dernière fois le code du menu général comme suit:

Private Sub Form_Open(Cancel As Integer)
' Minimize the database window and initialize the form.
' Move to the switchboard page that is marked as the default.
    Me.Filter = "[ItemNumber] = 0 AND [Argument] = 'Par défaut' "
    Me.FilterOn = True
    '----- Début Trousseau
    Shift_Desactive    'désactive la touche SHIFT
    If SysCmd(acSysCmdRuntime) = 0 Then    'mode runtime
        DoCmd.OpenForm "Frm_902_No_Runtime", acNormal, , , , acDialog
    End If
    '----- Fin trousseau
End Sub

Faire un MDE, ADE ou ACCDE

Commencez par compiler le code VBA, corrigez les éventuelles erreurs. Temps qu’il restera une erreur, vous ne pourrez pas fabriquer le .MDE
Vous trouverez beaucoup d’explications ici http://office.microsoft.com/fr-fr/access-help/fichiers-mde-et-ade-HP001051112.aspx

Faire MDR en v2007

Conclusion

Nous espérons que cela vous aura apporté des solutions. Vous pouvez renforcer la sécurité en utilisant en concomitance celle offerte par Access.