Azure AD: Single sign-on in una Web App multi-tenant con OpenID Connect e ADAL

Ciao a tutti,

in questo post vedremo come utilizzare Azure Active Directory (Azure AD) per gestire l’autenticazione (sign-in e sign-up) in una applicazione Web sviluppata in ASP.NET MVC.

Azure AD è l’identity provider di Azure che permette agli sviluppatori di semplificare enormemente i processi di autenticazione grazie al supporto per i protocolli standard più utilizzati come OAuth 2.0, OpenID Connect, WS-Federation o SAML 2.0 e a diverse librerie open source e cross-platform.

In questo esempio vedremo come implementare il Single sign-on (SSO) in una applicazione web grazie all’utilizzo di OpenID Connect con Azure Active Directory Authentication Library (ADAL), che mette a disposizione molte funzionalità (tra cui la completa esperienza di autenticazione) e che si occupa di gestire la maggior parte della complessità del processo, permettendo al programmatore di concentrarsi solo sulla logica dell’applicazione.

Grazie ad ADAL è possibile ricevere in modo veloce e sicuro il token di autenticazione da utilizzare per effettuare chiamate sicure alle Web API, come ad esempio le Graph API di Office 365, dato che Office utilizza proprio Azure AD come identity provider per tutti gli utenti.

Per il nostro esempio è necessario avere una sottoscrizione Azure dove creare le directory di Azure AD. Se non avete una sottoscrizione attiva è sufficiente attivare la trial gratuita di Azure a questo indirizzo link

Creazione delle directory su Azure AD

La procedura per la creazione di una nuova directory è molto semplice. E sufficiente accedere al portale di Azure all’indirizzo https://manage.windowsazure.com e creare una nuova directory selezionando ACTIVE DIRECTORY e cliccando sul bottone NUOVO. Selezionare poi DIRECTORY e cliccare su CREAZIONE PERSONALIZZATA

imageimage

 

Nel wizard che si presenta, impostare la creazione di una nuova directory e selezionare il nome, il dominio, l’area geografica e cliccare sul bottone di conferma

image

Una volta aggiunta la directory, passiamo a Visual Studio per la creazione dell’applicazione web nella quale vedremo come implementare l’autenticazione

 

Creazione dell’applicazione Web in Visual Studio 2015

In questo esempio viene utilizzato Visual Studio 2015 che è scaricabile gratuitamente nella versione Community a questo link.

Come abbiamo detto all’inizio implementeremo l’autenticazione in un’applicazione ASP.NET, quindi apriamo VS e nella finestra di creazione nuovo progetto selezioniamo ASP.NET Web Application e togliamo il flag per l’utilizzo di Application Insights. Dopodiché impostiamo ad esempio MyWebApp come nome dell’applicazione e clicchiamo su OK

image

Nella successiva finestra selezioniamo il template di MVC e andiamo a modificare il tipo di autenticazione cliccando sul bottone Change Authentication. Impostiamo Cloud – Multiple Organizations e selezioniamo il dominio creato in precedenza sul portale di Azure (DeveloperCompany.onmicrosoft.com). Infine confermiamo con OK e lasciamo che Visual Studio faccia un po’ di lavoro per noi Sorriso

image

 

Una volta creato il progetto andiamo ad analizzare nel dettaglio quali componenti sono stati aggiunti e come la nostra nuova applicazione si connetterà ad Azure AD.

Per prima cosa vediamo che nelle References del progetto sono stati automaticamente aggiunti tutti i pacchetti necessari

image

Inoltre se apriamo il file Web.config possiamo notare che è stato aggiunto il blocco appSettings contenente tutti i dati necessari per la connessione alla directory di Azure AD

image

In particolare troviamo i valori di ClientId e ClientSecret (oltre alla url per l’autenticazione) che permettono di associare la nostra applicazione alla directory. La cosa interessante è che lato Azure questa associazione è stata già impostata da Visual Studio infatti, se torniamo sul portale di Azure, nella sezione APPLICAZIONI della directory troviamo la nostra MyWebApp

image

Entrando nella parte di configurazione dell’applicazione vediamo che la URL di accesso è impostata su localhost. Questo valore andrà poi modificato con la URL reale di produzione una volta completato il deploy dell’applicazione

image

Scorrendo la pagina vediamo che l’applicazione è stata impostata come Multi-tenant, che il clientID è lo stesso che abbiamo nel Web.config della nostra applicazione.
Inoltre sono stati assegnati di default 2 permessi: Sign in and read user profile e Read directory data che permettono all’applicazione di accedere (previa autorizzazione dell’utente) al profilo utente e ai dati della directory. Se la nostra applicazione dovrà avere accesso ad altri dati o dovrà compiere particolari azioni, occorrerà impostare da qui i permessi necessari.

image

A questo punto se eseguiamo l’applicazione da Visual Studio, veniamo automaticamente reindirizzati sulla pagina di sign-in tramite la quale possiamo già autenticarci con l’account utilizzato per creare la directory (che è aggiunto di default agli utenti che possono accedere).

image

Una volta inseriti utente e password ci viene mostrata la pagina che richiede all’utente di autorizzare l’applicazione secondo i permessi che abbiamo impostato sul portale

image 

Una volta cliccato su Accetto, veniamo automaticamente reindirizzati alla nostra applicazione e a questo punti siamo autenticati e abbiamo il token da utilizzare per effettuare le chiamate alle API di Office. Se clicchiamo infatti sul link del nostro utente, vengono recuperate e visualizzate le informazioni relative all’account direttamente dalla directory di Azure

imageimage

Torniamo ora a Visual Studio e andiamo ad analizzare il codice utilizzato per l’autenticazione tramite le librerie ADAL.
Apriamo il file UserProfileController.cs che si trova nella cartella Controllers e vediamo che per prima cosa vengono recuperate le informazioni sul clientId, appKey e AADInstance dai settings dell’applicazione

image

All’interno della Action Index viene istanziato un oggetto di tipo ActiveDirectoryClient (che fa parte di Microsoft.Azure.ActiveDirectory.GraphClient) e nel suo costruttore viene recuperato il token attraverso il metodo GetTokenForApplication()

image

Se andiamo a vedere come è fatto tale metodo, notiamo che grazie agli oggetti di ADAL ClientCredential, AuthenticationContext e AuthenticationResult, che incapsulano tutta la logica delle chiamate, è possibile ottenere il token di autenticazione in pochi e semplici passaggi. Questi oggetti fanno parte di Microsoft.IdentityModel.Clients.ActiveDirectory

image

 

Aggiunta della logica di Sign-up

 

Ok, fino a qui abbiamo lasciato a Visual Studio il compito di sbrigare le faccende relative alla login, ma adesso è arrivato il momento di mettere le mani al codice per implementare anche la parte di Sign-up, ovvero aggiungere la possibilità per un utente appartenente ad un’altra directory di “registrarsi” per il Single Sign On (SSO) alla nostra applicazione.

Per prima cosa dobbiamo modificare la UI aggiungendo un bottone per attivare la procedura di sign-up, e per farlo apriamo il file _Layout.cshtml situato nella cartella Views—>Shared

image

e aggiungiamo queste righe di codice che inseriscono un nuovo ActionLink per il sign-up solo nel caso in cui non ci sia nessun utente loggato

 

 <div class="navbar-collapse collapse">
     <ul class="nav navbar-nav">
         <li>@Html.ActionLink("Home", "Index", "Home")</li>
         <li>@Html.ActionLink("About", "About", "Home")</li>
         <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
         @if (!Request.IsAuthenticated)
         {
             <li>@Html.ActionLink("Sign Up", "SignUp", "Account")</li>
         }
     </ul>
     @Html.Partial("_LoginPartial")
 </div>

 

Ora aggiungiamo il codice per il metodo di Sign Up nel controller AccountController.cs

 public ActionResult SignUp()
 {
     // genera un valore random per identificare la richiesta
     string stateMarker = Guid.NewGuid().ToString();
     
     //crea una richiesta OAuth2
     string authorizationRequest = String.Format(
         "https://login.microsoftonline.com/common/oauth2/authorize?response_type=code&client_id={0}&resource={1}&redirect_uri={2}&state={3}",
          Uri.EscapeDataString(System.Configuration.ConfigurationManager.AppSettings["ida:ClientID"]),
          Uri.EscapeDataString("https://graph.windows.net"),
          Uri.EscapeDataString(this.Request.Url.GetLeftPart(UriPartial.Authority).ToString() + "/Account/SignIn"),
          Uri.EscapeDataString(stateMarker)
          );
  
     // rimanda l'utente alla pagina di conferma permessi
     return new RedirectResult(authorizationRequest);
 }

Infine per comodità di test, andiamo a rimuovere l’attributo [Authorize] da HomeController.cs in modo da far aprire subito la Home page anche se non ancora autenticati

image

 

A questo punto per testare il Single Sign On ci occorre un utente che non faccia parte della nostra directory Developer Company, come ad esempio un utente di un tenant Office 365 (che come abbiamo detto si appoggia ad Azure AD) oppure semplicemente un utente di un’altra directory.

Per il nostro esempio utilizzerò infatti il mio utente di O365 per effettuare il sign-on

 

Bene, adesso siamo pronti a testare la nostra applicazione!

Torniamo quindi in Visual Studio e lanciamo l’esecuzione nel browser. Una volta avviata l’applicazione, se proviamo a cliccare sul nuovo link che abbiamo aggiunto, veniamo reindirizzati alla pagina standard di Sign-up

image  image

Una volta inseriti utente e password, ci viene automaticamente mostrata la pagina di richiesta dei permessi di cui l’applicazione ha bisogno e che l’utente deve autorizzare

image

Cliccando su “Accetto” veniamo reindirizzati alla home page della nostra applicazione con l’utente autenticato Sorriso

image

Accedendo ora alla directory del tenant Office 365 dell’utente che si è appena registrato, possiamo notare che l’applicazione MyWebApp è stata automaticamente aggiunta fra le applicazioni autorizzate

clip_image002

 

In conclusione, grazie all’integrazione di Visual Studio con Azure e grazie alle librerie a nostra disposizione, abbiamo visto come poter implementare l’autenticazione ed il SSO tramite Azure AD, sfruttando questi strumenti per minimizzare lo sforzo di gestire un flusso normalmente piuttosto complesso.

Good coding!