Usar Discourse como proveedor de identidad (SSO, DiscourseConnect)

¡Pude usar esto para crear un sistema de vinculación de cuentas para mi servidor de Minecraft! ¡Pensé en compartir cómo se ve! Era la primera vez que trabajaba con Discourse SSO, así que tal vez lo compliqué demasiado. Sin embargo, funciona, que es lo principal.

4 Me gusta

Hola, hice todo esto correctamente. Pero cuando el usuario no ha iniciado sesión en Discourse, se muestra una ventana emergente de inicio de sesión de usuario. Cuando relleno el nombre de usuario y la contraseña, no me redirige de vuelta a la return_url. ¿Podrías ayudarme?

Supongo que el nonce está ahí para prevenir ataques de repetición. Leí en línea que los ataques de repetición no son posibles con HTTPS, que es lo que estoy usando. ¿Así que todavía necesito usar el nonce? Pregunto porque no estoy seguro de dónde almacenarlo. ¿Tiene sentido almacenarlo como una cookie segura de texto plano en el navegador del usuario? ¿y luego leerlo desde el navegador junto con la carga útil de retorno?

Esta biblioteca, que está enlazada desde la publicación original GitHub - ArmedGuy/discourse_sso_node: npm package for Discourse SSO login features. no usa el nonce al validar al usuario.

Sí, todavía necesitas validar el nonce porque previene la reutilización de cargas útiles que Discourse envía cuando redirige a los usuarios de vuelta a tu sitio.

Por ejemplo, digamos que tu sitio tiene contenido detrás de un muro de pago al que solo pueden acceder los miembros del grupo subscribers en Discourse y usas el campo groups en la carga útil que Discourse envía a tu sitio para mostrar el contenido de pago solo a los miembros del grupo subscribers. Si no validas el nonce, un usuario que ya no esté en subscribers podría usar una carga útil antigua de cuando era miembro para iniciar sesión en tu sitio y ver el contenido de pago.

Es mejor almacenar el nonce en una base de datos con una fecha de caducidad corta y eliminar el nonce de la base de datos tan pronto como se utilice. Sin embargo, si no puedes usar una base de datos, entonces puedes usar una cookie para almacenar el nonce, pero necesitas hacer algunos pasos adicionales para prevenir la reutilización de la carga útil:

  1. adjunta una fecha de caducidad al nonce cuando lo generes, por ejemplo, 10 minutos a partir de la hora actual
  2. firma toda la cookie (nonce + fecha de caducidad) para evitar que los usuarios modifiquen el nonce y/o la fecha de caducidad
  3. verifica la firma de la cookie y asegúrate de que el nonce no haya caducado

Eso te dará una protección suficientemente buena contra la reutilización de la carga útil. Ten en cuenta que técnicamente sigue siendo posible reutilizar una carga útil, pero se limitará a una ventana de 10 minutos en lugar de para siempre.

Una solución más simple que no necesita una cookie es incluir la fecha de caducidad en un campo personalizado en la carga útil que generas. Luego, cuando Discourse redirija a los usuarios de vuelta a tu sitio con una carga útil, tus campos personalizados se incluirán y podrás recuperar la fecha de caducidad y verificar que no ha caducado. Para incluir un campo personalizado en la carga útil, necesitas incluir un campo con el prefijo custom., por lo que tu carga útil se vería así:

nonce=NONCE&return_sso_url=RETURN_URL&custom.expiration_date=TIMESTAMP
4 Me gusta

También podrías almacenar el nonce en la sesión, eso también evitará que el usuario lo manipule.

3 Me gusta

Volviendo a este hilo años después

¿Alguien puede decirme (@pfaffman o @tobiaseigen o @iamntz) qué devuelve el proveedor SSO de Discourse? Sé que puedo “probarlo y verlo”, pero sería bueno que estuviera documentado. El código de ejemplo de PHP de GitHub ni siquiera menciona otros campos.

Idealmente, enviaría los mismos campos que cuando Discourse utiliza el script externo para SSO, como el ID externo, el correo electrónico, el nombre de usuario, el nombre, la foto de avatar, etc. ¡Así podemos importarlo y crear un usuario de nuestro lado!

¿También le dice a WordPress el correo electrónico?

¿Qué hay de los grupos, insignias, etc.? ¿Podemos encontrar esta información haciendo llamadas REST?

Finalmente, ¿qué pasa con los mensajes privados del usuario y otras cosas? Supongo que si Discord fuera un proveedor de oAuth y permitiera a nuestras aplicaciones consumir estas cosas, sería increíble.

Al intentar habilitar Discourse Connect obtengo este error:
enable_discourse_connect: No puedes habilitar DiscourseConnect e invitar solo al mismo tiempo.

¿Alguna idea?

Veo que has hecho la misma pregunta aquí: Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso) - #537. Si intentas configurar el ajuste enable discourse connect y no el ajuste enable discourse connect provider, el otro tema es el lugar correcto para hacer tu pregunta.

El ajuste enable discourse connect provider es para cuando quieres usar tu sitio de Discourse como el proveedor de identidad para otro sitio. El ajuste enable discourse connect es para cuando quieres iniciar sesión de usuarios en Discourse a través de un sitio externo.

1 me gusta

He implementado el procedimiento en Python para una aplicación Flask que estoy construyendo. Aquí hay algo de código de ejemplo para cualquiera que lo necesite. Los pasos descritos en este tema fueron bastante sencillos de seguir, pero no soy un especialista en seguridad, así que si pasé algo por alto, ¡hágamelo saber!

2 Me gusta

Estamos intentando implementar Discourse como proveedor de SSO y lo que no entendemos es, ¿cómo sabe Discourse qué usuario necesita ser verificado? Las instrucciones dicen: “Crea una nueva carga útil con nonce y url de retorno”. Pero cuando publicas esto a través de una solicitud fetch a Discourse, ¿cómo sabe Discourse qué usuario comprobar para ver si ha iniciado sesión? Disculpen si esto suena a una pregunta estúpida, pero simplemente no puedo entender cómo funciona esto y he trabajado con muchos sistemas de autenticación a lo largo de los años, así que estoy algo familiarizado. ¿Es el correo electrónico del usuario para el que intentamos verificar el estado de inicio de sesión, el que necesita ser incluido en la carga útil enviada a Discourse? Si es así, ¿cuál es la estructura exacta de la carga útil que se debe enviar a Discourse? Si no, de nuevo, ¿qué está comprobando exactamente Discourse? Mi suposición es que le pedimos al usuario su correo electrónico en nuestro extremo, y luego enviamos la carga útil con el correo electrónico a Discourse para ver si ese usuario en particular ha iniciado sesión, pero esto no es lo que dicen las instrucciones, así que estoy totalmente confundido. Gracias por cualquier ayuda.

No importa. Lo hemos resuelto. Pensamos que la URL SSO necesitaba ser enviada como una solicitud POST a la instancia de Discourse y luego recibir una respuesta. Ahora vemos que es una redirección a Discourse, y luego Discourse redirige de vuelta a nuestro sitio. Así que ahora está claro qué hacer. Disculpa por la publicación anterior.

3 Me gusta

Para tu información/Para que lo sepas: Envié una PR para permitir un parámetro prompt=none en la solicitud de autenticación. Similar a una característica del protocolo OpenID Connect, esto permite a un consumidor SSO sondear si un usuario/cliente ya ha iniciado sesión, sin enviarlos a un diálogo de inicio de sesión si no lo están.

La PR ha estado esperando una revisión final por parte de alguien del equipo de Discourse durante aproximadamente 8 semanas; parece bastante más tiempo de lo que esperaría. :crying_cat_face:

7 Me gusta

Hola @mdoggydog - ¡perdón por la larga demora!

Acabo de revisar y fusionar la PR. ¡Gracias por tu contribución! :raised_hands:

3 Me gusta

¡Genial! Gracias, @david.

Como prometí, acabo de actualizar el artículo de la wiki aquí para incluir una descripción del nuevo parámetro (y el anterior nuevo parámetro logout, y para corregir algunos errores tipográficos/gramaticales menores, y para añadir una sección de referencias que documente la carga útil sso= tal como la entiendo por haber investigado el código fuente).

2 Me gusta

Quiero dejar de usar nuestro sitio web como SSO para Discourse y, en cambio, usar las herramientas de inicio de sesión integradas de Discourse para limitar el acceso a ciertos materiales en nuestro sitio web.

Creo que la herramienta adecuada para usar es: GitHub - discourse/discourse-auth-proxy: An http proxy that uses the DiscourseConnect protocol to authenticate users

No he encontrado instrucciones exhaustivas sobre cómo usarlo.

¿Puedo instalarlo en la misma droplet de DigitalOcean que nuestro sitio de Discourse, o necesito alojarlo en otro lugar?

Editar: he puesto en negrita mi pregunta :slight_smile:

1 me gusta

¿Alguna ayuda con la pregunta anterior? Use Discourse as an identity provider (SSO, DiscourseConnect) - #148 by alehandrof

Estoy configurando return_sso_url como una URL que a su vez tiene un parámetro de consulta:

http://localhost:7000/completeLogin?returnto=%2F

El payload que envío a /session/sso_provider como parámetro sso se ve así antes de la codificación base64:

nonce=ENIwf0bElViDu325dTd6&return_sso_url=http://localhost:7000/completeLogin?returnto=%2F

La URL a la que Discourse redirige realmente después de la autenticación es esta (con los parámetros sso y sig abreviados):

http://localhost:7000/completeLogin?returnto=/\u0026sso=...\u0026sig=...

Lo que me sorprende aquí es que la cadena de consulta que establecí para return_sso_url parece haber sido decodificada por URL por algo, porque tiene returnto=/ en lugar de returnto=%2F. El valor de return_sso_url que encuentro dentro de sso después de decodificarlo base64 también tiene una barra en lugar de %2F.

¿Es eso lo que debería esperar que sucediera? (Si es así, ¿por qué?) ¿Es esto un error en Discourse?

¿Cuál es la razón por la que la carga útil de sso contiene avatar_url en lugar de avatar_template como se devuelve en /u/{username}.json y /session/current.json?

avatar_url no está presente para los usuarios que no han configurado un avatar, mientras que avatar_template contiene la ruta leter_avatar_proxy que realmente se usa en Discourse para mostrar avatares para esos usuarios, y avatar_url apunta a la imagen de avatar sin procesar en lugar de una redimensionada al tamaño deseado para los usuarios que han configurado un avatar.

Me parece que avatar_template es lo que cualquiera que pretenda usar la información del avatar contenida en sso querrá; pero luego necesitará hacer una solicitud de API adicional para obtenerla.

2 Me gusta

En este momento estoy implementando SSO en mi aplicación, el inicio de sesión funciona muy bien hasta ahora, el cierre de sesión no.

Mi instancia de Discourse se redirige correctamente a la URL de retorno sin ningún parámetro sso o sig, pero cuando abro Discourse, mi cuenta todavía está iniciada.

¿Alguna idea?

Supongo que estás utilizando la configuración del sitio logout redirect de Discourse para redirigir a los usuarios de vuelta a tu aplicación después de que cierren sesión en Discourse.
Una posible causa del problema sería si la configuración login required está habilitada en tu sitio de Discourse. Cuando esa configuración está habilitada, Discourse redirigirá automáticamente a los usuarios no autenticados al sitio del proveedor SSO si han ido directamente al sitio de Discourse. Eso significa que, a menos que cierres la sesión de los usuarios en tu aplicación cuando se les redirige por primera vez a la URL logout redirect, se iniciará sesión automáticamente en Discourse la próxima vez que visiten el sitio. Puedes confirmar este comportamiento revisando el proceso con el inspector de tu navegador abierto en su pestaña de red.
En caso de que sea útil, así es como el plugin WP Discourse maneja la redirección de cierre de sesión de Discourse: wp-discourse/lib/sso-provider/discourse-sso.php at main · discourse/wp-discourse · GitHub.

2 Me gusta