Résumé

  • Le serveur crée un jeton unique pour chaque verrou WebDAV. Sa présence dans l’en-tête If prouve la soumission de cette valeur, non l’identité de l’émetteur, son privilège d’écriture ou la survie du verrou.
  • Une modification exige plusieurs décisions indépendantes : authentifier le principal, autoriser la méthode, déterminer toutes les ressources touchées, vérifier les verrous et les conditions, rattacher le principal au créateur du verrou ou à une dérogation, puis valider l’état au moment de l’écriture.
  • Les verrous partagés, les collections de profondeur infinie, COPY/MOVE et les délais choisis par le serveur interdisent de traiter le jeton comme un bail portable. Il s’agit d’une preuve de coordination limitée.

Le mauvais raccourci naît dans les journaux

Une équipe examine un PUT refusé. Le journal de la passerelle contient le jeton attendu. La console WebDAV indique qu’un verrou portait ce même identifiant. La conclusion paraît immédiate : le serveur a rejeté à tort le titulaire du verrou.

Trois informations manquent pourtant. Quel principal a été authentifié pour le PUT ? Ce principal possédait-il encore le privilège nécessaire ? Le verrou couvrait-il exactement toutes les ressources que la méthode allait modifier ?

RFC 4918 sépare ces questions. Lorsqu’une ressource verrouillée est modifiée, le serveur doit vérifier que le principal authentifié correspond au créateur du verrou, en plus de vérifier la soumission d’un jeton valide. Le verrou n’accorde pas, à lui seul, tous les privilèges de modification. Un utilisateur peut donc connaître le bon jeton et recevoir légitimement un refus.

Cette séparation n’est pas une complication administrative ajoutée autour du protocole. Elle empêche un identifiant de coordination de devenir un titre au porteur. Sans elle, un jeton copié depuis un rapport de propriétés, une trace ou un ancien processus suffirait à exercer un pouvoir que le système d’identité n’a jamais accordé.

Ce que le jeton affirme vraiment

WebDAV complète HTTP pour l’édition distante, les propriétés, les collections, les opérations d’espace de noms et la prévention de collisions. Le verrou sert notamment à limiter la perte de mises à jour lorsque plusieurs auteurs travaillent sur une même ressource.

Chaque verrou possède exactement un jeton unique, généré par le serveur. Le client ne doit pas en interpréter la structure. La norme impose l’unicité des URI de jeton à travers les ressources et dans le temps, afin qu’une valeur ne puisse être confondue avec un autre verrou. Une création réussie renvoie la valeur dans l’en-tête de réponse Lock-Token et dans le corps de la réponse.

L’unicité répond à la question « quel verrou ? ». Elle ne répond pas à « qui ? » ni à « avec quel droit ? ». Le serveur peut publier les verrous actifs dans la propriété DAV:lockdiscovery. La sécurité ne peut donc pas reposer sur l’idée que personne d’autre ne verra le jeton.

RFC 4918 conseille les URN UUID, mais accepte toute URI unique et conserve le schéma permanent opaquelocktoken. RFC 9562 recommande un générateur pseudo-aléatoire cryptographiquement sûr lorsque l’imprévisibilité est recherchée. Cela améliore la résistance à la devinette. Cela ne transforme pas l’UUID en décision d’accès.

Il faut conserver six plans distincts :

  • l’unicité distingue deux verrous ;
  • l’imprévisibilité réduit la découverte opportuniste ;
  • la possession montre la connaissance d’une valeur ;
  • l’authentification rattache la requête à un principal ;
  • l’autorisation décide ce que ce principal peut faire ;
  • l’exécution décide si l’état courant permet encore l’opération.

Le jeton ne peut pas absorber les trois derniers plans sans casser le modèle de sécurité.

Le créateur du verrou n’est pas propriétaire de la ressource

Le créateur bénéficie d’un rapport spécial avec le verrou, pas d’un droit général sur la ressource. Il peut l’utiliser pour coordonner une modification si ses privilèges ordinaires l’autorisent encore. Le serveur peut aussi permettre à un administrateur ou à un autre principal privilégié de détruire un verrou abandonné.

RFC 3744 rend la division concrète. DAV:write-content contrôle la modification du contenu existant. DAV:write-properties contrôle certaines propriétés. DAV:bind intervient pour l’appartenance à une collection, notamment lorsqu’un PUT crée une nouvelle ressource. DAV:unlock autorise un principal autre que le propriétaire du verrou à employer UNLOCK.

Un privilège d’écriture n’annule donc pas les contraintes du verrou. Inversement, le jeton ne contourne pas la liste de contrôle d’accès. Une dérogation administrative doit être reconnue comme telle, attribuée et auditée, plutôt que déguisée en possession ordinaire.

La doctrine de Heng Lu sur la différence entre registre et autorité éclaire ce choix. Un enregistrement peut décrire fidèlement une situation sans devenir la source souveraine de tous les droits. Le jeton désigne un état de coordination créé par le serveur ; il n’est pas la propriété de la ressource et ne commande pas le serveur.

Dans If, soumettre n’est pas seulement évaluer

L’en-tête WebDAV If porte deux fonctions qu’un intermédiaire ne doit pas réduire à un seul booléen.

Il exprime d’abord des conditions sur les jetons d’état et les étiquettes d’entité. Les conditions d’une même liste sont conjointes. Plusieurs listes sont des alternatives. Not inverse la condition qui suit. Une liste non étiquetée vise l’URI de la requête ; une liste étiquetée vise la ressource explicitement nommée.

Mais If sert aussi à soumettre les jetons de verrou. La présence d’un jeton dans l’en-tête indique au serveur que le client le connaît. Cette soumission ne disparaît pas parce qu’une autre liste alternative a produit la valeur vraie. L’optimisation qui ne transmettrait que la « branche gagnante » détruirait donc une partie de la sémantique WebDAV.

Les codes d’erreur permettent de voir la séparation. Si la condition If est fausse, le serveur renvoie 412 Precondition Failed, après les contrôles d’autorisation. Si une ressource touchée est verrouillée et que le jeton requis n’a pas été soumis, 423 Locked accompagné de la précondition lock-token-submitted décrit le manque. L’un concerne la vérité de la condition ; l’autre, la présence d’une preuve de verrou requise.

L’en-tête Lock-Token est plus spécialisé que son nom pourrait le laisser croire. Il renvoie le nouveau jeton dans une réponse LOCK et identifie le verrou à supprimer dans une requête UNLOCK. Pour les autres méthodes modificatrices, les jetons sont portés dans If.

La portée se calcule avant de décider

Un verrou possède une racine, une portée, un type et une profondeur. Un verrou direct commence à son URL racine. Un verrou de profondeur infinie posé sur une collection s’applique indirectement à ses descendants, y compris aux membres ajoutés plus tard.

Le client qui modifie /dossiers/a/note peut donc être soumis à un verrou créé sur /dossiers/. La valeur correcte n’est pas nécessairement celle que l’interface a associée à la seule note. Le serveur doit construire l’ensemble des verrous applicables à l’état actuel de l’espace de noms.

Pour LOCK, la profondeur vaut zéro ou infini et, en l’absence d’indication, infini. Si un descendant empêche le verrouillage d’une hiérarchie, le serveur ne doit pas laisser un demi-arbre verrouillé. L’opération est atomique dans sa portée, et Multi-Status peut indiquer l’élément bloquant.

COPY, MOVE et DELETE élargissent encore l’ensemble touché. Une méthode peut modifier la source, la destination, une collection parente et une ressource écrasée. Tous les jetons nécessaires doivent être soumis. Une passerelle qui ne regarde que la Request-URI approuve parfois une opération que le dépôt doit refuser.

MOVE montre pourquoi le jeton n’est pas un bail attaché au contenu. Un verrou direct ne suit pas la ressource vers sa nouvelle URL. La ressource peut sortir du champ d’un verrou indirect à la source et entrer dans celui d’un verrou de collection à la destination. La signification du jeton dépend de la topologie présente, non d’une essence durable du document.

Plusieurs verrous partagés restent plusieurs verrous

Un verrou partagé autorise d’autres verrous partagés compatibles. Chaque requête réussie crée néanmoins son propre verrou et son propre jeton. Trois collaborateurs ne se transmettent pas un mot de passe de groupe ; ils disposent de trois relations de coordination distinctes.

Rafraîchir l’une ne prolonge pas les deux autres. UNLOCK retire le verrou désigné, sans prouver que la ressource est désormais libre. Un autre verrou partagé ou un verrou indirect peut rester applicable.

L’application doit donc définir ce que « travailler ensemble » signifie : fusion, tour de rôle, validation éditoriale, arbitrage. WebDAV décrit la compatibilité des verrous et la soumission des jetons. Il ne crée pas une procédure de décision collective.

Une interface sérieuse affiche les créateurs, les racines, les profondeurs, les échéances et les relations directes ou indirectes. Le voyant unique « verrouillé » perd précisément l’information requise lors d’un conflit.

Le délai appartient finalement au serveur

Le client peut demander une durée dans Timeout, mais le serveur choisit la valeur effectivement accordée. Il peut ignorer la demande ou la modifier. Le temps restant est donc un état annoncé, non une promesse de bail conclue par le client.

Le rafraîchissement emploie une requête LOCK sans corps et un seul jeton dans If. Le serveur ignore Depth, redémarre le compteur en cas de succès, ne modifie pas les autres verrous partagés et renvoie la nouvelle valeur de DAV:lockdiscovery. Il ne renvoie pas un nouveau Lock-Token.

Un échec de rafraîchissement ne doit jamais être interprété comme un succès. Symétriquement, le client ne peut pas garantir la survie du verrou jusqu’à l’échéance calculée : une dérogation, une panne ou une perte d’état peut l’avoir supprimé. Il ne doit pas davantage affirmer que la suppression a eu lieu exactement à l’instant où son horloge locale atteint zéro.

La décision fiable se prend à nouveau au moment de la modification : soumettre le jeton, vérifier l’état du serveur et confronter la version de la ressource. Les délais servent au nettoyage et au renouvellement ; ils ne remplacent pas le contrôle de concurrence au commit.

Une chaîne d’écriture que l’on peut auditer

Une implémentation défendable expose chaque étape :

  1. authentifier le principal ;
  2. autoriser la méthode et la nature de la modification ;
  3. résoudre la source, la destination et toutes les ressources touchées ;
  4. découvrir les verrous directs, indirects, exclusifs et partagés ;
  5. analyser intégralement les listes If, les ETag et les négations ;
  6. établir quels jetons requis ont été soumis ;
  7. rattacher le principal au créateur ou à une dérogation explicite ;
  8. revérifier l’état et exécuter atomiquement selon la méthode ;
  9. conserver un dossier permettant de distinguer refus de privilège, condition fausse, jeton manquant, verrou disparu et conflit multi-ressource.

Le journal peut stocker une empreinte liée du jeton plutôt que sa valeur brute. Il doit conserver le principal, la méthode, l’ensemble touché, les racines et profondeurs de verrou, la décision d’autorisation, le délai réellement accordé, la version finale et le code de réponse.

Les tests doivent croiser ces portes : bon jeton avec mauvais principal ; bon privilège sans jeton ; jeton présent avec ETag faux ; déplacement vers une destination verrouillée ; verrou de collection appliqué à un nouveau membre ; échec de verrouillage hiérarchique sans état partiel ; rafraîchissement d’un seul verrou partagé ; suppression administrative attribuée ; écriture par un canal alternatif.

Le modèle ne prétend pas arrêter un accès direct au stockage, résoudre un interblocage métier ou fusionner deux modifications sémantiquement incompatibles. Il crée une coordination minimale, explicite et testable. Sa force vient de ce périmètre étroit.

Sources