.NET - IdentityServer4 : apprendre à mettre en place une interface d'authentification en utilisant OpenID Connect
Par Hinault Romaric

Le , par Hinault Romaric

0PARTAGES

IdentityServer est une solution open source .NET de gestion d’identité et de contrôle d’accès. Il repose sur les protocoles OpenID Connect et OAuth 2.0.

IdentityServer peut être utilisé par les entreprises pour mettre en place une solution pour :

  • la protection de leurs ressources ;
  • l’authentification des utilisateurs via une base de données ou des fournisseurs externes d’identité (Microsoft, Google, Facebook, etc.) ;
  • la gestion des sessions et la fédération (single sign-on) ;
  • la génération des jetons pour les clients ;
  • la validation des jetons et bien plus.


Ce billet est le quatrième que j’écris sur le sujet. Les billets précédents ont porté sur les points suivants :

Mise en place d’un STS avec IdentityServer4 pour sécuriser ses applications .NET

Sécurisation d’une Web API ASP.NET Core avec le STS IdentityServer4

IdentityServer4 : création et configuration du Client pour accéder à une Web API ASP.NET Core sécurisée

Nous disposons d’une application Web dont nous voulons sécuriser certaines pages. Pour accéder à ces pages, l’utilisateur doit s’authentifier au préalable en utilisant son compte.
Nous devons donc intégrer cette nouvelle application à notre IdentityServer. Lorsque l’utilisateur vaudra accéder à une page protégée, il sera redirigé vers IdentityServer qui affichera une fenêtre d’authentification. Une fois ce dernier authentifié, il sera redirigé vers la page à laquelle il voulait accéder.

Ajout de l’interface d’authentification

Actuellement notre solution IdentityServer ne dispose d’aucune interface. Tout ce qu’elle est en mesure d’afficher dans un navigateur c’est un « Hello World! ».

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
        { 
            if (env.IsDevelopment()) 
            { 
                app.UseDeveloperExceptionPage(); 
  
            } 
  
            app.UseIdentityServer(); 
  
            app.Run(async (context) => 
            { 
                await context.Response.WriteAsync("Hello World!"); 
            }); 
        }

Elle ne dispose donc d’aucune vue, aucun contrôleur, etc. Pourtant, nous avons besoin d’une solution permettant d’authentifier un utilisateur via un formulaire, mettre fin à sa session, etc. Pour mettre cela en place, nous allons nous appuyer sur un modèle Quickstart existant fourni par les développeurs de IdentityServer4.

Ce modèle est disponible dans le repository GitHub suivant https://github.com/IdentityServer/Id.../release/Views. Vous pouvez le télécharger et copier/coller les dossiers Quickstart, Views et wwwroot dans votre projet.

Vous pouvez aussi simplement ouvrir le terminal Powershell dans le dossier racine du projet et exécuter la commande :

Code : Sélectionner tout
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1'))
Je n’entrerais pas dans les détails d’implémentation de ce modèle.

Transformation du projet en solution MVC

Le Quickstart que nous avons intégré repose sur ASP.NET MVC. Nous allons apporter quelques modifications à notre projet pour prendre en charge ASP.NET Core MVC.

La première chose à faire sera de modifier la méthode ConfigureServices() et ajouter la ligne de code suivante au début :

Code c# : Sélectionner tout
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

Cette ligne de code permet d’enregistrer les services pour la prise en charge de ASP.NET Core MVC.

Par la suite, vous devez modifier la méthode Configure pour intégrer les middlewares nécessaires à la gestion des fichiers statistiques et le routage. Par ailleurs, vous devez supprimer la ligne de code permettant d’afficher le « Hello Word! » :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
        { 
            if (env.IsDevelopment()) 
            { 
                app.UseDeveloperExceptionPage() ; 
  
            } 
  
            app.UseStaticFiles(); 
  
            app.UseIdentityServer(); 
  
            app.UseMvcWithDefaultRoute(); 
        }

Ajout du support pour OpenID Connect

OpenID Connect est une couche d'identification basée sur le protocole OAuth 2.0, qui autorise les clients à vérifier l'identité d'un utilisateur final en se basant sur l'authentification fournie par un serveur d'autorisation, dont IdentityServer. L’authentification d’un utilisateur via un formulaire avec IdentityServer repose sur OpenID Connect.

L’implémentation utilise le concept de scopes (portés). Nous devons définir comme nous l’avons fait précédemment pour l’API les ressources auxquelles le client doit accéder. Sauf qu’ici, il s’agit des informations du profil utilisateur (id, nom, email, etc.) que nous souhaitons partager avec le client. Ces ressources sont donc de type IdentityResources.

Pour le faire, nous allons éditer le fichier Config.cs et ajouter les lignes de code suivantes :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
public static IEnumerable<IdentityResource> GetIdentityResources() 
{ 
    return new List<IdentityResource> 
    { 
        new IdentityResources.OpenId(), 
        new IdentityResources.Profile(), 
    }; 
}

Une fois cela fait, nous devons modifier la méthode ConfigureServices du fichier Startup.cs pour ajouter cette nouvelle ressource à la configuration d’IdentityServer. Cela se fait en utilisant la méthode d’extension AddInMemoryIdentityResources :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
public void ConfigureServices(IServiceCollection services) 
        { 
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 
  
            //configure identity server with in-memory stores, keys, clients and resources 
            services.AddIdentityServer() 
                   .AddDeveloperSigningCredential() 
                   .AddInMemoryIdentityResources(Config.GetIdentityResources()) 
                    .AddInMemoryApiResources(Config.GetApiResources()) 
                   .AddInMemoryClients(Config.GetClients()); 
  
        }

Ajout des utilisateurs pour les tests

Les informations saisies par l’utilisateur dans le formulaire d’authentification doivent être validées avant de lui donner les accès. Cependant nous ne disposons pas d’une base de données des utilisateurs que nous pouvons utiliser. IdentityServer pour des besoins de tests permet de définir et utiliser une liste de type TestUser.

Nous allons une nouvelle fois modifier le fichier Config.cs et ajouter le code suivant pour définir notre liste d’utilisateurs avec leurs revendications (claims):

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 public static List<TestUser> GetUsers() 
        { 
            return new List<TestUser> 
            { 
                new TestUser{SubjectId = "818727", Username = "alice", Password = "alice", 
                Claims = 
                { 
                    new Claim(JwtClaimTypes.Name, "Alice Smith"), 
                    new Claim(JwtClaimTypes.GivenName, "Alice"), 
                    new Claim(JwtClaimTypes.FamilyName, "Smith"), 
                    new Claim(JwtClaimTypes.Email, "AliceSmith@email.com"), 
                    new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), 
                    new Claim(JwtClaimTypes.WebSite, "http://alice.com"), 
                    new Claim(JwtClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json) 
                } 
            }, 
            new TestUser{SubjectId = "88421113", Username = "bob", Password = "bob", 
                Claims = 
                { 
                    new Claim(JwtClaimTypes.Name, "Bob Smith"), 
                    new Claim(JwtClaimTypes.GivenName, "Bob"), 
                    new Claim(JwtClaimTypes.FamilyName, "Smith"), 
                    new Claim(JwtClaimTypes.Email, "BobSmith@email.com"), 
                    new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), 
                    new Claim(JwtClaimTypes.WebSite, "http://bob.com"), 
                    new Claim(JwtClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json), 
                    new Claim("location", "somewhere") 
                } 
            } 
            }; 
        }

Nous devons également modifier la méthode ConfigureServices du fichier Startup.cs pour ajouter cette liste à la configuration d’IdentityServer. Cela se fait en utilisant la méthode d’extension AddTestUsers lors de l’appel de AddIdentityServer() :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
public void ConfigureServices(IServiceCollection services) 
        { 
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 
  
            //configure identity server with in-memory stores, keys, clients and resources 
            services.AddIdentityServer() 
                   .AddDeveloperSigningCredential() 
                   .AddInMemoryIdentityResources(Config.GetIdentityResources()) 
                    .AddInMemoryApiResources(Config.GetApiResources()) 
                   .AddInMemoryClients(Config.GetClients()) 
                   .AddTestUsers(Config.GetUsers()); ; 
  
        }

Enregistrez les modifications et exécutez l’application. Vous aurez le résultat suivant affiché dans le navigateur :


Si vous cliquez sur « Click here to manage your stored grants. », vous essayerez d’accéder à une page protégée. De ce fait, vous serez redirigé vers la page d’authentification :



Vous venez de mettre en place une interface d’authentification en utilisant OpenID Connect. Dans le prochain billet, nous verrons comment configurer une application Web pour utiliser cette nouvelle fonctionnalité que nous avons intégrée à IdentityServer pour valider l’identité d’un utilisateur.

Restez connecté !

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de tomlev
Rédacteur/Modérateur https://www.developpez.com
Le 12/12/2018 à 11:01
Bon à savoir : IdentityServer s'intègre aussi très bien avec ASP.NET Core Identity (il suffit de faire un petit .AddAspNetIdentity() sur la conf d'IdentityServer)
Avatar de Eric80
Membre averti https://www.developpez.com
Le 12/12/2018 à 13:28
Merci pour cette bonne série d articles sur la sécurité avec Azure, pt important pour bcp d entreprises!

Suggestion pour un prochain article sur le sujet, si pas déjà 'in the pipeline': comment sécuriser les connexions entre noeuds Dockers dans un cluster Kubernetes? Que cela soit avec SSL, IdentityServer4, etc?

Quelques pistes:
https://www.hanselman.com/blog/Setti...InMinutes.aspx
https://stackoverflow.com/questions/...ubernetes?rq=1
https://stackoverflow.com/questions/...erver4-service
Avatar de stan92
Nouveau Candidat au Club https://www.developpez.com
Le 27/02/2019 à 19:19
Merci pour ce tuto..tip top..

J'ai une question qui me prends un peu la tête et je n'arrive pas à piger la chose.

J'aimerais savoir s'il est possible d'affecter des utilisateurs à des "Applis" (des clients pour IIS) ?
En d'autres termes, si j'ai deux applis MVC et une SPA, est il possible d'octroyer les droits d'accès à l'utilisateur U1 à l'ensemble des applis et à l'utilisateur U2 que l'accès à la SPA ?

La réponse peut être "triviale" mais je reste preneur

Et merci pour tout.
Avatar de mictif
Membre du Club https://www.developpez.com
Le 21/03/2019 à 16:38
Merci pour toutes ces explication détaillées !

Pi : le liens vers les views n'est plus bon -> https://github.com/IdentityServer/Id....Quickstart.UI
Contacter le responsable de la rubrique Accueil

Partenaire : Hébergement Web