Lee y comprende la totalidad de esta sección antes de implementar un módulo validador. Un validador que no funcione correctamente es potencialmente peor que no tener autenticación en absoluto, tanto por la falsa sensación de seguridad que proporciona como porque puede contribuir a ataques contra otras partes de un ecosistema de OAuth.
Aunque los diferentes módulos pueden adoptar enfoques muy distintos para la validación de tokens, las implementaciones generalmente necesitan realizar tres acciones independientes:
El validador debe primero asegurarse de que el token presentado es de hecho un token portador (Bearer token) válido para su uso en la autenticación del cliente. La forma correcta de hacerlo depende del proveedor, pero generalmente implica operaciones criptográficas para demostrar que el token fue creado por una parte de confianza (validación fuera de línea o offline), o la presentación del token a esa parte de confianza para que pueda realizar la validación por ti (validación en línea o online).
La validación en línea, normalmente implementada a través de la Introspección de tokens de OAuth, requiere menos pasos de un módulo validador y permite la revocación centralizada de un token en caso de que sea robado o emitido erróneamente. Sin embargo, sí requiere que el módulo realice al menos una llamada de red por intento de autenticación (las cuales deben completarse dentro del tiempo de espera de autenticación configurado en authentication_timeout). Además, es posible que tu proveedor no proporcione endpoints de introspección para su uso por parte de servidores de recursos externos.
La validación fuera de línea es mucho más compleja, y normalmente requiere que un validador mantenga una lista de claves de firma de confianza para un proveedor y luego compruebe la firma criptográfica del token junto con su contenido. Las implementaciones deben seguir las instrucciones del proveedor al pie de la letra, incluida cualquier verificación del emisor (issuer, "¿de dónde es este token?"), la audiencia (audience, "¿para quién es este token?") y el período de validez (validity period, "¿cuándo se puede usar este token?"). Dado que no hay comunicación entre el módulo y el proveedor, los tokens no se pueden revocar de forma centralizada utilizando este método; las implementaciones de validadores fuera de línea pueden desear imponer restricciones sobre la duración máxima del período de validez de un token.
Si el token no se puede validar, el módulo debe fallar inmediatamente. Cualquier autenticación/autorización posterior no tiene sentido si el token portador no fue emitido por una parte de confianza.
A continuación, el validador debe asegurarse de que el usuario final ha dado permiso al cliente para acceder al servidor en su nombre. Esto generalmente implica comprobar los ámbitos (scopes) que se han asignado al token, para asegurarse de que cubren el acceso a la base de datos para los parámetros HBA actuales.
El propósito de este paso es evitar que un cliente de OAuth obtenga un token bajo falsas pretensiones. Si el validador requiere que todos los tokens lleven ámbitos que cubran el acceso a la base de datos, el proveedor debería solicitar claramente al usuario que conceda ese acceso durante el flujo. Esto les da la oportunidad de rechazar la solicitud si se supone que el cliente no debe usar sus credenciales para conectarse a las bases de datos.
Aunque es posible establecer la autorización del cliente sin ámbitos explícitos mediante el conocimiento fuera de banda de la arquitectura desplegada, al hacerlo se elimina al usuario del proceso, lo que le impide detectar errores de despliegue y permite que dichos errores se exploten de forma silenciosa. El acceso a la base de datos debe restringirse estrictamente a solo los clientes de confianza [17] si no se solicita a los usuarios ámbitos adicionales.
Incluso si falla la autorización, un módulo puede optar por continuar extrayendo información de autenticación del token para su uso en auditorías y depuración.
Finalmente, el validador debe determinar un identificador de usuario para el token,
ya sea pidiendo esta información al proveedor o extrayéndola
del propio token, y devolver ese identificador al servidor (el cual
tomará una decisión final de autorización utilizando la configuración
HBA). Este identificador estará disponible dentro de la sesión a través de
system_user
y se registrará en los registros del servidor si log_connections
está habilitado.
Los diferentes proveedores pueden registrar una variedad de información de autenticación diferente para un usuario final, normalmente denominada claims (declaraciones). Los proveedores suelen documentar cuáles de estas declaraciones son lo suficientemente confiables como para utilizarlas en las decisiones de autorización y cuáles no. (Por ejemplo, probablemente no sería prudente utilizar el nombre completo de un usuario final como identificador para la autenticación, ya que muchos proveedores permiten a los usuarios cambiar sus nombres para mostrar de forma arbitraria). En última instancia, la elección de qué declaración (o combinación de declaraciones) utilizar se reduce a la implementación del proveedor y a los requisitos de la aplicación.
Ten en cuenta que también es posible el inicio de sesión anónimo/pseudónimo habilitando la delegación de mapas de usuario; consulta la Section 50.1.3.
Los desarrolladores deben tener en cuenta lo siguiente al implementar la validación de tokens:
Los módulos no deben escribir tokens, o fragmentos de tokens, en el registro del servidor. Esto es así incluso si el módulo considera que el token no es válido; un atacante que confunda a un cliente para que se comunique con el proveedor equivocado no debería poder recuperar ese token (por lo demás válido) del disco.
Las implementaciones que envían tokens a través de la red (por ejemplo, para realizar la validación del token en línea con un proveedor) deben autenticar al par y asegurarse de que se está utilizando una seguridad de transporte sólida.
Los módulos pueden utilizar las mismas utilidades
de registro de errores que las extensiones estándar; sin embargo, las reglas para emitir
entradas de registro al cliente son sutilmente diferentes durante la fase de
autenticación de la conexión. En términos generales, los módulos deben registrar
los problemas de verificación en el nivel COMMERROR y retornar
normalmente, en lugar de utilizar ERROR/FATAL
para desenrollar la pila, para evitar filtrar información a clientes no
autenticados.
Los módulos deben seguir siendo interrumpibles por señales para que el servidor pueda
manejar correctamente los tiempos de espera de autenticación y las señales de apagado de
pg_ctl. Por ejemplo, las llamadas bloqueantes en los sockets
deben reemplazarse generalmente por código que maneje tanto los eventos de socket
como las interrupciones sin condiciones de carrera (consulta WaitLatchOrSocket(),
WaitEventSetWait(), etc.), y los bucles de larga duración
deben llamar periódicamente a CHECK_FOR_INTERRUPTS().
El incumplimiento de esta directriz puede dar lugar a sesiones de backend que no
responden.
La amplitud de las pruebas de un sistema OAuth está mucho más allá del alcance de esta documentación, pero como mínimo, las pruebas negativas deben considerarse obligatorias. Es trivial diseñar un módulo que permita la entrada de usuarios autorizados; todo el propósito del sistema es mantener fuera a los usuarios no autorizados.
Las implementaciones de los validadores deben documentar el contenido y el formato del
ID autenticado que se reporta al servidor para cada usuario final, ya que los
administradores de bases de datos pueden necesitar utilizar esta información para construir mapas pg_ident. (Por
ejemplo, ¿es una dirección de correo electrónico? ¿un número de identificación de la organización? ¿un UUID?).
También deben documentar si es seguro o no utilizar el módulo en modo
delegate_ident_mapping=1, y qué configuración adicional
se requiere para hacerlo.
El resultado estándar de un módulo de validación es el identificador de usuario,
que el servidor comparará con cualquier mapeo configurado en
pg_ident.conf
y determinará si el usuario final está autorizado a conectarse.
Sin embargo, OAuth es en sí mismo un marco de autorización, y los tokens pueden llevar
información sobre los privilegios del usuario. Por ejemplo, un token puede estar asociado
con los grupos organizativos a los que pertenece un usuario, o listar los roles
que un usuario puede asumir, y duplicar ese conocimiento en mapas de usuario locales
para cada servidor puede no ser deseable.
Para omitir por completo el mapeo de nombres de usuario y hacer que el módulo validador asuma la responsabilidad adicional de autorizar las conexiones de los usuarios, el HBA puede configurarse con delegate_ident_mapping. El módulo puede entonces utilizar los ámbitos del token o un método equivalente para decidir si el usuario tiene permitido conectarse bajo su rol deseado. El identificador de usuario seguirá siendo registrado por el servidor, pero no juega ningún papel en la determinación de si continuar la conexión o no.
Utilizando este esquema, la autenticación en sí misma es opcional. Siempre que el módulo informe de que la conexión está autorizada, el inicio de sesión continuará incluso si no hay ningún identificador de usuario registrado. Esto hace posible implementar un acceso anónimo o seudónimo a la base de datos, donde el proveedor externo realiza toda la autenticación necesaria pero no proporciona ninguna información de identificación del usuario al servidor. (Algunos proveedores pueden crear un número de identificación anónimo que puede registrarse en su lugar, para auditorías posteriores).
La delegación de mapas de usuario proporciona la mayor flexibilidad arquitectónica, pero convierte al módulo validador en un punto único de fallo para la autorización de conexiones. Úsalo con precaución.
[17] Es decir, "de confianza" en el sentido de que el cliente de OAuth y el servidor de PostgreSQL están controlados por la misma entidad. En particular, el flujo de cliente Device Authorization admitido por libpq no suele cumplir con este estándar, ya que está diseñado para su uso por parte de clientes públicos/no confiables.