Gestione dell'adesione ai gruppi tramite autenticazione

@david Continuando la discussione da

Come puoi probabilmente immaginare, anch’io sono molto interessato a vedere una soluzione stabile a questo problema, che non è specifico del plugin openid-connect. Vediamo se possiamo trovare una strada da seguire.

Per riprendere il punto che hai sollevato.

Come decidi quali gruppi aggiungere o rimuovere dall’utente? E come ciò influisce sull’aggiunta o rimozione manuale degli utenti dai gruppi direttamente in Discourse?

  1. un utente si autentica tramite OIDC con i gruppi ['group1', 'group2']
  2. Nell’interfaccia utente di Discourse, l’utente viene aggiunto a group3
  3. successivamente, lo stesso utente si autentica tramite OIDC con i gruppi ['group1']

Osservando la situazione come esseri umani, possiamo vedere che lo stato finale dovrebbe essere group1, group3 (group2 dovrebbe essere rimosso). Ma non credo ci siano sufficienti dati di stato tracciati per prendere quella decisione in modo programmatico. Allo stesso modo:

  1. un utente si autentica tramite OIDC con i gruppi ['group1', 'group2']
  2. Nell’interfaccia utente di Discourse, l’utente viene rimosso da group1
  3. successivamente, lo stesso utente si autentica tramite OIDC con i gruppi ['group1', 'group2']

Ora cosa dovrebbe succedere? Un amministratore ha esplicitamente rimosso l’utente da group1, ma OIDC li ha appena aggiunti di nuovo. Questa è un’esperienza utente molto confusa per l’amministratore. Potremmo aver bisogno di un modo per identificare i gruppi come ‘gestiti esternamente’ e nascondere tutta l’interfaccia di aggiunta/rimozione :thinking:

Penso che ci siano alcuni modi in cui potremmo gestire questo problema (non si escludono a vicenda)

Identificazione dei gruppi e degli attributi del token

In qualsiasi implementazione, l’identificazione esplicita di

  1. quali gruppi possono avere la loro appartenenza gestita tramite autenticazione; e
  2. quali attributi in un token di autenticazione governano l’appartenenza ai gruppi

dovrebbe essere obbligatoria, sia che ciò avvenga tramite impostazioni del sito, impostazioni dei gruppi o altro, e l’impostazione predefinita dovrebbe essere “disattivata”.

Gestione rigorosa o permissiva

La gestione è “rigorosa” se un utente viene rimosso quando il gruppo è assente dall’attributo del token identificato. La gestione è “permissiva” se un utente non viene rimosso quando il gruppo è assente dall’attributo del token identificato.

Lo stato rigoroso/permissivo verrebbe impostato su base per gruppo. C’è un esempio di come potresti farlo in un’impostazione del sito qui: Handle groups by mattcg · Pull Request #7 · discourse/discourse-openid-connect · GitHub. Lo stesso approccio potrebbe essere realizzato tramite un’impostazione del gruppo.

Come suggerisci, potresti disabilitare l’aggiunta o la rimozione dell’appartenenza ai gruppi tramite l’amministratore dei gruppi se la gestione fosse “rigorosa”.

Identificazione della fonte dell’appartenenza

Potresti anche memorizzare la fonte dell’appartenenza al gruppo nella tabella group_users per consentire un approccio “misto” all’interno di un gruppo, ovvero un amministratore non può rimuovere le appartenenze create tramite token di autenticazione.

Più ci penso, più sono convinto che questo dovrebbe essere fatto tramite le impostazioni del gruppo.

11 Mi Piace

Grazie @angus per aver dato il via a questa discussione! So che molte persone sono molto interessate a questa funzionalità!

Interessante! Avevo sempre immaginato che i gruppi venissero creati automaticamente durante l’autenticazione e che il nome del gruppo corrispondesse 1:1 al nome del gruppo sul provider di identità. È così che funziona DiscourseConnect al momento.

Ma in realtà mi piace molto di più questa opzione più esplicita! Significa che le istanze di Discourse delle persone non saranno contaminate da gruppi non necessari provenienti dal loro provider di identità, e che gli amministratori possono personalizzare i nomi dei gruppi a loro piacimento. Ha molta affinità con la nostra attuale membership basata sul dominio email

Questo sembra buono dal punto di vista tecnico. La mia unica preoccupazione è che potrebbe essere difficile da spiegare agli utenti/amministratori. Se seguiamo la tua idea di ‘identificazione esplicita’ dei gruppi gestiti dall’autenticazione, penso che potremmo semplicemente implementare la gestione ‘rigorosa’?

Quando un gruppo è configurato come gestito dall’autenticazione, l’aggiunta/rimozione manuale è nascosta dietro un grande avviso e si comporta come la modalità ‘rigorosa’ che hai descritto.

Che ne pensi?

A parte: dovremmo anche assicurarci che tutte le aggiunte/rimozioni automatiche degli utenti vengano registrate nel log del gruppo. Questo renderà più facile per tutti capire cosa sta succedendo e perché.

7 Mi Piace

Sì, penso che sia meglio essere espliciti, almeno per la versione 1 di questa serie di funzionalità. Non ho ancora incontrato un caso d’uso in cui la creazione automatica fosse realmente necessaria, ovvero in cui il gruppo non potesse semplicemente essere configurato dall’amministratore del sito prima di gestire qualsiasi rivendicazione.

Forse potremmo passare alla creazione automatica come opzione dopo aver implementato la versione esplicita?

Per quanto riguarda le Impostazioni del Gruppo, sarebbe qualcosa del genere:

Sezione Impostazioni: Membri (ovvero la sezione esistente)
Titolo del Gruppo di Impostazioni: Gestione Autenticazione
Impostazioni:

  • Servizio: Elenco dei servizi di autenticazione. “Tutti” sarebbe un’opzione. Questa impostazione fungerebbe anche da stato “abilitato/disabilitato” per questa serie di funzionalità. Cioè, l’impostazione predefinita sarebbe “Nessuno”.
  • Rivendicazione (Claim): campo di testo per identificare la rivendicazione del token ID. La “descrizione” per questa funzionalità (forse in un post qui su Meta) spiegherebbe i formati supportati, ad esempio booleano, stringa delimitata da virgole, ecc.
  • Modalità: vedi sotto

Sì, se ci fosse un’impostazione rigorosa/permissiva dovremmo spiegarla in modo conciso. Penso che l’approccio migliore sia concentrarsi su “aggiunta” e “rimozione”. Potresti descriverla più o meno così:

Impostazione: “Modalità”

Opzione 1 (permissiva):

  • Etichetta: “Aggiungi Membri”
  • Descrizione: “Consenti l’aggiunta di membri a questo gruppo durante l’autenticazione”

Opzione 2 (rigorosa):

  • Etichetta: “Aggiungi e Rimuovi Membri”
  • Descrizione: “Consenti l’aggiunta e la rimozione di membri durante l’autenticazione. Questo disabiliterà i controlli manuali dell’iscrizione.”

Il motivo per cui tengo molto a mantenere l’opzione “permissiva” è che, lavorando in passato con clienti su questo tipo di cose, questo è il caso d’uso più comune, ovvero:

  • La necessità principale è consentire l’accesso a un gruppo in base a uno stato in un servizio esterno

  • La necessità di rimuovere l’accesso in base allo stato nel servizio esterno è più marginale, ovvero le persone perdono l’accesso e dovrebbero essere rimosse, ma questo è relativamente meno importante

  • Spesso c’è il desiderio di mantenere la possibilità di controllare manualmente l’iscrizione su Discourse. Quando ho implementato l’approccio “rigoroso”, questo è stato “sorprendente” (ovvero “Perché la persona X ha perso l’iscrizione?”) nonostante le spiegazioni e il funzionamento (tecnico) corretto.

Sì, è importante, poiché spesso ci si chiederà “perché” qualcuno è stato aggiunto o rimosso, specialmente in modalità rigorosa, e noi (cioè “Discourse”) non avremo il controllo sulla veridicità delle rivendicazioni fatte dal servizio di autenticazione esterno.

Forse un nuovo tipo di azione “Rimuovi Utente” e “Aggiungi Utente” che includa il servizio di autenticazione responsabile dell’azione, ovvero “Rimuovi Utente ([nome servizio])”.

3 Mi Piace

Un’altra “trappola” qui è che dovremo chiarire che questa non è una soluzione miracolosa per il caso d’uso “voglio che le appartenenze a un gruppo siano basate sul servizio esterno X”, poiché le persone non si autenticano frequentemente, o almeno non secondo le esigenze del caso d’uso standard di quel tipo.

Questa (gestione dell’autenticazione) è una parte necessaria per gestire quel tipo di caso d’uso, ma per servirlo adeguatamente è anche necessario configurare integrazioni basate su eventi, ad esempio un ricevitore webhook (abbiamo un plugin privato di ricezione webhook progettato per la gestione dei gruppi che spero di rendere open source entro breve tempo).

5 Mi Piace

@david Che ne pensi? Se preparassi una PR, saresti aperto a discuterne?

2 Mi Piace

Questo è un lavoro prezioso che state facendo qui! :sunflower:

Solo a titolo di confronto funzionale, volevo condividere cosa facciamo noi alla Global Legal Empowerment Network, che utilizza WordPress e il plugin Discourse per WordPress. Abbiamo configurato il sistema in modo che ogni volta che un utente viene aggiornato su WordPress, l’aggiornamento venga riflesso anche su Discourse. Questo include alcuni gruppi speciali (ad esempio, membro principale, contribuente alle risorse, ecc.) nonché i dettagli del profilo. Abbiamo aggiunto un campo utente nascosto per “ultima modifica”, che ci ha aiutato nella risoluzione dei problemi e nel verificare che tutto funzionasse correttamente.

Blocciamo quei gruppi gestiti da remoto in modo che gli utenti non possano unirsi o uscire da essi su Discourse, ma non abbiamo visto la necessità di impedire la gestione dell’iscrizione ai gruppi da parte dello staff. Mi piace l’aspetto di ciò che state cercando di fare, ma devo ammettere che va un po’ oltre le mie capacità.

Abbiamo alcuni clienti di Discourse for Teams che utilizzano attivamente Okta per gestire l’accesso a tutte le applicazioni aziendali. Lì configurano anche dei ruoli, che vengono poi supportati, ad esempio, per fornire determinati livelli di accesso a Microsoft Tableau, ecc. Okta funge anche da directory, quindi gestiscono avatar utente, biografia, posizione e altre informazioni di profilo. Vorrebbero vedere queste informazioni sul profilo aggiornate in Teams anche esternamente a Okta.

5 Mi Piace

Dovremmo cercare di mantenere il più possibile le funzionalità super-tecniche fuori dalle impostazioni del gruppo. Se è necessario collegarsi alla documentazione sulla sintassi, probabilmente significa che dovrebbe essere semplificata o relegata alle impostazioni del sito per gli amministratori. Penso che dovremmo lasciare questa parte a ciascun plugin di autenticazione da implementare, poiché può variare notevolmente.

Prendendo OIDC come esempio, quel plugin aggiungerebbe una nuova impostazione del sito openid_connect_roles_claim. Se si utilizza Okta, l’amministratore lo configurerebbe come groups. Penso che un array di stringhe sia un formato piuttosto standard per OIDC, ma potremmo esplorare opzioni più complesse qui se davvero necessario.

Per ricevere queste informazioni, Auth::Result riceverebbe un nuovo attributo roles, che accetta un semplice array di stringhe. Il core prenderà quindi questo (in Auth::Result#apply_user_attributes!) e lo caricherà in una nuova tabella UserAssociatedRoles con le colonne (provider_name, user_id, role). Questa tabella UserAssociatedRoles ci fornisce l’“identificazione della fonte di appartenenza” che hai menzionato nel post originale.

Immagino che le impostazioni del gruppo assomiglino a qualcosa del genere:

I nomi dei ruoli sarebbero preceduti dal provider_name. Il completamento automatico si baserebbe su tutti i valori esistenti nella tabella UserAssociatedRoles, ma accetteremmo anche valori non completati automaticamente nel caso in cui il ruolo non fosse ancora stato visto da Discourse.

La bellezza di avere una tabella completa user_associated_roles nel database è che gli amministratori possono fare ciò che vogliono con i gruppi di Discourse e le appartenenze verranno aggiornate istantaneamente senza che gli utenti debbano accedere nuovamente.

È giusto. Penso che sarebbe meglio mantenere tutto il più semplice possibile, almeno per la v1, quindi preferirei non avere più “modalità”. Che ne dici di avere questo come comportamento predefinito:

  • Aggiungi membri quando hanno un ruolo corrispondente dal provider di autenticazione
  • Rimuovi membri quando quel ruolo scompare
  • Consenti l’aggiunta/rimozione anche in Discourse
  • Se un amministratore tenta di rimuovere un utente che è stato aggiunto tramite un provider di autenticazione, mostra un avviso: “questo utente potrebbe essere aggiunto di nuovo la prossima volta che accede”

Penso che dovremmo cercare di essere sicuri per impostazione predefinita qui e rimuovere i membri quando perdono il ruolo sul provider di identità. Con i miglioramenti al registro delle appartenenze, spero che dovrebbe essere meno confuso rispetto allo status quo attuale.

Per i siti che non vogliono davvero questo, potremmo avere un’impostazione del sito come remove_group_membership_when_auth_role_lost (predefinito true).

Sì, certamente. Abbiamo anche questo problema con altri metadati utente come nome, avatar, ecc. Penso che a breve dovremo esaminare la possibilità di creare un equivalente di sync_sso per altri plugin di autenticazione. Potrebbe essere passata tutte le informazioni che normalmente vengono passate tramite OIDC / SAML / ecc., comprese queste nuove informazioni sui “ruoli”. Probabilmente un progetto separato, però.


Come ti sembra tutto questo @angus? È leggermente meno flessibile rispetto alle modalità separate rigorose/permissive, ma penso che avere una sola modalità renderà molto più semplice la risoluzione dei problemi / la documentazione / il supporto.


Con quel piano, ecco una visione d’insieme di come appare dal punto di vista di un amministratore:

Configurazione iniziale

  1. Configura l’autenticazione Okta e abilita il claim dei gruppi sul lato di Okta

  2. In Discourse, imposta openid_connect_roles_claim su groups

Configurazione di un nuovo gruppo

  1. Crea un gruppo Discourse come al solito. Configura nome/nome completo/flair/ecc. come preferisci

  2. Vai alle preferenze “appartenenza”, posiziona il cursore nel menu a tendina dei ruoli SSO e scegli un ruolo dal menu. Se Discourse non ha ancora visto qualcuno accedere con quel ruolo, dovrai inserirlo manualmente

    Puoi specificare più ruoli per un singolo gruppo Discourse. Ad esempio, un gruppo “team” in Discourse potrebbe essere una combinazione di oidc:employees e oidc:contractors

  3. Premi salva e l’appartenenza al gruppo verrà aggiornata istantaneamente con le informazioni sul ruolo che Discourse ha memorizzato nella cache dai precedenti accessi.

  4. Nei futuri accessi, eventuali modifiche ai ruoli del provider di identità verranno riflesse nel gruppo Discourse

  5. Puoi ancora aggiungere/rimuovere utenti dal gruppo nell’interfaccia nativa di Discourse

    • Se provi a rimuovere un utente che è stato aggiunto tramite un provider di identità, verrà mostrato un avviso che indica che l’utente potrebbe essere re-aggiunto al prossimo accesso
  6. Se in seguito decidi di non voler associare quel ruolo IDP al gruppo, puoi rimuoverlo e tutti gli utenti che erano membri tramite quel ruolo verranno rimossi

2 Mi Piace

Concordo.

Sì, però ci sono casi in cui ha senso supportare un claim booleano. Ma sì, concordo: teniamolo semplice per ora supportando solo un array di stringhe.

Facendolo autentificatore per autentificatore, immagino avremmo anche un metodo group_sync_enabled? in Auth::Authenticator, che verrebbe sovrascritto nei singoli autentificatori e, negli autentificatori generici, in base all’esistenza di un valore nell’impostazione rilevante.

Questo in realtà solleva una domanda interessante. Potrebbe essere utilizzato anche dagli specifici autentificatori di servizio, come Facebook (“groups”?), Google (“groups”?) e Discord (“roles”). Non sono sicuro che i loro token ID contengano tali informazioni, ma forse vale la pena considerarlo dal punto di vista del design tecnico (cioè la possibilità di aggiungerlo in futuro). Non credo sia una preoccupazione primaria per la v1.

Questi meccanismi sembrano corretti, però sono curioso del motivo per cui siamo passati dall’uso di “groups” a “roles” qui. Non è un grosso problema, ma voglio essere sicuro di non aver perso qualcosa.

Dal punto di vista dell’esperienza utente, vedo che potrebbe sorgere confusione dall’uso di questa nomenclatura (cioè “roles” e “groups” contemporaneamente), anche se è fondata su una distinzione tecnica utile. È anche possibile che ci sia confusione tra gli sviluppatori che si avvicinano a questo senza il contesto di fondo.

Mi piace la tabella separata, ma forse dovremmo avere un’associazione di chiave esterna con user_associated_accounts invece di provider_name? Potrebbe essere utile in operazioni come quelle di pulizia. Immagino che la risposta a questa domanda dipenda in parte da quanto vogliamo che l’associazione gruppo/ruolo sia interconnessa con l’account associato dal punto di vista del prodotto. Ci sarebbero degli svantaggi nel collegare i due ora?

** Modifica, immagino che abbiamo già l’associazione tramite user_id.

Sembra corretto, però sto pensando che abbiamo anche queste informazioni su base provider grazie all’impostazione del sito che hai proposto, che coprirebbe anche il caso in cui il ruolo non sia stato ancora visto. Forse c’è un modo per usare Discourse.authenticators qui, cioè un elenco in memoria dei provider e delle loro affermazioni?

Penso che sia un buon compromesso. Soprattutto se abbiamo anche l’impostazione del sito menzionata di seguito.

Su base plugin (cioè autentificatore)? Se è così, sono d’accordo. Dovrebbe soddisfare questa esigenza per la v1.

Buona sintesi del flusso utente :+1: In attesa dei suggerimenti relativamente minori che ho fatto, sono d’accordo con la direzione presa.

1 Mi Piace

:+1:

Sì, certo. Stavo pensando in particolare a Google, dato che le persone amano utilizzarlo per le loro organizzazioni GSuite, che presumo abbiano un concetto di gruppi.

Credo di aver cercato di evitare qualsiasi confusione tra “Gruppi del Provider di Identità” e “Gruppi di Discourse”… ma è possibile che cambiando il nome abbia solo reso le cose più confuse. Sono molto felice di attenermi a “gruppi” qui.

Il mio ragionamento era che supportiamo ancora provider di autenticazione non gestiti, quindi potrebbe non esserci un record user_associated_account. Possiamo comunque fare il join su di esso tramite user_id come hai detto :+1:

Non sono sicuro che l’impostazione del sito sia d’aiuto qui. Se stiamo parlando di un array di stringhe che rappresentano “ruoli”, l’impostazione del sito non specificherebbe quali sono effettivamente i ruoli. Specificherebbe solo come ottenere l’array. Ha senso?

Sembra ottimo :smiley:

1 Mi Piace

Sì, hai ragione. Stavo ancora pensando a un’implementazione precedente in cui avevo incluso gruppi specifici direttamente nell’impostazione, ma in questo caso non lo stiamo facendo, il che va bene.

Penso che ci siano sufficienti informazioni per iniziare a lavorare sulla PR, che inizierò più avanti questa settimana, a meno che tu non abbia altre preoccupazioni? Aggiornò qui se dovessero sorgere problemi durante il percorso.

Sembra ottimo: siamo felici di aiutarti con qualsiasi problema o domanda lungo il percorso :slight_smile:

2 Mi Piace

Ok, finalmente ho una versione in lavorazione da condividere qui

Alcune note.

Per l’implementazione iniziale ho scelto il caso leggermente più complesso dei gruppi hd di Google Apps, poiché ritengo che aiuti a considerare tutte le possibili combinazioni, ad esempio la necessità di gestire gruppi specifici di dominio provenienti da un provider.

Per implementare questo caso d’uso, ho dovuto introdurre un nuovo concetto di “autorizzazione secondaria” al momento dell’autenticazione, per consentire un’autorizzazione incrementale. Ho valutato diverse modalità per richiedere le autorizzazioni di gruppo specifiche di un utente (ovvero se si sta autenticando con un hd), e questa mi è sembrata la più fattibile. Riconosco che si tratta forse di un cambiamento più significativo del previsto in questo ambito, ma potrebbe valere la pena discuterne.

Si noti che per implementare il caso dei gruppi hd di Google è necessario concedere ai membri non amministratori dei gruppi hd di Google Apps l’autorità di amministratore delegato per elencare i propri gruppi (tramite l’API directory amministrativa). Esiste effettivamente un ruolo predefinito di amministratore “beta” chiamato “Lettore di gruppi” che funziona bene per questo scopo. Vedere Prebuilt administrator roles  |  User management  |  Google Workspace Help

L’implementazione di Google funziona. Se la configurate e poi vi autenticate con un hd, i vostri gruppi hd di Google saranno disponibili nelle impostazioni di appartenenza automatica ai gruppi; sarete aggiunti a quel gruppo Discourse se quel gruppo hd viene selezionato, rimossi se viene rimosso (entrambe le azioni vengono registrate con un certo grado di dettaglio) e gli utenti successivi in quel gruppo hd di Google che si autenticano verranno aggiunti immediatamente.

I dettagli dovrebbero essere evidenti dal codice e dai test. Noterete anche che ho finito per aggiungere tre nuove tabelle. Ho tentato alcune soluzioni più “leggere”, ma ciascuna si è rivelata più contorta e inefficiente quando si trattava di gestire gli aggiornamenti dei gruppi associati a un utente e dei gruppi associati a un gruppo. È difficile evitare di creare nuove tabelle per ciascuno. Sono aperto a idee sul fronte della modellazione dei dati, e più in generale.


Alcuni task tecnici rimasti (a parte le domande concettuali/di prodotto sollevate sopra). Anche su questo fronte sono benvenute le suggerimenti:

  • Forse serializzare l’attributo label di associated_groups (invece di modellarlo sul client).
  • Aggiungere i test mancanti e i qunit.
  • Forse spostare la creazione/distruzione di user_associated_group / group_associated_group in un job in background, poiché con un gran numero di elementi potrebbe essere lento.
3 Mi Piace

Questo sta venendo molto bello!

Sono un po’ esitante riguardo alla questione dell’“autorizzazione secondaria” e anche alla colonna provider_domain. Potresti spiegare meglio perché sono necessari? Sembra che siano piuttosto specifici di Google… c’è un motivo per cui non possiamo richiedere l’ambito admin.directory.group.readonly durante la prima richiesta di autenticazione? E magari anteporre semplicemente il nome del gruppo al dominio? (o escludere completamente il dominio, dato che presumo che le persone lo useranno solo con un singolo dominio ‘hosted’ di Google?)

Sì, sono assolutamente d’accordo con le 3 tabelle qui: mantiene tutto più pulito

Concordo :+1:

Dobbiamo fare attenzione qui. Qualsiasi appartenenza a gruppi deve essere assegnata prima che l’utente carichi il sito per la prima volta. Altrimenti, non vedrà le cose specifiche del gruppo al primo accesso (ad esempio, categorie sicure). Quindi penso che le modifiche ai record user_associated_group debbano essere elaborate in modo sincrono.

Ma per le modifiche ai record group_associated_group, penso che tu abbia ragione. Le modifiche lì potrebbero influenzare migliaia di utenti, quindi dovranno essere elaborate in_batches. Penso che inizierei facendolo in modo sincrono, con un indicatore di caricamento nell’interfaccia utente. In questo modo, gli amministratori potranno chiaramente vedere quando è in esecuzione/completato.

Se vediamo che ci si avvicina ai 30 secondi (il timeout della richiesta di unicorn), allora potremmo dover pensare a un job in background.

Potremmo anche dover pensare di aggiungere un blocco DistributedMutex qui. Ad esempio, se un utente accede mentre viene elaborata una modifica a group_associated_group, cosa succede? Sono felice di discutere questo tipo di cose su GitHub una volta che avremo finalizzato l’architettura complessiva.

Seguo l’argomento con interesse — e aggiungo questo come correlato: Does `sso overrides groups` work with Oauth2?

Per il mio caso d’uso, sarei perfettamente soddisfatto se il comportamento di Discourse Connect venisse implementato anche per altri provider di autenticazione.

2 Mi Piace

Ottimo :slight_smile: ci stiamo arrivando.

Affronterò ogni punto a turno.

Autorizzazione incrementale

Il motivo per cui non puoi richiedere le autorizzazioni per i gruppi nella prima richiesta è che non sai chi sta effettuando l’accesso o cosa è disposto a condividere. Potresti limitare la mappatura dei gruppi associati a Google alle persone che utilizzano l’impostazione google_oauth2_hd, tuttavia ciò limiterebbe notevolmente la portata della funzionalità. È relativamente comune avere un team che utilizza Google Apps insieme a utenti “pubblici” che desiderano anche utilizzare l’autenticazione Google.

*edit Dovrei chiarire che, se richiedi uno scope per i gruppi e l’utente non può concederlo (ad esempio, il suo HD non ha delegato l’autorità agli utenti non amministratori come descritto sopra), l’autenticazione fallirà. Non puoi richiedere scope opzionali insieme a scope obbligatori.

Inoltre, quell’approccio, ovvero richiedere uno scope per i gruppi in anticipo come pratica standard nell’implementazione di questa funzionalità nei vari metodi di autenticazione, sarebbe probabilmente più specifico di Google rispetto all’alternativa, poiché non hai sempre l’equivalente del sistema di hosted domain per limitare l’accesso. Ad esempio, potrei sbagliarmi, ma non credo esista un modo per limitare l’accesso tramite Github OAuth2 a una specifica organizzazione Github.

In altre parole, in molti casi ti troveresti con la scelta di chiedere a tutti coloro che utilizzano quel metodo di autenticazione di concedere lo scope groups pertinente o di non utilizzare la funzionalità. Tale approccio potrebbe funzionare in alcuni contesti, ma non in molti. Questo approccio di autorizzazione incrementale offre ai diversi metodi di autenticazione maggiore flessibilità nell’implementare la funzionalità.

È vero che Google ha sostenuto l’autorizzazione incrementale nello spazio OAuth2; ad esempio, tutti i documenti di lavoro sull’argomento sono stati scritti da un dipendente di Google.

Tuttavia, il concetto non è specifico di Google (altre persone non lo chiamano necessariamente “autorizzazione incrementale”). È relativamente comune in diverse forme nelle app mobili e sta venendo adottato in OAuth2 da altri provider. Ad esempio, ecco la documentazione di Facebook sullo stesso argomento.

Probabilmente sei già familiare con questo ambito, ma è considerato “buona pratica”

  • informare gli utenti che stai per chiedere più autorizzazioni rispetto alle informazioni di base standard;
  • e forse spiegare il motivo.

Se l’utente ha cliccato “Iscriviti con Facebook” in un modulo di accesso Discourse e, oltre alla sua email, gli è stato chiesto anche l’accesso ai suoi gruppi Facebook, potrebbe abbandonare. Facebook lo esprime così:

Come regola generale, più autorizzazioni richiede un’app, meno è probabile che le persone utilizzino Facebook per accedere alla tua app. In effetti, le nostre ricerche mostrano che le app che richiedono più di quattro autorizzazioni subiscono un calo significativo nel numero di accessi completati.

Questo pone la questione se sia una buona idea richiedere scope aggiuntivi al momento dell’autenticazione; fondamentalmente ho concluso che non abbiamo davvero altre buone opzioni. C’è la necessità di avere accesso immediato ai gruppi in alcuni scenari (come hai accennato), e c’è anche la realtà che, senza richiederlo in anticipo, molti utenti non compirebbero un’ulteriore azione per autorizzare i loro gruppi su un servizio, ad esempio nel loro profilo o nella pagina dei gruppi.

Deve essere fatto al momento dell’autenticazione, il che ci riporta al problema citato sopra e al motivo per cui ho implementato un sistema di “autorizzazione secondaria”. È effettivamente inteso come un “sistema” leggero, nella misura in cui è relativamente facile per un altro servizio, ad esempio Facebook o Github, implementare una richiesta di autorizzazione secondaria per ottenere l’accesso ai gruppi dell’utente dopo che si sono autenticati e, opzionalmente, superando un certo test relativo alle loro informazioni di base.

Ogni provider deve solo:

  • Restituire un risultato con secondary_authorization_url

  • Utilizzare il parametro state per rilevare a quale richiesta di autorizzazione l’utente sta arrivando

  • Fornire un omniauth_secondary_authorization_description per users/omniauth_callbacks/secondary_authorization.html.erb. Ad esempio, ecco quello per Google, che l’utente vede prima di confermare il reindirizzamento per l’autorizzazione secondaria:

    Poiché hai effettuato l'accesso con un'email di %{domain}, dobbiamo chiedere il permesso di visualizzare i tuoi gruppi %{domain}.

Nessuna di queste parti è specifica di Google.

Ciò che vorrei fare qui è permettere all’utente di dire “no” alla richiesta secondaria e autenticarsi comunque. Nello scenario Google Apps HD questo non è davvero un problema, poiché se il loro account fa parte di un hosted domain, è improbabile che vogliano o siano in grado di dire di no. Tuttavia, dovrebbe essere previsto per consentire l’intera gamma di scenari di autenticazione, penso.

Infine, va notato anche che l’autorizzazione secondaria non è obbligatoria per il funzionamento di associated_groups. Un provider di autenticazione può semplicemente richiedere lo scope per i gruppi in anticipo e poi aggiungere i gruppi al risultato dell’autenticazione dopo aver ricevuto la prima risposta. In effetti, dovremmo probabilmente integrarlo come opzione nei plugin oauth2 e openid connect di base.

Dominio del provider

Penso che ci debba essere una qualche forma di identificatore secondario nella tabella associated_groups leggibile dall’amministratore del sito. Ci sono diversi scenari in cui il nome del gruppo da solo potrebbe non essere sufficiente. C’è la possibilità di conflitti di nomi tra il concetto equivalente di ciascun servizio, ad esempio:

  1. gestione dei gruppi Google multi-dominio (puoi avere più domini in un unico workspace)
  2. gestione dei gruppi Github multi-organizzazione
  3. gestione dei ruoli Discord multi-server
    ecc.

Potremmo cambiare domain in namespace. Potremmo includerlo nel name del gruppo, ma ci darebbe qualche vantaggio? Potrebbe essere utile interrogare per “dominio” o “namespace” in qualche momento. Sì, forse namespace sarebbe meglio di domain.

Il motivo per cui deve essere “leggibile dall’amministratore” è che viene utilizzato nell’etichetta visibile all’amministratore nell’interfaccia utente dei gruppi, in parte per scopi di disambiguazione.

Sto valutando se abbia senso tentare di memorizzare anche un provider_id qui (se esiste). Potrebbe essere utile in futuro.

Sì, sono d’accordo con tutto questo e grazie per i consigli. Proverò a fare questa parte e ne discuteremo ulteriormente nella PR.

4 Mi Piace

@david Ho appena applicato alcuni aggiornamenti su questo, tra cui:

  • DistributedMutxes e in_batches in group_associated_group
  • Test di accettazione (avevamo già rspec)

Senza dubbio sarà necessario un ulteriore lavoro, ma al momento funziona secondo le specifiche e tutti i test sono superati. Prova a usarlo, fammi sapere cosa ne pensi e quali modifiche vorresti apportare.

5 Mi Piace

Forse vale la pena segnalarlo come non bozza per ora?

1 Mi Piace

Ciao @angus! Sono curioso di sapere se hai fatto ulteriori progressi su questo? Sono molto interessato al comportamento “strict” semplice, per come lo ho capito, e dato che controlliamo noi il nostro provider OAuth2/OpenID Connect, non mi preoccupa il caso della “autorizzazione secondaria”. C’è la possibilità che qualcosa del genere possa essere implementato prima?

Se può essere d’aiuto, il nostro ambiente è documentato qui: Infrastructure/Authentication - Fedora Project Wiki, e ho configurato Discourse per richiedere l’ambito OAuth2 openid profile email https://id.fedoraproject.org/scope/groups.

Fondamentalmente, ciò che voglio è:

  • Lasciare invariato il livello di fiducia e i gruppi dello staff
  • Aggiungere l’utente a eventuali gruppi Discourse esistenti nella lista proveniente dall’SSO, se non vi è già presente
  • Rimuovere l’utente da tutti i gruppi in cui si trova che non sono presenti nella lista

Ammetto liberamente di non comprendere tutte le sottigliezze… c’è una complicazione che non ho capito?

2 Mi Piace

Ho messo da parte del tempo questo weekend per lavorare su questo, Matt. Avrò un aggiornamento la prossima settimana, probabilmente sulla PR su GitHub.

2 Mi Piace

Fantastico, grazie mille. Non voglio essere insistente, ma il supporto di Discourse ha suggerito che pubblicare in questo argomento sia il modo migliore per conoscere lo stato attuale delle cose. :slight_smile:

Non vedo l’ora di vedere il tuo lavoro su questo, perché con i siti Discourse di Fedora avremo molte possibilità che al momento non abbiamo!

2 Mi Piace