DiscourseConnect es una característica central de Discourse que te permite configurar “Inicio de sesión único (SSO)” para delegar completamente todo el registro y acceso de usuarios de Discourse a otro sitio. Disponible para nuestros clientes de alojamiento Pro, Business y Enterprise.
(Feb 2021) ‘Discourse SSO’ ahora es ‘DiscourseConnect’. Si ejecutas una versión antigua de Discourse, la configuración a continuación se nombrará
sso_...en lugar dediscourse_connect_...
El problema
Muchos sitios que desean integrarse con un sitio de Discourse quieren mantener todo el registro de usuarios en un sitio separado. En tal configuración, todas las operaciones de inicio de sesión deben delegarse a ese otro sitio.
¿Qué pasa si quiero SSO junto con la autenticación existente?
La intención de DiscourseConnect es reemplazar la autenticación de Discourse. Si deseas agregar un nuevo proveedor, consulta plugins existentes como: Discourse VK Authentication (vkontakte)
Habilitar DiscourseConnect
Para habilitar DiscourseConnect, debes completar 3 configuraciones:
enable_discourse_connect: debe estar habilitado, interruptor global
discourse_connect_url: la URL externa a la que se enviarán los usuarios cuando intenten iniciar sesión
discourse_connect_secret: una cadena secreta utilizada para hashear las cargas útiles de SSO. Asegura que las cargas útiles sean auténticas.
Una vez que enable_discourse_connect se establece en true:
- Hacer clic en “iniciar sesión” o en el avatar te redirigirá a
/session/sso, que a su vez redirigirá a los usuarios adiscourse_connect_urlcon una carga útil firmada. - No se permitirá a los usuarios “cambiar contraseña”. Ese campo se elimina del perfil de usuario.
- Los usuarios ya no podrán usar la autenticación de Discourse (nombre de usuario/contraseña, Google, etc.).
¿Qué pasa si lo marcas por error?
Consulta: Log back in as admin after locking yourself out with read-only mode or an invalid SSO configuration
Implementar DiscourseConnect en tu sitio
Discourse utiliza correos electrónicos para mapear usuarios externos a usuarios de Discourse, y asume que los correos electrónicos externos son seguros. ¡SI NO VALIDAS LAS DIRECCIONES DE CORREO ELECTRÓNICO ANTES DE ENVIARLAS A DISCOURSE, TU SITIO SERÁ EXTREMADAMENTE VULNERABLE!
Alternativamente, si insistes en enviar correos electrónicos no validados, ASEGÚRATE de establecer require_activation=true, lo que obligará a que todos los correos electrónicos sean validados por Discourse. AÚN RECOMENDAMOS ENÉRGICAMENTE QUE NO HAGAS ESTO, por lo que si procedes con esa configuración habilitada, asumes un riesgo sustancial.
Discourse redirigirá a los clientes a discourse_connect_url con una carga útil firmada: (digamos que discourse_connect_url es https://somesite.com/sso)
Recibirás tráfico entrante con lo siguiente:
https://somesite.com/sso?sso=CARGA&sig=FIRMA
La carga útil es una cadena codificada en Base64 que consta de un nonce y una return_sso_url. La carga útil siempre es una cadena de consulta válida.
Por ejemplo, si el nonce es ABCD, la carga útil cruda será:
nonce=ABCD&return_sso_url=https%3A%2F%2Fdiscourse_site%2Fsession%2Fsso_login, esta carga útil cruda está codificada en base 64.
El punto de acceso que se llama debe:
- Validar la firma: asegurarse de que el HMAC-SHA256 de
CARGA(usandodiscourse_connect_secretcomo clave) sea igual asig(sigestará codificado en hexadecimal). - Realizar la autenticación que corresponda.
- Crear una nueva carga útil codificada en URL con al menos nonce, email y external_id. También puedes proporcionar datos adicionales; aquí tienes una lista de todas las claves que Discourse entenderá:
- nonce debe copiarse desde la carga útil de entrada.
- email debe ser una dirección de correo electrónico verificada. Si la dirección de correo electrónico no ha sido verificada, establece require_activation en “true”.
- external_id es cualquier cadena única para el usuario que nunca cambiará, incluso si su correo electrónico, nombre, etc. cambian. El valor sugerido es el número de fila ‘id’ de tu base de datos.
- username se convertirá en el nombre de usuario en Discourse si el usuario es nuevo o si
SiteSetting.auth_overrides_usernameestá establecido. - name se convertirá en el nombre completo en Discourse si el usuario es nuevo o si
SiteSetting.auth_overrides_nameestá establecido. - avatar_url se descargará y establecerá como el avatar del usuario si el usuario es nuevo o si
SiteSetting.discourse_connect_overrides_avatarestá establecido. - avatar_force_update es un campo booleano. Si se establece en
true, obligará a Discourse a actualizar el avatar del usuario, haya cambiadoavatar_urlo no. - bio se convertirá en el contenido de la biografía del usuario si el usuario es nuevo, su biografía está vacía o
SiteSetting.discourse_connect_overrides_bioestá establecido. - title establecerá el título del usuario.
- website establecerá el sitio web del usuario en su perfil.
- location establecerá la ubicación del usuario en su perfil.
- profile_background_url se descargará y establecerá como el fondo del perfil del usuario si el usuario es nuevo o si
SiteSetting.discourse_connect_overrides_profile_backgroundestá establecido. - card_background_url se descargará y establecerá como el fondo de la tarjeta del usuario si el usuario es nuevo o si
SiteSetting.discourse_connect_overrides_card_backgroundestá establecido. - locale establecerá la configuración regional del usuario si el usuario es nuevo y
SiteSetting.allow_user_localeestá habilitado. - locale_force_update es un campo booleano. Si se establece en
truejunto con locale, forzará la actualización de la configuración regional para usuarios existentes (requiereSiteSetting.allow_user_locale). - Los campos booleanos adicionales (“true” o “false”) son: admin, moderator, suppress_welcome_message, logout
- Codificar la carga útil en Base64.
- Calcular un hash HMAC-SHA256 de la carga útil usando
discourse_connect_secretcomo clave y la carga útil codificada en Base64 como texto. - Redirigir de nuevo a
return_sso_urlcon un parámetro de consultassoysig(http://discourse_site/session/sso_login?sso=carga&sig=firma).
Discourse validará que el nonce sea válido y, si lo es, lo expirará inmediatamente para que no pueda usarse nuevamente. Luego, intentará:
- Iniciar sesión en el usuario buscando un external_id ya asociado en el modelo
SingleSignOnRecord. - Iniciar sesión en el usuario usando el correo electrónico proporcionado (actualizando external_id) (a menos que require_activation = true).
- Crear una nueva cuenta para el usuario proporcionando (email, username, name) y actualizando external_id.
Preocupaciones de seguridad
El nonce (token de un solo uso) expirará automáticamente después de 30 minutos. Esto significa que tan pronto como el usuario sea redirigido a tu sitio, tendrá 30 minutos para iniciar sesión o crear una nueva cuenta.
El protocolo es seguro contra ataques de repetición, ya que el nonce solo puede usarse una vez. El nonce está vinculado a la sesión actual del navegador para proteger contra ataques CSRF.
Especificar membresía en grupos
Si se especifica la opción discourse connect overrides groups, Discourse considerará la lista separada por comas de grupos pasada en groups.
Además de groups, también puedes especificar la membresía en grupos en tu carga útil SSO usando los atributos add_groups y remove_groups, independientemente de la opción discourse connect overrides groups.
add_groups es una lista separada por comas de nombres de grupos de los que nos aseguraremos de que el usuario sea miembro.
remove_groups es una lista separada por comas de nombres de grupos de los que nos aseguraremos de que el usuario no sea miembro.
Implementación de referencia
Discourse contiene una implementación de referencia de la clase SSO:
Una implementación trivial sería:
class DiscourseSsoController < ApplicationController
def sso
secret = "MY_SECRET_STRING"
sso = DiscourseApi::SingleSignOn.parse(request.query_string, secret)
sso.email = "user@email.com"
sso.name = "Bill Hicks"
sso.username = "bill@hicks.com"
sso.external_id = "123" # id único para cada usuario de tu aplicación
sso.sso_secret = secret
redirect_to sso.to_url("http://l.discourse/session/sso_login")
end
end
Transición hacia y desde el inicio de sesión único.
Mientras el parámetro require_activation no se establezca en true en la carga útil de la solicitud, el sistema confiará en los correos electrónicos proporcionados por el punto de acceso SSO. Esto significa que si tenías una cuenta existente en el pasado en Discourse con DiscourseConnect deshabilitado, DiscourseConnect simplemente la reutilizará y evitará crear una nueva cuenta.
Si alguna vez desactivas DiscourseConnect, los usuarios podrán restablecer sus contraseñas y recuperar el acceso a sus cuentas.
Ejemplo del mundo real:
Dadas las siguientes configuraciones:
Dominio de Discourse: http://discuss.example.com
URL de DiscourseConnect: http://www.example.com/discourse/sso
Secreto de DiscourseConnect: d836444a9e4084d5b224a60c208dce14
Correo electrónico validado: No (agrega require_activation=true a la carga útil)
Intento de inicio de sesión del usuario
-
Se genera un nonce:
cb68251eefb5211e58c00ff1395f0c0b -
Se genera la carga útil cruda:
nonce=cb68251eefb5211e58c00ff1395f0c0b -
La carga útil se codifica en Base64:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI= -
La carga útil se codifica en URL:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D -
Se genera un HMAC-SHA256 en la carga útil codificada en Base64:
1ce1494f94484b6f6a092be9b15ccc1cdafb1f8460a3838fbb0e0883c4390471
Finalmente, el navegador se redirige a:
http://www.example.com/discourse/sso?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D&sig=1ce1494f94484b6f6a092be9b15ccc1cdafb1f8460a3838fbb0e0883c4390471
En el otro extremo
- La carga útil se valida usando HMAC-SHA256; si la firma no coincide, el proceso se interrumpe.
- Al revertir los pasos anteriores, se extrae el nonce.
El usuario inicia sesión:
name: sam
external_id: hello123
email: test@test.com
username: samsam
require_activation: true
Se genera una carga útil sin firmar:
nonce=cb68251eefb5211e58c00ff1395f0c0b&name=sam&username=samsam&email=test%40test.com&external_id=hello123&require_activation=true
el orden no importa, los valores están codificados en URL
La carga útil se codifica en Base64:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ==
La carga útil se codifica en URL:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ%3D%3D
La carga útil codificada en Base64 se firma:
3d7e5ac755a87ae3ccf90272644ed2207984db03cf020377c8b92ff51be3abc3
El navegador redirige a:
http://discuss.example.com/session/sso_login?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ%3D%3D&sig=3d7e5ac755a87ae3ccf90272644ed2207984db03cf020377c8b92ff51be3abc3
Sincronizar registros de DiscourseConnect
Puedes usar el punto de acceso POST /admin/users/sync_sso para sincronizar un registro de DiscourseConnect; pásale el mismo registro que pasarías al punto de acceso de DiscourseConnect; el nonce no importa.
Si llamas a admin/users/sync_sso desde otro sitio, deberás incluir una api_key de administrador válida y un api_username válido en los encabezados de la solicitud. Consulta Sync DiscourseConnect user data with the sync_sso route para más detalles sobre cómo estructurar la solicitud.
Borrar registros de DiscourseConnect
Si los valores de external_id de tu proveedor de DiscourseConnect han cambiado (quizás cambiaste el algoritmo de generación, quizás es un punto de acceso diferente), puedes eliminar de forma segura todos los registros existentes usando la consola de Rails:
SingleSignOnRecord.destroy_all
Cerrar sesión de usuarios
Puedes usar el punto de acceso POST /admin/users/{USER_ID}/log_out para cerrar la sesión de cualquier usuario en el sistema si es necesario.
Para configurar el punto de acceso al que Discourse redirige al cerrar sesión, busca la configuración logout redirect. Si no se ha establecido ninguna URL aquí, serás redirigido de nuevo a la URL configurada en discourse connect url.
Buscar usuarios por external_id
Los datos del perfil del usuario se pueden acceder usando el punto de acceso /users/by-external/{EXTERNAL_ID}.json. Esto devolverá una carga útil JSON que contiene la información del usuario, incluido el user_id, que se puede usar con el punto de acceso log_out.
Implementaciones existentes
-
El gem
discourse_apise puede usar para SSO. Echa un vistazo al código SSO en su directorio de ejemplos para ver una implementación básica. -
Nuestro plugin de WordPress facilita la configuración de SSO entre WordPress y Discourse. Los detalles sobre cómo configurarlo se encuentran en la pestaña SSO de la página de opciones del plugin.
Trabajo futuro
- Nos gustaría recopilar más implementaciones de referencia para SSO en otras plataformas. Si tienes una, por favor publica en la categoría Dev / SSO.
Características avanzadas
- Puedes pasar campos de usuario personalizados anteponiendo el nombre del campo con
custom. Por ejemplo,custom.user_field_1se puede usar para establecer el valor deUserCustomFieldque tiene el nombreuser_field_1. - Puedes pasar
avatar_urlpara sobrescribir el avatar del usuario (se debe habilitarSiteSetting.discourse_connect_overrides_avatar). Los avatares se almacenan en caché, así que pasaavatar_force_update=truepara forzar su actualización si la URL es la misma. Por ahora, no puedes pasar una URL vacía para deshabilitar el avatar de los usuarios. - Por defecto, el mensaje de bienvenida se enviará a todos los usuarios nuevos creados a través de SSO. Si deseas suprimir esto, puedes pasar
suppress_welcome_message=true. - Para configurar tu instancia de Discourse como proveedor de Discourse Connect, consulta: Usar DiscourseConnect como proveedor de identidad.
Depurar tu proveedor de DiscourseConnect
Para ayudar en la depuración de DiscourseConnect, puedes habilitar la configuración del sitio verbose_discourse_connect_logging. Al habilitar esa configuración del sitio, aparecerán diagnósticos detallados en YOURSITE.com/logs. Asegúrate de marcar la casilla
de warnings en la parte inferior de YOURSITE.com/logs.
Registraremos una advertencia en los registros con un volcado completo de la carga útil SSO:
-
Cada vez que se inicia el proceso de DiscourseConnect, registraremos una advertencia en el registro con un volcado completo de la carga útil de DiscourseConnect.
-
Cada vez que un usuario no logra completar DiscourseConnect (debido a la expiración del nonce o bloqueo de IP).
¿Necesitas automatizar los registros de usuarios? Consulta Auto-provisioning user accounts when SSO is enabled

