Como probablemente puedas imaginar, también estoy muy interesado en ver una solución estable para este problema, que no sea específica del plugin openid-connect. Veamos si podemos encontrar una forma de avanzar.
Retomando el punto que has planteado.
¿Cómo decides a qué grupos agregar y de cuáles quitar al usuario? ¿Y cómo afecta eso a la adición o eliminación manual de usuarios de grupos en el propio Discourse?
Un usuario se autentica vía OIDC con los grupos ['group1', 'group2']
En la interfaz de Discourse, el usuario se agrega al group3
Más tarde, el mismo usuario se autentica vía OIDC con los grupos ['group1']
Al inspeccionar esto como humanos, podemos ver que el estado final debería ser group1, group3 (se debería eliminar group2). Pero creo que no hay suficiente estado siendo rastreado para tomar esa decisión de forma programática. De manera similar:
Un usuario se autentica vía OIDC con los grupos ['group1', 'group2']
En la interfaz de Discourse, el usuario se elimina del group1
Más tarde, el mismo usuario se autentica vía OIDC con los grupos ['group1', 'group2']
¿Qué debería ocurrir ahora? Un administrador ha eliminado explícitamente al usuario del group1, pero OIDC acaba de volver a agregarlo. Esto es una experiencia de usuario (UX) muy confusa para el administrador. Podríamos necesitar alguna forma de identificar los grupos como ‘gestionados externamente’ y ocultar toda la interfaz de agregar/quitar
Creo que hay varias formas en las que podríamos abordar este problema (no son excluyentes entre sí).
Identificación de grupos y atributos del token
En cualquier implementación, se debería requerir la identificación explícita de:
qué grupos pueden tener su membresía gestionada mediante la autenticación; y
qué atributos en un token de autenticación gobiernan la membresía del grupo
ya sea a través de la configuración del sitio, la configuración del grupo o de otra manera, y el valor predeterminado debería ser “desactivado”.
Manejo estricto o permisivo
El manejo es “estricto” si un usuario se elimina cuando el grupo está ausente en el atributo del token identificado. El manejo es “permisivo” si un usuario no se elimina cuando el grupo está ausente en el atributo del token identificado.
Como sugieres, podrías desactivar la adición/eliminación de membresía de grupos a través del administrador de grupos si el manejo fuera “estricto”.
Identificación de la fuente de la membresía
También podrías almacenar la fuente de la membresía del grupo en la tabla group_users para permitir un enfoque “mixto” dentro de un grupo, es decir, un administrador no puede eliminar las membresías creadas mediante un token de autenticación.
Cuanto más pienso en esto, más creo que esto debería hacerse mediante la configuración del grupo.
¡Gracias @angus por poner esto en marcha! Sé que mucha gente está muy interesada en esta funcionalidad.
¡Interesante! Siempre imaginé que los grupos se crearían automáticamente durante la autenticación y que el nombre del grupo sería 1:1 con el nombre del grupo en el proveedor de identidad. Así es como funciona DiscourseConnect en este momento.
¡Pero de hecho me gusta mucho más esta opción más explícita! Significa que las instancias de Discourse de las personas no se verán contaminadas por grupos innecesarios de su proveedor de identidad, y significa que los administradores pueden personalizar los nombres de los grupos a su gusto. Tiene mucha paridad con nuestra membresía existente basada en dominios de correo electrónico.
Esto suena bien desde un punto de vista técnico. Mi única preocupación es que podría ser difícil de explicar a los usuarios/administradores. Si seguimos con tu idea de ‘identificación explícita’ de los grupos gestionados por autenticación, creo que podríamos simplemente implementar el manejo ‘estricto’.
Cuando un grupo está configurado para ser gestionado por autenticación, la adición/eliminación manual se oculta detrás de una gran advertencia y se comporta como el modo ‘estricto’ que describiste.
¿Qué te parece?
Aparte: también deberíamos asegurarnos de que toda la adición/eliminación automática de usuarios se registre en el registro del grupo. Eso facilitará a todos entender qué está sucediendo y por qué.
Sí, creo que es mejor ser explícito, al menos en la versión 1 de este conjunto de funciones. Hasta ahora no he encontrado ningún caso de uso donde la creación automática haya sido realmente necesaria, es decir, donde el grupo no pudiera simplemente configurarse y ser gestionado por el administrador del sitio antes de que se procesara cualquier reclamación.
¿Quizás podríamos pasar a la creación automática como una opción después de implementar la versión explícita?
En cuanto a la Configuración de Grupos, sería algo así:
Sección de Configuración: Membresía (es decir, la sección existente) Título del Grupo de Configuración: Gestión de Autenticación Configuraciones:
Servicio: Lista de servicios de autenticación. “Todos” sería una opción. Esta configuración también funcionaría como un estado “habilitado / deshabilitado” para este conjunto de funciones. Es decir, el valor predeterminado sería “Ninguno”.
Reclamación (Claim): campo de texto para identificar la reclamación del token de ID. La “descripción” de esta función (quizás en una publicación aquí en meta) explicaría los formatos compatibles, por ejemplo, booleano, cadena delimitada por comas, etc.
Modo: ver más abajo
Sí, si hubiera una configuración de estricto / permisivo, tendríamos que explicarla de forma concisa. Creo que la mejor manera de abordarlo sería centrarse en la “adición” y la “eliminación”. Podríamos describirlo de la siguiente manera:
Configuración: “Modo”
Opción 1 (permisivo):
Etiqueta: “Agregar miembros”
Descripción: “Permitir que se agreguen miembros a este grupo durante la autenticación”
Opción 2 (estricto):
Etiqueta: “Agregar y eliminar miembros”
Descripción: “Permitir que los miembros se agreguen y eliminen durante la autenticación. Esto deshabilitará los controles manuales de membresía.”
La razón por la que me interesa mantener la opción “permisiva” es que, al trabajar anteriormente con clientes en este tipo de cosas, ese es el caso de uso más común, es decir:
La necesidad principal es permitir el acceso a un grupo dependiendo de un estado en un servicio externo.
La necesidad de eliminar el acceso dependiendo del estado en el servicio externo es más marginal; es decir, las personas pierden acceso y deberían ser eliminadas, pero esto es relativamente menos importante.
A menudo existe el deseo de conservar la capacidad de controlar manualmente la membresía en Discourse. Cuando he implementado el enfoque “estricto”, esto ha resultado “sorprendente” (es decir, “¿Por qué la persona X perdió la membresía?”) a pesar de las explicaciones y de que funcionara (técnicamente) como debería.
Sí, esto es importante, ya que a menudo la gente se preguntará “por qué” alguien fue agregado o eliminado, especialmente en modo estricto, y nosotros (es decir, “Discourse”) no tendremos control sobre la veracidad de las reclamaciones que hace el servicio de autenticación externo.
Quizás un nuevo tipo de acción “Eliminar usuario” y “Agregar usuario” que incluya el servicio de autenticación responsable de la acción, es decir, “Eliminar usuario ([nombre del servicio])”.
Otro ‘truco’ aquí es que debemos dejar claro que esto no es una solución mágica para el caso de uso de ‘Quiero que las membresías de un grupo se basen en el servicio externo X’, ya que las personas no se autentican con tanta frecuencia, o al menos, no según las necesidades del caso de uso estándar de ese tipo.
Esto (la gestión de autenticación) es una parte necesaria para manejar ese tipo de caso de uso, pero para atenderlo adecuadamente también necesitas configurar integraciones basadas en eventos, por ejemplo, un receptor de webhooks (tenemos un plugin de receptor de webhooks privado diseñado para la gestión de grupos que espero hacer de código abierto en un futuro cercano).
¡Este es un trabajo muy valioso que están haciendo aquí!
Solo como comparación de funcionalidades, pensé en compartir lo que hacemos en la Red Global de Empoderamiento Legal, que utiliza WordPress y el plugin Discourse para WordPress. Lo tenemos configurado de modo que cada vez que se actualiza un usuario en WordPress, se actualiza en Discourse. Esto incluye algunos grupos especiales (por ejemplo, miembro principal, contribuyente de recursos, etc.), así como detalles del perfil. Agregamos un campo de usuario oculto llamado “última actualización”, lo cual ayudó a solucionar problemas y asegurarnos de que todo funcionara correctamente.
Bloqueamos esos grupos gestionados de forma remota para que los usuarios no puedan unirse o salir de ellos desde Discourse, pero no vimos la necesidad de impedir que el personal gestione la pertenencia a grupos. Me gusta la apariencia de lo que estás intentando, pero la verdad es que está un poco más allá de mis conocimientos.
Tenemos algunos clientes de Discourse for Teams que utilizan Okta activamente para gestionar el acceso a todas sus aplicaciones corporativas. También configuran roles allí, los cuales luego se utilizan para proporcionar, por ejemplo, ciertos niveles de acceso a Microsoft, Tableau, etc. Okta también funciona como un directorio, por lo que gestionan avatares de usuario, biografía, ubicación y otra información de perfil. Les gustaría ver que esta información de perfil se actualice en Teams desde fuera de Okta también.
Deberíamos intentar mantener los aspectos más técnicos fuera de la configuración de los grupos, si es posible. Tener que enlazar a la documentación de sintaxis probablemente signifique que debería simplificarse o relegarse a la configuración del sitio de administración. Creo que deberíamos dejar esa parte a la implementación de cada plugin de autenticación, ya que puede variar mucho.
Tomando OIDC como ejemplo, ese plugin añadiría una nueva configuración del sitio llamada openid_connect_roles_claim. Si se está usando Okta, el administrador la configuraría como groups. Creo que un array de cadenas es un formato bastante estándar para OIDC, pero podríamos explorar opciones más complejas aquí si fuera realmente necesario.
Para recibir esta información, Auth::Result recibiría un nuevo atributo roles, que acepta un simple array de cadenas. El núcleo tomaría esto (en Auth::Result#apply_user_attributes!) y lo cargaría en una nueva tabla UserAssociatedRoles con las columnas (provider_name, user_id, role). Esta tabla UserAssociatedRoles nos proporciona la «identificación de la fuente de membresía» que mencionaste en el primer mensaje.
Imagino que la configuración de los grupos se vería algo así:
Los nombres de los roles llevarían el prefijo provider_name. La autocompletación se basaría en todos los valores existentes en la tabla UserAssociatedRoles, pero también aceptaríamos valores que no se autocompleten, por si el rol aún no ha sido visto por Discourse.
La belleza de tener una tabla completa user_associated_roles en la base de datos es que los administradores pueden hacer lo que quieran con los grupos de Discourse, y las membresías se actualizarán instantáneamente sin que los usuarios tengan que iniciar sesión nuevamente.
Es justo. Creo que lo mejor sería mantenerlo lo más simple posible, al menos para la versión 1, así que prefiero no tener múltiples «modos». ¿Qué tal si establecemos esto como el comportamiento predeterminado:
Añadir miembros cuando tengan un rol coincidente del proveedor de autenticación
Eliminar miembros cuando ese rol desaparezca
Permitir añadir/eliminar en Discourse también
Si un administrador intenta eliminar a un usuario que fue añadido mediante un proveedor de autenticación, mostrar una advertencia: «este usuario podría ser añadido nuevamente la próxima vez que inicie sesión»
Creo que deberíamos intentar ser seguros por defecto aquí, y eliminar a los miembros cuando pierdan el rol en el proveedor de identidad. Con las mejoras en el registro de membresías, espero que sea menos confuso que el estado actual.
Para los sitios que realmente no quieran eso, podríamos tener una configuración del sitio como remove_group_membership_when_auth_role_lost (predeterminado: true).
Sí, por supuesto. También tenemos este problema con otros metadatos de usuario como el nombre, el avatar, etc. Creo que en algún momento pronto tendremos que considerar crear un equivalente a sync_sso para otros plugins de autenticación. Eso podría recibir toda la información que normalmente se pasa mediante OIDC / SAML / etc., incluida esta nueva información de «rol». Probablemente sería un proyecto separado, sin embargo.
¿Qué te parece todo esto @angus? Es ligeramente menos flexible que tener modos estricto/permisivo por separado, pero creo que tener solo un modo hará que la resolución de problemas, la documentación y el soporte sean mucho más fáciles.
Con ese plan, aquí tienes una visión general de cómo se vería desde la perspectiva de un administrador:
En Discourse, establece openid_connect_roles_claim como groups.
Configuración de un nuevo grupo
Crea un grupo en Discourse como de costumbre. Configura el nombre, el nombre completo, el estilo, etc., como prefieras.
Ve a las preferencias de «membresía», coloca el cursor en el menú desplegable de roles SSO y elige un rol de la lista. Si Discourse aún no ha visto a nadie iniciar sesión con ese rol, tendrás que ingresarlo manualmente.
Puedes especificar múltiples roles para un solo grupo de Discourse. Por ejemplo, un grupo de «equipo» en Discourse podría ser una combinación de oidc:employees y oidc:contractors.
Presiona guardar y la membresía del grupo se actualizará instantáneamente con la información de rol que Discourse haya almacenado en caché de sesiones anteriores.
En futuras sesiones, cualquier cambio en los roles del proveedor de identidad se reflejará en el grupo de Discourse.
Todavía puedes añadir/eliminar usuarios del grupo en la interfaz nativa de Discourse.
Si intentas eliminar a un usuario que fue añadido mediante un proveedor de identidad, se mostrará una advertencia indicando que el usuario podría ser añadido nuevamente en la próxima sesión.
Si más adelante decides que no quieres que ese rol del IDP esté asociado con el grupo, puedes eliminarlo y todos los usuarios que eran miembros a través de ese rol serán eliminados.
Sí, sin embargo, hay casos en los que tiene sentido admitir un reclamo booleano. Pero sí, estoy de acuerdo: mantengámoslo simple por ahora admitiendo solo un array de cadenas.
Haciéndolo autenticador por autenticador, supongo que también tendríamos un método group_sync_enabled? en Auth::Authenticator, que sería sobrescrito en los autenticadores individuales y, en los autenticadores genéricos, según la existencia de un valor en la configuración relevante.
Eso en realidad plantea una pregunta interesante. Esto también podría ser utilizado por los autenticadores de servicios específicos, como Facebook (¿“grupos”?), Google (¿“grupos”?) y Discord (¿“roles”?). No estoy seguro de si sus tokens de identidad contendrían esa información, pero quizás valga la pena considerarlo desde una perspectiva de diseño técnico (es decir, la capacidad de añadir esto más adelante). No creo que sea una preocupación principal para la v1.
Esos mecanismos suenan bien, pero tengo curiosidad por saber por qué hemos cambiado de usar “roles” a “grupos” aquí. No es un gran problema, pero quiero asegurarme de que no esté pasando nada por alto.
Desde una perspectiva de UX, puedo ver que surge confusión por el uso de esa nomenclatura (es decir, “roles” y “grupos” al mismo tiempo), incluso si se basa en una distinción técnica útil. También es posible la confusión de los desarrolladores si llegan a esto sin este contexto de fondo.
Me gusta la tabla separada, sin embargo, quizás deberíamos tener una asociación de clave foránea con user_associated_accounts en lugar de provider_name. Podría ser útil en cosas como operaciones de limpieza. Supongo que la respuesta a esa pregunta depende en parte de cuánto queramos que la asociación de grupo/rol esté interconectada con la cuenta asociada desde una perspectiva de producto. ¿Habría alguna desventaja en vincular los dos ahora?
** Edición: supongo que ya tenemos la asociación a través del user_id.
Eso suena bien, sin embargo, solo estoy pensando que también tenemos esta información por proveedor debido a la configuración de sitio que propusiste, lo que también cubriría el caso en que el rol no haya sido visto. Quizás haya una manera de usar Discourse.authenticators aquí, es decir, una lista en memoria de los proveedores y sus reclamos.
Creo que es un buen compromiso. Especialmente si también tenemos la configuración de sitio mencionada a continuación.
¿En la base de un plugin (es decir, autenticador)? Si es así, estoy de acuerdo. Eso debería cubrir esa necesidad para la v1.
Buen resumen del flujo de usuario Pendientes de las sugerencias relativamente menores que he hecho, estoy de acuerdo con la dirección.
Sí, sin duda. Pensaba especialmente en Google, ya que a mucha gente le gusta usarlo para sus organizaciones de GSuite, que, supongo, tienen algún concepto de grupos.
Supongo que intentaba evitar cualquier confusión entre “Grupos del proveedor de identidad” y “Grupos de Discourse”… pero es posible que solo haya complicado más las cosas al cambiar el nombre. Estoy muy dispuesto a mantener “grupos” aquí.
Mi razonamiento fue que todavía soportamos proveedores de autenticación no gestionados, por lo que podría no haber un registro en user_associated_account. Aún podemos unirnos a él a través del user_id, como dijiste
No estoy seguro de que la configuración del sitio ayude aquí. Si estamos hablando de un array de cadenas que representan “roles”, la configuración del sitio no especificaría cuáles son los roles realmente. Solo especificaría cómo obtener el array. ¿Tiene sentido?
Sí, tienes razón. Todavía estaba pensando en una implementación anterior donde había incluido grupos específicos en la propia configuración, pero no estamos haciendo eso aquí, lo cual está bien.
Creo que hay suficiente información aquí para comenzar a trabajar en la PR, que empezaré más adelante esta semana, a menos que tengas alguna preocupación pendiente. Te actualizaré aquí si surge algo en el camino.
Ok, finalmente tengo un trabajo en progreso para compartir aquí
Algunas notas.
He optado por el caso ligeramente más complicado de los grupos hd de Google Apps para la implementación inicial, ya que creo que ayuda a reflexionar sobre las posibles permutaciones de esto, por ejemplo, la necesidad de tener en cuenta los grupos específicos de dominio de un proveedor.
Para implementar ese caso de uso, también he tenido que introducir un nuevo concepto de “autorización secundaria” en el punto de autenticación, para permitir una autorización incremental. Consideré varias formas diferentes de implementar la solicitud de permisos de grupo de usuarios específicos (es decir, si se estaban autenticando con un hd), y esto pareció ser la opción más viable. Aprecio que esto quizás sea un cambio mayor en ese sentido de lo anticipado, pero quizás valga la pena discutirlo.
Tenga en cuenta que para implementar el caso de los grupos hd de Google, debe otorgar a los miembros no administradores de sus grupos hd de Google Apps autoridad de administrador delegada para listar sus grupos (a través de la API de directorio de administración). De hecho, existe un rol de administrador predefinido “beta” llamado “Lector de grupos” que funciona bien para esto. Consulte Prebuilt administrator roles | User management | Google Workspace Help
La implementación de Google funciona. Si la configura y luego se autentica con un hd, sus grupos hd de Google estarán disponibles en la configuración de membresía de grupo automática; se le añadirá a ese grupo de Discourse si se selecciona ese grupo hd, se le eliminará si se elimina (ambas acciones se registrarán con cierta especificidad) y los usuarios subsiguientes de ese grupo hd de Google que se autentiquen se añadirán inmediatamente.
Los detalles deberían ser evidentes a partir del código y las pruebas. También notará que he terminado añadiendo tres nuevas tablas. Intenté algunas soluciones más “ligeras”, pero cada una terminó siendo más complicada e ineficiente a la hora de manejar las actualizaciones de los grupos asociados de un usuario y de los grupos asociados de un grupo. Es difícil evitar simplemente crear nuevas tablas para cada una. Estoy abierto a ideas en el frente del modelado de datos, y en general.
Algunas tareas técnicas pendientes (además de las preguntas conceptuales/de producto planteadas anteriormente). También se aceptan sugerencias en este sentido:
Quizás serializar el label de associated_groups (en lugar de modelarlo en el cliente).
Añadir pruebas y qunits faltantes.
Quizás mover la creación/destrucción de user_associated_group / group_associated_group a un trabajo en segundo plano, ya que con grandes cantidades esto podría ser lento.
Soy un poco reacio a lo de la «autorización secundaria» y también a la columna provider_domain. ¿Podrías explicar un poco más por qué son necesarias? Parece que son bastante específicas de Google… ¿hay alguna razón por la que no podamos solicitar el ámbito admin.directory.group.readonly durante la primera solicitud de autenticación? ¿Y quizás simplemente prefixar el nombre del grupo con el dominio? (o excluir el dominio por completo, ya que asumo que solo se usará esto con un único «dominio alojado» de Google).
Sí, estoy totalmente de acuerdo con 3 tablas aquí; mantiene las cosas más limpias.
De acuerdo
Debemos tener cuidado aquí. Cualquier membresía de grupo debe asignarse antes de que el usuario cargue el sitio por primera vez. De lo contrario, no verá elementos específicos del grupo la primera vez que inicie sesión (por ejemplo, categorías seguras). Así que creo que los cambios en los registros user_associated_group deben procesarse de forma síncrona.
Pero para los cambios en los registros group_associated_group, creo que tienes razón. Los cambios allí podrían afectar a miles de usuarios, por lo que deberán procesarse in_batches. Creo que empezaría haciéndolo de forma síncrona, con un spinner de carga en la interfaz de usuario. De esa manera, los administradores podrán ver claramente cuándo se está ejecutando o cuándo ha terminado.
Si vemos que se acerca a los 30 segundos (el tiempo de espera de la solicitud de unicorn), entonces quizás tengamos que pensar en un trabajo en segundo plano.
También podríamos necesitar pensar en agregar algún bloqueo DistributedMutex aquí. Por ejemplo, ¿qué sucede si un usuario inicia sesión mientras se está procesando un cambio en group_associated_group? Estoy encantado de discutir este tipo de cosas en GitHub una vez que finalicemos la arquitectura general.
La razón por la que no puedes solicitar permisos de grupo en la primera solicitud es que no sabes quién está iniciando sesión ni qué está dispuesto a compartir. Podrías restringir la asignación de grupos asociados a Google mediante el ajuste google_oauth2_hd, pero esto limitaría bastante el alcance de la función. Es relativamente común tener un equipo que utiliza Google Apps junto con usuarios «públicos» que también desean usar la autenticación de Google.
*edición: debo aclarar que, si solicitas un ámbito de grupos y el usuario no puede concederlo (por ejemplo, su HD no ha delegado autoridad en usuarios no administradores, como se describió anteriormente), la autenticación fallará. No puedes solicitar ámbitos opcionales junto con ámbitos obligatorios.
Además, ese enfoque, es decir, solicitar un ámbito de grupos de entrada como práctica estándar al implementarlo en los diversos métodos de autenticación, sería, en cierto modo, más específico de Google que la alternativa, ya que no siempre tienes el equivalente al sistema de dominio alojado para restringir el inicio de sesión. Por ejemplo, podría estar equivocado, pero no creo que exista una forma de restringir el inicio de sesión con Github OAuth2 a una organización específica de Github.
En otras palabras, en varios casos te quedarías con la opción de pedir a todos los que usan ese método de autenticación que concedan el ámbito groups relevante, o de no utilizar la función. Ese enfoque puede funcionar en algunos contextos, pero no en muchos. Este enfoque de autorización incremental ofrece a los diferentes métodos de autenticación más flexibilidad a la hora de implementar la función.
Es cierto que Google ha estado impulsando la autorización incremental en el ámbito de OAuth2; por ejemplo, todos los documentos de trabajo sobre el tema han sido escritos por un empleado de Google:
Sin embargo, el concepto no es específico de Google (otras personas no necesariamente lo llaman «autorización incremental»). Es relativamente común en diferentes formas en aplicaciones móviles y está siendo adoptado en OAuth2 por otros proveedores. Por ejemplo, aquí están los documentos de Facebook sobre el mismo tema.
Probablemente ya estés familiarizado con el tema, pero se considera una «buena práctica»:
informar a las personas de que estás a punto de solicitar más permisos que la información básica estándar;
y quizás explicar por qué.
Si el usuario hace clic en «Registrarse con Facebook» en un formulario de inicio de sesión de Discourse y, además de su correo electrónico, también se le solicita acceso a sus grupos de Facebook, podría abandonar. Facebook lo expresa así:
Como regla general, cuanto más permisos solicite una aplicación, menos probable será que las personas utilicen Facebook para iniciar sesión en tu aplicación. De hecho, nuestra investigación muestra que las aplicaciones que solicitan más de cuatro permisos experimentan una caída significativa en el número de inicios de sesión completados.
Esto plantea la cuestión de si es buena idea solicitar ámbitos adicionales en el momento de la autenticación en primer lugar, y básicamente llegué a la conclusión de que realmente no tenemos otras buenas opciones. Existe la necesidad de tener acceso inmediato a los grupos en algunos escenarios (como mencionaste), y también está la realidad de que, si no se solicita de entrada, muchos usuarios no darían un paso adicional para autorizar sus grupos en un servicio, por ejemplo, en su perfil o en la página de grupos.
Debe hacerse en el momento de la autenticación, lo que nos lleva de nuevo al problema mencionado anteriormente y a por qué implementé un sistema de «autorización secundaria». En efecto, está diseñado para ser un sistema «ligero» en la medida en que es relativamente fácil que otro servicio, como Facebook o Github, implemente una solicitud de autorización secundaria para obtener acceso a los grupos del usuario después de que este se haya autenticado y, opcionalmente, haya superado cierta prueba relacionada con su información básica.
Cada proveedor solo necesita:
Devolver un resultado con secondary_authorization_url
Utilizar el parámetro state para detectar a qué solicitud de autorización está llegando el usuario
Proporcionar un omniauth_secondary_authorization_description para users/omniauth_callbacks/secondary_authorization.html.erb. Por ejemplo, este es el de Google, que el usuario ve antes de confirmar la redirección de autorización secundaria:
Como has iniciado sesión con un correo electrónico de %{domain}, necesitamos pedir permiso para ver tus grupos de %{domain}.
Ninguna de estas partes es específica de Google.
Lo que me gustaría hacer aquí es permitir que el usuario diga «no» a la solicitud secundaria y aun así autenticarse. En el escenario de Google Apps HD esto no es realmente un problema, ya que si su cuenta forma parte de un dominio alojado, es poco probable que quiera o pueda decir que no. Sin embargo, debería acomodarse para permitir toda la gama de escenarios de autenticación aquí, creo.
Finalmente, también cabe señalar que la autorización secundaria no es necesaria para que associated_groups funcione. Un proveedor de autenticación puede simplemente solicitar el ámbito de grupos de entrada y luego agregar los grupos al resultado de la autenticación después de recibir la primera respuesta. De hecho, probablemente deberíamos incluirlo como una opción en los plugins básicos de oauth2 y openid connect.
Dominio del proveedor
Creo que debe haber alguna forma de identificador secundario en la tabla associated_groups que sea legible por el administrador del sitio. Hay varios escenarios en los que el nombre de un grupo por sí solo puede no ser suficiente. Existe la posibilidad de conflictos de nombres entre el concepto equivalente de cada servicio, por ejemplo:
gestión de grupos de Google con múltiples dominios (también puedes tener varios dominios en un mismo espacio de trabajo)
gestión de grupos de Github con múltiples organizaciones
gestión de roles de Discord con múltiples servidores
etc.
Podríamos cambiar domain por namespace. Podríamos incluirlo en el name del grupo, pero ¿nos daría alguna ventaja? Podría ser útil consultar por el «dominio» o el «namespace» en algún momento. Sí, quizás namespace sería mejor que domain.
La razón por la que debe ser «legible por el administrador» es que se utiliza en la etiqueta que ve el administrador en la interfaz de grupos, en parte para fines de desambiguación.
Estoy pensando si tiene sentido intentar almacenar también un provider_id aquí (si existe). Podría ser útil en el futuro.
Sí, estoy de acuerdo con todo esto, y gracias por los consejos. Voy a probar esta parte y podemos seguir discutiéndola en la PR.
@david Acabo de subir algunas actualizaciones en esto, incluyendo:
DistributedMutxes y in_batches en group_associated_group
Pruebas de aceptación (ya teníamos rspec)
Sin duda hará falta más trabajo, pero actualmente funciona según la especificación y todas las pruebas están pasando. Pruébalo y dime qué te parece y qué cambios te gustaría hacer.
¡Hola @angus! Tengo curiosidad por saber si has avanzado más en esto. Estoy muy interesado en el comportamiento simple “estricto”, según mi entendimiento, y dado que controlamos nuestro proveedor de Oauth2/OpenID Connect, no me preocupa el caso de “autorización secundaria”. ¿Existe alguna posibilidad de que algo así se implemente antes?
Si puede ser de ayuda, nuestro entorno está documentado aquí: Infrastructure/Authentication - Fedora Project Wiki, y he configurado Discourse para solicitar el ámbito oauth2 openid profile email https://id.fedoraproject.org/scope/groups.
Básicamente, todo lo que quiero es:
Dejar el nivel de confianza y los grupos de personal sin cambios
Agregar el usuario a cualquier grupo existente de Discourse en la lista provista por SSO que no esté ya en la lista
Eliminar al usuario de cualquier grupo en el que esté y que no se encuentre en la lista
Admito libremente que no entiendo todas las complejidades… ¿hay alguna complicación que no conozco?
¡Genial, muchas gracias! No quiero insistir, pero el soporte de Discourse sugirió que publicar en este tema sería la mejor manera de conocer el estado actual de las cosas.
Estoy entusiasmado con su trabajo en esto, porque hay mucho que podemos hacer con los sitios de Discourse de Fedora una vez que tengamos esto, algo que simplemente no podemos hacer ahora mismo.