DiscourseConnect è una funzionalità fondamentale di Discourse che ti consente di configurare l’“Autenticazione Singola (SSO)” per delegare completamente a un altro sito la registrazione e l’accesso degli utenti, rimuovendo queste operazioni da Discourse. Disponibile per i nostri clienti con hosting Pro, Business e Enterprise.
(Febbraio 2021) ‘Discourse SSO’ è ora ‘DiscourseConnect’. Se stai utilizzando una versione vecchia di Discourse, le impostazioni sotto saranno nominate
sso_...invece didiscourse_connect_...
Il problema
Molti siti che desiderano integrarsi con un sito Discourse vogliono mantenere tutta la registrazione degli utenti su un sito separato. In una configurazione del genere, tutte le operazioni di accesso devono essere delegate a quel diverso sito.
Cosa succede se desidero l’SSO insieme all’autenticazione esistente?
L’intenzione di DiscourseConnect è sostituire l’autenticazione di Discourse. Se desideri aggiungere un nuovo provider, consulta i plugin esistenti come: Discourse VK Authentication (vkontakte)
Abilitare DiscourseConnect
Per abilitare DiscourseConnect devi compilare tre impostazioni:
enable_discourse_connect: deve essere abilitato, interruttore globale
discourse_connect_url: l’URL esterno a cui gli utenti verranno reindirizzati quando tenteranno di accedere
discourse_connect_secret: una stringa segreta utilizzata per hashare i payload SSO. Garantisce che i payload siano autentici.
Una volta impostato enable_discourse_connect su true:
- Cliccando su accesso o avatar verrai reindirizzato a
/session/sso, che a sua volta reindirizzerà gli utenti adiscourse_connect_urlcon un payload firmato. - Gli utenti non potranno “cambiare la password”. Quel campo viene rimosso dal profilo utente.
- Gli utenti non potranno più utilizzare l’autenticazione di Discourse (nome utente/password, Google, ecc).
Cosa succede se lo attivi per errore?
Vedi: Log back in as admin after locking yourself out with read-only mode or an invalid SSO configuration
Implementare DiscourseConnect sul tuo sito
Discourse utilizza gli indirizzi email per mappare gli utenti esterni agli utenti di Discourse e assume che le email esterne siano sicure. SE NON VALIDI GLI INDIRIZZI EMAIL PRIMA DI INVIARLI A DISCOURSE, IL TUO SITO SARÀ ESTREMAMENTE VULNERABILE!
In alternativa, se insisti nell’invio di email non validate, ASSICURATI di impostare require_activation=true; questo costringerà tutte le email a essere validate da Discourse. CONSIGLIAMO ANCORA FORTEMENTE DI NON FARE QUESTO, quindi se procedi con questa impostazione abilitata, assumi un rischio sostanziale.
Discourse reindirizzerà i client a discourse_connect_url con un payload firmato: (supponiamo che discourse_connect_url sia https://somesite.com/sso)
Riceverai traffico in entrata con il seguente formato:
https://somesite.com/sso?sso=PAYLOAD&sig=SIG
Il payload è una stringa codificata in Base64 composta da un nonce e un return_sso_url. Il payload è sempre una stringa di query valida.
Ad esempio, se il nonce è ABCD, il raw_payload sarà:
nonce=ABCD&return_sso_url=https%3A%2F%2Fdiscourse_site%2Fsession%2Fsso_login, questo raw payload è codificato in base 64.
L’endpoint chiamato deve:
- Validare la firma: assicurarsi che l’HMAC-SHA256 del
PAYLOAD(utilizzandodiscourse_connect_secretcome chiave) sia uguale alsig(sigsarà codificato in esadecimale). - Eseguire l’autenticazione necessaria.
- Creare un nuovo payload codificato in URL contenente almeno nonce, email e external_id. Puoi anche fornire dati aggiuntivi; ecco un elenco di tutte le chiavi che Discourse comprenderà:
- nonce deve essere copiato dal payload di input
- email deve essere un indirizzo email verificato. Se l’indirizzo email non è stato verificato, imposta require_activation su “true”.
- external_id è qualsiasi stringa unica per l’utente che non cambierà mai, anche se la sua email, il nome, ecc. cambiano. Il valore suggerito è il numero di riga ‘id’ del tuo database.
- username diventerà il nome utente su Discourse se l’utente è nuovo o se
SiteSetting.auth_overrides_usernameè impostato. - name diventerà il nome completo su Discourse se l’utente è nuovo o se
SiteSetting.auth_overrides_nameè impostato. - avatar_url verrà scaricato e impostato come avatar dell’utente se l’utente è nuovo o se
SiteSetting.discourse_connect_overrides_avatarè impostato. - avatar_force_update è un campo booleano. Se impostato su true, costringerà Discourse ad aggiornare l’avatar dell’utente, indipendentemente dal fatto che
avatar_urlsia cambiato o meno. - bio diventerà il contenuto della biografia dell’utente se l’utente è nuovo, la sua biografia è vuota o
SiteSetting.discourse_connect_overrides_bioè impostato. - title imposterà il titolo dell’utente.
- website imposterà il sito web dell’utente nel suo profilo.
- location imposterà la posizione dell’utente nel suo profilo.
- profile_background_url verrà scaricato e impostato come sfondo del profilo dell’utente se l’utente è nuovo o se
SiteSetting.discourse_connect_overrides_profile_backgroundè impostato. - card_background_url verrà scaricato e impostato come sfondo della scheda dell’utente se l’utente è nuovo o se
SiteSetting.discourse_connect_overrides_card_backgroundè impostato. - locale imposterà la localizzazione dell’utente se l’utente è nuovo e
SiteSetting.allow_user_localeè abilitato. - locale_force_update è un campo booleano. Se impostato su true insieme a locale, costringerà l’aggiornamento della localizzazione per gli utenti esistenti (richiede
SiteSetting.allow_user_locale). - I campi booleani aggiuntivi (“true” o “false”) sono: admin, moderator, suppress_welcome_message, logout
- Codificare il payload in Base64.
- Calcolare un hash HMAC-SHA256 del payload utilizzando
discourse_connect_secretcome chiave e il payload codificato in Base64 come testo. - Reindirizzare indietro a
return_sso_urlcon un parametro di queryssoesig(http://discourse_site/session/sso_login?sso=payload&sig=sig).
Discourse validerà che il nonce sia valido e, se valido, lo farà scadere immediatamente in modo che non possa essere riutilizzato. Successivamente, tenterà di:
- Effettuare l’accesso dell’utente cercando un external_id già associato nel modello
SingleSignOnRecord. - Effettuare l’accesso dell’utente utilizzando l’email fornita (aggiornando external_id) (a meno che require_activation = true).
- Creare un nuovo account per l’utente fornendo (email, username, name) e aggiornando external_id.
Preoccupazioni sulla sicurezza
Il nonce (token monouso) scadrà automaticamente dopo 30 minuti. Ciò significa che non appena l’utente viene reindirizzato al tuo sito, ha 30 minuti per accedere o creare un nuovo account.
Il protocollo è sicuro contro gli attacchi di replay poiché il nonce può essere utilizzato solo una volta. Il nonce è legato alla sessione corrente del browser per proteggere dagli attacchi CSRF.
Specificare l’iscrizione ai gruppi
Se è specificata l’opzione discourse connect overrides groups, Discourse prenderà in considerazione l’elenco separato da virgola di gruppi passati in groups.
Oltre a groups, puoi anche specificare l’iscrizione ai gruppi nel tuo payload SSO utilizzando gli attributi add_groups e remove_groups, indipendentemente dall’opzione discourse connect overrides groups.
add_groups è un elenco separato da virgola di nomi di gruppi di cui ci assicureremo che l’utente sia membro.
remove_groups è un elenco separato da virgola di nomi di gruppi di cui ci assicureremo che l’utente non sia membro.
Implementazione di riferimento
Discourse contiene un’implementazione di riferimento della classe SSO:
Un’implementazione banale sarebbe:
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 univoco per ogni utente della tua applicazione
sso.sso_secret = secret
redirect_to sso.to_url("http://l.discourse/session/sso_login")
end
end
Transizione verso e dall’autenticazione singola.
Finché il parametro require_activation non è impostato su true nel payload della richiesta, il sistema si fida delle email fornite dall’endpoint SSO. Ciò significa che se in passato avevi un account esistente su Discourse con DiscourseConnect disabilitato, DiscourseConnect lo riutilizzerà semplicemente evitando di creare un nuovo account.
Se disattivi DiscourseConnect, gli utenti potranno reimpostare le password e riaccedere ai loro account.
Esempio reale:
Dati i seguenti impostazioni:
Dominio Discourse: http://discuss.example.com
URL DiscourseConnect: http://www.example.com/discourse/sso
Segreto DiscourseConnect: d836444a9e4084d5b224a60c208dce14
Email validata: No (aggiungi require_activation=true al payload)
Tentativo di accesso dell’utente
-
Viene generato un nonce:
cb68251eefb5211e58c00ff1395f0c0b -
Viene generato il raw payload:
nonce=cb68251eefb5211e58c00ff1395f0c0b -
Il payload viene codificato in Base64:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI= -
Il payload viene codificato in URL:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D -
Viene generato un HMAC-SHA256 sul payload codificato in Base64:
1ce1494f94484b6f6a092be9b15ccc1cdafb1f8460a3838fbb0e0883c4390471
Infine, il browser viene reindirizzato a:
http://www.example.com/discourse/sso?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D&sig=1ce1494f94484b6f6a092be9b15ccc1cdafb1f8460a3838fbb0e0883c4390471
All’altra estremità
- Il payload viene validato utilizzando HMAC-SHA256; se la firma non corrisponde, il processo si interrompe.
- Invertendo i passaggi sopra, viene estratto il nonce.
L’utente accede:
name: sam
external_id: hello123
email: test@test.com
username: samsam
require_activation: true
Viene generato un payload non firmato:
nonce=cb68251eefb5211e58c00ff1395f0c0b&name=sam&username=samsam&email=test%40test.com&external_id=hello123&require_activation=true
L’ordine non importa, i valori sono codificati in URL
Il payload viene codificato in Base64:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ==
Il payload viene codificato in URL:
bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ%3D%3D
Il payload codificato in Base64 viene firmato:
3d7e5ac755a87ae3ccf90272644ed2207984db03cf020377c8b92ff51be3abc3
Il browser viene reindirizzato a:
http://discuss.example.com/session/sso_login?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1zYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRlcm5hbF9pZD1oZWxsbzEyMyZyZXF1aXJlX2FjdGl2YXRpb249dHJ1ZQ%3D%3D&sig=3d7e5ac755a87ae3ccf90272644ed2207984db03cf020377c8b92ff51be3abc3
Sincronizzazione dei record DiscourseConnect
Puoi utilizzare l’endpoint admin POST /admin/users/sync_sso per sincronizzare un record DiscourseConnect; passagli lo stesso record che invieresti all’endpoint DiscourseConnect, il nonce non importa.
Se chiami admin/users/sync_sso da un altro sito, dovrai includere una api_key admin valida e un api_username valido negli header della richiesta. Vedi Sync DiscourseConnect user data with the sync_sso route per ulteriori dettagli su come strutturare la richiesta.
Pulizia dei record DiscourseConnect
Se i valori external_id dal tuo provider DiscourseConnect sono cambiati (magari hai cambiato l’algoritmo di generazione, oppure è un endpoint diverso), puoi rimuovere in sicurezza tutti i record esistenti utilizzando la console rails:
SingleSignOnRecord.destroy_all
Disconnessione degli utenti
Puoi utilizzare l’endpoint admin POST /admin/users/{USER_ID}/log_out per disconnettere qualsiasi utente nel sistema, se necessario.
Per configurare l’endpoint a cui Discourse reindirizza alla disconnessione, cerca l’impostazione logout redirect. Se nessun URL è stato impostato qui, verrai reindirizzato all’URL configurato in discourse connect url.
Ricerca utenti per external_id
I dati del profilo utente possono essere accessibili utilizzando l’endpoint /users/by-external/{EXTERNAL_ID}.json. Questo restituirà un payload JSON contenente le informazioni dell’utente, incluso l’user_id che può essere utilizzato con l’endpoint log_out.
Implementazioni esistenti
-
Il gem
discourse_apipuò essere utilizzato per l’SSO. Dai un’occhiata al codice SSO nella sua directory examples per vedere un’implementazione di base. -
Il nostro plugin WordPress rende facile configurare l’SSO tra WordPress e Discourse. I dettagli sulla configurazione si trovano nella scheda SSO della pagina delle opzioni del plugin.
Lavori futuri
- Vorremmo raccogliere più implementazioni di riferimento per l’SSO su altre piattaforme. Se ne hai una, pubblica nella categoria Dev / SSO.
Funzionalità avanzate
- Puoi passare campi utente personalizzati anteponendo il nome del campo con
custom. Ad esempio,custom.user_field_1può essere utilizzato per impostare il valore diUserCustomFieldcon il nomeuser_field_1. - Puoi passare
avatar_urlper sovrascrivere l’avatar dell’utente (è necessario abilitareSiteSetting.discourse_connect_overrides_avatar). Gli avatar vengono memorizzati nella cache, quindi passaavatar_force_update=trueper forzare l’aggiornamento se l’URL è lo stesso. Al momento, non puoi passare un URL vuoto per disabilitare l’avatar degli utenti. - Di default, il messaggio di benvenuto verrà inviato a tutti i nuovi utenti creati tramite SSO. Se desideri sopprimerlo, puoi passare
suppress_welcome_message=true. - Per configurare la tua istanza Discourse come provider Discourse Connect, vedi: Utilizzare DiscourseConnect come provider di identità.
Debug del provider DiscourseConnect
Per协助 nel debug di DiscourseConnect, puoi abilitare l’impostazione del sito verbose_discourse_connect_logging. Abilitando tale impostazione, diagnostica dettagliata apparirà in TUOSITO.com/logs. Assicurati di
la casella warnings in fondo a TUOSITO.com/logs.
Registreremo un avviso nei log con un dump completo del payload SSO:
-
Ogni volta che il processo DiscourseConnect viene avviato, registreremo un avviso nel log con un dump completo del payload DiscourseConnect.
-
Ogni volta che un utente non riesce a completare DiscourseConnect (a causa della scadenza del nonce o del blocco IP).
Hai bisogno di automatizzare le registrazioni degli utenti? Vedi Auto-provisioning user accounts when SSO is enabled


