Como você provavelmente pode imaginar, também estou ansioso para ver uma solução estável para esse problema, que não é específico ao plugin openid-connect. Vamos ver se conseguimos encontrar um caminho a seguir.
Para retomar o ponto que você levantou.
Como você decide a quais grupos adicionar e remover o usuário? E como isso afeta a adição/remoção manual de usuários de grupos no próprio Discourse?
um usuário se autentica via OIDC com os grupos ['group1', 'group2']
Na interface do Discourse, o usuário é adicionado ao group3
mais tarde, o mesmo usuário se autentica via OIDC com os grupos ['group1']
Analisando isso como um humano, podemos ver que o estado final deve ser group1, group3 (group2 deve ser removido). Mas não acho que haja estado suficiente sendo rastreado para tomar essa decisão programaticamente. Da mesma forma:
um usuário se autentica via OIDC com os grupos ['group1', 'group2']
Na interface do Discourse, o usuário é removido do group1
mais tarde, o mesmo usuário se autentica via OIDC com os grupos ['group1', 'group2']
Agora, o que deve acontecer? Um administrador removeu explicitamente o usuário do group1, mas o OIDC acabou de adicioná-lo de volta. Isso é uma UX muito confusa para o administrador. Talvez precisemos de alguma maneira de identificar grupos como ‘gerenciados externamente’ e ocultar toda a interface de adicionar/remover
Acho que há algumas maneiras de lidarmos com essa questão (elas não são mutuamente exclusivas).
Identificação de grupo e atributo do token
Em qualquer implementação, a identificação explícita de
quais grupos podem ter sua associação gerenciada via autenticação; e
quais atributos em um token de autenticação governam a associação a grupos
deve ser obrigatória, seja por meio de configurações do site, configurações de grupo ou de outra forma, e o padrão deve ser “desligado”.
Tratamento estrito ou permissivo
O tratamento é “estrito” se um usuário for removido quando o grupo estiver ausente no atributo do token identificado. O tratamento é “permissivo” se um usuário não for removido quando o grupo estiver ausente no atributo do token identificado.
Como você sugere, você pode desabilitar a adição/remoção de associação a grupos via administração de grupos se o tratamento for “estrito”.
Identificação da fonte de associação
Você também poderia armazenar a fonte da associação ao grupo na tabela group_users para permitir uma abordagem “mista” dentro de um grupo, ou seja, um administrador não pode remover associações criadas via token de autenticação.
Quanto mais penso nisso, mais acho que isso deve ser feito por meio de configurações de grupo.
Obrigado, @angus, por dar início a isso! Sei que muitas pessoas estão entusiasmadas com essa funcionalidade!
Interessante! Sempre imaginei que os grupos seriam criados automaticamente durante a autenticação e que o nome do grupo seria 1:1 com o nome do grupo no provedor de identidade. É assim que o DiscourseConnect funciona atualmente.
Mas, na verdade, gosto muito mais dessa opção mais explícita! Isso significa que as instâncias do Discourse das pessoas não ficarão poluídas por grupos desnecessários de seu provedor de identidade, e também significa que os administradores podem personalizar os nomes dos grupos conforme preferirem. Tem muita paridade com nossa membresia baseada em domínio de e-mail existente
Isso soa bem do ponto de vista técnico. Minha única preocupação é que possa ser difícil explicar para usuários/administradores. Se seguirmos sua ideia de “identificação explícita” de grupos gerenciados por autenticação, acho que poderíamos simplesmente implementar o tratamento “estrito”?
Quando um grupo for configurado para ser gerenciado por autenticação, a adição/remoção manual ficará oculta atrás de um grande aviso, e se comportará como o modo “estrito” que você descreveu.
O que acha disso?
Observação: também devemos garantir que toda adição/remoção automática de usuários seja registrada no log do grupo. Isso facilitará para todos entenderem o que está acontecendo e por quê.
Sim, acho que é melhor ser explícito, pelo menos na v1 deste conjunto de recursos. Ainda não encontrei nenhum caso de uso em que a criação automática tenha sido realmente necessária, ou seja, o grupo poderia simplesmente ser configurado e gerenciado pelo administrador do site antes de qualquer reivindicação ser processada.
Talvez pudéssemos migrar para a criação automática como uma opção após implementarmos a versão explícita?
Em termos de Configurações de Grupo, seria algo como:
Seção de Configurações: Membros (ou seja, a seção existente) Título do Grupo de Configurações: Gerenciamento de Autenticação Configurações:
Serviço: Lista de serviços de autenticação. “Todos” seria uma opção. Essa configuração também funcionaria como um estado “habilitado / desabilitado” para este conjunto de recursos. Ou seja, o padrão seria “Nenhum”.
Reivindicação: campo de texto para identificar a reivindicação do token de ID. A “descrição” para esse recurso (talvez em um post aqui no meta) explicaria os formatos suportados, como booleano, string delimitada por vírgula, etc.
Modo: ver abaixo
Sim, se houvesse uma configuração estrita/permitida, teríamos que explicá-la de forma concisa. Acho que a maneira de abordar isso seria focar em “adição” e “remoção”. Você poderia descrever algo assim:
Configuração: “Modo”
Opção 1 (permitida):
Rótulo: “Adicionar Membros”
Descrição: “Permitir que membros sejam adicionados a este grupo durante a autenticação”
Opção 2 (estrita):
Rótulo: “Adicionar e Remover Membros”
Descrição: “Permitir que membros sejam adicionados e removidos durante a autenticação. Isso desabilitará os controles manuais de associação.”
A razão pela qual estou ansioso para manter a opção “permitida” é que, ao trabalhar com clientes nesse tipo de coisa anteriormente, esse é o caso de uso mais comum, ou seja:
A principal necessidade é permitir o acesso a um grupo dependendo de um estado em um serviço externo
A necessidade de remover o acesso dependendo do estado no serviço externo é mais marginal, ou seja, as pessoas perdem o acesso e devem ser removidas, mas isso é relativamente menos importante
Frequentemente há o desejo de manter a capacidade de controlar manualmente a associação no Discourse. Quando implementei a abordagem “estrita”, isso foi “surpreendente” (ou seja, “Por que a pessoa X perdeu a associação?”) apesar das explicações e do funcionamento (tecnicamente) como deveria.
Sim, isso é importante, pois as pessoas frequentemente se perguntarão “por que” alguém foi adicionado ou removido, especialmente no modo estrito, e nós (ou seja, “Discourse”) não teremos controle sobre a veracidade das reivindicações feitas pelo serviço de autenticação externo.
Talvez um novo tipo de ação “Remover Usuário” e “Adicionar Usuário” que inclua o serviço de autenticação responsável pela ação, ou seja, “Remover Usuário ([nome do serviço])”.
Outro ‘pulo do gato’ aqui é que precisaremos deixar claro que isso não é uma solução mágica para o caso de uso de ‘quero que as participações de um grupo sejam baseadas no serviço externo X’, pois as pessoas não se autenticam com tanta frequência, ou pelo menos, de acordo com as necessidades do caso de uso padrão desse tipo.
Isso (gerenciamento de autenticação) é uma parte necessária para lidar com esse tipo de caso de uso, mas para atendê-lo adequadamente, você também precisa configurar integrações baseadas em eventos, por exemplo, um receptor de webhook (temos um plugin privado de receptor de webhook projetado para gerenciamento de grupos que espero tornar de código aberto em breve).
Esse é um trabalho valioso que vocês estão fazendo aqui!
Apenas como uma comparação de funcionalidades, achei que valeria a pena compartilhar o que fazemos na Global Legal Empowerment Network, que usa WordPress e o plugin Discourse para WordPress. Configuramos para que, sempre que um usuário for atualizado no WordPress, a atualização seja refletida no Discourse. Isso inclui alguns grupos especiais (por exemplo, membro principal, contribuidor de recursos, etc.), além de detalhes do perfil. Adicionamos um campo oculto de usuário chamado “última atualização”, o que ajudou na solução de problemas e na confirmação de que tudo estava funcionando corretamente.
Bloqueamos esses grupos gerenciados remotamente, de modo que os usuários não possam entrar ou sair deles no Discourse, mas não vimos necessidade de impedir que a equipe gerencie a participação nesses grupos. Gosto da aparência do que vocês estão tentando acima, mas, para ser sincero, está um pouco além do meu alcance.
Temos alguns clientes do Discourse for Teams que usam o Okta ativamente para gerenciar o acesso a todos os aplicativos de suas empresas. Eles também configuram funções lá, que são então suportadas, por exemplo, para fornecer certos níveis de acesso ao Microsoft Tableau, etc. O Okta também é um diretório, então eles gerenciam avatares de usuário, biografia, localização e outras informações do perfil. Eles gostariam de ver essas informações de perfil atualizadas no Teams externamente ao Okta também.
Devemos tentar manter as coisas super técnicas fora das configurações do grupo, se possível. Ter que vincular à documentação de sintaxe provavelmente significa que isso deve ser simplificado ou relegado às configurações do site de administração. Acredito que devemos deixar essa parte a cargo de cada plugin de autenticação para implementar, pois pode variar muito.
Tomando o OIDC como exemplo, esse plugin adicionaria uma nova configuração de site chamada openid_connect_roles_claim. Se estiver usando o Okta, o administrador configuraria isso como groups. Acredito que um array de strings seja um formato bastante padrão para OIDC, mas poderíamos explorar opções mais complexas aqui se realmente necessário.
Para receber essas informações, o Auth::Result receberia um novo atributo roles, que aceita um array simples de strings. O núcleo então pegaria isso (em Auth::Result#apply_user_attributes!) e o carregaria em uma nova tabela UserAssociatedRoles com as colunas (provider_name, user_id, role). Essa tabela UserAssociatedRoles nos fornece a “identificação da fonte de associação” que você mencionou no OP.
Imagino que as configurações do grupo se pareçam com algo assim:
Os nomes dos roles seriam prefixados com o provider_name. O preenchimento automático seria baseado em todos os valores existentes na tabela UserAssociatedRoles, mas também aceitaríamos valores que não foram preenchidos automaticamente, caso o role ainda não tenha sido visto pelo Discourse.
A beleza de ter uma tabela completa user_associated_roles no banco de dados é que os administradores podem fazer o que quiserem com os grupos do Discourse, e as associações serão atualizadas instantaneamente, sem que os usuários precisem fazer login novamente.
Isso é justo. Acredito que seria melhor manter isso o mais simples possível, pelo menos para a v1, então prefiro não ter múltiplos “modos”. Que tal termos isso como o comportamento padrão:
Adicionar membros quando eles tiverem um role correspondente do provedor de autenticação
Remover membros quando esse role desaparecer
Permitir adicionar/remover também no Discourse
Se um administrador tentar remover um usuário que foi adicionado via um provedor de autenticação, mostrar um aviso: “este usuário pode ser adicionado novamente na próxima vez que fizer login”
Acredito que devemos tentar ser seguros por padrão aqui e remover membros quando eles perderem o role no provedor de identidade. Com as melhorias no log de associações, espero que seja menos confuso do que o status quo atual.
Para sites que realmente não querem isso, poderíamos ter uma configuração de site como remove_group_membership_when_auth_role_lost (padrão: true).
Sim, com certeza. Também temos esse problema com outros metadados de usuário, como nome, avatar, etc. Acredito que em algum momento próximo precisaremos examinar a criação de um equivalente ao sync_sso para outros plugins de autenticação. Isso poderia receber todas as informações normalmente passadas via OIDC / SAML / etc., incluindo essas novas informações de “role”. Provavelmente seria um projeto separado, no entanto.
Como isso tudo soa para você, @angus? É um pouco menos flexível do que modos separados estrito/permissivo, mas acredito que ter apenas um modo tornará a solução de problemas, a documentação e o suporte muito mais fáceis.
Com esse plano, aqui está uma visão de alto nível de como isso se parece da perspectiva de um administrador:
No Discourse, defina openid_connect_roles_claim como groups
Configurando um novo grupo
Crie um grupo no Discourse normalmente. Configure o nome, nome completo, flair, etc., como desejar
Vá para as preferências de “associação”, coloque o cursor na lista suspensa de roles SSO e escolha um role da lista. Se o Discourse ainda não tiver visto alguém fazer login com aquele role, você terá que inseri-lo manualmente
Você pode especificar múltiplos roles para um único grupo do Discourse. Por exemplo, um grupo “equipe” no Discourse poderia ser uma combinação de oidc:employees e oidc:contractors
Pressione salvar e a associação do grupo será atualizada instantaneamente com as informações de role que o Discourse armazenou em cache a partir de logins anteriores.
Em logins futuros, quaisquer alterações nos roles do provedor de identidade serão refletidas no grupo do Discourse
Você ainda pode adicionar/remover usuários ao grupo na interface nativa do Discourse
Se tentar remover um usuário que foi adicionado via um provedor de identidade, um aviso será exibido informando que o usuário pode ser re-adicionado no próximo login
Se mais tarde você decidir que não quer que esse role do IDP esteja associado ao grupo, poderá removê-lo, e todos os usuários que eram membros via aquele role serão removidos
Sim, entendo, no entanto, existem casos em que suportar uma claim booleana faz sentido. Mas sim, concordo, vamos manter simples por enquanto, suportando apenas um array de strings.
Fazendo isso autenticador por autenticador, imagino que também teríamos um método group_sync_enabled? em Auth::Authenticator, que seria sobrescrito nos autenticadores individuais e, nos autenticadores genéricos, com base na existência de um valor na configuração relevante.
Isso, na verdade, levanta uma questão interessante. Isso também poderia ser usado pelos autenticadores de serviço específicos, como Facebook (“groups”?), Google (“groups”?) e Discord (“roles”). Não tenho certeza se seus tokens de ID conteriam essas informações, mas talvez valha a pena considerar do ponto de vista do design técnico (ou seja, a capacidade de adicionar isso no futuro). Não é uma preocupação primária para a v1, creio eu.
Esses mecanismos parecem bons, no entanto, estou curioso sobre por que mudamos para usar “roles” em vez de “groups” aqui. Não é um grande problema, mas quero ter certeza de que não estou perdendo algo.
Do ponto de vista da UX, consigo ver confusão surgindo desse uso de nomenclatura (ou seja, “roles” e “groups” ao mesmo tempo), mesmo que seja fundamentado em uma distinção técnica útil. Também é possível haver confusão de desenvolvedores se chegarem a isso sem esse contexto de fundo.
Gosto da tabela separada, no entanto, talvez devêssemos ter uma associação de chave estrangeira com user_associated_accounts em vez de provider_name? Poderia ser útil em coisas como operações de limpeza. Acho que a resposta para essa pergunta depende parcialmente de quanto queremos que a associação grupo/role esteja interligada com a conta associada do ponto de vista do produto. Haveria alguma desvantagem em vincular os dois agora?
** Edição, acho que já temos a associação via user_id.
Isso parece bom, no entanto, estou pensando que também temos essas informações por provedor, em virtude da configuração de site que você propôs, o que também cobriria o caso em que a função ainda não foi vista. Talvez haja uma maneira de usar Discourse.authenticators aqui, ou seja, uma lista em memória de provedores e suas claims?
Acho que é um bom compromisso. Especialmente se também tivermos a configuração de site mencionada abaixo.
Em base de plugin (ou seja, autenticador)? Se for assim, estou de acordo. Isso deve atender a essa necessidade para a v1.
Bom resumo do fluxo do usuário Pendentes as sugestões relativamente menores que fiz, estou de acordo com a direção.
Sim, com certeza. Estava pensando especialmente no Google, já que as pessoas gostam de usá-lo para suas organizações do GSuite, que, suponho, tenham algum conceito de grupos.
Acho que eu estava tentando evitar qualquer confusão entre “Grupos do Provedor de Identidade” e “Grupos do Discourse”… mas é possível que eu tenha apenas tornado as coisas mais confusas ao mudar o nome. Fico muito feliz em manter “grupos” aqui.
Minha ideia era que ainda suportamos provedores de autenticação não gerenciados, então pode não haver um registro de user_associated_account. Ainda podemos fazer o join nele via user_id, como você disse
Não tenho certeza se a configuração do site ajudaria aqui. Se estivermos falando de um array de strings representando “funções”, a configuração do site não especificaria quais são as funções. Ela apenas especificaria como obter o array. Faz sentido?
Sim, você tem razão. Eu ainda estava pensando em uma implementação anterior em que eu havia incluído grupos específicos na própria configuração, mas não estamos fazendo isso aqui, o que está ótimo.
Acho que há informações suficientes aqui para começar a trabalhar na PR, que vou iniciar mais tarde esta semana, a menos que você tenha alguma preocupação remanescente? Vou atualizar aqui se surgir algo no caminho.
Ok, finalmente tenho um trabalho em andamento para compartilhar aqui
Algumas observações.
Optei pelo caso um pouco mais complexo de grupos do Google Apps HD para a implementação inicial, pois acredito que isso ajuda a pensar nas possíveis permutações disso, como a necessidade de considerar grupos específicos de domínio de um provedor.
Para implementar esse caso de uso, também precisei introduzir um novo conceito de “autorização secundária” no momento da autenticação, para permitir autorização incremental. Considerei algumas maneiras diferentes de implementar a solicitação de permissões de grupo de usuários específicos (ou seja, se eles estivessem autenticando com um HD), e essa parecia ser a mais viável. Agradeço que isso talvez seja uma mudança maior nessa frente do que o antecipado, mas vale a pena discutir.
Observe que, para implementar o caso de grupos do Google HD, você precisa conceder aos membros não administradores dos seus grupos do Google Apps HD autoridade de administrador delegada para listar seus grupos (via a API de diretório de administração). Na verdade, há um papel de administrador pré-construído “beta” chamado “Leitor de Grupos” que funciona bem para isso. Veja Prebuilt administrator roles | User management | Google Workspace Help
A implementação do Google funciona. Se você configurá-la e depois autenticar com um HD, seus grupos do Google HD estarão disponíveis na configuração de associação automática de grupos; você será adicionado a esse grupo do Discourse se esse grupo do HD for selecionado, removido se for removido (com ambas as ações registradas com certa especificidade), e usuários subsequentes nesse grupo do Google HD que autenticarem serão adicionados imediatamente.
Os detalhes devem ser evidentes a partir do código e dos testes. Você também notará que acabei adicionando três novas tabelas. Tentei algumas soluções mais “leves”, mas cada uma acabou sendo mais complicada e ineficiente ao lidar com atualizações nos grupos associados de um usuário e nos grupos associados de um grupo. É difícil evitar simplesmente criar novas tabelas para cada caso. Estou aberto a ideias sobre modelagem de dados, no entanto, e de forma mais geral.
Algumas tarefas técnicas pendentes (além das questões conceituais/de produto levantadas acima). Sugestões também são bem-vindas nesse aspecto:
Talvez serializar o label de associated_groups (em vez de modelar no cliente).
Adicionar testes e qunits faltantes.
Talvez mover a criação/destruição de user_associated_group / group_associated_group para um job em segundo plano, pois com grandes números isso pode ser lento.
Estou um pouco hesitante quanto à questão da “autorização secundária” e também à coluna provider_domain. Você poderia elaborar um pouco mais sobre por que elas são necessárias? Parece que são bastante específicas do Google… há algum motivo para não podermos solicitar o escopo admin.directory.group.readonly durante a primeira solicitação de autenticação? E talvez apenas prefixar o nome do grupo com o domínio? (ou excluir o domínio por completo, já que presumo que as pessoas usarão isso apenas com um único domínio “hospedado” do Google?)
Sim, estou totalmente de acordo com as 3 tabelas aqui — isso mantém as coisas mais limpas.
Concordo
Precisamos ter cuidado aqui. Quaisquer associações de grupo precisam ser atribuídas antes de o usuário carregar o site pela primeira vez. Caso contrário, eles não verão itens específicos do grupo na primeira vez que fizerem login (por exemplo, categorias seguras). Então, acho que alterações nos registros de user_associated_group devem ser processadas de forma síncrona.
Mas para alterações nos registros de group_associated_group, acho que você está certo. Alterações ali podem afetar milhares de usuários, então elas precisarão ser processadas in_batches. Acho que começaria fazendo isso de forma síncrona, com um spinner de carregamento na interface. Assim, os administradores poderão ver claramente quando está em execução/concluído.
Se virmos que está se aproximando de 30 segundos (o tempo limite de solicitação do unicorn), talvez precisemos pensar em uma tarefa em segundo plano.
Também podemos precisar pensar em adicionar algum bloqueio com DistributedMutex aqui. Por exemplo, se um usuário fizer login enquanto uma alteração de group_associated_group estiver sendo processada, o que acontece? Estou aberto a discutir esse tipo de coisa no GitHub assim que finalizarmos a arquitetura geral.
Para o meu caso de uso, ficaria perfeitamente satisfeito se o comportamento do Discourse Connect fosse implementado para outros provedores de autenticação.
A razão pela qual você não pode solicitar permissões de grupo na primeira solicitação é que você não sabe quem está fazendo login ou com o que essa pessoa se sente confortável em compartilhar. Você poderia restringir o mapeamento de grupos associados ao Google para pessoas que usam a configuração google_oauth2_hd; no entanto, isso limitaria bastante o escopo do recurso. Ter uma equipe que usa o Google Apps, além de usuários “públicos” que também desejam usar a autenticação do Google, é relativamente comum.
*edição: devo esclarecer que, se você solicitar um escopo de grupos e o usuário não puder concedê-lo (por exemplo, se o HD dele não tiver delegado autoridade a usuários não administradores, conforme descrito acima), a autenticação falhará. Você não pode solicitar escopos opcionais junto com escopos obrigatórios.
Além disso, essa abordagem, ou seja, solicitar um escopo de grupos de imediato como prática padrão ao implementar isso em vários métodos de autenticação, seria, argumentavelmente, mais específica do Google do que a alternativa, pois você nem sempre tem o equivalente ao sistema de domínio hospedado para restringir o login. Por exemplo, posso estar errado, mas não acho que exista uma maneira de restringir o login via Github OAuth2 a uma organização específica do Github.
Em outras palavras, em vários casos, você ficaria com a escolha de pedir a todos que usam esse método de autenticação que concedam o escopo relevante de groups, ou não usar o recurso. Essa abordagem pode funcionar em alguns contextos, mas não em muitos. Essa abordagem de autorização incremental oferece mais flexibilidade a diferentes métodos de autenticação na implementação do recurso.
É verdade que o Google tem sido um defensor da autorização incremental no espaço OAuth2; por exemplo, todos os documentos de trabalho sobre o assunto foram escritos por um funcionário do Google.
No entanto, o conceito não é específico do Google (outras pessoas nem sempre chamam de “autorização incremental”). É relativamente comum em diferentes formas em aplicativos móveis e está sendo adotado no OAuth2 por outros provedores. Por exemplo, veja a documentação do Facebook sobre o mesmo assunto.
Você provavelmente já está familiarizado com o campo, mas é considerado “boa prática”:
informar as pessoas de que você está prestes a solicitar mais permissões do que as informações básicas padrão;
e talvez explicar o porquê.
Se o usuário clicou em “Cadastrar com Facebook” em um formulário de login do Discourse e, além do e-mail, também foi solicitado acesso aos grupos do Facebook, ele pode desistir. O Facebook resume assim:
Como regra geral, quanto mais permissões um aplicativo solicita, menos provável é que as pessoas usem o Facebook para fazer login no seu aplicativo. Na verdade, nossas pesquisas mostram que aplicativos que solicitam mais de quatro permissões experimentam uma queda significativa no número de logins concluídos.
Isso levanta a questão de saber se é uma boa ideia solicitar escopos adicionais no momento da autenticação em primeiro lugar e, basicamente, concluí que não temos realmente nenhuma outra boa opção. Há a necessidade de ter acesso imediato a grupos em alguns cenários (como você aludiu) e também a realidade de que, sem ser solicitado de imediato, muitos usuários não dariam um passo adicional para autorizar seus grupos em um serviço, digamos, em seu perfil ou na página de grupos.
Isso deve ser feito no momento da autenticação, o que nos traz de volta à questão mencionada acima e ao motivo pelo qual implementei um sistema de “autorização secundária”. Ele realmente é destinado a ser um “sistema” leve, na medida em que é relativamente fácil para outro serviço, como Facebook ou Github, implementar uma solicitação de autorização secundária para obter acesso aos grupos do usuário após a autenticação e, opcionalmente, passar por um determinado teste relacionado às informações básicas.
Cada provedor precisa apenas:
Retornar um resultado com secondary_authorization_url;
Usar o parâmetro state para detectar em qual solicitação de autorização o usuário está;
Fornecer um omniauth_secondary_authorization_description para users/omniauth_callbacks/secondary_authorization.html.erb. Por exemplo, este é o do Google, que o usuário vê antes de confirmar o redirecionamento da autorização secundária:
Como você fez login com um e-mail de %{domain}, precisamos pedir permissão para visualizar seus grupos de %{domain}.
Nenhuma dessas partes é específica do Google.
O que eu gostaria de fazer aqui é permitir que o usuário diga “não” à solicitação secundária e ainda assim se autentique. No cenário do Google Apps HD, isso não é realmente um problema, pois, se a conta dele fizer parte de um domínio hospedado, é improvável que ele queira ou esteja em posição de dizer não. No entanto, deve ser acomodado para permitir toda a gama de cenários de autenticação aqui, acho.
Por fim, também deve ser notado que a autorização secundária não é obrigatória para que associated_groups funcione. Um provedor de autenticação pode simplesmente solicitar o escopo de grupos de imediato e, em seguida, adicionar os grupos ao resultado da autenticação após receber a primeira resposta. De fato, provavelmente deveríamos incluir isso como uma opção nos plugins básicos oauth2 e openid connect.
Domínio do provedor
Acho que realmente precisa haver alguma forma de identificador secundário na tabela associated_groups que seja legível pelo administrador do site. Existem vários cenários nos quais o nome do grupo, por si só, pode não ser suficiente. Há a possibilidade de conflitos de nome entre o conceito equivalente de cada serviço, por exemplo:
gerenciamento de grupos do Google com múltiplos domínios (você também pode ter vários domínios em um único workspace);
gerenciamento de grupos do Github com múltiplas organizações;
gerenciamento de funções do Discord com múltiplos servidores;
etc.
Poderíamos mudar domain para namespace, talvez. Poderíamos incluí-lo no name do grupo, mas isso nos traria alguma vantagem? Pode ser útil consultar por “domínio” ou “namespace” em algum momento. Sim, talvez namespace fosse melhor do que domain.
O motivo pelo qual precisa ser “legível pelo administrador” é que é usado no rótulo visto pelo administrador na interface de grupos, em parte para fins de desambiguação.
Estou ponderando se faz sentido tentar armazenar também um provider_id aqui (se existir). Poderia ser útil no futuro, talvez.
Sim, concordo com tudo isso e obrigado pelas dicas. Vou tentar essa parte e podemos discutir mais sobre isso na PR.
@david Acabei de enviar algumas atualizações aqui, incluindo:
DistributedMutxes e in_batches em group_associated_group
Testes de aceitação (já tínhamos rspec)
Sem dúvida, ainda precisará de mais trabalho, mas atualmente está funcionando conforme a especificação e todos os testes estão passando. Dê uma testada, me diga o que achou e quais mudanças gostaria de ver.
Olá @angus! Estou curioso se você teve algum progresso adicional nisso? Estou muito interessado no comportamento simples de “strict”, conforme entendi, e como controlamos nosso provedor OAuth2/OpenID Connect, não me preocupo com o caso de “autorização secundária”. Há alguma chance de algo assim ser implementado mais cedo?
Se for de alguma ajuda, nosso ambiente está documentado aqui: Infrastructure/Authentication - Fedora Project Wiki, e configurei o Discourse para solicitar o escopo OAuth2 openid profile email https://id.fedoraproject.org/scope/groups.
Basicamente, tudo o que quero é:
Manter os níveis de confiança e grupos de equipe inalterados
Adicionar o usuário a quaisquer grupos existentes do Discourse na lista fornecida pelo SSO, caso ele ainda não esteja neles
Remover o usuário de quaisquer grupos em que ele esteja, mas que não estejam na lista
Eu admito livremente que não entendo todas as complexidades… há alguma complicação que eu não estou percebendo?
Ótimo — muito obrigado. Não quero ser chato, mas o suporte do Discourse sugeriu que postar neste tópico seria a melhor maneira de ver o estado atual das coisas.
Estou animado com o seu trabalho nisso, porque há muito o que podemos fazer com os sites do Fedora no Discourse assim que tivermos isso, algo que simplesmente não conseguimos fazer agora!