mirror of
https://github.com/almet/notmyidea.git
synced 2025-04-28 19:42:37 +02:00
663 lines
No EOL
31 KiB
HTML
663 lines
No EOL
31 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<title>
|
||
Service de nuages : La gestion des permissions - Alexis Métaireau </title>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<link rel="stylesheet"
|
||
href="https://blog.notmyidea.org/theme/css/main.css?v2"
|
||
type="text/css" />
|
||
<link href="https://blog.notmyidea.org/feeds/all.atom.xml"
|
||
type="application/atom+xml"
|
||
rel="alternate"
|
||
title="Alexis Métaireau ATOM Feed" />
|
||
</head>
|
||
<body>
|
||
<div id="content">
|
||
<section id="links">
|
||
<ul>
|
||
<li>
|
||
<a class="main" href="/">Alexis Métaireau</a>
|
||
</li>
|
||
<li>
|
||
<a class=""
|
||
href="https://blog.notmyidea.org/journal/index.html">Journal</a>
|
||
</li>
|
||
<li>
|
||
<a class="selected"
|
||
href="https://blog.notmyidea.org/code/">Code, etc.</a>
|
||
</li>
|
||
<li>
|
||
<a class=""
|
||
href="https://blog.notmyidea.org/weeknotes/">Notes hebdo</a>
|
||
</li>
|
||
<li>
|
||
<a class=""
|
||
href="https://blog.notmyidea.org/lectures/">Lectures</a>
|
||
</li>
|
||
<li>
|
||
<a class=""
|
||
href="https://blog.notmyidea.org/projets.html">Projets</a>
|
||
</li>
|
||
</ul>
|
||
</section>
|
||
<header>
|
||
<h1 class="post-title">Service de nuages : La gestion des permissions</h1>
|
||
<time datetime="2015-05-01T00:00:00+02:00">01 mai 2015</time>
|
||
</header>
|
||
<article>
|
||
<p><em>Cet article est repris depuis le blog « Service de Nuages » de mon équipe à Mozilla</em></p>
|
||
<p>Dans le cadre de la création d’un service de stockage de données personnelles
|
||
(Kinto), la gestion des permissions est un des gros challenges : qui doit avoir
|
||
accès à quoi, et comment le définir ?</p>
|
||
<p><strong>tl;dr: Quelques retours sur le vocabulaire des systèmes de permission et sur nos idées pour l’implementation des permissions dans un stockage générique.</strong></p>
|
||
<div class="section" id="la-problematique">
|
||
<h2>La problématique</h2>
|
||
<p>La problématique est simple : des données sont stockées en ligne, et il
|
||
faut un moyen de pouvoir les partager avec d’autres personnes.</p>
|
||
<p>En regardant les cas d’utilisations, on se rend compte qu’on a plusieurs types
|
||
d’utilisateurs :</p>
|
||
<ul class="simple">
|
||
<li>les utilisateurs “finaux” (vous) ;</li>
|
||
<li>les applications qui interagissent en leurs noms.</li>
|
||
</ul>
|
||
<p>Tous les intervenants n’ont donc pas les mêmes droits : certains doivent
|
||
pouvoir lire, d’autres écrire, d’autres encore créer de nouveaux
|
||
enregistrements, et le contrôle doit pouvoir s’effectuer de manière fine : il
|
||
doit être possible de lire un enregistrement mais pas un autre, par exemple.</p>
|
||
<p>Nous sommes partis du constat que les solutions disponibles n’apportaient pas
|
||
une réponse satisfaisante à ces besoins.</p>
|
||
</div>
|
||
<div class="section" id="un-probleme-de-vocabulaire">
|
||
<h2>Un problème de vocabulaire</h2>
|
||
<p>Le principal problème rencontré lors des réflexions fût le vocabulaire.</p>
|
||
<p>Voici ci-dessous une explication des différents termes.</p>
|
||
<div class="section" id="le-concept-de-principal">
|
||
<h3>Le concept de « principal »</h3>
|
||
<p>Un <em>principal</em>, en sécurité informatique, est une entité qui peut être
|
||
authentifiée par un système informatique. <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a> En Français il s’agit
|
||
du « commettant », l’acteur qui commet l’action (oui, le terme est conceptuel !)</p>
|
||
<p>Il peut s’agir aussi bien d’un individu, d’un ordinateur, d’un
|
||
service ou d’un groupe regroupant l’une de ces entités, ce qui
|
||
est plus large que le classique « <em>user id</em> ».</p>
|
||
<p>Les permissions sont alors associées à ces <em>principals</em>.</p>
|
||
<p>Par exemple, un utilisateur est identifié de manière unique lors de la
|
||
connexion par le système d’authentification dont le rôle est de
|
||
définir une liste de <em>principals</em> pour l’utilisateur se connectant.</p>
|
||
<table class="docutils footnote" frame="void" id="footnote-1" rules="none">
|
||
<colgroup><col class="label" /><col /></colgroup>
|
||
<tbody valign="top">
|
||
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>Pour en savoir plus sur les <em>principals</em> :
|
||
<a class="reference external" href="https://en.wikipedia.org/wiki/Principal_%28computer_security%29">https://en.wikipedia.org/wiki/Principal_%28computer_security%29</a></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="section" id="la-difference-entre-role-et-groupe">
|
||
<h3>La différence entre rôle et groupe</h3>
|
||
<p>De but en blanc, il n’est pas évident de définir précisément la
|
||
différence entre ces deux concepts qui permettent d’associer
|
||
des permissions à un groupe de <em>principals</em>. <a class="footnote-reference" href="#footnote-2" id="footnote-reference-2">[2]</a></p>
|
||
<p>La différence est principalement sémantique. Mais on peut y voir une
|
||
différence dans la « direction » de la relation entre les deux concepts.</p>
|
||
<ul class="simple">
|
||
<li>Un rôle est une liste de permissions que l’on associe à un <em>principal</em>.</li>
|
||
<li>Un groupe est une liste de <em>principals</em> que l’on peut associer à une permission.</li>
|
||
</ul>
|
||
<table class="docutils footnote" frame="void" id="footnote-2" rules="none">
|
||
<colgroup><col class="label" /><col /></colgroup>
|
||
<tbody valign="top">
|
||
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-2">[2]</a></td><td>Plus d’informations :
|
||
<a class="reference external" href="http://stackoverflow.com/questions/7770728/group-vs-role-any-real-difference">http://stackoverflow.com/questions/7770728/group-vs-role-any-real-difference</a></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="section" id="la-difference-entre-permission-acl-ace">
|
||
<h3>La différence entre permission, <span class="caps">ACL</span>, <span class="caps">ACE</span></h3>
|
||
<blockquote class="epigraph">
|
||
<p>Une <span class="caps">ACL</span> est une liste d’Access Control Entry (<span class="caps">ACE</span>) ou entrée de contrôle d’accès
|
||
donnant ou supprimant des droits d’accès à une personne ou un groupe.</p>
|
||
<p class="attribution">—<a class="reference external" href="https://fr.wikipedia.org/wiki/Access_Control_List">https://fr.wikipedia.org/wiki/Access_Control_List</a></p>
|
||
</blockquote>
|
||
<p>Je dirais même plus, dans notre cas, « à un <em>principal</em> ». Par exemple:</p>
|
||
<div class="highlight"><pre><span></span>create_record: alexis,remy,tarek
|
||
</pre></div>
|
||
<p>Cet <span class="caps">ACE</span> donne la permission <tt class="docutils literal">create</tt> sur l’objet <tt class="docutils literal">record</tt> aux
|
||
utilisateurs Tarek, Rémy et Alexis.</p>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="la-delegation-de-permissions">
|
||
<h2>La délégation de permissions</h2>
|
||
<p>Imaginez l’exemple suivant, où un utilisateur stocke deux types de données en
|
||
ligne :</p>
|
||
<ul class="simple">
|
||
<li>des contacts ;</li>
|
||
<li>une liste de tâches à faire qu’il peut associer à ses contacts.</li>
|
||
</ul>
|
||
<p>L’utilisateur a tous les droits sur ses données.</p>
|
||
<p>Cependant il utilise deux applications qui doivent elles avoir un accès restreint :</p>
|
||
<ul class="simple">
|
||
<li>une application de gestion des contacts à qui il souhaite déléguer
|
||
la gestion intégrale de ses contacts : <tt class="docutils literal">contacts:write</tt> ;</li>
|
||
<li>une application de gestion des tâches à qui il souhaite déléguer la
|
||
gestion des tâches : <tt class="docutils literal">contacts:read tasks:write</tt></li>
|
||
</ul>
|
||
<p>Il souhaite que son application de contacts ne puisse pas accéder à
|
||
ses tâches et que son application de tâches ne puisse pas modifier ses
|
||
contacts existants, juste éventuellement en créer de nouveaux.</p>
|
||
<p>Il lui faut donc un moyen de déléguer certains de ses droits à un tiers (l’application).</p>
|
||
<p>C’est précisément le rôle des <a class="reference external" href="http://tools.ietf.org/html/rfc6749#page-23">scopes OAuth2</a>.</p>
|
||
<p>Lors de la connexion d’un utilisateur, une fenêtre lui demande quels
|
||
accès il veut donner à l’application qui va agir en son nom.</p>
|
||
<p>Le service aura ensuite accès à ces <em>scopes</em> en regardant le jeton
|
||
d’authentification utilisé. Cette information doit être
|
||
considérée comme une entrée utilisateur (c’est à dire qu’on ne peut
|
||
pas lui faire confiance). Il s’agit de ce que l’utilisateur souhaite.</p>
|
||
<p>Or, il est également possible que l’utilisateur n’ait pas accès aux données
|
||
qu’il demande. Le service doit donc utiliser deux niveaux de permissions :
|
||
celles de l’utilisateur, et celles qui ont été déléguées à l’application.</p>
|
||
</div>
|
||
<div class="section" id="espace-de-noms">
|
||
<h2>Espace de noms</h2>
|
||
<p>Dans notre implémentation initiale de <em>Kinto</em> (notre service de stockage en
|
||
construction), l’espace de nom était implicite : les données stockées étaient
|
||
nécessairement celles de l’utilisateur connecté.</p>
|
||
<p>Les données d’un utilisateur étaient donc cloisonnées et impossible à partager.</p>
|
||
<p>L’utilisation d’espaces de noms est une manière simple de gérer le partage des données.</p>
|
||
<p>Nous avons choisi de reprendre le modèle de GitHub et de Bitbucket, qui
|
||
utilisent les « organisations » comme espaces de noms.</p>
|
||
<p>Dans notre cas, il est possible de créer des “buckets”, qui correspondent à ces
|
||
espaces de noms. Un bucket est un conteneur de collections et de groupes utilisateurs.</p>
|
||
<p>Les ACLs sur ces collections peuvent être attribuées à certains groupes du
|
||
<em>bucket</em> ainsi qu’à d’autres <em>principals</em> directement.</p>
|
||
</div>
|
||
<div class="section" id="notre-proposition-d-api">
|
||
<h2>Notre proposition d’<span class="caps">API</span></h2>
|
||
<div class="section" id="les-objets-manipules">
|
||
<h3>Les objets manipulés</h3>
|
||
<p>Pour mettre en place la gestion des permissions, nous avons identifié les
|
||
objets suivants :</p>
|
||
<table border="1" class="docutils">
|
||
<colgroup>
|
||
<col width="23%" />
|
||
<col width="77%" />
|
||
</colgroup>
|
||
<thead valign="bottom">
|
||
<tr><th class="head">Objet</th>
|
||
<th class="head">Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody valign="top">
|
||
<tr><td><strong>bucket</strong></td>
|
||
<td>On peut les voir comme des espaces de noms. Ils
|
||
permettent d’avoir différentes collections portant
|
||
le même nom mais stockées dans différents <em>buckets</em> de
|
||
manière à ce que les données soient distinctes.</td>
|
||
</tr>
|
||
<tr><td><strong>collection</strong></td>
|
||
<td>Une liste d’enregistrements.</td>
|
||
</tr>
|
||
<tr><td><strong>record</strong></td>
|
||
<td>Un enregistrement d’une collection.</td>
|
||
</tr>
|
||
<tr><td><strong>group</strong></td>
|
||
<td>Un groupe de commetants (« <em>principals</em> »).</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Pour la définition des ACLs, il y a une hiérarchie et les objets « héritent » des
|
||
ACLs de leur parents :</p>
|
||
<div class="highlight"><pre><span></span> +---------------+
|
||
| Bucket |
|
||
+---------------+
|
||
+----->+ - id +<---+
|
||
| | - permissions | |
|
||
| +---------------+ |
|
||
| |
|
||
| |
|
||
| |
|
||
| |
|
||
| |
|
||
+---+-----------+ +------+---------+
|
||
| Collection | | Group |
|
||
+---------------+ +----------------+
|
||
| - id | | - id |
|
||
| - permissions | | - members |
|
||
+------+--------+ | - permissions |
|
||
^ +----------------+
|
||
|
|
||
|
|
||
+------+---------+
|
||
| Record |
|
||
+----------------+
|
||
| - id |
|
||
| - data |
|
||
| - permissions |
|
||
+----------------+
|
||
</pre></div>
|
||
</div>
|
||
<div class="section" id="les-permissions">
|
||
<h3>Les permissions</h3>
|
||
<p>Pour chacun de ces objets nous avons identifié les permissions suivantes :</p>
|
||
<table border="1" class="docutils">
|
||
<colgroup>
|
||
<col width="23%" />
|
||
<col width="77%" />
|
||
</colgroup>
|
||
<thead valign="bottom">
|
||
<tr><th class="head">Permission</th>
|
||
<th class="head">Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody valign="top">
|
||
<tr><td><strong>read</strong></td>
|
||
<td>La permission de lire le contenu de
|
||
l’objet et de ses sous-objets.</td>
|
||
</tr>
|
||
<tr><td><strong>write</strong></td>
|
||
<td>La permission de modifier et
|
||
d’administrer un objet et ses sous-
|
||
objets. La permission <em>write</em> permet la
|
||
lecture, modification et suppression
|
||
d’un objet ainsi que la gestion de ses
|
||
permissions.</td>
|
||
</tr>
|
||
<tr><td><strong>create</strong></td>
|
||
<td>La permission de créer le sous-objet
|
||
spécifié. Par exemple:
|
||
<tt class="docutils literal">collections:create</tt></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>À chaque permission spécifiée sur un objet est associée une liste de
|
||
<em>principals</em>.</p>
|
||
<p>Dans le cas de la permission <tt class="docutils literal">create</tt> on est obligé de spécifier
|
||
l’objet enfant en question car un objet peut avoir plusieurs types
|
||
d’enfants. Par exemple : <tt class="docutils literal">collections:create</tt>, <tt class="docutils literal">groups:create</tt>.</p>
|
||
<p>Nous n’avons pour l’instant pas de permission pour <cite>delete</cite> et <cite>update</cite>,
|
||
puisque nous n’avons pas trouvé de cas d’utilisation qui les nécessitent.
|
||
Quiconque avec le droit d’écriture peut donc supprimer un enregistrement.</p>
|
||
<p>Les permissions d’un objet sont héritées de son parent. Par exemple,
|
||
un enregistrement créé dans une collection accessible à tout le monde
|
||
en lecture sera lui aussi accessible à tout le monde.</p>
|
||
<p>Par conséquent, les permissions sont cumulées. Autrement dit, il n’est pas
|
||
possible qu’un objet ait des permissions plus restrictives que son parent.</p>
|
||
<p>Voici la liste exhaustive des permissions :</p>
|
||
<table border="1" class="docutils">
|
||
<colgroup>
|
||
<col width="21%" />
|
||
<col width="32%" />
|
||
<col width="47%" />
|
||
</colgroup>
|
||
<thead valign="bottom">
|
||
<tr><th class="head">Objet</th>
|
||
<th class="head">Permissions associées</th>
|
||
<th class="head">Commentaire</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody valign="top">
|
||
<tr><td>Configuration
|
||
(.ini)</td>
|
||
<td><cite>buckets:create</cite></td>
|
||
<td>Les <em>principals</em> ayant le droit
|
||
de créer un bucket sont définis
|
||
dans la configuration du serveur.
|
||
(<em>ex. utilisateurs authentifiés</em>)</td>
|
||
</tr>
|
||
<tr><td rowspan="4"><tt class="docutils literal">bucket</tt></td>
|
||
<td><cite>write</cite></td>
|
||
<td>C’est en quelque sorte le droit
|
||
d’administration du <em>bucket</em>.</td>
|
||
</tr>
|
||
<tr><td><cite>read</cite></td>
|
||
<td>C’est le droit de lire le contenu
|
||
de tous les objets du <em>bucket</em>.</td>
|
||
</tr>
|
||
<tr><td><cite>collections:create</cite></td>
|
||
<td>Permission de créer des
|
||
collections dans le <em>bucket</em>.</td>
|
||
</tr>
|
||
<tr><td><cite>groups:create</cite></td>
|
||
<td>Permission de créer des groupes
|
||
dans le <em>bucket</em>.</td>
|
||
</tr>
|
||
<tr><td rowspan="3"><tt class="docutils literal">collection</tt></td>
|
||
<td><cite>write</cite></td>
|
||
<td>Permission d’administrer tous les
|
||
objets de la collection.</td>
|
||
</tr>
|
||
<tr><td><cite>read</cite></td>
|
||
<td>Permission de consulter tous les
|
||
objets de la collection.</td>
|
||
</tr>
|
||
<tr><td><cite>records:create</cite></td>
|
||
<td>Permission de créer des nouveaux
|
||
enregistrement dans la collection.</td>
|
||
</tr>
|
||
<tr><td rowspan="2"><tt class="docutils literal">record</tt></td>
|
||
<td><cite>write</cite></td>
|
||
<td>Permission de modifier ou de
|
||
partager l’enregistrement.</td>
|
||
</tr>
|
||
<tr><td><cite>read</cite></td>
|
||
<td>Permission de consulter
|
||
l’enregistrement.</td>
|
||
</tr>
|
||
<tr><td rowspan="2"><tt class="docutils literal">group</tt></td>
|
||
<td><cite>write</cite></td>
|
||
<td>Permission d’administrer le
|
||
groupe</td>
|
||
</tr>
|
||
<tr><td><cite>read</cite></td>
|
||
<td>Permission de consulter les
|
||
membres du groupe.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="section" id="les-principals">
|
||
<h3>Les « <em>principals</em> »</h3>
|
||
<p>Les acteurs se connectant au service de stockage peuvent s’authentifier.</p>
|
||
<p>Ils reçoivent alors une liste de <em>principals</em> :</p>
|
||
<ul class="simple">
|
||
<li><tt class="docutils literal">Everyone</tt>: le <em>principal</em> donné à tous les acteurs (authentifiés ou pas) ;</li>
|
||
<li><tt class="docutils literal">Authenticated</tt>: le <em>principal</em> donné à tous les acteurs authentifiés ;</li>
|
||
<li>un <em>principal</em> identifiant l’acteur, par exemple <tt class="docutils literal">fxa:32aa95a474c984d41d395e2d0b614aa2</tt></li>
|
||
</ul>
|
||
<p>Afin d’éviter les collisions d’identifiants, le <em>principal</em> de l’acteur dépend
|
||
de son type d’authentification (<tt class="docutils literal">system</tt>, <tt class="docutils literal">basic</tt>, <tt class="docutils literal">ipaddr</tt>, <tt class="docutils literal">hawk</tt>,
|
||
<tt class="docutils literal">fxa</tt>) et de son identifiant (unique par acteur).</p>
|
||
<p>En fonction du <em>bucket</em> sur lequel se passe l’action, les groupes dont
|
||
fait partie l’utilisateur sont également ajoutés à sa liste de
|
||
<tt class="docutils literal">principals</tt>. <tt class="docutils literal">group:moderators</tt> par exemple.</p>
|
||
<p>Ainsi, si Bob se connecte avec <em>Firefox Accounts</em> sur le <em>bucket</em>
|
||
<tt class="docutils literal">servicedenuages_blog</tt> dans lequel il fait partie du groupe
|
||
<tt class="docutils literal">moderators</tt>, il aura la liste de <em>principals</em> suivante :
|
||
<tt class="docutils literal">Everyone, Authenticated, fxa:32aa95a474c984d41d395e2d0b614aa2, group:moderators</tt></p>
|
||
<p>Il est donc possible d’assigner une permission à Bob en utilisant l’un de
|
||
ces quatre <em>principals</em>.</p>
|
||
<div class="admonition note">
|
||
<p class="first admonition-title">Note</p>
|
||
<p class="last">Le <em>principal</em> <tt class="docutils literal"><userid></tt> dépend du <em>back-end</em> d’authentification (e.g.
|
||
<tt class="docutils literal">github:leplatrem</tt>).</p>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="quelques-exemples">
|
||
<h3>Quelques exemples</h3>
|
||
<p><strong>Blog</strong></p>
|
||
<table border="1" class="docutils">
|
||
<colgroup>
|
||
<col width="35%" />
|
||
<col width="18%" />
|
||
<col width="46%" />
|
||
</colgroup>
|
||
<thead valign="bottom">
|
||
<tr><th class="head">Objet</th>
|
||
<th class="head">Permissions</th>
|
||
<th class="head">Principals</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody valign="top">
|
||
<tr><td><tt class="docutils literal">bucket:blog</tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<blog</span> owner id></tt></td>
|
||
</tr>
|
||
<tr><td rowspan="2"><tt class="docutils literal">collection:articles</tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal">group:moderators</tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">read</tt></td>
|
||
<td><tt class="docutils literal">Everyone</tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">record:569e28r98889</tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<co-author</span> id></tt></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Wiki</strong></p>
|
||
<table border="1" class="docutils">
|
||
<colgroup>
|
||
<col width="35%" />
|
||
<col width="18%" />
|
||
<col width="46%" />
|
||
</colgroup>
|
||
<thead valign="bottom">
|
||
<tr><th class="head">Object</th>
|
||
<th class="head">Permissions</th>
|
||
<th class="head">Principals</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody valign="top">
|
||
<tr><td><tt class="docutils literal">bucket:wiki</tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<wiki</span> administrator id></tt></td>
|
||
</tr>
|
||
<tr><td rowspan="2"><tt class="docutils literal">collection:articles</tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal">Authenticated</tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">read</tt></td>
|
||
<td><tt class="docutils literal">Everyone</tt></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Sondages</strong></p>
|
||
<table border="1" class="docutils">
|
||
<colgroup>
|
||
<col width="34%" />
|
||
<col width="31%" />
|
||
<col width="35%" />
|
||
</colgroup>
|
||
<thead valign="bottom">
|
||
<tr><th class="head">Objet</th>
|
||
<th class="head">Permissions</th>
|
||
<th class="head">Principals</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody valign="top">
|
||
<tr><td rowspan="2"><tt class="docutils literal">bucket:poll</tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<admin</span> id></tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">collection:create</tt></td>
|
||
<td><tt class="docutils literal">Authenticated</tt></td>
|
||
</tr>
|
||
<tr><td rowspan="2"><tt class="docutils literal"><span class="pre">collection:<poll</span> id></tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<poll</span> author id></tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">record:create</tt></td>
|
||
<td><tt class="docutils literal">Everyone</tt></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Cartes colaboratives</strong></p>
|
||
<table border="1" class="docutils">
|
||
<colgroup>
|
||
<col width="34%" />
|
||
<col width="31%" />
|
||
<col width="35%" />
|
||
</colgroup>
|
||
<thead valign="bottom">
|
||
<tr><th class="head">Objet</th>
|
||
<th class="head">Permissions</th>
|
||
<th class="head">Principals</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody valign="top">
|
||
<tr><td rowspan="2"><tt class="docutils literal">bucket:maps</tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<admin</span> id></tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">collection:create</tt></td>
|
||
<td><tt class="docutils literal">Authenticated</tt></td>
|
||
</tr>
|
||
<tr><td rowspan="2"><tt class="docutils literal"><span class="pre">collection:<map</span> id></tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<map</span> author id></tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">read</tt></td>
|
||
<td><tt class="docutils literal">Everyone</tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal"><span class="pre">record:<record</span> id></tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<maintainer</span> id></tt>
|
||
(<em>ex. event staff member
|
||
maintaining venues</em>)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Plateformes</strong></p>
|
||
<p>Bien sûr, il y a plusieurs façons de modéliser les cas d’utilisation typiques.
|
||
Par exemple, on peut imaginer une plateforme de wikis (à la wikia.com), où les
|
||
wikis sont privés par défaut et certaines pages peuvent être rendues publiques :</p>
|
||
<table border="1" class="docutils">
|
||
<colgroup>
|
||
<col width="32%" />
|
||
<col width="30%" />
|
||
<col width="38%" />
|
||
</colgroup>
|
||
<thead valign="bottom">
|
||
<tr><th class="head">Objet</th>
|
||
<th class="head">Permissions</th>
|
||
<th class="head">Principals</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody valign="top">
|
||
<tr><td rowspan="3"><tt class="docutils literal">bucket:freewiki</tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<administrator</span> id></tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">collection:create</tt></td>
|
||
<td><tt class="docutils literal">Authenticated</tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">group:create</tt></td>
|
||
<td><tt class="docutils literal">Authenticated</tt></td>
|
||
</tr>
|
||
<tr><td rowspan="2"><tt class="docutils literal"><span class="pre">collection:<wiki</span> id></tt></td>
|
||
<td><tt class="docutils literal">write</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">fxa:<wiki</span> owner id></tt>,
|
||
<tt class="docutils literal"><span class="pre">group:<editors</span> id></tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal">read</tt></td>
|
||
<td><tt class="docutils literal"><span class="pre">group:<readers</span> id></tt></td>
|
||
</tr>
|
||
<tr><td><tt class="docutils literal"><span class="pre">record:<page</span> id></tt></td>
|
||
<td><tt class="docutils literal">read</tt></td>
|
||
<td><tt class="docutils literal">Everyone</tt></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="section" id="l-api-http">
|
||
<h3>L’<span class="caps">API</span> <span class="caps">HTTP</span></h3>
|
||
<p>Lors de la création d’un objet, l’utilisateur se voit
|
||
attribué la permission <tt class="docutils literal">write</tt> sur l’objet :</p>
|
||
<div class="highlight"><pre><span></span><span class="nf">PUT</span> <span class="nn">/v1/buckets/servicedenuages_blog</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
|
||
<span class="na">Authorization</span><span class="o">:</span> <span class="l">Bearer 0b9c2625dc21ef05f6ad4ddf47c5f203837aa32ca42fced54c2625dc21efac32</span>
|
||
<span class="na">Accept</span><span class="o">:</span> <span class="l">application/json</span>
|
||
|
||
HTTP/1.1 201 Created
|
||
Content-Type: application/json; charset=utf-8
|
||
|
||
{
|
||
"id": "servicedenuages_blog",
|
||
"permissions": {
|
||
"write": ["fxa:49d02d55ad10973b7b9d0dc9eba7fdf0"]
|
||
}
|
||
}
|
||
</pre></div>
|
||
<p>Il est possible d’ajouter des permissions à l’aide de <tt class="docutils literal"><span class="caps">PATCH</span></tt> :</p>
|
||
<div class="highlight"><pre><span></span><span class="nf">PATCH</span> <span class="nn">/v1/buckets/servicedenuages_blog/collections/articles</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
|
||
<span class="na">Authorization</span><span class="o">:</span> <span class="l">Bearer 0b9c2625dc21ef05f6ad4ddf47c5f203837aa32ca42fced54c2625dc21efac32</span>
|
||
<span class="na">Accept</span><span class="o">:</span> <span class="l">application/json</span>
|
||
|
||
{
|
||
"permissions": {
|
||
"read": ["+system.Everyone"]
|
||
}
|
||
}
|
||
|
||
HTTP/1.1 201 Created
|
||
Content-Type: application/json; charset=utf-8
|
||
|
||
{
|
||
"id": "servicedenuages_blog",
|
||
"permissions": {
|
||
"write": ["fxa:49d02d55ad10973b7b9d0dc9eba7fdf0"],
|
||
"read": ["system.Everyone"]
|
||
}
|
||
}
|
||
</pre></div>
|
||
<p>Pour le <tt class="docutils literal"><span class="caps">PATCH</span></tt> nous utilisons la syntaxe préfixée par un <tt class="docutils literal">+</tt> ou
|
||
par un <tt class="docutils literal">-</tt> pour ajouter ou enlever des <em>principals</em> sur un <span class="caps">ACL</span>.</p>
|
||
<p>Il est également possible de faire un <tt class="docutils literal"><span class="caps">PUT</span></tt> pour réinitialiser les ACLs,
|
||
sachant que le <tt class="docutils literal"><span class="caps">PUT</span></tt> va ajouter l’utilisateur courant à la
|
||
liste automatiquement mais qu’il pourra se retirer avec un <tt class="docutils literal"><span class="caps">PATCH</span></tt>.
|
||
Ajouter l’utilisateur courant permet d’éviter les situations où plus
|
||
personne n’a accès aux données.</p>
|
||
<div class="admonition note">
|
||
<p class="first admonition-title">Note</p>
|
||
<p class="last">La permission <tt class="docutils literal">create</tt> est valable pour <tt class="docutils literal"><span class="caps">POST</span></tt> mais aussi pour <tt class="docutils literal"><span class="caps">PUT</span></tt>
|
||
lorsque l’enregistrement n’existe pas.</p>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="le-cas-specifique-des-donnees-utilisateurs">
|
||
<h3>Le cas spécifique des données utilisateurs</h3>
|
||
<p>Une des fonctionnalités actuelles de <em>Kinto</em> est de pouvoir gérer des
|
||
collections d’enregistrements par utilisateur.</p>
|
||
<p>Sous <em>*nix</em> il est possible, pour une
|
||
application, de sauvegarder la configuration de l’utilisateur courant
|
||
dans son dossier personnel sans se soucier de l’emplacement sur
|
||
le disque en utilisant <tt class="docutils literal">~/</tt>.</p>
|
||
<p>Dans notre cas si une application souhaite sauvegarder les contacts d’un
|
||
utilisateur, elle peut utiliser le raccourci <tt class="docutils literal">~</tt> pour faire référence au
|
||
<em>bucket</em> <strong>personnel</strong> de l’utilisateur : <tt class="docutils literal"><span class="pre">/buckets/~/collections/contacts</span></tt></p>
|
||
<p>Cette <span class="caps">URL</span> retournera le code <tt class="docutils literal"><span class="caps">HTTP</span> 307</tt> vers le <em>bucket</em> de l’utilisateur courant :</p>
|
||
<div class="highlight"><pre><span></span><span class="nf">POST</span> <span class="nn">/v1/buckets/~/collections/contacts/records</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
|
||
|
||
{
|
||
"name": "Rémy",
|
||
"emails": ["remy@example.com"],
|
||
"phones": ["+330820800800"]
|
||
}
|
||
|
||
HTTP/1.1 307 Temporary Redirect
|
||
Location: /v1/buckets/fxa:49d02d55ad10973b7b9d0dc9eba7fdf0/collections/contacts/records
|
||
</pre></div>
|
||
<p>Ainsi il est tout à fait possible à Alice de partager ses contacts
|
||
avec Bob. Il lui suffit pour cela de donner la permission <tt class="docutils literal">read</tt> à
|
||
Bob sur sa collection et de donner l’<span class="caps">URL</span> complète
|
||
<tt class="docutils literal">/v1/buckets/fxa:49d02d55ad10973b7b9d0dc9eba7fdf0/collections/contacts/records</tt>
|
||
à Bob.</p>
|
||
</div>
|
||
<div class="section" id="la-delegation-des-permissions">
|
||
<h3>La délégation des permissions</h3>
|
||
<p>Dans le cas de <em>Kinto</em>, nous avons défini un format pour restreindre les
|
||
permissions via les scopes OAuth2:
|
||
<tt class="docutils literal"><span class="pre">storage:<bucket_id>:<collection_id>:<permissions_list></span></tt>.</p>
|
||
<p>Ainsi, si on reprend l’exemple précédent de la liste de tâches, il est possible pour
|
||
Bob de créer un token OAuth spécifique avec les <em>scopes</em> suivants :
|
||
<tt class="docutils literal">profile storage:todolist:tasks:write <span class="pre">storage:~:contacts:read+records:create</span></tt></p>
|
||
<p>Donc, bien que Bob a la permission <tt class="docutils literal">write</tt> sur ses contacts,
|
||
l’application utilisant ce token pourra uniquement lire les contacts
|
||
existants et en ajouter de nouveaux.</p>
|
||
<p>Une partie de la complexité est donc de réussir à présenter ces <em>scopes</em> de
|
||
manière lisible à l’utilisateur, afin qu’il choisisse quelles permissions
|
||
donner aux applications qui agissent en son nom.</p>
|
||
<p>Voilà où nous en sommes de notre réflexion !</p>
|
||
<p>Si vous avez des choses à ajouter, des points de désaccord ou autres
|
||
réflexions, n’hésitez pas à nous interrompre pendant qu’il est encore temps !</p>
|
||
</div>
|
||
</div>
|
||
|
||
</article>
|
||
<footer>
|
||
<a id="feed" href="/feeds/all.atom.xml">
|
||
<img alt="RSS Logo" src="/theme/rss.svg" />
|
||
</a>
|
||
</footer>
|
||
</div>
|
||
</body>
|
||
</html> |