Servir et gérer des fichiers avec WebDav

Posted on lun. 09 décembre 2013 in web

J’ai récement eu besoin de pouvoir stocker des fichiers en ligne. Je voulais un minimum d’authentification, quelque chose qui soit standard, pas de client lourd etc, etc. Bref, après m’être renseigné à minima j’ai décidé de tenter ma chance avec WebDav en l’occurence puisque je fais tourner ça avec apache).

Les caractéristiques voulues :

  • accès en HTTP et HTTPs
  • un dossier /public/ accessible en lecture par tous (HTTP et HTTPs)
  • redirection de HTTP vers HTTPs sinon
  • authentification via BasicAuth
  • tous les utilisateurs peuvent écrire dans /public/
  • chaque utilisateurs ne peut écrire sur dans l’URI /<utilisateur>/

Maintenant la conf et les explications :

  • La conf du VirtualHost pour l’accès en HTTP :
<VirtualHost *:80>
    ServerName my.server.tld
    DocumentRoot /$document_root/

    <Directory /$document_root/public/>
        Options -Indexes
    </Directory>
    <Directory /$document_root/public/*/>
        Options +Indexes
    </Directory>

    RewriteEngine On
    # Cette RewriteCond vérifie que l'URI de la requête concerne le notre
    # dossier /public/ (ou les images qui servent à l'affichage des indexes
    # chez apache). La RewriteCond ne s'applique que pour la RewriteRule
    # suivante.
    RewriteCond %{REQUEST_URI} ^/(public/(?|.*)|icons/(?|.*)|favicon\.ico|robots\.txt|$)$
    RewriteRule ^.* - [L]

    # Cette dernière RewriteRule s'assure que tous ce qui n'a pas matché
    # plus haut est redirigé vers le même domaine en HTTPs
    RewriteRule ^/?(.*) https://%{HTTP_HOST}/$1 [QSA,L,R=301]

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log vhost_combined
    LogLevel warn
</VirtualHost>
  • La conf du VirtualHost pour l’accès en HTTPs :
<VirtualHost *:443>
    ServerName my.server.tld
    SSLEngine on

    DocumentRoot /$document_root/

    DavLockDB /run/lock/apache_dav
    DAVMinTimeout 600

    # On empêche les robots des snifer le roots où il y a
    # la liste des users (leurs dossiers perso en fait)
    <Directory /$document_root/>
        Options -Indexes
        Dav On
    </Directory>

    # On définit qu'une authentification est nécessaire pour
    # accéder à n'importe quel dossier.
    <Directory /$document_root/*/>
        Options +Indexes +FollowSymLinks +MultiViews
        AllowOverride None

        Order allow,deny
        Allow from all
        Dav On

        AuthType Basic
        AuthName "My Server WebDav"
        AuthUserFile /path/to/htpasswd
        Require valid-user
    </Directory>

    # On est pas trop méchant et on laisse
    # quand même les robots accéder à leurs conf
    <Files /$document_root/robots.txt>
        Order Allow,Deny
        Allow from all
        Satisfy any
        Require all granted
    </Files>

    # On surcharge la précédente définition pour le dossier /public/.
    <Directory /$document_root/public/>
        Options -Indexes +FollowSymLinks +MultiViews
        AllowOverride None

        Order Allow,Deny
        Allow from all
        Dav On

        <LimitExcept GET OPTIONS>
            AuthType Basic
            AuthName "My Server WebDav"
            AuthUserFile /path/to/htpasswd
            Require valid-user
        </LimitExcept>
    </Directory>
    # On autorise les indexes sur les dossiers contenu dans /public/
    # même si ils ne sont pas autorisés dans ce dernier
    <Directory /$document_root/public/*/>
        Options +Indexes
    </Directory>

    RewriteEngine On
    # On autorise l'accès au robot.txt sans redirection aucune
    RewriteCond %{REQUEST_URI} ^/robots.txt$
    RewriteRule ^/?(.*) http://%{HTTP_HOST}/robots.txt [QSA,L,R=301]

    # Comme précédemment, on ne touche à rien si
    # l'URI de la requête concerne le dossier /public/.
    RewriteCond %{REQUEST_URI} ^/(public/(?|.*)|icons/(?|.*)|favicon\.ico)$
    RewriteRule ^.* - [L]

    # La règle qui empêche un utilisateur d'accéder
    # à un dossier qui n'est pas à eux.
    RewriteCond %{LA-U:REMOTE_USER} ^(.+)
    RewriteCond %1:/$1 !^([^:]+):/\1$
    RewriteRule ^/([^/]*) - [F,L]

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log vhost_combined
    LogLevel warn
</VirtualHost>

Les dernières RewriteCond sont utilisées pour s’assurer que chaque utilisateur n’accèdera qu’à son dossier utilisent LA-U:. Ce préfix est décrit dans la documentation de mod_rewrite.

L’idée derrière cette subtilité est que les règles de réécriture sont exécutées avant que l’authentification n’ait lieu. La variable REMOTE_USER, elle, définie lors de l’authentification, n’est pas disponible pour la comparaison avec l’URI de la requête. LA-U: permet de prefetch cette valeur. La dernière condition de réécriture véréfie que cette valeur correspond bien au début de l’URI de la requête.

La syntaxe de la condition de réécriture est assez compliquée (et honteusement copiée de cet article). Elle doit sa structure au fait que apache ne permet pas à une valeur d’être à droite de la comparaison du RewriteCond.