DiscourseConnect é um recurso central do Discourse que permite configurar o “Single Sign-On (SSO)” para terceirizar completamente todo o registro e login de usuários do Discourse para outro site. Disponível para nossos clientes de hospedagem Pro, Business e Enterprise.
(Fev 2021) ‘Discourse SSO’ agora é ‘DiscourseConnect’. Se você estiver executando uma versão antiga do Discourse, as configurações abaixo serão nomeadas
sso_...em vez dediscourse_connect_...
O Problema
Muitos sites que desejam integrar-se a um site do Discourse querem manter todo o registro de usuários em um site separado. Nesse tipo de configuração, todas as operações de login devem ser terceirizadas para esse outro site.
E se eu quiser SSO em conjunto com autenticação existente?
A intenção do DiscourseConnect é substituir a autenticação do Discourse. Se você deseja adicionar um novo provedor, consulte plugins existentes, como: Discourse VK Authentication (vkontakte)
Habilitando o DiscourseConnect
Para habilitar o DiscourseConnect, você precisa preencher 3 configurações:
enable_discourse_connect: deve ser habilitado, interruptor global
discourse_connect_url: a URL externa para a qual os usuários serão redirecionados ao tentar fazer login
discourse_connect_secret: uma string secreta usada para hash de payloads SSO. Garante que os payloads sejam autênticos.
Uma vez que enable_discourse_connect seja definido como true:
- Clicar em login ou avatar redirecionará você para
/session/sso, que, por sua vez, redirecionará os usuários paradiscourse_connect_urlcom um payload assinado. - Os usuários não poderão “alterar a senha”. Esse campo é removido do perfil do usuário.
- Os usuários não poderão mais usar a autenticação do Discourse (nome de usuário/senha, Google, etc).
E se você marcá-lo por engano?
Veja: Log back in as admin after locking yourself out with read-only mode or an invalid SSO configuration
Implementando o DiscourseConnect no seu site
O Discourse usa e-mails para mapear usuários externos para usuários do Discourse e assume que os e-mails externos são seguros. SE VOCÊ NÃO VALIDAR ENDEREÇOS DE E-MAIL ANTES DE ENVIÁ-LOS PARA O DISCOURSE, SEU SITE SERÁ EXTREMAMENTE VULNERÁVEL!
Alternativamente, se você insistir em enviar e-mails não validados, CERTIFIQUE-SE de definir require_activation=true, o que forçará a validação de todos os e-mails pelo Discourse. AINDA RECOMENDAMOS FORTMENTE QUE VOCÊ NÃO FAÇA ISSO. Portanto, se você prosseguir com essa configuração habilitada, estará assumindo um risco substancial.
O Discourse redirecionará os clientes para discourse_connect_url com um payload assinado: (digamos que discourse_connect_url seja https://somesite.com/sso)
Você receberá tráfego de entrada com o seguinte:
https://somesite.com/sso?sso=PAYLOAD&sig=SIG
O payload é uma string codificada em Base64 composta por um nonce e um return_sso_url. O payload é sempre uma string de consulta válida.
Por exemplo, se o nonce for ABCD, o raw_payload será:
nonce=ABCD&return_sso_url=https%3A%2F%2Fdiscourse_site%2Fsession%2Fsso_login, esse raw payload é codificado em base 64.
O endpoint chamado deve:
- Validar a assinatura: garantir que o HMAC-SHA256 de
PAYLOAD(usandodiscourse_connect_secretcomo chave) seja igual aosig(sigserá codificado em hexadecimal). - Realizar qualquer autenticação necessária.
- Criar uma nova payload codificada em URL com pelo menos nonce, email e external_id. Você também pode fornecer alguns dados adicionais; aqui está uma lista de todas as chaves que o Discourse entenderá:
- nonce deve ser copiado do payload de entrada.
- email deve ser um endereço de e-mail verificado. Se o endereço de e-mail não foi verificado, defina require_activation como “true”.
- external_id é qualquer string exclusiva para o usuário que nunca mudará, mesmo que seu e-mail, nome, etc. mudem. O valor sugerido é o número da linha ‘id’ do seu banco de dados.
- username se tornará o nome de usuário no Discourse se o usuário for novo ou
SiteSetting.auth_overrides_usernameestiver definido. - name se tornará o nome completo no Discourse se o usuário for novo ou
SiteSetting.auth_overrides_nameestiver definido. - avatar_url será baixado e definido como o avatar do usuário se o usuário for novo ou
SiteSetting.discourse_connect_overrides_avatarestiver definido. - avatar_force_update é um campo booleano. Se definido como true, forçará o Discourse a atualizar o avatar do usuário, independentemente de
avatar_urlter mudado ou não. - bio se tornará o conteúdo da biografia do usuário se o usuário for novo, sua biografia estiver vazia ou
SiteSetting.discourse_connect_overrides_bioestiver definido. - title definirá o título do usuário.
- website definirá o site do usuário em seu perfil.
- location definirá a localização do usuário em seu perfil.
- profile_background_url será baixado e definido como o plano de fundo do perfil do usuário se o usuário for novo ou
SiteSetting.discourse_connect_overrides_profile_backgroundestiver definido. - card_background_url será baixado e definido como o plano de fundo do cartão do usuário se o usuário for novo ou
SiteSetting.discourse_connect_overrides_card_backgroundestiver definido. - locale definirá o locale do usuário se o usuário for novo e
SiteSetting.allow_user_localeestiver habilitado. - locale_force_update é um campo booleano. Se definido como true junto com locale, forçará a atualização do locale para usuários existentes (requer
SiteSetting.allow_user_locale). - Campos booleanos adicionais (“true” ou “false”) são: admin, moderator, suppress_welcome_message, logout
- Codificar o payload em Base64.
- Calcular um hash HMAC-SHA256 do payload usando
discourse_connect_secretcomo chave e o payload codificado em Base64 como texto. - Redirecionar de volta para o
return_sso_urlcom um parâmetro de consultassoesig(http://discourse_site/session/sso_login?sso=payload&sig=sig).
O Discourse validará que o nonce é válido e, se válido, expirará imediatamente para que não possa ser usado novamente. Em seguida, tentará:
- Fazer login no usuário procurando um external_id já associado no modelo
SingleSignOnRecord. - Fazer login no usuário usando o e-mail fornecido (atualizando external_id) (a menos que require_activation = true).
- Criar uma nova conta para o usuário fornecendo (email, username, name) e atualizando external_id.
Preocupações de segurança
O nonce (token de uso único) expirará automaticamente após 30 minutos. Isso significa que, assim que o usuário for redirecionado para seu site, ele terá 30 minutos para fazer login ou criar uma nova conta.
O protocolo é seguro contra ataques de replay, pois o nonce só pode ser usado uma vez. O nonce está vinculado à sessão atual do navegador para proteger contra ataques CSRF.
Especificando associação a grupos
Se a opção discourse connect overrides groups for especificada, o Discourse considerará a lista separada por vírgulas de grupos passada em groups.
Além de groups, você também pode especificar a associação a grupos em seu payload SSO usando os atributos add_groups e remove_groups, independentemente da opção discourse connect overrides groups.
add_groups é uma lista separada por vírgulas de nomes de grupos dos quais garantiremos que o usuário seja membro.
remove_groups é uma lista separada por vírgulas de nomes de grupos dos quais garantiremos que o usuário não seja membro.
Implementação de referência
O Discourse contém uma implementação de referência da classe SSO:
Uma implementação trivial seria:
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 usuário do seu aplicativo
sso.sso_secret = secret
redirect_to sso.to_url("http://l.discourse/session/sso_login")
end
end
Transição para e a partir do single sign-on.
Enquanto o parâmetro require_activation não estiver definido como true no payload da solicitação, o sistema confiará nos e-mails fornecidos pelo endpoint de single sign-on. Isso significa que, se você tiver uma conta existente no passado no Discourse com o DiscourseConnect desabilitado, o DiscourseConnect simplesmente a reutilizará e evitará criar uma nova conta.
Se você desabilitar o DiscourseConnect, os usuários poderão redefinir senhas e recuperar o acesso às suas contas.
Exemplo do mundo real:
Dadas as seguintes configurações:
Domínio do Discourse: http://discuss.example.com
URL do DiscourseConnect: http://www.example.com/discourse/sso
Segredo do DiscourseConnect: d836444a9e4084d5b224a60c208dce14
E-mail validado: Não (adicione require_activation=true ao payload)
Tentativa de login do usuário
-
Um nonce é gerado:
cb68251eefb5211e58c00ff1395f0c0b -
Um raw payload é gerado:
nonce=cb68251eefb5211e58c00ff1395f0c0b -
O payload é codificado em Base64:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI= -
O payload é codificado em URL:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D -
Um HMAC-SHA256 é gerado no payload codificado em Base64:
1ce1494f94484b6f6a092be9b15ccc1cdafb1f8460a3838fbb0e0883c4390471
Finalmente, o navegador é redirecionado para:
http://www.example.com/discourse/sso?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D&sig=1ce1494f94484b6f6a092be9b15ccc1cdafb1f8460a3838fbb0e0883c4390471
No outro extremo
- O payload é validado usando HMAC-SHA256; se a assinatura não corresponder, o processo é abortado.
- Revertendo as etapas acima, o nonce é extraído.
Usuário faz login:
name: sam
external_id: hello123
email: test@test.com
username: samsam
require_activation: true
Um payload sem assinatura é gerado:
nonce=cb68251eefb5211e58c00ff1395f0c0b&name=sam&username=samsam&email=test%40test.com&external_id=hello123&require_activation=true
a ordem não importa, os valores são codificados em URL
O payload é codificado em Base64:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ==
O payload é codificado em URL:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ%3D%3D
O payload codificado em Base64 é assinado:
3d7e5ac755a87ae3ccf90272644ed2207984db03cf020377c8b92ff51be3abc3
O navegador redireciona para:
http://discuss.example.com/session/sso_login?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ%3D%3D&sig=3d7e5ac755a87ae3ccf90272644ed2207984db03cf020377c8b92ff51be3abc3
Sincronizando registros do DiscourseConnect
Você pode usar o endpoint de administração POST /admin/users/sync_sso para sincronizar um registro do DiscourseConnect; passe a ele o mesmo registro que você passaria para o endpoint do DiscourseConnect; o nonce não importa.
Se você chamar admin/users/sync_sso de outro site, precisará incluir uma api_key de administrador válida e um api_username válido nos cabeçalhos da solicitação. Veja Sync DiscourseConnect user data with the sync_sso route para mais detalhes sobre como estruturar a solicitação.
Limpando registros do DiscourseConnect
Se seus valores de external_id do seu provedor DiscourseConnect mudaram (talvez você tenha alterado o algoritmo de geração, talvez seja um endpoint diferente), você pode remover com segurança todos os registros existentes usando o console do rails:
SingleSignOnRecord.destroy_all
Deslogando usuários
Você pode usar o endpoint de administração POST /admin/users/{USER_ID}/log_out para deslogar qualquer usuário no sistema, se necessário.
Para configurar o endpoint para o qual o Discourse redireciona ao fazer logout, pesquise pela configuração logout redirect. Se nenhuma URL tiver sido definida aqui, você será redirecionado de volta para a URL configurada em discourse connect url.
Pesquisar usuários por external_id
Os dados do perfil do usuário podem ser acessados usando o endpoint /users/by-external/{EXTERNAL_ID}.json. Isso retornará um payload JSON que contém as informações do usuário, incluindo o user_id, que pode ser usado com o endpoint log_out.
Implementações existentes
-
O gem
discourse_apipode ser usado para SSO. Veja o código SSO em seu diretório de exemplos para ver uma implementação básica. -
Nosso plugin WordPress facilita a configuração do SSO entre WordPress e Discourse. Detalhes sobre como configurá-lo são encontrados na aba SSO da página de opções do plugin.
Trabalhos futuros
- Gostaríamos de reunir mais implementações de referência para SSO em outras plataformas. Se você tiver uma, por favor, poste na categoria Dev / SSO.
Recursos Avançados
- Você pode passar campos de usuário personalizados prefixando o nome do campo com
custom. Por exemplo,custom.user_field_1pode ser usado para definir o valor doUserCustomFieldque tem o nomeuser_field_1. - Você pode passar
avatar_urlpara substituir o avatar do usuário (SiteSetting.discourse_connect_overrides_avatarprecisa estar habilitado). Avatares são armazenados em cache, então passeavatar_force_update=truepara forçar a atualização se a URL for a mesma. Atualmente, você não pode passar uma URL vazia para desabilitar o avatar do usuário. - Por padrão, a mensagem de boas-vindas será enviada a todos os novos usuários criados via SSO. Se desejar suprimir isso, você pode passar
suppress_welcome_message=true. - Para configurar sua instância do Discourse como um provedor DiscourseConnect, veja: Usando DiscourseConnect como provedor de identidade.
Depurando seu provedor DiscourseConnect
Para auxiliar na depuração do DiscourseConnect, você pode habilitar a configuração de site verbose_discourse_connect_logging. Ao habilitar essa configuração de site, diagnósticos detalhados aparecerão em YOURSITE.com/logs. Certifique-se de marcar a caixa de
warnings na parte inferior de YOURSITE.com/logs.
Registraremos um aviso nos logs com um dump completo do payload SSO:
-
Toda vez que o processo DiscourseConnect for iniciado, registraremos um aviso no log com um dump completo do payload DiscourseConnect.
-
Toda vez que um usuário falhar ao completar o DiscourseConnect (devido ao nonce expirado ou bloqueio de IP).
Precisa automatizar inscrições de usuários? Veja Auto-provisioning user accounts when SSO is enabled


