Script auth-user-pass-verify de OpenVPN: el código de salida correcto
El estado de salida del hook es la decisión, no su línea de registro. Asigne los resultados del verificador a 0, 1 o diferido, lea el archivo de credenciales como datos y falle cerrado.
OpenVPN actúa sobre exactamente una salida de un script de inicio de sesión: el estado de salida. Todo lo demás que hace el script es decoración. Un hook puede llegar al verificador correcto, analizar la respuesta e imprimir una línea amable mientras devuelve un estado que significa lo contrario de lo que pretendía su autor. Lea primero el contrato y escriba el adaptador a su alrededor, y toda esa clase de errores desaparece.
El contrato es pequeño: identifique la cuenta que se envió, haga al verificador aprobado la pregunta prevista y acepte solo el resultado positivo documentado de ese verificador para esa solicitud. Todo lo demás es infraestructura.
Los tres estados que el hook puede devolver
Para auth-user-pass-verify, el manual de OpenVPN 2.6 define el código de salida 0 como aceptación, 1 como rechazo y 2 como autenticación diferida. Esas son las únicas tres respuestas que entiende el servidor, y cada una tiene una consecuencia distinta para la conexión. Un script que sale con el estado de su último comando ha dejado, en la práctica, que una llamada de registro o un paso de limpieza vote. Escriba el estado explícitamente en cada rama, incluidas las ramas que nunca llegaron al verificador.
El éxito HTTP y el éxito de autenticación son capas separadas, y confundirlos es la forma más común de que este hook falle. Una respuesta 202 significa que la solicitud se aceptó para su procesamiento, no que se haya verificado una contraseña. Defina el estado esperado, la forma de la respuesta y el veredicto final a partir del contrato de API que le dieron, y no invente un nombre de campo porque parezca plausible.
Si la respuesta llega de verdad más tarde, esa es la ruta diferida y hay que construirla como tal. Un intento diferido que nunca se completa retiene recursos hasta que vence el tiempo de espera.
Lea el archivo de credenciales exactamente como está escrito
Con el método documentado vía archivo, el servidor escribe el nombre de usuario y la contraseña como las dos primeras líneas de un archivo temporal, pasa esa ruta al script y elimina el archivo cuando el script regresa. Lea esas dos líneas como datos: nunca haga source del archivo, nunca lo evalúe y nunca pegue su contenido en una línea de comandos donde la tabla de procesos pueda verlo. Conserve la contraseña byte a byte, porque normalizarla como normalizaría un nombre de usuario cambia la credencial en silencio. El directorio usado para ese archivo temporal es una decisión de despliegue, así que confirme que existe y que no es legible por todos en el host.
Mantenga la credencial propia del verificador separada de la del usuario: pertenece a la integración de la pasarela, vive en el almacén de secretos de la plataforma y solo necesita el permiso de verificar, así que no es prueba de que se haya autenticado una persona concreta. Tampoco deje que el hook se convierta en un segundo verificador de contraseñas. Reimplementar a mano una comparación de hash no se vuelve seguro optimizando el bucle, y un verificador mantenido ya entiende el esquema con sal y coste del almacén de cuentas.
Decida qué significa una respuesta no clasificable
Los tiempos de espera, los errores de transporte, las respuestas mal formadas y un backend no disponible comparten una propiedad: ninguno de ellos es una verificación positiva. El hook debería fallar cerrado ante cada uno de ellos y registrar un motivo sobre el que un operador pueda actuar. Ese motivo pertenece a un registro protegido, no a un mensaje devuelto a la persona que intenta conectarse.
Sea igual de cuidadoso con las rutas que nunca llegan al verificador. Un valor de configuración ausente, un secreto ilegible o una dependencia no instalada deberían producir un rechazo con un marcador operativo distinto en lugar de una aceptación accidental. Pruebe esas ramas eliminando la dependencia en un laboratorio en vez de razonar sobre ellas. Donde un fallo de registro puede cambiar el estado de salida, el registro se ha vuelto parte de la decisión y hay que hacerlo inofensivo.
La configuración del servidor también importa aquí: los scripts definidos por el usuario solo se respetan cuando la configuración en ejecución los permite en el nivel de seguridad requerido, y ese ajuste es una elección deliberada, no un valor predeterminado que haya que subir.
Verifique el veredicto, no la línea impresa
Construya una prueba que inspeccione directamente el estado de salida. Escriba un archivo de credenciales de muestra, ejecute el hook contra él con una cuenta buena conocida y una mala conocida, y lea el estado que informa el intérprete de comandos en lugar del texto que imprime el script. Esa única comprobación atrapa la mayoría de los errores de contrato antes de que un cliente llegue a conectarse.
Después pase los mismos casos por un cliente real contra un escucha que no sea de producción y confirme qué registró el servidor: aceptado, rechazado o diferido. Cubra una cuenta deshabilitada, una contraseña incorrecta, una respuesta mal formada del verificador, un tiempo de espera y un verificador inalcanzable. Si algún caso acaba en un estado que no puede nombrar, el adaptador no está terminado.
Mantenga la correspondencia entre el resultado del verificador y el estado de salida junto al script en el repositorio, para que el siguiente ingeniero pueda leer el contrato sin hacer ingeniería inversa del código.