Esporta (0) Stampa
Espandi tutto

Sviluppo di applicazioni Web multi-tenant con Azure AD

Aggiornamento: maggio 2014

noteNota
Questo esempio è obsoleto. La tecnologia, i metodi e/o le istruzioni dell'interfaccia utente sono stati sostituiti da nuove funzionalità. Per un esempio aggiornato che consente di creare un'applicazione simile, vedere WebApp-MultiTenant-OpenIdConnect-DotNet.

Nel primo documento della serie dedicata a Azure AD per sviluppatori è stato descritto come sfruttare il tenant di Azure AD per consentire agli utenti di usare funzionalità di accesso Web con applicazioni line-of-business, in locale e nel cloud. Leggere l'articolo Aggiunta del processo di accesso nell'applicazione Web tramite Microsoft Azure AD

Il secondo documento si basa sul primo e illustra come consentire all'app line-of-business di eseguire query sulle informazioni di directory tramite l'API Graph. Leggere l'articolo Uso dell'API Graph per effettuare query su Azure AD

Il presente documento consente di approfondire la conoscenza di Azure AD, descrivendo le modalità di sviluppo di applicazioni SaaS (Software-as-a-Service) progettate per essere usate con più tenant e per caricare automaticamente nuovi clienti, sfruttando nel contempo le funzionalità di Azure AD apprese nelle prime due fasi.

In termini di identità e di accesso, le sfide comuni che uno sviluppatore di app SaaS deve affrontare riguardano per la maggior parte il caricamento di clienti e l'accesso all'infrastruttura delle identità del cliente. Ogni cliente potenziale non solo dispone di una soluzione di accesso Web diversa, rendendo pertanto difficile la procedura per standardizzare un processo di caricamento che risulti semplice per il cliente e di facile gestione per l'app, ma gestisce anche i dati di identità e directory in un'infrastruttura cui le applicazioni cloud non possono accedere.

Azure AD fornisce una soluzione semplice per entrambi i problemi. Nel primo documento è stato illustrato il modo in cui l'amministratore può usare il portale di gestione di Azure per registrare le applicazioni sviluppate per accedere al tenant di directory. Questa procedura dettagliata dimostra che le stesse applicazioni possono essere configurate per essere accessibili anche da altri tenant di Azure AD. Azure AD offre un meccanismo tramite il quale le applicazioni stesse possono chiedere agli amministratori di clienti potenziali di concedere l'accesso ai relativi tenant di directory. A tale scopo, si può usare il portale di gestione di Azure AD per presentare all'amministratore del cliente un'interfaccia utente di consenso con un'esperienza simile a quella delle azioni di consenso usuali per tutte le applicazioni Web di social networking più comuni.

Il presente documento illustra come modificare in Azure AD la voce dell'app MVC 4 sviluppata nei primi due documenti al fine di rendere l'app disponibile a più tenant di Azure AD. Descrive inoltre in modo dettagliato le modifiche del codice da apportare all'app per passare da una soluzione per la connessione a un unico tenant a una soluzione multi-tenant completa in grado di caricare più organizzazioni del cliente. Nelle istruzioni della procedura dettagliata sono incluse spiegazioni di concetti di livello più alto necessari per comprendere il funzionamento di Azure AD anche oltre il ristretto ambito dell'applicazione di esempio descritta in questa sede.

Per riepilogare, le attività descritte in questo documento sono tutte successive rispetto alla soluzione sviluppata nei primi due documenti ed è pertanto necessario leggere prima questi ultimi e seguirne le istruzioni contenute prima di continuare con la lettura.

Questo documento è costituito dalle seguenti sezioni:

  • Prerequisiti: questa sezione elenca tutti i requisiti da soddisfare per completare la procedura dettagliata.

  • Architettura della soluzione: questa sezione fornisce un'introduzione approfondita su uno dei modi in cui un'applicazione SaaS può essere strutturata per sfruttare i vantaggi di Azure AD.

  • Alzare di livello la voce di applicazione in Azure AD per renderla disponibile all'esterno: questa sezione rivede la voce dell'applicazione line-of-business nel portale di Azure e illustra gli elementi da modificare per estendere la disponibilità dell'app esistente ai tenant di directory diversi da quelli di proprietà dell'utente.

  • Preparare il progetto dell'applicazione in Visual Studio per la gestione di più tenant: questa sezione illustra come modificare il codice sorgente dell'app MVC 4, destinata attualmente a eseguire l'accesso al Web e all'API Graph con un unico tenant di directory, per gestire un set dinamico di tenant di Azure AD. La sezione è divisa in più sottosezioni che descrivono aspetti diversi della gestione delle identità dell'app che devono essere generalizzati per il caso multi-tenant.

  • Aggiungere funzionalità di iscrizione all'applicazione: questa sezione illustra come modificare il codice sorgente dell'app MVC 4, destinata attualmente a eseguire l'accesso al Web e all'API Graph con un unico tenant di directory, per gestire un set dinamico di tenant di Azure AD. La sezione è divisa in più sottosezioni che descrivono aspetti diversi della gestione delle identità dell'app che devono essere generalizzati per il caso multi-tenant.

  • Facoltativo: Creare una sottoscrizione di test: la sottoscrizione Azure creata nella prima esercitazione contiene solo una directory, ovvero quella di proprietà dell'utente, ma per testare il funzionamento dell'app in uno scenario con carichi di lavoro multi-tenant si deve accedere a un tenant di Azure AD diverso dal proprio. Questa sezione descrive una strategia per ottenerne uno.

  • Testare l'applicazione: questa sezione illustra il modo in cui tutte le attività eseguite nella procedura dettagliata convergono per creare un'esperienza end-to-end coerente per l'applicazione SaaS.

Per completare l'esercitazione, verificare che siano soddisfatti i seguenti prerequisiti:

Architettura della soluzione per un'applicazione multi-tenant

Le applicazioni line-of-business tradizionali sono pensate per essere usate e gestite da utenti della stessa organizzazione che ha sviluppato e distribuito l'app in prima istanza. Le applicazioni aziendali di tipo SaaS, al contrario, vengono sviluppate e gestite da un fornitore di software indipendente e sono destinate a essere usate da organizzazioni di terze parti. Tali applicazioni vengono in genere compilate come risorse multi-tenant, ovvero un'applicazione viene condivisa da più organizzazioni clienti (tenant), in cui ogni tenant usa l'app come se ne fosse l'unico cliente.

Come indicato nella sezione delle informazioni generali, Azure AD consente di rendere disponibile un'applicazione line-of-business esistente ad altri amministratori di tenant di Azure AD (clienti potenziali) perché possano usarla nella propria organizzazione. All'amministratore del cliente potenziale sarà sufficiente accedere a un URL specifico e successivamente al proprio tenant di Azure AD. Dopo l'accesso, viene visualizzata una pagina di descrizione dell'app, del relativo autore e del livello di accesso richiesto sulla directory (SSO, SSO e accesso in sola lettura, SSO e accesso in lettura e scrittura). L'amministratore del cliente può usare i controlli presenti nella pagina per consentire all'applicazione di accedere alla directory di Azure dell'amministratore stesso, in questo caso l'app viene registrata automaticamente nel tenant di Azure AD del cliente senza dover eseguire altre operazioni.

L'applicazione MVC 4 creata nella procedura dettagliata sulle applicazioni line-of-business contiene riferimenti diretti al tenant di Azure AD configurato per l'integrazione. Questo significa che l'app è stata configurata in modo da reindirizzare ogni richiesta non autenticata all'indirizzo di accesso specifico del tenant e da accettare solo token provenienti da tale tenant. La maggior parte delle operazioni da eseguire in questa procedura dettagliata consiste nel generalizzare la logica di gestione delle identità dell'app, in modo che quest'ultima sia in grado di gestire l'accesso Web e le chiamate all'API Graph tramite uno qualsiasi dei tenant registrati del cliente. Un'altra importante area funzionale è costituita dall'aggiunta della possibilità di indirizzare clienti potenziali alla pagina di consenso descritta in precedenza e di elaborare i risultati per aumentare dinamicamente l'elenco di tenant di Azure AD accettati come autorità valide. A tale scopo, viene sfruttato il modello di estendibilità di Windows Identity Foundation (WIF) in alcune aree strategiche.

Il componente centrale dell'architettura dell'app modificata è costituito dalla classe MultiTenantIssuerNameRegistry (più avanti denominata MTINR) e dall'archivio permanente dei relativi tenant.

La classe MTINR gestisce un elenco di tutti i tenant di Azure AD che devono essere considerati origini di autenticazione valide. L'elenco include i seguenti elementi:

  • Elementi consultati al momento dell'accesso. Solo i token emessi da tenant registrati sono considerati validi.

  • Elementi aggiornati al momento dell'iscrizione. Quando un cliente potenziale consente all'app di accedere alla relativa directory, nel portale di gestione l'utente viene reindirizzato all'app con l'ID tenant associato. La procedura dettagliata descrive come elaborare questo messaggio a livello di codice per aggiungere il nuovo cliente all'elenco MTINR.

La classe MTINR gestisce inoltre la chiave da usare per verificare le firme sui token provenienti da Azure AD. Questo documento illustra come modificare la logica di aggiornamento automatizzato delle chiavi per garantire che l'app registri tutti gli eventi di distribuzione delle chiavi sul servizio e riduca il tempo di inattività.

L'aggiunta di un passaggio di iscrizione indica che l'app deve ora essere in grado di fornire un'interfaccia utente anche a utenti non autenticati. Si imparerà come modificare le impostazioni WIF per applicare requisiti di accesso Web in modo selettivo sui controller anziché usare i criteri di protezione generici descritti nella procedura dettagliata relativa alle applicazioni line-of-business.

Il primo passo consiste nell'indicare ad Azure AD che si desidera rendere l'applicazione disponibile ad altri tenant. A tale scopo, si devono modificare le impostazioni dell'applicazione nel portale di gestione di Azure.

Accedere al portale di gestione di Azure con lo stesso account usato per eseguire le procedure dettagliate sull'applicazione line-of-business e sull'API Graph. Passare alla scheda Active Directory, selezionare la propria directory, fare clic sull'intestazione Applicazioni, quindi sulla voce creata nell'esercitazione sull'applicazione line-of-business dopo averla individuata.

Viene visualizzata la stessa pagina Avvio rapido mostrata al termine del processo di registrazione. Fare clic sull'intestazione Configura.

noteNota
Se durante l'ultima procedura dettagliata è stata selezionata la casella "Ignora Avvio rapido alla visita successiva", viene visualizzata direttamente la schermata Configura.

Accesso esterno

A metà della pagina è presente un interruttore denominato Accesso esterno

la cui posizione predefinita è di disattivazione perché al momento della creazione le applicazioni sono configurate per essere accessibili solo dagli utenti dello stesso tenant di Azure AD in cui sono state create.

Se si attiva l'accesso esterno, si consente ad altri tenant di effettuare il provisioning dell'applicazione nelle proprie directory. Concretamente, questo significa che in Azure AD viene attivato l'URL di consenso dei clienti che può essere usato da altri amministratori di tenant per concedere all'applicazione l'autorizzazione di accedere alle loro directory. La concessione dell'autorizzazione da parte degli amministratori attiva il provisioning nei relativi tenant di Azure AD di una voce che descrive l'applicazione nonché l'impostazione dei parametri dell'app (URI ID APP, URL APP, chiavi usate per accedere all'API Graph e così via) nella pagina corrispondente.

ImportantImportante
L'abilitazione dell'accesso esterno per un'applicazione non modifica alcuna delle autorizzazioni esistenti di cui l'applicazione dispone già nel tenant di Azure AD dell'utente. Tenere presente inoltre che la disabilitazione dell'accesso esterno per un'applicazione non influisce sui livelli di accesso già concessi all'applicazione stessa nei tenant dell'utente o di altri quando era disponibile. In altre parole, questo interruttore influisce solo sull'esperienza correlata al consenso e sul meccanismo di provisioning associato per i clienti esterni e non sulle voci di applicazione che ha contribuito a creare.

Fare clic sull'opzione di attivazione dell'interruttore. Il colore del pulsante diventa viola e sulla barra dei comandi nella parte inferiore della schermata viene visualizzato un pulsante Salva. Se si prova a fare clic sul pulsante Salva, l'operazione ha esito negativo, ma è importante acquisire familiarità con il messaggio di errore risultante.

Aggiornamento configurazione non riuscito

L'operazione di aggiornamento non è riuscita. Fare clic sull'icona Dettagli per risolvere il problema.

Dettagli errore

Il messaggio indica che il formato dell'URI ID APP non è valido per l'operazione.

Poiché le applicazioni disponibili all'esterno saranno accessibili da un numero elevato di destinatari, probabilmente senza relazioni aziendali precedenti con l'organizzazione che offre l'app, in Azure AD vengono imposti alcuni requisiti supplementari a tale tipo di app per semplificarne l'identificazione.

Dato che le app line-of-business possono disporre di un URI qualsiasi come valore URI ID APP, con il solo vincolo di univocità a livello di tenant, per essere impostate come disponibili all'esterno le applicazioni devono soddisfare i seguenti requisiti:

  • Solo gli URI che usano https:// come schema di protocollo sono accettabili

  • La parte host dell'URI deve corrispondere a un dominio verificato associato al tenant di Azure AD

Se si ha un dominio personalizzato da usare con Azure AD, per verificarlo è possibile attenersi alla seguente procedura. I domini personalizzati già verificati sono disponibili sotto l'intestazione Domini, allo stesso livello dell'intestazione Applicazioni nel portale di gestione di Azure per il tenant.

Se non si ha un dominio personalizzato o se non si desidera usarlo, si può sfruttare il dominio a tre livelli predefinito assegnato a ogni tenant di Azure AD con il formato <tenantname>.onmicrosoft.com. Poiché questa è un'opzione predefinita sicura, verrà usata nel presente documento.

Scorrere verso il basso nella parte inferiore della pagina fino alla sezione relativa all'accesso Single Sign-On. Immettere l'URI ID APP specificando il valore https://<tenantname>.onmicrosoft.com/ExpenseReport e sostituendo la stringa <tenantname> con il nome del proprio tenant di Azure AD. Fare clic su Salva.

Dato che il formato dell'URI ID APP è quello previsto, l'operazione di aggiornamento avrà esito positivo. Nella parte inferiore dello schermo viene visualizzato un avviso popup, tuttavia si può conoscere l'esito dell'operazione anche in base ad alcune modifiche delle chiavi riportate nelle impostazioni dell'app, come illustrato nella seguente figura.

URL per la concessione dell'accesso

L'interruttore relativo all'accesso esterno è ora nella posizione di attivazione. È inoltre presente una nuova casella di testo denominata URL per la concessione dell'accesso che rappresenta l'URL dell'endpoint che viene usato dai clienti potenziali per concedere all'app l'accesso alla directory. La struttura dell'URL verrà esaminata in dettaglio più avanti nella procedura dettagliata al momento di integrare la funzionalità di iscrizione nel codice dell'applicazione.

Per quanto riguarda il tenant di Azure AD, a questo punto l'applicazione è pronta per funzionare a livello multi-tenant purché se ne modifichi il codice di conseguenza.

noteNota
Questa esercitazione prosegue ancora con la fase di sviluppo del ciclo di vita dell'app. Una volta che l'app è pronta per la produzione, si viene reindirizzati a questa schermata per perfezionare l'aspetto dell'app nella pagina di consenso (caricando un logo appropriato) e per modificare l'URL di risposta dell'app nel relativo indirizzo di produzione. Nel secondo caso si possono usare le stesse istruzioni fornite nella sezione "Distribuzione dell'app in Siti Web di Azure" della procedura dettagliata relativa all'app line-of-business. Anche se i passaggi di distribuzione effettivi possano variare in base all'ambiente di destinazione, le istruzioni per aggiornare la voce dell'app nel portale di gestione possono essere applicate nel modo indicato.

In Visual Studio 2012 aprire il progetto MVC 4 creato nelle procedure dettagliate precedenti.

Come anticipato nella sezione "Architettura della soluzione", sarà necessario applicare diverse modifiche mirate per aggiungere funzionalità multi-tenancy all'applicazione line-of-business creata nelle prime due procedure dettagliate. Queste modifiche saranno applicate gradualmente per area funzionale per rimanere in linea con il resto delle procedure dettagliate della serie, il cui obiettivo principale è quello di consentire all'utente di comprendere le operazioni eseguite in modo che possa applicare le conoscenze acquisite alle proprie applicazioni.

noteNota
Le modifiche proposte tentano inoltre di ridurre il refactoring del codice creato. Potrebbe verificarsi pertanto una situazione di ridondanza, ad esempio per la creazione di nuovi controller anziché il consolidamento di più funzionalità in una più generica, che renderà l'esercitazione più semplice da seguire, anche se è possibile effettuare il refactoring e normalizzare il funzionamento in base alle proprie esigenze.

La prima attività da eseguire consiste nell'aggiornare le coordinate WS-Federation nel file Web.config per riflettere le nuove impostazioni. In Esplora progetti individuare il file Web.config e aprirlo.

noteNota
È opportuno leggere la sezione avanzata sulle impostazioni WIF in dettaglio nella procedura relativa all'applicazione line-of-business. Alcune di queste attività possono essere eseguite con lo strumento di gestione delle identità e degli accessi, ma è stato scelto di descriverne l'esecuzione modificando direttamente il file Web.config perché le modifiche necessarie vengono illustrate in modo più chiaro.

Scorrere verso il basso fino alla sezione <system.identityModel>. Poiché l'elemento identityConfiguration/AudienceURI contiene ancora il valore precedente dell'URI ID APP, modificarlo in base al nuovo valore immesso nel portale di gestione di Azure, come indicato di seguito.

<system.identityModel>
    <identityConfiguration>
      <audienceUris>
        <add value=”https://<tenantname>.onmicrosoft.com/ExpenseReport” />
      </audienceUris> 

In questo modo l'app accetterà come validi i token nell'ambito del nuovo URI ID APP.

Scorrere ulteriormente fino all'elemento <wsFederation> in system.identityModel.Services/federationConfiguration.

A questo punto si devono applicare due modifiche.

  • Modificare il valore dell'attributo realm in base allo stesso URI ID APP usato per la sezione <audienceUris> precedente.

  • Modificare il valore dell'attributo issuer sostituendo il GUID tenantID con la stringa common.

<federationConfiguration>
   <cookieHandler requireSsl="false" />
   <wsFederation passiveRedirectEnabled="true" issuer="https://login.windows.net/common/wsfed" realm="https://<tenantname>.onmicrosoft.com/ExpenseReport" requireHttps="false" />
</federationConfiguration> 

Il valore realm corrisponde al valore del parametro wtrealm di WS-Federation incluso nei messaggi di accesso all'autorità (provider di identità) da indicare al destinatario desiderato del token richiesto e deve corrispondere al valore che identifica l'app nel tenant di Azure AD di destinazione.

Il valore issuer indica l'endpoint che deve ricevere le richieste di accesso. Mentre nella prima esercitazione questo elemento corrispondeva al tenant di Azure, in questo caso non è possibile conoscere in anticipo a quale tenant sarà associato l'utente successivo (tra tutti quelli che hanno concesso il consenso all'app). Azure AD fornisce un endpoint speciale, cui si fa riferimento in genere come endpoint indipendente dal tenant, che consente all'app di posticipare la decisione sul tenant da usare fino al momento in cui l'utente immetterà il proprio nome utente. Poiché nel nome utente sono incluse informazioni sul dominio, a quel punto il tenant scelto viene univocamente determinato e il flusso di autenticazione viene eseguito nel modo usuale.

noteNota
È importante ricordare che in Azure AD viene emesso un token solo se all'applicazione destinataria (indicata dal parametro realm come descritto in precedenza) è stato concesso l'accesso nel tenant di Azure AD dell'utente. L'uso di un endpoint indipendente dal tenant non indebolisce i vincoli di accesso stabiliti a livello di directory, ma aggiunge solo generalizzazione al processo di accesso.

Nel file Web.config scorrere fino all'elemento IssuerNameRegistry.

Come indicato nella prima esercitazione, questo elemento è destinato a registrare i parametri che definiscono un token valido, ovvero l'identificazione personale del certificato X.509 da usare per convalidare la firma del token e il valore dell'emittente che identifica il tenant di Azure attendibile.

Si tratta di un'informazione rilevante anche nel caso multi-tenant, con la differenza che, anziché un unico valore, è disponibile un elenco di emittenti accettabili corrispondenti ai tenant dei clienti dell'app. La classe usata per implementare l'oggetto IssuerNameRegistry, ovvero ValidatingIssuerNameRegistry (VINR), può essere usata con più voci nel relativo elemento <validIssuers>. Un'applicazione multi-tenant, tuttavia, può acquisire nuovi clienti durante l'esecuzione ed essere usata da quelli esistenti e pertanto la modifica del file Web.config potrebbe avere conseguenze non previste sulla disponibilità dell'app.

Per evitare il problema, in questa esercitazione le informazioni del tenant vengono archiviate in un file esterno e viene realizzata un'implementazione personalizzata di VINR per usare il file esterno come origine delle coordinate di convalida.

noteNota
In questa esercitazione l'implementazione viene ridotta al minimo per dimostrare il ruolo funzionale dell'archivio. Per le prestazioni di un'applicazione reale, disponibilità e affidabilità dell'archivio devono rappresentare gli aspetti chiave della soluzione.

Il primo passo consiste nella creazione dell'archivio esterno. Nella cartella Contenuto creare un nuovo file XML (in Esplora soluzioni fare clic con il pulsante destro del mouse su Contenuto, Aggiungi nuovo elemento, scegliere la categoria Dati a sinistra, selezionare il file XML) e denominarlo tenants.xml.

Modificare il file incollando il seguente codice:

<?xml version="1.0" encoding="utf-8" ?>
<authority>
  <tenants>
    <tenant id="95ca3807-2313-4cfe-93b3-20ef9f46ae88" />    
  </tenants>
  <keys>
    <key id="3A38FA984E8560F19AADC9F86FE9594BB6AD049B" />
  </keys>
</authority>

Gli elementi <tenants> e <keys> possono essere lasciati vuoti oppure possono essere loro assegnati i valori thumbprint e tenantID dall'oggetto IssuerNameRegistry corrente. Al termine di queste operazioni, l'applicazione dispone già dei diritti di accesso al tenant di Azure AD.

Dopo aver creato il repository esterno, si può creare l'implementazione personalizzata di VINR usando il repository come origine della convalida.

Creare una nuova cartella AADUtils nella radice del progetto. Fare clic con il pulsante destro del mouse sulla cartella, scegliere Aggiungi, fare clic su Nuovo elemento, selezionare codice nelle categorie a sinistra, fare clic su Classe, quindi denominare il file MultiTenantIssuerNameRegistry.

Aggiungere le seguenti direttive using:

using System.IdentityModel.Tokens;
using System.Xml.Linq;

Definire la nuova classe come un'implementazione di VINR, aggiungere alcune proprietà statiche per registrare il percorso e il contenuto di tenants.xml, quindi aggiungere un costruttore predefinito statico (tutti i metodi usati saranno statici) per inizializzarli al momento della creazione.

namespace ExpenseReport.AADUtils
{
    public class MultiTenantIssuerNameRegistry: ValidatingIssuerNameRegistry
    {
        private static XDocument doc;
        private static string filePath;

        static MultiTenantIssuerNameRegistry()
        {
            filePath = HttpContext.Current.Server.MapPath("~/Content/tenants.xml");
            doc = XDocument.Load(filePath);
        }
    }
}

Aggiungere metodi per eseguire il probing del repository per la presenza di elementi tenantID o di chiavi:

public static bool ContainsTenant(string tenantId)
{
    return 
    doc.Descendants("tenant").Where(x => x.Attribute("id").Value == tenantId).Any();
}

public static bool ContainsKey(string thumbprint)
{
    return 
    doc.Descendants("key").Where(x => x.Attribute("id").Value == thumbprint).Any();
}
noteNota
Entrambi i metodi seguono lo stesso principio basato sulla sintassi concisa di LINQ, ovvero selezionano tutti gli elementi del tipo di destinazione, tenant o chiave, e verificano se almeno uno corrisponde al valore di input. In caso affermativo, la chiamata ad Any() sul set di risultati restituisce true.

Infine, si può eseguire l'override della logica di convalida come indicato di seguito:

protected override bool IsThumbprintValid(string thumbprint, string issuer)
{
    string issuerID = issuer.TrimEnd('/').Split('/').Last();

    if (ContainsTenant(issuerID))
    {
        if (ContainsKey(thumbprint))
            return true;
    }
    return false;
}

Il metodo viene chiamato automaticamente da WIF al ricevimento di un token. La logica, estremamente semplice, prevede di verificare che il tenant emittente sia presente nell'elenco e che il token sia firmato con il certificato registrato.

Sarà necessario aggiungere più metodi a MultiTenantIssuerNameRegistry, ma in relazione alla convalida la classe dispone di tutti gli elementi necessari.

Per garantire che venga attivata nella fase corretta della pipeline di autenticazione, è necessario aggiungerla al file Web.config in sostituzione dell'oggetto IssuerNameRegistry predefinito.

Aprire il file Web.config, individuare l'elemento <issuerNameRegistry> e sostituirlo con il seguente codice:

<issuerNameRegistry type="ExpenseReport.AADUtils.MultiTenantIssuerNameRegistry, ExpenseReport" />

Con la prima procedura dettagliata nell'app è stata introdotta la logica per l'aggiornamento delle coordinate dell'emittente (emittente e identificazione personale del certificato X.509 usato per verificare la firma del token) a ogni avvio dell'applicazione. Tutti i dettagli sono disponibili nella sezione relativa all'aggiunta dell'aggiornamento automatico dei metadati.

Ora che le informazioni sul tenant e sulla chiave sono presenti in un file diverso da Web.config, non è più necessario eseguire l'aggiornamento nell'evento Application_Start(). Poiché si tratta comunque di un momento favorevole nel ciclo di vita dell'applicazione, ai fini di questa esercitazione si manterranno in questa posizione.

È necessario tuttavia risolvere alcuni problemi:

  • Il metodo ValidatingIssuerNameRegistry.WriteToConfig() usa la voce di configurazione originale e ne prevede la presenza nel file Web.config, pertanto non funzionerà con l'oggetto MTINR personalizzato creato.

  • L'elenco di tenant accettati non proviene più da metadati di un unico tenant.

Entrambi i problemi sono di facile soluzione. È sufficiente aggiungere un altro metodo statico alla classe MTINR che aggiorni le chiavi nel file tenants.xml. Di seguito viene riportato il codice del metodo, da aggiungere alla classe MultiTenantIssuerNameRegistry nel file MultiTenantIssuerNameRegistry.cs corrispondente.

public static void RefreshKeys(string metadataAddress)
{
    IssuingAuthority ia = 
           ValidatingIssuerNameRegistry.GetIssuingAuthority(metadataAddress);

    bool newKeys = false;
    foreach (string thumbp in ia.Thumbprints)
        if (!ContainsKey(thumbp))
        {
            newKeys = true;
            break;
        }

    if (newKeys)
    {                
        XElement keysRoot = 
             (XElement)(from tt in doc.Descendants("keys") select tt).First();
        keysRoot.RemoveNodes();
        foreach (string thumbp in ia.Thumbprints)
        {
            XElement node = new XElement("key", new XAttribute("id", thumbp));
            keysRoot.Add(node);
        }
        doc.Save(filePath);           
    }
} 

Il metodo può essere diviso nelle tre attività indicate di seguito:

  • Chiamata a GetIssuingAuthority(), un metodo statico disponibile in ValidatingIssuerNameRegistry, che estrae da un documento di metadati le chiavi pubblicate dal servizio da usare per verificare i token in ingresso.

  • Il primo blocco foreach controlla se le chiavi trovate nel documento di metadati sono già presenti nel file tenants.xml.

  • Se nei metadati non è stata trovata alcuna nuova informazione, il metodo può essere eseguito senza modifiche. In caso contrario, le chiavi presenti nel file tenants.xml vengono eliminate e sostituite da quelle nuove presenti nel documento di metadati.

noteNota
Gli stessi avvisi sulla convalida degli endpoint HTTPS forniti nella sezione relativa all'aggiunta dell'aggiornamento automatico dei metadati della prima procedura dettagliata sono validi anche in questa sezione.

Questa è tutta la logica necessaria per implementare l'aggiornamento automatico delle chiavi. Il passaggio successivo consisterà nella modifica del file Global.asax per chiamare RefreshKeys anziché la routine basata su Web.config. Individuare il file Global.asax e modificare RefreshValidationSettings nel modo indicato di seguito:

protected void RefreshValidationSettings()
{
    string metadataAddress = 
           ConfigurationManager.AppSettings["ida:FederationMetadataLocation"];
    AADUtils.MultiTenantIssuerNameRegistry.RefreshKeys(metadataAddress);
}
noteNota
È possibile aver notato che il metodo si basa ancora sull'indirizzo dei metadati del tenant di Azure AD dell'utente, ovvero del tenant in cui l'applicazione è stata inizialmente sviluppata e acquisita dalla prima esecuzione dello strumento per la gestione delle identità e degli accessi, anziché spostarsi su un endpoint indipendente dal tenant. In effetti, i due tenant sono all'incirca equivalenti. La voce dell'applicazione in Azure AD è collegata al tenant dell'utente, pertanto l'endpoint di metadati corrispondente sarà sicuramente funzionante. D'altra parte, lo spostamento sull'endpoint indipendente dal tenant semplificherebbe il riuso del codice come punto di partenza per altre applicazioni. È possibile scegliere entrambi gli approcci, anche se nell'esercitazione è stato scelto di usare quello che richiedeva il numero minimo di modifiche del codice.

In un'applicazione line-of-business classica, tutti gli utenti provengono dalla stessa autorità, pertanto il flusso di autenticazione può, in qualsiasi momento, decidere in modo non ambiguo dove indirizzare gli utenti non autenticati. Gli utenti inoltre si trovano spesso in una sessione attiva con l'autorità (si pensi agli utenti che hanno già effettuato l'accesso ai domini Active Directory locali tramite le richieste della workstation), pertanto la fase di autenticazione può essere eseguita in modo trasparente, senza alcuna interruzione percepita tra la digitazione dell'indirizzo dell'app nel browser e l'autorizzazione ad accedere alla relativa interfaccia utente. Questo è il comportamento predefinito delle app Web configurate per l'uso di protocolli di accesso come WS-Federation.

In un'applicazione multi-tenant, per definizione, gli utenti possono provenire da tenant diversi e vengono invitati a partecipare al processo di definizione dell'autorità da coinvolgere nell'autenticazione, noto come individuazione dell'area di autenticazione principale (HRD, Home Realm Discovery). In Azure AD questa fase viene gestita dall'endpoint indipendente dal tenant, che guida l'utente nei passaggi necessari senza che sia richiesta alcuna modifica del codice. Come illustrato di seguito, oltre al processo di individuazione dell'area di autenticazione principale sono presenti tuttavia altri aspetti che potrebbero richiedere l'esecuzione di operazioni specifiche.

Un'applicazione multi-tenant include spesso esperienze disponibili a utenti anonimi, ad esempio pagine di destinazione, funzionalità di caricamento, notizie, forum di supporto pubblici, punti di ingresso per versioni di valutazione e così via. L'approccio di protezione generica non è adatto per supportare tali funzionalità e pertanto in questa sezione verrà illustrato come modificare le impostazioni WIF per applicare più requisiti di autenticazione con granularità fine su base controller per controller.

Modificare il file Web.config

  1. Aprire il file Web.config e individuare l'elemento <authorization> in <system.web> sotto il commento etichettato "Commented by Identity and Access VS Package".

    noteNota
    Non confondere tale elemento con quelli omonimi presenti nei blocchi <location>.

  2. L'impostazione corrente <deny users="?" /> indica ad ASP.NET che solo agli utenti autenticati deve essere consentito di richiedere risorse all'applicazione. Poiché non si desidera più che questo vincolo venga imposto dal file Web.config, impostare come commento l'intero elemento authorization.

    <!--<authorization>
      <deny users="?" />
    </authorization>-->
    
    Il risultato che si desidera ottenere è la possibilità di definire direttamente le modalità di gestione dell'autenticazione. A tale scopo, è necessario ripristinare l'autenticazione basata su form per indicare ad ASP.NET che, quando l'autenticazione è richiesta, è necessario eseguire il reindirizzamento a un indirizzo specifico cui inviare la richiesta con un nuovo controller incaricato di attivare l'autenticazione federata.

  3. Individuare l'elemento <authentication>, impostarlo come commento e incollare il seguente elemento nel file Web.config sotto il blocco di commento creato.

    <!--<authentication mode="None" />-->
    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>
    
  4. Scorrere verso il basso fino all'elemento <system.webServer>, quindi individuare l'elenco <modules>. Si noti che per il modulo FormsAuthentication è presente una direttiva <remove>. Impostarla come commento come illustrato di seguito.

    <modules>
          <!--<remove name="FormsAuthentication" />-->
    
  5. Infine, scorrere verso il basso fino al termine del file Web.config. Nell'elemento <wsFederation>, già modificato in precedenza in questa esercitazione, impostare passiveRedirectEnable su false.

    <wsFederation passiveRedirectEnabled="false" 
    issuer="https://login.windows.net/common/wsfed" realm="https://<your-tenant-name>.onmicrosoft.com/ExpenseReport" requireHttps="false" />
    
    noteNota
    Per impostazione predefinita, nei moduli WIF verranno esaminati tutti i codici 401 restituiti dall'app e, se è presente un'autorità configurata in modo corretto, quest'ultima li trasformerà in reindirizzamenti 302 con messaggi di accesso all'autorità attendibile. In base a quest'ultima impostazione, WIF ignorerà i messaggi 401 in uscita in modo che possano essere reindirizzati secondo le impostazioni dell'autenticazione basata su form (in questo caso, al controller personalizzato).

Creare il controller di account

  1. A questo punto l'app è configurata per eseguire il reindirizzamento ad ~/Account/LogOn al momento dell'autenticazione. Si può creare un controller che gestirà il percorso specifico.

    Fare clic con il pulsante destro del mouse sulla cartella Controller, scegliere Aggiungi, fare clic su Aggiungi controller, quindi assegnare al controller il nome AccountController.

  2. Aggiungere la seguente direttiva using:

    using System.IdentityModel.Services;
    
  3. Eliminare l'implementazione predefinita del controller e sostituirla con la seguente:

    public void LogOn()
    {
        RedirectResult result;
        if (!Request.IsAuthenticated)
        {
            SignInRequestMessage sirm = FederatedAuthentication.WSFederationAuthenticationModule.CreateSignInRequest("", HttpContext.Request.RawUrl, false);
            result = Redirect(sirm.RequestUrl.ToString());               
        }
        else
        {
            result = Redirect("~/");
        }
        result.ExecuteResult(this.ControllerContext);
    }
    
    

In pratica il controller esegue quasi la stessa logica implementata dal modulo WIF, come indicato di seguito.

  • Se la richiesta non è autenticata:

    • Genera un messaggio di accesso WS-Federation in base alle impostazioni di configurazione (contenuto dell'elemento <wsFederation>)

    • Reindirizza il browser dell'utente di conseguenza

  • Se la richiesta è autenticata:

    • Esegue un reindirizzamento alla home page

Il vantaggio consiste nell'avere il pieno controllo sul momento in cui questo si verifica. Come illustrato più avanti nell'esercitazione, in questo modo sarà possibile aggiungere un'operazione di accesso esplicita all'interfaccia utente dell'applicazione mantenendo al contempo il vantaggio dei reindirizzamenti automatici attivati dai criteri di autenticazione della risorsa richiesta.

noteNota
Per questa procedura dettagliata è stato scelto un approccio minimalista, in base al quale l'esperienza di autenticazione è completamente gestita da Azure AD. Questo tuttavia non implica necessariamente che nelle soluzioni realizzate debba essere seguito lo stesso approccio. A questo punto si dispone del controllo completo su ciò che accade quando viene attivato il flusso di autenticazione. Se si desidera mostrare una visualizzazione per richiedere all'utente ulteriori informazioni (o per fornire indicazioni), è possibile modificare l'azione LogOn.

Per realizzare l'integrazione tra l'autenticazione basata su form e l'autenticazione completamente federata, è necessario effettuare un'ultima operazione.

Quando l'azione LogOn viene chiamata in risposta a una richiesta a una risorsa protetta, il modulo di autenticazione basata su form include l'URL della risorsa di origine nel parametro di query ReturnUrl, mentre in WIF viene ignorato. Nella situazione corrente, dopo l'autenticazione l'utente viene reindirizzato alla home page dell'applicazione anziché alla risorsa richiesta. L'esecuzione di un reindirizzamento interno supplementare alla risorsa è un'operazione semplice perché prevede la sola aggiunta di logica per gestire l'evento End_Request nel file Global.asax.

  1. Aprire il file Global.asax e aggiungere la seguente direttiva:

    using System.Security.Claims;
    
  2. Aggiungere quindi il metodo riportato di seguito:

    protected void Application_EndRequest(object sender, EventArgs e)
    {
        string wsFamRedirectLocation = HttpContext.Current.Response.RedirectLocation;
        if (wsFamRedirectLocation != null && 
            wsFamRedirectLocation.Contains("ReturnUrl") && 
            ClaimsPrincipal.Current.Identity.IsAuthenticated)
        {
            HttpContext.Current.Response.RedirectLocation =
                        HttpUtility.ParseQueryString(
                          wsFamRedirectLocation.Split('?')[1])["ReturnUrl"];
        }
    }
    

Il metodo viene eseguito al termine della pipeline di elaborazione della richiesta HTTP e verifica la posizione dell'intestazione HTTP usata in caso di reindirizzamento. Se specificata, l'utente viene autenticato (poiché il flusso del protocollo WS-Federation è stato completamente eseguito) e il valore contenuto è ReturnUrl (che indica l'archiviazione di informazioni restituite dall'autenticazione basata su form). Successivamente il browser viene reindirizzato alla posizione definita da ReturnUrl.

Proteggere i controller

Dopo aver disattivato la protezione dell'autenticazione generica, ogni singolo controller è responsabile della specifica dei propri requisiti di autenticazione. Il modo più semplice per ottenere questo risultato consiste nell'associare a ogni azione l'attributo [Authorize], in modo analogo a qualsiasi altro scenario di autenticazione ASP.NET.

WarningAvviso
Sebbene nell'esercitazione vengano trattate applicazioni di tipo MVC, è possibile seguire lo stesso approccio in Web Form (usando ad esempio gli elementi <location> e <authorization> nel file Web.config).

Di seguito è possibile visualizzare la modifica applicata all'azione About() del controller Home:

[Authorize]
public ActionResult About()
{
    ViewBag.Message = "Your app description page.";

    return View();
}

Eseguire la stessa operazione per ogni azione del controller Home, ad eccezione di Index(). In questa esercitazione l'azione Index è riservata per il punto di ingresso non autenticato per l'esperienza dell'applicazione.

Mentre nella prima procedura dettagliata Index è stata usata per estrarre informazioni utente dalle attestazioni, in questa procedura gli utenti non autenticati saranno in grado di accedere all'azione e di conseguenza non sarà possibile eseguire quel codice poiché l'assenza di un utente autenticato implica che non è disponibile alcuna attestazione. Impostarlo come commento e sostituire l'assegnazione a ViewBag.Message con un qualsiasi messaggio adatto.

Public ActionResult Index()
{
    //ClaimsPrincipal cp = ClaimsPrincipal.Current;
    //string fullname =
    //       string.Format(“{0} {1}”, cp.FindFirst(ClaimTypes.GivenName).Value,
    //       cp.FindFirst(ClaimTypes.Surname).Value);
    ViewBag.Message = "Welcome to the Expense Note App";
    return View();
}
noteNota
Sebbene nell'esercitazione non vengano fornite istruzioni per eseguire questa operazione, se si desidera è possibile aggiungere al messaggio (o alla visualizzazione associata) testo di benvenuto e di spiegazione sull'uso dell'applicazione. Questo sarà particolarmente utile in seguito per le parti relative all'accesso.

Modificare le operazioni per l'accesso nel file _Layout.cshtml

Le modifiche apportate in precedenza attiveranno il flusso di autenticazione non appena l'utente fa clic su un elemento dell'interfaccia utente che richiede un'azione protetta da [Authorize]. Nelle applicazioni non protette in modo generico, molto spesso è tuttavia disponibile un'operazione di interfaccia utente per eseguire l'accesso.

A tale scopo, verrà rivisto il testo relativo ai saluti nell'area superiore dello schermo, definito nel file _Layout.cshtml e usato durante la spiegazione delle modalità di aggiunta della disconnessione nella procedura dettagliata per l'aggiunta dell'accesso. Mentre in tale procedura ogni elemento è stato incorporato nel file _Layout.cshtml, in questa esercitazione sarà necessario aggiungere maggiori funzionalità, con la conseguente necessità di un'operazione di refactoring.

  1. Aprire il file _Layout.cshtml, individuare la sezione di accesso <section id=”login”> e modificarla nel modo indicato di seguito:

    <section id=”login”>
       @Html.Partial("_LoginPartial")
       @* @if (Request.IsAuthenticated) 
        {                       
           <text> Hello, <span class=”username”>@User.Identity.Name</span>! @Html.ActionLink(“Signout”,”SignOut”, “SignOut”)</text>
        } 
        else {          
            <text>  You are not authenticated </text> 
         } *@
    </section>
    
    
  2. Al termine dell'operazione, fare clic con il pulsante destro del mouse sulla cartella Views/Shared, fare clic su Aggiungi, quindi su Visualizzazione, assegnare un nome alla nuova visualizzazione _LoginPartial, scegliere Razor come motore di visualizzazione e infine fare clic su Aggiungi.

  3. Sostituire il contenuto del file _LoginPartial.cshtml con il seguente codice:

    @if (Request.IsAuthenticated) 
        {                       
           <text> Hello, <span class=”username”>@User.Identity.Name</span>! @Html.ActionLink("Signout","SignOut", "SignOut")</text>
        } 
        else {          
             <ul>       
            <li>@Html.ActionLink("Sign in", "LogOn", "Account", routeValues: null, htmlAttributes: new { id = "signLink" })</li>
        </ul> 
         }
    

Questa è la stessa logica incorporata nell'esercitazione sulle applicazioni line-of-business, con la sola differenza che il testo relativo all'utente non autenticato è stato sostituito con un collegamento selezionabile che attiverà l'azione LogOn del controller Account.

Controller di disconnessione

Per adattare la logica di disconnessione al caso multi-tenant, non è necessaria alcuna modifica. Il controller era già stato configurato per recuperare l'endpoint emittente da usare nel flusso di disconnessione dal file Web.config e di conseguenza apporterà automaticamente la modifica all'endpoint indipendente dal tenant applicata all'inizio dell'esercitazione.

Personalizzare la logica di accesso all'API Graph

La logica di accesso all'API Graph è già progettata per creare endpoint di risorse sulla base del tenantID ricevuto nelle attestazioni che descrivono l'utente corrente, pertanto continuerà a funzionare anche quando gli utenti inizieranno a provenire da più tenant.

noteNota
Una delle funzionalità di Azure AD che rende possibile questa situazione è costituita dal fatto che ClientId e il segreto client non subiscono modifiche nei tenant. Quando un amministratore di tenant consente all'app di accedere al tenant di Azure AD, i valori della nuova voce di applicazione corrispondente nel tenant saranno gli stessi di quelli di qualsiasi altro utente. Si noti tuttavia che questo non significa che un amministratore malintenzionato sia in grado di recuperare il segreto dell'app e di provare a usarlo in relazione a un altro tenant di Azure AD che ha concesso il consenso alla stessa app. Come illustrato nella procedura dettagliata relativa all'API Graph, i segreti non possono essere recuperati dopo la creazione.

L'ultima funzionalità da aggiungere all'app per completare la transizione a un modello multi-tenancy è la possibilità di caricare nuove organizzazioni clienti.

Come illustrato in questo documento, le applicazioni contrassegnate come disponibili esternamente in Azure AD vengono associate a un URL creato in modo specifico che può essere usato da clienti potenziali per consentire all'app di accedere alle loro directory e di disporre di una voce per l'app di cui è stato effettuato il provisioning automatico nei tenant. In questa sezione verrà aggiunto un controller SignUp che può reindirizzare gli utenti all'URL di consenso e un'operazione di interfaccia utente per attivare l'azione.

noteNota
In questa esercitazione la funzionalità viene aggiunta direttamente nell'app, tuttavia, una volta compreso il funzionamento del meccanismo, è possibile implementare la logica di consenso all'esterno dell'applicazione, raggruppandola con collegamenti di consenso per altre app nel proprio portfolio e così via.

  1. Aggiungere un controller SignUp vuoto seguendo le istruzioni per le creazioni di controller fornite in precedenza nelle procedure dettagliate.

  2. Aggiungere la seguente direttiva using:

    using System.Configuration;
    
    
  3. Sostituire l'implementazione predefinita del controller con i due metodi seguenti:

    private string CreateConsentURL(string clientId, string requestedPermissions, 
                                    string consentReturnURL, string context)
    {
        string consentUrl = string.Format("https://account.activedirectory.windowsazure.com/Consent.aspx?ClientId={0}", clientId);
        if(!String.IsNullOrEmpty(requestedPermissions))
          consentUrl+= "&RequestedPermissions="+requestedPermissions;
        if(!String.IsNullOrEmpty(consentReturnURL))
            consentUrl+= "&ConsentReturnURL="+HttpUtility.UrlEncode(
                consentReturnURL+(String.IsNullOrEmpty(context) ?
                                         String.Empty : "?"+context ));
        return consentUrl;        
    }
    public void SignUp()
    {
        string request = System.Web.HttpContext.Current.Request.Url.ToString();
        string returnurl = request.Substring(0, request.Length -6);
        string clientID = ConfigurationManager.AppSettings["ClientId"];
    
        RedirectResult result = 
           Redirect(CreateConsentURL(clientID, "DirectoryReaders", returnurl, string.Empty));
        result.ExecuteResult(this.ControllerContext);
    } 
    
    

Il primo metodo crea l'URL che permette ai clienti potenziali di consentire all'app di accedere ai loro tenant di directory. Anche se nel portale di gestione di Azure è presente l'URL di consenso per l'app, la disponibilità del codice che lo genera a partire da alcuni parametri di base consente di operare in modo più flessibile. Di seguito sono indicati i parametri e la relativa semantica.

  • ClientId rappresenta l'identificatore dell'applicazione. Il parametro è obbligatorio ed è stato aggiunto nella procedura dettagliata relativa all'API Graph.

  • RequestedPermissions indica il livello di accesso alla directory che si desidera venga concesso all'applicazione da parte del cliente potenziale. I valori possibili riflettono le scelte per i livelli di accesso disponibili nel portale di gestione di Azure al momento della registrazione dell'app, anche se qui si possono richiedere livelli diversi da quelli selezionati nell'interfaccia utente per il proprio tenant. I valori sono i seguenti:

    • DirectoryReaders: consente di richiedere l'accesso in lettura alla directory

    • DirectoryWriters: consente di richiedere l'accesso in lettura/scrittura

    • <Empty>: non specificare alcun valore se si desiderano solo funzionalità SSO

  • ConsentReturnUrl indica la posizione cui reindirizzare la sessione del browser una volta che l'utente ha concesso (o negato) il consenso all'applicazione. Più avanti vengono forniti dettagli relativi alla possibilità di specificare un percorso nell'app in cui posizionare la logica di elaborazione dell'iscrizione.

Il metodo CreateConsentURL espone tutti i parametri indicati in precedenza più un parametro supplementare. Il parametro context consente di includere informazioni supplementari, che verranno inviate alla pagina di consenso codificate in ConsentReturnUrl e verranno trasferite nuovamente una volta completato il reindirizzamento. Il parametro viene offerto come separato per comodità, in modo che non sia necessario combinare l'URL restituito principale con la logica di contesto.

Il parametro context può risultare utile quando si desidera registrare informazioni aggiuntive relative alla richiesta. Il reindirizzamento al consenso, ad esempio, viene spesso eseguito durante il processo di caricamento specifico dell'app ed è probabile che si desideri registrare parte del contesto.

Il secondo metodo è l'azione effettiva che attiverà il reindirizzamento. Tale metodo richiama CreateConsentURL passando come parametri ClientId dalla configurazione, la radice del controller corrente come URL restituito, DirectoryReaders come livello di accesso richiesto e nessun valore come contesto, quindi esegue il reindirizzamento all'URL creato.

Dopo aver aggiunto la logica per attivare il reindirizzamento all'URL di consenso, è necessario completare il flusso tramite il codice che elaborerà i risultati. Come stabilito di seguito dalla scelta di ReturnURL, nell'esercitazione il codice verrà inserito nell'azione Index del controller SignUp.

  1. Aggiungere la seguente direttiva using:

    using ExpenseReport.AADUtils;
    
  2. Aggiungere il seguente metodo al controller SignUp.

    public void Index()
    {
        if ((!string.IsNullOrEmpty(Request.QueryString["TenantId"]) && 
            (!string.IsNullOrEmpty(Request.QueryString["Consent"]))))
        {
            if (Request.QueryString["Consent"].Equals("Granted",
                                                StringComparison.InvariantCultureIgnoreCase))
            {
                MultiTenantIssuerNameRegistry.AddTenant(Request.QueryString["TenantId"]);
            }
        
            //redirect to SignIn
            RedirectResult result = Redirect("~/Account/LogOn");
            result.ExecuteResult(this.ControllerContext);
        }
    }
    
    noteNota
    Nel codice del metodo non è inclusa la gestione degli errori.

In seguito alla concessione o alla negazione dell'accesso, viene eseguito il reindirizzamento al percorso indicato dall'elemento ReturnURL e vengono aggiunti i due parametri supplementari indicati di seguito.

  • Consent: indica il risultato dell'operazione e può assumere il valore "Granted" o "Denied".

  • TenantID: se il valore del parametro Consent è "Granted", TenantID sarà presente e conterrà l'identificatore del tenant che ha concesso il consenso alle richieste di accesso dell'applicazione.

Lo scopo di questo metodo consiste quindi nell'acquisire l'ID di tenant che hanno effettuato il provisioning dell'app e di registrarli come autorità valide nella raccolta MTINR. In base alla logica di convalida creata in precedenza nella procedura dettagliata, gli utenti provenienti dai nuovi tenant potranno essere accettati al momento dell'accesso.

Nel codice precedente viene esaminato l'URL di richiesta e, se viene rilevato che contiene un nuovo tenant, l'URL viene salvato nell'elenco MTINR (tramite un metodo che verrà implementato a breve).

noteNota
L'implementazione qui non aggiunge alcuna limitazione alle richieste che arrivano nel percorso e, se sono nel formato corretto, il contenuto del parametro TenantID verrà inserito nell'archivio MTINR. Questo comportamento non è quello previsto per un'applicazione reale perché il numero di elementi falsi in ingresso all'archivio potrebbe essere eccessivo o perché potrebbero verificarsi accessi non autorizzati.

Come indicato in precedenza, è probabile che l'esperienza di consenso faccia parte del processo di caricamento (ad esempio in relazione alla raccolta di informazioni sul cliente potenziale, al ricevimento di pagamenti oppure a qualsiasi altro passaggio di caricamento necessario all'app). È necessario pertanto verificare di includere tale contesto nella creazione dell'URL di consenso e di eseguirne la convalida quando si elabora la risposta in modo da garantire il rifiuto delle richieste fraudolente.

Dopo il salvataggio del tenant, il metodo termina attivando un'operazione di accesso in modo che l'utente sia in grado di usare immediatamente l'applicazione.

noteNota
Se il processo di caricamento richiede ulteriori passaggi, è possibile differire l'operazione di accesso in un momento successivo e salvare invece la visualizzazione.

L'azione Index del controller SignUp ha introdotto un nuovo metodo MTINR, ovvero AddTenant. Per aggiungerne un'implementazione, aprire MultiTenantIssuerNameRegistry.cs e aggiungere il seguente metodo alla classe MultiTenantIssuerNameRegistry:

public static void AddTenant(string tenantId)
{
    if (!ContainsTenant(tenantId))
    {
        XElement node = new XElement("tenant", new XAttribute("id", tenantId));
        XElement tenantsRoot = 
                (XElement)(from tt in doc.Descendants("tenants") select tt).First();

        tenantsRoot.Add(node);
        doc.Save(filePath);
    }
}

Il metodo AddTenant è molto semplice. Se l'elemento tenantId in input non esiste già nell'archivio (l'operazione di consenso è idempotente), viene aggiunta una nuova voce correlata nel nodo <tenants>.

Infine, per l'applicazione è necessario definire un'operazione di interfaccia utente per attivare il flusso di iscrizione. A tale scopo, è sufficiente aggiungere una voce nel file _LoginPartial.cshtml. Aprire il file e modificare il blocco <li> per l'iscrizione come mostrato di seguito.

@if (Request.IsAuthenticated) 
    {                       
       <text> Hello, <span class="username">@User.Identity.Name</span>! @Html.ActionLink("Signout","SignOut", "SignOut")</text>
    } 
    else {          
         <ul>  
       <li>@Html.ActionLink("Sign up", "SignUp", "SignUp", routeValues: null, htmlAttributes: new { id = "signupLink" })</li>     
        <li>@Html.ActionLink("Sign in", "LogOn", "Account", routeValues: null, htmlAttributes: new { id = "signLink" })</li>
    </ul> 
     }

noteNota
L'interfaccia utente corrente è caratterizzata da un approccio estremamente minimalista. In un'applicazione reale potrebbe essere opportuno creare la semantica di controlli di iscrizione e di accesso e tale risultato può essere ottenuto in modi diversi, ovvero mediante l'inclusione di un testo di collegamento più dettagliato, di una spiegazione nel corpo principale della home page e così via.

In questa sezione verranno illustrate alcune opzioni che consentono di testare la nuova applicazione multi-tenant.

Per testare un'applicazione multi-tenant in tutti gli aspetti, è opportuno disporre di un secondo tenant di Azure AD da usare per provare tutti i flussi correlati al consenso nell'applicazione di esempio. In questo momento, ciò corrisponde a disporre dell'accesso a un'altra sottoscrizione Azure. Per ottenerla, è possibile eseguire una seconda volta il flusso di iscrizione e di creazione delle directory descritto all'inizio della prima procedura dettagliata oppure seguire le istruzioni fornite nel presente documento per l'iscrizione a una sottoscrizione di prova con un utente da un tenant di Azure AD esistente.

Poiché l'operazione di concessione del consenso è idempotente, è inoltre possibile usare il proprio tenant di Azure AD per eseguire la prova con l'iscrizione. In questo modo è possibile evitare la creazione di una seconda sottoscrizione, ma non è possibile vedere cosa si verifica quando si tenta di effettuare l'accesso con un tenant di cui non è stato effettuato il provisioning né sperimentare il flusso di revoca del consenso (posto che per il tenant l'app sia ancora un'applicazione line-of-business di cui sia stato eseguito esplicitamente il provisioning e di conseguenza senza alcuna necessità espressa di passaggi per la concessione del consenso).

Il test potrebbe anche essere eseguito tramite un tenant di Azure AD non necessariamente correlato a una sottoscrizione Azure, ad esempio il tenant di directory ottenuto quando si esegue la sottoscrizione a servizi quali Office365 o Intune.

noteNota
Poiché solo gli amministratori di tenant di Azure AD possono concedere il consenso alle applicazioni, indipendentemente dal metodo di test scelto è necessario disporre dell'accesso a credenziali utente come amministratore di tenant. Se il proprio tenant di Azure AD è stato creato mediante una sottoscrizione Azure basata su un Windows Live ID, è necessario verificare che il proprio tenant contenga almeno un utente di tenant con il ruolo di amministratore globale. Per creare tale ruolo, è sufficiente seguire le istruzioni fornite nella prima procedura dettagliata, assicurandosi di scegliere "Amministratore globale" nella schermata relativa al profilo utente.

A questo punto è possibile esaminare il comportamento dell'applicazione multi-tenant. Se si desidera osservare il funzionamento interno dell'app, si può inserire un punto di interruzione in uno dei frammenti di codice aggiunti durante l'esercitazione.

Esecuzione dell'applicazione

noteNota
Se si usa un tenant di Azure AD diverso dal proprio, può essere necessario chiudere tutte le istanze del browser prima di iniziare. In alternativa, si può indicare a Visual Studio di avviare la sessione di debug in un Web browser diverso da quello predefinito. Tali espedienti possono essere necessari per garantire che non si verifichino interferenze tra le sessioni Web esistenti e la sessione di debug.

In Visual Studio premere F5.

Home page dell'applicazione

Come previsto, anziché essere reindirizzati immediatamente ad Azure AD per l'autenticazione, viene visualizzata la home page dell'applicazione.

Nella barra superiore è possibile individuare la sezione di accesso, in cui vengono correttamente visualizzati i pulsanti di iscrizione e di accesso dato che l'autenticazione non è ancora stata effettuata.

Per iniziare a testare il flusso di caricamento, fare clic sul pulsante di iscrizione.

Accedi ad AAD

Si viene immediatamente reindirizzati alla pagina con la richiesta di autenticazione di Azure AD. Accedere con le credenziali di amministratore di tenant di Azure AD che si è deciso di usare per il test.

Concedi accesso

noteNota
Se in questa fase viene visualizzato un messaggio di errore, verificare che l'accesso sia effettuato come amministratore di un tenant di Azure AD. Attualmente gli utenti con un Windows Live ID non possono essere usati per concedere il consenso nel flusso qui descritto.

Non appena completata l'autenticazione, in Azure AD viene richiesto di concedere o negare l'accesso al tenant di directory per l'applicazione Expense Reporting per il livello di accesso specificato nel controller SignUp.

Fare clic su Concedi accesso.

Home page dell'applicazione

Nella pagina viene registrato il consenso nella directory dell'utente corrente, quindi viene attivata una richiesta di accesso. Poiché l'autenticazione è già stata effettuata al momento del consenso in Azure AD, non è più necessario immettere le credenziali e l'accesso verrà eseguito in modo automatico. La sezione di accesso riflette il nuovo stato e mostra il nome utente e il pulsante di disconnessione.

È possibile fare clic in un punto qualsiasi dell'app per verificare di trovarsi in una sessione autenticata. Se ad esempio si fa clic sulla scheda Utenti, sarà possibile visualizzare l'elenco di utenti.

noteNota
Quando un'applicazione multi-tenant tenta di acquisire un token per accedere all'API Graph per un tenant di Azure AD che di recente ha autorizzato l'applicazione, è possibile che la richiesta di token dia esito negativo e restituisca un errore ACS50012. Per risolvere il problema, attendere qualche minuto e ripetere l'operazione. In alternativa, chiedere all'amministratore di tenant che ha fornito il consenso di accedere all'applicazione dopo il consenso. Per ulteriori informazioni, vedere Codici di errore di ACS.

Per testare la disconnessione, fare clic sul relativo pulsante.

Disconnesso

Dopo alcuni reindirizzamenti, verrà visualizzata la pagina di disconnessione.

Per verificare di essere effettivamente disconnessi, fare clic di nuovo sulla scheda Utenti. Verrà richiesto di effettuare l'accesso.

Immettere le proprie credenziali e osservare che, dopo i reindirizzamenti alla fase di autenticazione, nel browser viene mostrata correttamente l'interfaccia utente richiesta in prima istanza, a dimostrazione che la logica aggiunta nell'evento End_Request funziona nel modo previsto.

Revoca dei diritti di accesso

Sarà possibile eseguire le attività descritte in questa sezione solo se il provisioning dell'applicazione è stato effettuato in un tenant di Azure AD diverso dal proprio e associato a una sottoscrizione Azure.

Accedere al portale di gestione di Azure con le credenziali di amministratore di tenant di Azure AD usato per effettuare il provisioning dell'applicazione.

Passare alla scheda Active Directory, selezionare la propria directory, scegliere Applicazioni, individuare l'app Expense Reporting e fare clic su di essa.

Dettagli applicazione integrata

Mentre nel tenant in cui l'app è stata creata verrebbe visualizzata l'interfaccia utente di configurazione che consente di modificare le impostazioni dell'app, qui il ruolo giocato è quello di un cliente che ha acquistato l'applicazione e viene visualizzata pertanto una pagina di descrizione generica con il riepilogo delle coordinate dell'applicazione e i livelli di accesso concessi.

Fare clic sul pulsante Gestisci accesso sulla barra dei comandi in basso.

Gestisci accesso

L'interfaccia utente visualizzata consente di revocare l'accesso all'app qualora non si desideri più che sia in grado di accedere alla directory nei termini stabiliti.

Fare clic su Rimuovi accesso.

Accesso rimosso

L'app è stata rimossa e non è più presente nell'elenco Applicazioni.

Tornare a Visual Studio e premere nuovamente F5.

Fare clic su Accedi, effettuare l'autenticazione come amministratore di tenant del cliente e osservare cosa accade.

Errore ACS50000

L'utente viene autenticato in modo corretto in relazione alla directory, ma l'app che dovrebbe essere destinataria del token di autenticazione non è più presente nell'elenco di quelle che possono accedere al tenant di directory dell'utente. Di conseguenza, la directory non emette il token richiesto e viene visualizzata una pagina di errore.

Aggiunte alla community

Mostra:
© 2014 Microsoft