Cet article est publié sous licence CC BY-NC-SA
Nous utilisons pour la plupart de nos applications web des systèmes d’autorisations d’accès. Ce que je vous propose c’est de revenir sur la conception de ces systèmes et de prendre un exemple en utilisant les gems cancancan pour la gestion des autorisations et rolify pour la gestion des rôles.
Tout d’abord parlons du Role-Based Access Control (RBAC). Pour certains cette notion peut sembler floue mais pourtant c’est une notion que nous utilisons très régulièrement.
Le RBAC c’est quoi ? Un peu d’histoire : C’est un modèle de contrôle d’accès proposé en 1992 par Ferraiolo et Kuhn qui est basé sur le fait d’attacher des rôles aux utilisateurs afin de leur donner certains accès. Il a été mis en place afin de donner une alternative à deux modèles :
Mandatory Access contrôle (MAC), modèle utilisé majoritairement pour des systèmes de sécurité militaire, qui permet de restreindre l’accès à des informations en fonction du niveau de sensibilité de celle-ci et de l’autorisation des utilisateurs à pouvoir accéder à un tel niveau d’information.
Discretionary Access contrôle (DAC), modèle utilisé pour les entreprises ou encore pour des systèmes de sécurité militaire de bas niveau, qui permet à un utilisateur d’accorder ou révoquer l’accès à l’un des objets sous son contrôle sans l’intervention d’un administrateur.
Prenons pour exemple le modèle DAC qui est orienté entreprise : je suis un docteur et j’ai la permission de prescrire des médicaments. Si on se base sur la logique du modèle, étant donné que la prescription de médicament est sous le contrôle du docteur, il peut la donner à qui il veut, par exemple à une infirmière. Or cela est aberrant car une infirmière n’a pas le droit de prescrire de médicaments.
Les utilisateurs peuvent dans le cas du modèle DAC passer leurs permissions à d’autres utilisateurs. C’est la différence fondamentale avec le modèle RBAC qui pour ce dernier permet de protéger les données ainsi que leurs intégralités et leurs confidentialités.
Ce modèle est basé sur 3 notions :
Les rôles dans leurs formes les plus simples sont basés sur les niveaux d’utilisation : Admin, Modérateur, Utilisateur, etc. Mais pour des formes plus complexes, les rôles vont représenter les corps de métier, les projets ou encore les activités.
Ce modèle RBAC est devenu le modèle de gestion le plus employé car il s’applique aisément aux différentes structures. Chaque rôle est une simple collection de permissions et les utilisateurs reçoivent des autorisations uniquement à travers les rôles auxquels ils sont affectés.
Passons à une utilisation pratique afin de comprendre le fonctionnement de ce modèle RBAC.
Nous allons utiliser 2 gems : Cancancan et Rolify. Ajoutons à notre Gemfile les 2 gems :
gem 'cancancan'
gem 'rolify'
Installons les gems avec un bundle install
puis passons à la configuration.
Dans un premier temps nous allons créer un rôle User. Pour cette démonstration les attributs nous importent peu :
rails generate model User
Dans un second temps nous allons créer la classe Ability
qui va nous permettre de définir les permissions de nos utilisateurs avec Cancancan.
rails generate cancan:ability
Enfin nous allons nous simplifier la gestion des rôles avec Rolify
rails generate rolify Role User
Lancez la migration avec un rake db:migrate
Que venons nous de faire ? Nous venons de créer un modèle User qui dispose grâce à Cancancan et Rolify d’un gestionnaire d’autorisations et de rôles.
Configurons maintenant l’ensemble. Dans le fichier Ability
, ajoutons dans la méthode initialize
les autorisations suivantes :
# app/models/ability.rb
if user.has_role? :employee
can :go, :cloakroom
elsif user.has_role? :doctor
can [:heal, :give_medications], :patient
elsif user.has_role? :nurse
can :heal, :patient
else
can :wait, :waiting_room
end
Si on traduit nos droits littéralement, cela nous donne : 1. Un employé va pouvoir aller dans les vestiaires 2. Un docteur va pouvoir soigner et prescrire des médicaments aux patients 3. Une infirmière va pouvoir soigner les patients 4. Les personnes qui ne sont ni employés, ni docteurs et ni infirmières sont conviées à attendre bien gentiment dans la salle d’attente
Passons en console rails console
Nous allons ici créer des utilisateurs et tester leurs droits en fonction de leurs rôles et faire une comparaison avec les 3 notions d’un modèle RBAC.
patient = User.new
patient.save
patient.roles
=> []
patient.roles
nous permet de lister les rôles associés aux patients. Comme nous n’avons pas attribué de rôles à celui-ci, cette commande nous retourne une liste vide. Nous allons maintenant récupérer les droits du patient et comprendre leurs fonctionnements.
ability = Ability.new(patient)
ability.can? :wait, :waiting_room
=> true
ability.can? :go, :cloakroom
=> false
ability.can? :wait, :waiting_room
nous permet de vérifier si les autorisations du patient lui permettent d’attendre dans la salle d’attente. La réponse retournée est oui.
Même principe avec la commande ability.can? :go, :cloakroom
qui permet de vérifier si le patient peut aller dans le vestiaire, la réponse retournée est non.
En regardant notre méthode initialize
cela semble évident mais pourquoi ? Reprenons les 3 notions sur lequel un modèle RBAC est fondé :
C’est la première notion ici qui fait défaut dans notre exemple. Le patient n’aillant aucun rôle, il ne peut donc effectuer aucune tache et est contraint à rester dans la salle d’attente.
Passons à une nurse. Une nurse (en anglais) est comme son nom l’indique une infirmière mais elle est aussi une employée. Nous allons donc lui appliquer les 2 rôles.
nurse = User.new
nurse.save
nurse.add_role [:employee, :nurse]
nurse.roles
=> [:employee, :nurse]
Dans cet exemple, nous avons attribué des rôles à notre nurse. De ce fait nous avons remplis la première notion du modèle RBAC. Mais ce n’est pas tout. Si nous avons pu attribuer un rôle à notre nurse, c’est que celle-ci avait l’autorisation pour détenir ce rôle.
Il est important de vérifier deux choses pour valider notre 2nd notion du modèle RBAC et de la dissocier de la 1ère :
Ai-je les permissions (le rôle) pour pouvoir attribuer ce rôle ? Si oui, l’entité qui demande le rôle est-elle autorisée à l’avoir ? Sans cette vérification, notre 2nd notion n’existe plus et le modèle RBAC perd de son utilité.
Pour finir avec cette application du modèle RBAC, nous allons vérifier les autorisations de notre nurse.
ability = Ability.new(nurse)
ability.can? :go, :cloakroom
=> true
ability.can? :heal, :patient
=> true
ability.can? :give_medications, :patient
=> false
Une nurse peut aller soigner un patient ou encore aller dans le vestiaire car ses rôles l’y autorisent. Mais bien qu’elle ait accès au patient, ce n’est pas pour autant qu’elle peut lui prescrire des médicaments.
C’est la qu’intervient la 3ème notion du modèle RBAC. Dans cet exemple nous avons autorisé dans notre méthode initialize
la nurse à accéder au modèle patient mais nous lui avons autorisé uniquement les soins sur celui-ci.
L’accès au modèle patient est bien autorisé à notre nurse mais les autorisations qu’elle reçoit à travers les rôles ne lui permettent pas de réaliser l’ensemble des opérations.
J’espère que ce petit retour sous forme d’application du modèle RBAC vous a permis de mieux comprendre son fonctionnement et de l’importance à respecter les différentes notions qui le compose afin d’optimiser la sécurité de vos applications.
Une bonne configuration et une bonne gestion des rôles vous permettra d’éviter bien des problèmes et de gagner pas mal de temps.
L’équipe Synbioz.
Libres d’être ensemble.
Nos conseils et ressources pour vos développements produit.