Use Discourse como provedor de identidade (SSO, DiscourseConnect)

Consegui usar isso para criar um sistema de vinculação de contas para o meu servidor do Minecraft! Pensei em compartilhar como ficou! Esta foi minha primeira vez trabalhando com Discourse SSO, então talvez eu tenha complicado tudo. No entanto, funciona, que é o principal.

4 curtidas

Olá, fiz tudo isso corretamente. mas quando o usuário não está logado no discourse, ele mostra um pop-up de login do usuário. quando preencho nome de usuário e senha, ele não me redireciona de volta para o return_url. você pode me ajudar?

Presumo que o nonce esteja lá para prevenir ataques de repetição. Li online que ataques de repetição não são possíveis com HTTPS, que é o que estou usando. Então, ainda preciso fazer o nonce? Pergunto porque não tenho certeza de onde armazená-lo. Faz sentido armazená-lo como um cookie seguro e em texto simples no navegador do usuário? e depois lê-lo do navegador junto com o payload de retorno?

Esta biblioteca, que está vinculada à postagem original GitHub - ArmedGuy/discourse_sso_node: npm package for Discourse SSO login features. não usa o nonce ao validar o usuário.

Sim, você ainda precisa validar o nonce porque ele impede o reuso de cargas úteis que o Discourse envia ao redirecionar usuários de volta para o seu site.

Por exemplo, digamos que seu site tenha algum conteúdo protegido por paywall que apenas membros do grupo subscribers no Discourse podem acessar e você usa o campo groups na carga útil que o Discourse envia para o seu site para exibir o conteúdo pago apenas para membros do grupo subscribers. Se você não validar o nonce, um usuário que não faz mais parte dos subscribers poderia usar uma carga útil antiga de quando ele era membro para fazer login no seu site e ver o conteúdo pago.

É melhor armazenar o nonce em um banco de dados com uma data de expiração curta e excluir o nonce do banco de dados assim que ele for usado. No entanto, se você não puder usar um banco de dados, poderá usar um cookie para armazenar o nonce, mas precisará fazer algumas etapas adicionais para evitar o reuso da carga útil:

  1. anexe uma data de expiração ao nonce quando você o gerar, por exemplo, 10 minutos a partir do momento atual
  2. assine todo o cookie (nonce + data de expiração) para impedir que os usuários modifiquem o nonce e/ou a data de expiração
  3. verifique a assinatura do cookie e certifique-se de que o nonce não expirou

Isso lhe dará proteção suficiente contra o reuso da carga útil. Tenha em mente que tecnicamente ainda é possível reutilizar uma carga útil, mas será limitada a uma janela de 10 minutos em vez de para sempre.

Uma solução mais simples que não precisa de um cookie é incluir a data de expiração em um campo personalizado na carga útil que você gera. Então, quando o Discourse redirecionar os usuários de volta para o seu site com uma carga útil, seus campos personalizados serão incluídos e você poderá recuperar a data de expiração e verificar se ela não expirou. Para incluir um campo personalizado na carga útil, você precisa incluir um campo prefixado com custom., então sua carga útil ficaria assim:

nonce=NONCE&return_sso_url=RETURN_URL&custom.expiration_date=TIMESTAMP
4 curtidas

Você também pode armazenar o nonce na sessão, o que impedirá que o usuário o manipule também.

3 curtidas

Voltando a este tópico anos depois

Alguém pode me dizer (@pfaffman ou @tobiaseigen ou @iamntz) o que o provedor Discourse SSO retorna? Eu sei que posso “tentar e ver”, mas seria bom ter isso documentado. O código de exemplo PHP do GitHub nem sequer menciona outros campos.

Idealmente, ele enviaria os mesmos campos que quando o Discourse usa o script externo para SSO, como ID externo, e-mail, nome de usuário, nome, foto de avatar, etc. Assim, podemos importar isso e criar um usuário do nosso lado!

Ele também informa o e-mail ao WordPress?

E quanto a grupos, distintivos, etc.? Podemos encontrar essas informações fazendo chamadas REST?

Finalmente, e quanto às mensagens privadas do usuário e outras coisas? Acho que se o Discord fosse um provedor oAuth e permitisse que nossos aplicativos consumissem essas coisas, seria incrível.

Ao tentar habilitar o Discourse Connect, recebo este erro:
enable_discourse_connect: Você não pode habilitar DiscourseConnect e convite apenas ao mesmo tempo.

Alguma ideia?

Vejo que você fez a mesma pergunta aqui: Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso) - #537. Se você está tentando configurar a configuração enable discourse connect e não a configuração enable discourse connect provider, o outro tópico é o lugar correto para fazer sua pergunta.

A configuração enable discourse connect provider é para quando você deseja usar seu site Discourse como o provedor de identidade para outro site. A configuração enable discourse connect é para quando você deseja fazer login de usuários no Discourse através de um site externo.

1 curtida

Implementei o procedimento em Python para um aplicativo Flask que estou construindo. Aqui está algum código boilerplate para quem precisar. As etapas descritas neste tópico foram bem simples de seguir, mas não sou um especialista em segurança, então se eu negligenciei algo, por favor, me avise!

2 curtidas

Estamos tentando implementar o Discourse como um provedor de SSO e o que não entendemos é como o Discourse sabe qual usuário precisa ser verificado? As instruções dizem: “Crie uma nova carga útil com nonce e url de retorno”. Mas quando você envia isso via fetch para o Discourse, como o Discourse sabe qual usuário verificar para ver se ele está logado? Desculpe se isso parece uma pergunta estúpida, mas eu simplesmente não consigo entender como isso está funcionando e trabalhei com muitos sistemas de autenticação ao longo dos anos, então estou um tanto familiarizado. O e-mail do usuário para o qual estamos tentando verificar o status de login precisa ser incluído na carga útil enviada ao Discourse? Se sim, qual é a estrutura exata da carga útil que precisa ser enviada ao Discourse? Se não, novamente, o que o Discourse está verificando exatamente? Minha suposição é que pedimos ao usuário seu e-mail em nosso sistema e, em seguida, enviamos a carga útil com o e-mail para o Discourse para ver se aquele usuário específico está logado, mas isso não é o que as instruções dizem, então estou totalmente confuso. Obrigado por qualquer ajuda.

Não se preocupe. Nós resolvemos isso. Pensamos que o URL do SSO precisava ser enviado como uma requisição POST para a instância do Discourse e então receber uma resposta. Agora vemos que isso é um redirecionamento para o Discourse, e então o Discourse redireciona de volta para o nosso site. Então, agora está claro o que fazer. Desculpe pelo post anterior.

3 curtidas

FYI/FWIW: Enviei um PR para permitir um parâmetro prompt=none na solicitação de autenticação. Semelhante a um recurso no protocolo OpenID Connect, isso permite que um consumidor SSO verifique se um usuário/cliente já está logado, sem enviá-los para uma caixa de diálogo de login caso não estejam.

O PR está aguardando uma revisão final por alguém da equipe do Discourse há cerca de 8 semanas; parece um tempo bastante longo do que eu esperaria. :crying_cat_face:

7 curtidas

Olá @mdoggydog - desculpe pela demora!

Acabei de revisar e mesclar o PR - obrigado pela contribuição! :raised_hands:

3 curtidas

Yay! Obrigado, @david.

Conforme prometido, acabei de atualizar o artigo da wiki aqui para incluir uma descrição do novo parâmetro (e do parâmetro logout anterior, e para corrigir alguns pequenos erros de digitação/gramática, e para adicionar uma seção de referências documentando a carga útil sso= como eu a entendo após ter pesquisado no código-fonte).

2 curtidas

Quero parar de usar nosso site como SSO para Discourse e, em vez disso, usar as ferramentas de login integradas do Discourse para limitar o acesso a certos materiais em nosso site.

Acho que a ferramenta certa a usar é: GitHub - discourse/discourse-auth-proxy: An http proxy that uses the DiscourseConnect protocol to authenticate users

Não encontrei instruções extensas sobre como usá-lo.

Posso instalá-lo na mesma droplet DigitalOcean do nosso site Discourse ou preciso hospedá-lo em outro lugar?

Editar: negrito na minha pergunta :slight_smile:

1 curtida

Alguma ajuda com a pergunta acima? Use Discourse as an identity provider (SSO, DiscourseConnect) - #148 by alehandrof

Estou definindo return_sso_url como uma URL que, por si só, tem um parâmetro de consulta:

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

O payload que envio para /session/sso_provider como parâmetro sso se parece com isto antes da codificação base64:

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

A URL para a qual o Discourse realmente redireciona após a autenticação é esta (com os parâmetros sso e sig abreviados):

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

O que me surpreende aqui é que a string de consulta que defini para return_sso_url parece ter sido decodificada por URL por algo, porque tem returnto=/ em vez de returnto=%2F. O valor de return_sso_url que encontro dentro de sso após decodificá-lo de base64 também tem uma barra em vez de %2F.

É isso que eu deveria esperar que acontecesse? (Se sim, por quê?) Isso é um bug no Discourse?

Qual é o motivo para a carga útil sso conter avatar_url em vez de avatar_template, como é retornado em /u/{username}.json e /session/current.json?

avatar_url não está presente para usuários que não definiram um avatar, enquanto avatar_template contém o caminho leter_avatar_proxy realmente usado no Discourse para exibir avatares para esses usuários, e avatar_url aponta para a imagem bruta do avatar em vez de uma dimensionada para o tamanho desejado para usuários que definiram um avatar.

Parece-me que avatar_template é o que qualquer pessoa que pretenda usar as informações de avatar contidas em sso desejará — mas que precisará fazer uma solicitação de API adicional para obtê-lo.

2 curtidas

No momento, estou implementando SSO no meu aplicativo, o login funciona muito bem até agora, o logout não.\n\nMinha Instância Discourse está redirecionando corretamente de volta para a URL de retorno sem nenhum parâmetro sso ou sig, mas quando abro o Discourse, minha conta ainda está logada.\n\n

\n\nAlguma ideia?

Estou assumindo que você está usando a configuração do site logout redirect do Discourse para redirecionar os usuários de volta para seu aplicativo após o logout do Discourse.
Uma causa possível para o problema seria se a configuração login required estiver habilitada em seu site Discourse. Quando essa configuração está habilitada, o Discourse redirecionará automaticamente usuários não autenticados para o site do provedor SSO se eles tiverem acessado diretamente o site do Discourse. Isso significa que, a menos que você esteja deslogando os usuários de seu aplicativo quando eles são redirecionados pela primeira vez para a URL logout redirect, eles serão automaticamente logados no Discourse na próxima vez que visitarem o site. Você pode confirmar esse comportamento passando pelo processo com o inspetor do seu navegador aberto na aba de rede.
Caso seja útil, veja como o plugin WP Discourse lida com o redirecionamento de logout do Discourse: wp-discourse/lib/sso-provider/discourse-sso.php at main · discourse/wp-discourse · GitHub.

2 curtidas