Conf nginx sous-dossier?

Bonjour,

Je suis en train d’essayer d’installer https://github.com/wheelybird/ldap-user-manager sans docker, avec nginx comme serveur web et derrière un reverse proxy nginx.

Installation sans docker : OK
Installation derrière un reverse proxy nginx avec certificat let’sencrypt : a priori OK
Installation avec serveur web nginx dans debian buster : OK à la racine d’un domaine avec le fichier de conf suivant

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html/ldap-user-manager;

        index index.html index.php index.htm index.nginx-debian.html;

        server_name _;

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
	}

	location ~ \.php$ {
		include snippets/fastcgi-php.conf;
		fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
		fastcgi_param SCRIPT_FILENAME $request_filename;
		include /etc/nginx/lum.nginx.conf;
        }
        
        location ~ /\.ht {
                deny all;
        }
}

Si je vais sur https://URL.FR, ldap-user-manager semble fonctionner. Je peux aller sur https://URL.FR/setup, entrer mon mot de passe et être bien renvoyé vers https://URL.FR/setup/run_checks.php

Ce que j’aimerais faire pour des raisons de sécurité (si c’est absurde vous pouvez me le dire aussi) c’est de modifier ce fichier de conf nginx de tel façon que root soit ainsi

        root /var/www/html;

mon idée étant que si un robot se rend sur la racine du nom de domaine https://URL.FR, il tombe sur le contenu de index.nginx-debian.html sans indication qu’il existe autre chose mais je veux pouvoir aller sur https://URL.FR/ldap-user-manager y trouver mon application et pouvoir l’utiliser.
J’ai bien essayé de bidouiller mon fichier de conf nginx mais sans véritable succès. Par exemple, avec

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        index index.html index.php index.htm index.nginx-debian.html;

        server_name _;

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
	}
	
	location ~ \.php$ {
        	include snippets/fastcgi-php.conf;
        	fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
	}
	
    location  /ldap-user-manager {
        	alias /var/www/html/ldap-user-manager;
                
        	location ~ /\.ht {
                	deny all;
        	}

        	location ~ \.php$ {
                	include snippets/fastcgi-php.conf;
                	fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
                	fastcgi_param SCRIPT_FILENAME $request_filename;
                	include /etc/nginx/lum.nginx.conf;
        	}
	}        
}

https://URL.FR m’affiche bien le contenu de index.nginx-debian.html, je peux aller sur https://URL.FR/ldap-user-manager/setup et entrer mon mot de passe mais je ne suis pas renvoyé vers https://URL.FR/ldap-user-manager/setup/run_checks.php comme souhaité mais vers https://URL.FR/setup/run_checks.php qui évidement m’offre une belle page 404.

Comment faire pour dire à nginx que quand il est dans https://URL.FR/ldap-user-manager/, il doit toujours rester dans https://URL.FR/ldap-user-manager/ et jamais retourner à https://URL.FR/ ?

Dès que j’arrive à résoudre ça, je teste un peu le logiciel et je proposerais un script d’installation au mainteneur du logiciel.

Merci par avance pour votre aide.

Si ça aide, voici la conf nginx du reverse proxy :

server {
    location / {
        include proxy_params;
        proxy_pass http://xxx.xxx.xxx.xxx;
    }
    server_name URL.FR;

    listen [::]:443 ssl; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/caserne.atossa.fr/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/caserne.atossa.fr/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
    if ($host = URL.FR) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    server_name URL.FR;    listen [::]:80;
    listen 80;
    return 404; # managed by Certbot
}

J’ai essayé avec cette config mais sans succès

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        index index.html index.php index.htm index.nginx-debian.html;

        server_name _;

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
        }

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
        }

        location  /ldap-user-manager {
                alias /var/www/html/ldap-user-manager;
                try_files $uri $uri/ @lum;

                location ~ /\.ht {
                        deny all;
                }

                location ~ \.php$ {
                        include snippets/fastcgi-php.conf;
                        fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
                        fastcgi_param SCRIPT_FILENAME $request_filename;
                        include /etc/nginx/lum.nginx.conf;
                }
        }
    location @lum {
        rewrite /ldap-user-manager/(.*)$ /ldap-user-manager/index.php?/$1 last;
    }

}

J’ai l’impression que c’est parce qu’il redirige de cette façon :

header("Location: //${_SERVER["HTTP_HOST"]}/${THIS_MODULE_PATH}/run_checks.php\n\n");

peut-être que ce n’est pas dans nginx la modif à faire en plus mais dans un fichier de conf de ldap-user-manager en fait…

ah ben si, on dirait bien que c’est ça.
Si je modifie

$THIS_MODULE_PATH=end($paths);
en
$THIS_MODULE_PATH=« ldap-user-manager/ ».end($paths);

dans ldap-user-manager/includes/web_functions.inc.php

Je retrouve le bon fonctionnement. Je vais creuser un peu avant de crier victoire.

:thinking: :cold_sweat:

ça fonctionne pas encore comme il faudrait…
Ca ne sert à rien que je touche à $THIS_MODULE_PATH=end($paths);

En effet, sans aller plus loin que le bouton log in du menu, ça bloque puisque lui redirige vers

header(« Location: // » . $_SERVER[« HTTP_HOST »] . « /log_in/index.php?$reason&redirect_to= » . base64_encode($_SERVER[‹ REQUEST_URI ›]) . « \n\n »);

donc la solution que j’entrevoie mais je ne sais pas si c’est possible, est de dire à nginx que quand un utilisateur est dans /ldap-user-manager , alors
$_SERVER[« HTTP_HOST »] = $_SERVER[« HTTP_HOST »] + /ldap-user-manager

Est-ce possible? Comment faire?

En fait on peut raisonner sur le code PHP suivant pour simplifier, puisque c’est ce que semble faire ton code PHP :

<?php
header("Location: https://chatons.org");

Ce dernier va créer une redirection HTTP temporaire (code 302 Found) en HTTP.
Donc potentiellement, ce que tu veux capturer, ce sont ces redirections 302 Found pour les faire réécrire par NGINX avant de les transmettre à ton client. Avec ça, tu peux commencer à faire des recherches sur Internet, par exemple ce fil Stack Overflow semble faire la même chose que toi, et donc ce serait l’instruction proxy-redirect que tu cherches. Tu aurais probablement une directive comme ça (pas testé) :

proxy_redirect https://URL.FR/ /ldap-user-manager;

Après pas sûr que ça marche avec fastcgi. À voir si un équivalent existe.

Bon, maintenant, c’est une très mauvaise idée ce que tu essayes de faire. Pour deux raisons :

  • Parce que tu complexifies ton système et que c’est du bidouillage : ton app a pas été conçue pour avoir un préfix d’URL et probablement que plein d’autres trucs vont casser (par exemple, si elle envoie des emails, les liens dans l’email seront faux).
  • Parce que tu essayes de faire de la sécurité par l’obscurité. Pas sûr que la complexité que tu ajoutes, et donc les risques de sécurité, soit compensée par un préfixe d’URL.

Ce que je te conseille :

  • Si tu veux vraiment avoir une préfixe d’URL, profite que ton projet PHP soit open source, patche le ! Et peut-être même propose ton patch au dév et apporte ta pierre à l’édifice ! Ce sera beaucoup mieux !
  • Si tu veux limiter les gens qui accèdent à ton interface, tu peux filtrer facilement par IP, mettre une HTTP basic auth, faire de l’auth TLS des clients, bind ton service que sur 127.0.0.1 et y accéder à travers un tunnel SSH, faire du rate limiting, filtrer sur le user agent, et bien encore. Tout ça c’est de la défense en profondeur mais ça ne compense pas le besoin d’avoir un mot de passe fort et un logiciel sûr.

Et sinon instant auto promo, on a dev notre explorateur LDAP (guichet) et notre serveur LDAP (bottin). Peut-être que ça pourrait t’intéresser :slight_smile:

Bon courage pour la suite :smiley:

1 « J'aime »

Est-ce que bottin (sympa le nom) prend en charge memberof?
Est-ce qu’il est possible d’avoir des imprim’écran de guichet pour voir à quoi il ressemble?

J’ai commencé à patcher le projet Ldap User Management comme je l’explique ici https://github.com/wheelybird/ldap-user-manager/issues/92
mais je me dis que si je commence comme ça, je ne sais pas jusqu’où ça va me mener et je n’ai pas prévu d’investir autant de temps dans ce projet précis.

Je voulais juste pouvoir gérer des utilisateurs et groupe facilement depuis le web (pas avec un client lourd type apache directory) ni par ssh ni VPN car si moi j’ai ça en place chez moi, mes collègues ne savent pas ce que ça veut dire.
Je me disais qu’accéder à https://url.fr/quelquechose, c’était simple à expliquer à tous mes collègues.

Je ne cherche pas à faire de la sécurité par obscurité absolument mais je ne vois pas pourquoi les robots devraient tomber sur une demande d’authentification à la racine du nom de domaine. Pourquoi ne pas les laisser passer leur chemin et avoir ma web app accessible dans un sous-dossier. J’ai bien compris que Ldap User Management n’avait pas été conçu avec cette possibilité en tête, c’est dommage. Tant pis.

Est-ce que guichet peut fonctionner dans un sous-dossier nativement?
Guichet fonctionne avec quel serveur web apache ou nginx?
Est-ce qu’il peut fonctionner dans un container accessible en http derrière un reverse proxy nginx qui lui est accessible en https?

Est-ce que bottin (sympa le nom) prend en charge memberof?

Oui, il prend en charge l’extension memberof nativement mais c’est la seule extension qu’il supporte.
Par contre, il faut savoir que pour l’instant bottin ne sait pas stocker les données directement sur ton disque dur, il utilise Consul comme « base de données ». C’est d’ailleurs sa raison d’être : être un serveur LDAP distribué simple.

Est-ce qu’il est possible d’avoir des imprim’écran de guichet pour voir à quoi il ressemble?

Oui bien sûr, on planifie de faire une doc tout comme il faut un jour mais le temps…

Là tu as la page d’accueil une fois connecté. Les gens qui sont pas administrateurs ont pas accès au bloc Administration, évidemment :

Capture d’écran de 2021-05-15 10-50-09

Si tu cliques sur Explorateur LDAP, dans Administration, tu as ça :

Capture d’écran de 2021-05-15 09-09-56

L’édition d’une entrée :

Capture d’écran de 2021-05-15 10-52-59

Je ne t’ai pas fait pas de capture des fonctionnalités utilisateur (editer mon profil, editer mon mot de passe, inviter quelqu’un) car elles sont très basiques. Si ça manque, je pourrai rajouter.

Je ne cherche pas à faire de la sécurité par obscurité absolument mais je ne vois pas pourquoi les robots devraient tomber sur une demande d’authentification à la racine du nom de domaine.

Tu peux mettre un robots.txt si tu veux aussi pour leur dire de passer leur chemin. En fait si tu leak pas le (sous) domaine, les robots ne pourront pas le deviner. Si tu le leak, alors tu vas probablement leaker aussi le bout d’URL pour la connexion. Aussi tu peux mettre sur un port différent, par exemple :4443.

Est-ce que guichet peut fonctionner dans un sous-dossier nativement?

J’ai regardé rapidement, et plutôt non. On a une option web_address pour les emails, donc en mettant bien ton prefixe, les URLs seront bonnes. Il faudra réécrire les URL pour le backend, mais ça tu as déjà fait. Restera encore les redirections, ceci dit guichet se configure avec proxy_pass et non fastcgi, du coup tu pourrais utiliser proxy_redirect.

Guichet fonctionne avec quel serveur web apache ou nginx?

Guichet fonctionne avec n’importe quel logiciel qui sait faire du reverse proxy, soit Apache, Nginx, Caddy, Traefik, Fabio, etc. etc.

Est-ce qu’il peut fonctionner dans un container accessible en http derrière un reverse proxy nginx qui lui est accessible en https?

Oui c’est même plutôt l’idée. Nous il tourne en HTTP dans un conteneur Docker derrière un reverse proxy Traefik qui fait du HTTPS via Let’s Encrypt.

1 « J'aime »

Comme c’est beau, je crois que je vais adopter votre guichet de bottin. En plus c’est local :slight_smile:
Merci pour vos efforts. :+1:
LDAP + memberof c’est tout ce dont on a besoin avec nextcloud and co…

J’ai quand même fait une mise à jour de mon script d’install pour LUM qui fonctionne pas trop mal
https://github.com/Thatoo/ldap-user-manager/blob/master/install-debian-nginx.sh

Il y a juste cette ligne de code
print "<a href='/{$module}/'>$this_module_name</a></li>\n";
que j’ai dû changer en
print "<a href=https://" . $_SERVER["HTTP_HOST"] . "/{$module}/>$this_module_name</a></li>\n";
https://github.com/Thatoo/ldap-user-manager/commit/a60c3bda161bc776b193aef9bcf3c32e98533a65#diff-33b510d94d642b59649581216e2a686b2a8d3945fd5f9e19b1e82398f8a4878d

mais ce n’est pas propre car je code https:// en dur donc si il y a des gens en http, ça va ù**$ù* …
et je n’arrive pas à faire quelque chose avec $SITE_PROTOCOL

Et merci pour le rappel de la redirection du port.
J’ai déjà passé pas mal de temps sur ce sujet, je vais laisser couler un peu d’eau et je reviendrai t’embêter lorsque je testerai bottin et guichet au lieu d’openLDAP et LUM.

1 « J'aime »

Finalement, comme suggéré, j’ai fait un PR pour apporter cette fonctionnalité à l’appli : https://github.com/wheelybird/ldap-user-manager/pull/96

J’attends un retour du mainteneur de l’app.

1 « J'aime »