Objectif
La toute première dépendance fonctionnelle de l’application test est l’Identity and Authorization Management : il faut gérer les utilisateurs, leur capacité à prouver leur identité et les attributs d’identification qui découlent de l’authentification, et qui vont servir ensuite pour la gestion des autorisations.
Il s’agit de la toute première découpe claire des responsabilités qu’il est essentiel d’avoir dans une application :
- Identification : ce qui décrit le compte, et par delà le compte la personne qui le possède quand il s’agit de comptes individuels.
- Authentification : preuve que la personne qui manipule le compte est bien celle qui est prévue pour cela. Un mot de passe ou toute autre preuve fait en sorte que l’identification soit validée électroniquement. Attention, on a parfois tendance à en déduire que c’est une preuve d’identité, mais pour cela, il faudrait aussi que le compte soit délivré par une autorité de confiance qui a vérifié que les attributs du compte étaient bien ceux d’une personne physique à laquelle le compte a été confiée. Et encore, cela ne suffit pas dans le sens où une personne peut très bien confier son compte à une autre. Mais dans ce cas, la charge de la preuve d’usurpation est à l’utilisateur (c’est la raison pour laquelle les conditions générales incluent souvent que vous ne devez pas confier votre compte à une autre personne : pour se couvrir en cas de dispute sur l’identité).
- Autorisation : les droits que le compte obtient de par ses attributs d’identité, ou associés à son identité. Par exemple, des groupes d’appartenance, des caractéristiques particulières, etc.
L’IAM Keycloak est un produit open source qui va nous permettre de gérer l’authentification et l’identification des comptes pour notre application. La gestion des autorisations sera réalisée dans l’application, encore que comme elle est basée sur des attributs d’identité, on pourrait dire que l’IAM a une responsabilité partielle (nous y reviendrons, mais sur les 5 responsabilités des autorisations telles que définies dans XACML, l’application sera le PDP, le PRP, le PEP, tandis que l’IAM sera le PIP ; il n’y aura pas de PAP dans un premier temps).
L’authentification sera assurée par le protocole OpenID Connect. L’avantage d’utiliser un tel protocole standard est qu’il nous permettra d’élargir aisément vers des fournisseurs d’authentification différents comme Microsoft LiveID, Google ID, France Connect, etc.
L’identification sera assurée par un simple annuaire interne géré par Keycloak. Dans le futur, peut-être qu’un annuaire LDAP sera utilisé, mais c’est tout l’avantage de passer par le protocole normalisé fourni par Keycloak : l’application se branchera sur OIDC et consommera des tokens JWT, et c’est Keycloak qui fera l’indirection avec les implémentations sur des mots de passe et des caractéristiques stockées localement. Si l’implémentation change, ce sera absolument transparent pour l’application. Afin de tester ceci, nous pourrons par exemple remplacer Keycloak par un LemonLDAP-NG, et vérifier que, le paramétrage mis à jour, l’application fonctionne sans ajustement de code quelconque.
Démarrage de Keycloak
Grâce à Docker, rien de plus simple que de démarrer un server Keycloak :
docker run -p 8080:8080 -d -e KEYCLOAK_ADMIN=armoire -e KEYCLOAK_ADMIN_PASSWORD=vBWtB2PloopC042cszXZ –name iam quay.io/keycloak/keycloak:18.0.2 start-dev
Le nom d’utilisateur n’est pas admin ni administrator ni root ou n’importe quelle autre valeur qui puisse faciliter la vie à un éventuel attaquant. Le mot de passe est robuste (et unique pour ce service + stocké dans un outil comme Keepass). Le port 8080 est réexposé sur la machine locale avec le même numéro. Le conteneur est nommé pour faciliter les manipulations dessus. L’image est dans sa version la plus récente au moment de l’écriture de ce blog. C’est une bonne pratique d’utiliser des images fixes : bien sûr, il faut faire l’effort de réaliser les mises à jour régulières, mais au moins, on ne risque pas d’être surpris en production par une modification non compatible. Le choix dépend toutefois aussi de l’importance de la mise à jour et de la confiance que vous avez dans la capacité du fournisseur à respecter la compatibilité ascendante. Enfin, les arguments de ligne de commande correspondent pour l’instant à un démarrage en mode développement. Dans un article plus loin, nous passerons Keycloak dans un mode plus proche de la production (SSL, gestion de la persistance dans une base de données, etc.).
Pas d’inquiétude si le port ne répond pas tout de suite :
Keycloak est un peu lent à se mettre en route, comme vous pourrez le constater en suivant les logs en mode dynamique :
Une fois démarré pour de bon, la page d’accueil permet d’accéder à la console :
Et vous vous connecterez alors avec le compte et le mot de passe utilisé plus haut :
Nous pouvons passer au…
Paramétrage de Keycloak
Tout d’abord, nous allons paramétrer un tenant dans Keycloak, ce qui s’appelle un royaume (realm en anglais) dans le jargon de l’IAM :
Ce royaume pourrait servir pour authentifier plusieurs utilisateurs pour plusieurs applications : en tant que tenant, il faut vraiment se positionner comme si vous lanciez plusieurs fois l’application Keycloak, sauf que celle-ci vous permet en fait de n’avoir qu’un seul serveur qui tourne, mais avec des contextes complètement étanche que sont les tenants. Pour notre exemple, nous pourrions imaginer le nom d’une société fictice qui s’appellerait Coucou Incorporated. Le royaume sera donc nommé comme ceci :
A l’intérieur de ce royaume, nous allons créer un client. Cette fois, il s’agit de l’entité qui va supporter un mode d’authentification particulier dédié à une application. Comme notre but est d’apporter l’authentification et l’identification à l’application TestOIDCBlazorWASM, il est logique que le client s’appelle pareil :
A noter que le protocole SAML est également proposé, en plus d’OpenID Connect, mais il s’agit d’un protocole plus ancien, et proche de l’obsolescence même si, les choses changeant lentement dans le domaine de l’IAM, il est encore largement utilisé.
Dans le client, nous allons commencer par l’onglet Settings, dans lequel il faudra déclarer les URLs valides pour la redirection. OIDC fonctionne en effet en prenant la main sur le navigateur, en demandant les crédentiels, et ensuite en redirigeant vers la page web initiale tout en lui passant un code qui lui permettra d’appeler en retour le service d’IAM et d’obtenir un token JWT portant l’identification de la personne (en tout cas, dans le flow standard). Par sécurité, les URLs autorisées pour cette redirection doivent donc être spécifiées. Nous anticipons un peu, mais l’application sera déployée dans un premier temps en local, sur le port 88. Et comme nous utiliserons le mécanisme d’authentification intégré de .NET, les URLs à paramétrer sont comme ceci :
Ensuite, pour ne pas avoir de problème de CORS, il faut également déclarer que l’application web est une origine autorisée pour l’appel à l’IAM (sinon la requête avec le code fourni lors de la redirection ne sera pas autorisé). Ceci est fait un peu plus bas dans le même onglet :
Attention à ne surtout pas mettre un slash à la fin, sinon le mécanisme plante ! Oui, c’est très sensible…
Dans l’onglet Roles, déclarez ensuite deux rôles qu’on appellera administrateur et lecteur. Le but est en effet de faire en sorte que l’application soit propre du point de vue RBAC (Role Based Access Control), c’est à dire que les autorisations reposent sur la définitions de rôles associés aux groupes ou aux utilisateurs. La question de la persistance de ces définitions de rôles et de leur association aux attributs d’identité se pose : une séparation stricte des responsabilités voudrait qu’elles se trouvent dans l’application, car seul le métier fonctionnel peut au final définir clairement des autorisations sur les entités qu’il manipule. Mais la tentation de la centralisation de la gestion des rôles est en général forte dans les entreprises, et nous sacrifierons ici à cette approche. Nous reviendrons toutefois sur ce point lors de l’article sur la gestion complète des autorisations, avec XACML ou avec OPA. En attendant, les rôles sont déclarés dans Keycloak, mais sur le client défini (attention à ne pas définir des rôles globaux au niveau du royaume, en utilisant le menu sur la gauche ; c’est bien l’onglet Roles du client juste créé qui doit être utilisé) :
Pour que les rôles soient envoyés lors de l’authentification / identification, il faut créer un mapper qui va les associer au ticket (bouton Add builtin dans l’onglet Mappers). Pour cela, on générera un mapper de type client roles puis on accédera à ce mapper pour modifier le paramétrage et faire en sorte que les rôles soient disponibles aussi dans le token d’identification :
Cette manipulation est nécessaire parce que les rôles seront sinon uniquement dans l’access token, qui est le second JWT utilisé, et envoyé au serveur pour qu’il décide des autorisations. Dans notre cas, l’application est une SPA en Blazor et pour pouvoir n’afficher des menus que si les droits sont présents (ce qui ne veut bien sûr pas dire qu’on peut se permettre de ne pas revérifier les autorisations côté serveur), il faut bien que nous ayons cette info dès la phase d’authentification passée et le premier JWT (celui d’identification) récupéré.
Création d’un utilisateur
Le client (au sens OIDC, à savoir la définition dans l’IAM de l’application autorisée à utiliser le service) étant prêt, il reste à créer un utilisateur. A terme, nous ferons quelque chose de plus sophistiqué en branchant Keycloak sur un annuaire LDAP ou – mieux – sur une application qui simulerait un legacy, ce qui nous permettra de montrer l’extensibilité de Keycloak à l’aide d’un plugin intégré dans un JAR. Mais là encore, j’anticipe…
Pour créer un utilisateur, pas besoin d’explications particulières, ça se passe dans le menu Users. Dans un premier temps, on peut se contenter d’un utilisateur auquel on donnera les deux rôles clients administrateur et lecteur :
Quand vous donnez les crédentiels, inutile de laisser le mode de passe en temporaire : vu que vous utiliserez vous-même le compte, pas besoin qu’on vous demande à la première connexion de changer le mot de passe…
Test
Si vous retournez sur les informations générales du client, vous verrez que les endpoints sont en fait des liens :
En ouvrant le premier, qui est celui qui nous concerne, vous obtenez la définition formelle du endpoint OIDC :
En réduisant l’URL à juste le début, vous accédez à une page plus réduite qui expose la clé publique utilisée par le client, ainsi que l’adresse pour le token et l’adresse pour la gestion de compte :
C’est cette dernière qui nous intéresse pour tester que l’utilisateur fonctionne bien. En allant dessus, vous arrivez sur l’interface de gestion de son compte pour l’utilisateur. Et il peut bien sûr se connecter avec le bouton en haut à droite :
Si ça marche, c’est que l’utilisateur – au moins – est bien créé :
Ca ne veut pas dire que tout est bien paramétré, mais pour l’utilisation de cette IAM dans une application, nous verrons au prochain article !