Script auth-user-pass-verify d’OpenVPN : le bon code de sortie
L’état de sortie du hook est la décision, pas sa ligne de journal. Associez les résultats du vérificateur à 0, 1 ou différé, lisez le fichier d’identifiants comme des données et échouez en fermé.
OpenVPN agit sur exactement une sortie d’un script de connexion : l’état de sortie. Tout le reste de ce que fait le script est de la décoration. Un hook peut atteindre le bon vérificateur, analyser la réponse et afficher une ligne aimable tout en renvoyant un état qui signifie l’inverse de ce que son auteur voulait. Lisez d’abord le contrat et écrivez l’adaptateur autour de lui, et toute cette classe de bugs disparaît.
Le contrat est petit : identifiez le compte soumis, posez au vérificateur approuvé la question prévue et n’acceptez que le résultat positif documenté de ce vérificateur pour cette demande. Tout le reste est de la plomberie.
Les trois états que le hook peut renvoyer
Pour auth-user-pass-verify, le manuel d’OpenVPN 2.6 définit le code de sortie 0 comme acceptation, 1 comme rejet et 2 comme authentification différée. Ce sont les trois seules réponses que le serveur comprend, et chacune a une conséquence différente pour la connexion. Un script qui sort avec l’état de sa dernière commande a en pratique laissé un appel de journalisation ou une étape de nettoyage voter. Écrivez l’état explicitement dans chaque branche, y compris dans les branches qui n’ont jamais atteint le vérificateur.
Le succès HTTP et le succès de l’authentification sont des couches distinctes, et les confondre est la façon la plus courante dont ce hook se trompe. Une réponse 202 signifie que la demande a été acceptée pour traitement, pas qu’un mot de passe a été vérifié. Définissez l’état attendu, la forme de la réponse et le verdict final à partir du contrat d’API qui vous a été fourni, et n’inventez pas un nom de champ parce qu’il paraît plausible.
Si la réponse arrive vraiment plus tard, c’est le chemin différé et il doit être construit comme tel. Une tentative différée qui n’est jamais terminée retient des ressources jusqu’à l’expiration du délai.
Lisez le fichier d’identifiants exactement tel qu’il est écrit
Avec la méthode documentée via un fichier, le serveur écrit le nom d’utilisateur et le mot de passe comme deux premières lignes d’un fichier temporaire, transmet ce chemin au script et supprime le fichier au retour du script. Lisez ces deux lignes comme des données : ne faites jamais de source du fichier, ne l’évaluez jamais et ne collez jamais son contenu dans une ligne de commande où la table des processus peut le voir. Conservez le mot de passe octet par octet, car une normalisation, comme vous en appliqueriez à un nom d’utilisateur, modifie silencieusement l’identifiant. Le répertoire de ce fichier temporaire est une décision de déploiement, alors vérifiez qu’il existe et qu’il n’est pas lisible par tous sur l’hôte.
Gardez l’identifiant propre au vérificateur séparé de celui de l’utilisateur : il appartient à l’intégration de la passerelle, vit dans le coffre de secrets de la plateforme et n’a besoin que de la permission de vérifier, ce n’est donc pas la preuve qu’une personne précise s’est authentifiée. Ne laissez pas non plus le hook devenir un second vérificateur de mots de passe. Réimplémenter à la main une comparaison de hachage ne devient pas sûr en optimisant la boucle, et un vérificateur maintenu comprend déjà le schéma salé et coûteux du magasin de comptes.
Décidez ce que signifie une réponse non classifiable
Les délais d’attente, les erreurs de transport, les réponses mal formées et un backend indisponible partagent une propriété : aucun d’eux n’est une vérification positive. Le hook devrait échouer en fermé pour chacun et consigner une raison sur laquelle un opérateur peut agir. Cette raison appartient à un journal protégé, pas à un message renvoyé à la personne qui tente de se connecter.
Soyez tout aussi prudent avec les chemins qui n’atteignent jamais le vérificateur. Une valeur de configuration absente, un secret illisible ou une dépendance non installée devraient produire un rejet avec un marqueur opérationnel distinct plutôt qu’une acceptation accidentelle. Testez ces branches en supprimant la dépendance dans un laboratoire au lieu de raisonner à leur sujet. Là où un échec de journalisation peut changer l’état de sortie, la journalisation fait partie de la décision et doit être rendue inoffensive.
La configuration du serveur compte aussi ici : les scripts définis par l’utilisateur ne sont honorés que lorsque la configuration en cours les autorise au niveau de sécurité requis, et ce réglage est un choix délibéré, pas une valeur par défaut à relever.
Vérifiez le verdict, pas la ligne imprimée
Construisez un test qui inspecte directement l’état de sortie. Écrivez un fichier d’identifiants d’exemple, exécutez le hook dessus avec un compte connu comme bon et un compte connu comme mauvais, et lisez l’état que le shell rapporte plutôt que le texte que le script imprime. Cette seule vérification attrape la plupart des bugs de contrat avant même qu’un client se connecte.
Passez ensuite les mêmes cas par un vrai client contre un écouteur hors production et confirmez ce que le serveur a enregistré : accepté, rejeté ou différé. Couvrez un compte désactivé, un mauvais mot de passe, une réponse mal formée du vérificateur, un délai d’attente et un vérificateur injoignable. Si un cas finit dans un état que vous ne pouvez pas nommer, l’adaptateur n’est pas terminé.
Gardez l’association entre le résultat du vérificateur et l’état de sortie à côté du script dans le dépôt, pour que l’ingénieur suivant puisse lire le contrat sans faire d’ingénierie inverse du code.