Sécuriser une application Spring Boot/Angular avec KeyCloak [Part 1]
Dans cette première partie, nous allons apprendre à installer, configurer et utiliser Keycloak, créer une API REST avec Spring Boot et la sécuriser, nous verrons dans la deuxième partie la création d’un front avec Angular et comment sécuriser l’application entière avec Keycloak.
Keycloak c’est quoi ?
Comme vous pouvez le savoir, la majorité des applications aujourd’hui ont besoin de mettre en place un système d’authentification robuste, pour répondre à ce besoin il existe un paquet de solutions comme OpenAM, WSO2, KeyCloak, donc nous pouvons définir Keycloak comme identity/access manager open source.
Quelques mots sur Keycloak ?
- Solution open source développée en Java et portée par Redhat.
- Il propose plusieurs adaptateurs/connecteurs Spring Boot & Spring Security & Tomcat , JavaScript, NodeJS , Android …
- Prise en charge d’openID Connect (une extension de OAuth 2.0) et SAML 2.0
- Il offre une API Rest pour la partie administration
- Il propose une console d’administration pour la gestion centralisée des utilisateurs
- Il permet la gestion de session / Prise en charge de CORS
- Une bonne documentation 😃
- ….
Dans ce tutoriel, nous allons se baser sur le protocole OpenID connect (OIDC), comme j’ai déjà mentionné, OIDC est une extension d’ OAuth 2.0 qui utilise quelques normes de JWT ( JSON WEB Token), ce dernier donne la possibilité de définir un token en format JSON comme suite :
Un Token JWT est simplement constitué de trois parties séparées par un point : header.payload.signature.
Le header indique l’algorithme utilisé dans l’encodage, le payload contient les informations en base64 sur l’utilisateur connecté, l’expiration du token … les champs utilisés sont définis par la spécification registered claims, et enfin la signature c’est l’encodage du header et du payload en utilisant l’algorithme prédéfini dans le header.
Pour mieux connaître JWT n’hésitez pas d’aller sur leur site officiel
=> Donc tout ça pour dire que le token généré par Keycloak est un JWT.
Installation de KeycLoak
Pour une installation en local il suffit de suivre les étapes suivantes :
- Aller sur la page de téléchargement de Keycloak
- Récupérer la version 4.8.1.Final en “Standalone server distribution”
- Décompresser cette version dans votre répertoire de travail
Pour démarrer Keycloak en local, il suffit de lancer le script standalone.bat situé dans le répertoire bin/
Keycloak est démarré par défaut sur localhost:8080
Pour pouvoir configurer Keycloak, il nous faut un compte admin que nous pouvons créer via la console d’administration comme suit :
Cliquez sur Create, une fois vous êtes connectés, la console d’administration doit ressembler à l’image suivante :
Fonctionnement de KeyCloak
Il est nécessaire de connaître certains concepts et termes clés avant d’essayer d’utiliser Keycloak pour sécuriser vos applications Web et vos services REST
Utilisateurs : Ils sont des entités pouvant se connecter à votre système
Rôles : ils identifient un type ou une catégorie d’utilisateur. Admin
, user
, …
Groupe : permet de gérer un groupe d’utilisateur
Royaumes (realms): un domaine qui gère un ensemble d’utilisateurs, d’informations d’identification, des rôles et des groupes.
Clients : ils sont des entités pouvant demander à Keycloak d’authentifier un utilisateur ( comme des applications )
Identity token: un token qui fournit des informations d’identité sur l’utilisateur
Access token : un token pouvant être fourni dans le cadre d’une requête HTTP autorisant l’accès au service invoqué.
Thèmes : Les thèmes et styles CSS à appliquer aux templates Keycloak sur les pages (login, registration, account ..Ect) et les emails.
Pour approfondir le sujet, n’hésitez pas d’aller jeter un œil sur la documentation
Le schéma suivant résume le fonctionnement de Keycloak
Maintenant, nous allons mettre tout ça en pratique en essayant de sécuriser une application Spring Boot. Nous allons commencer par créer un projet Spring Boot de type web pour mettre en place une API Rest de gestion de produits
Les dépendances Maven
Pour sécuriser une application Spring Boot avec Keycloak, nous aurions besoin des deux dépendances, le starter spring boot et l’adapter keycloak
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-adapter</artifactId>
<version>${keycloak.version}</version>
</dependency>
Une classe model ‘Produit’
package fr.tuto.keycloak.app.modele;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@AllArgsConstructor
public class Product {
private String id;
private String reference;
private double price;
}
Remarque : les annotations @Setter @Getter proviennent de la libraire lombok qui permet de générer les getters et les setters à la compilation.
Un contrôleur qui propose une unique ressource ‘/products’ qui permet de récupérer la liste des produits
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping("/products")
public List<Product> getProducts() {
return productService.getProducts();
}
}
Un service de produit qui nous construit une liste de produits
package fr.tuto.keycloak.app.services;
import fr.tuto.keycloak.app.modele.Product;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProductService {
public List<Product> getProducts(){
return List.of(
new Product("id1","XXABC",120.00),
new Product("id2","XXZER",130.00),
new Product("id3","XXRFR",110.00),
new Product("id4","XXTER",140.00)
);
}
}
Remarque : List.of est une nouveauté de Java 1.9, si vous utilisez une version antérieure, vous pouvez passer par Arrays.asList() pour construire votre liste.
Un petit index.html permettant d’accéder à la resource /products.
<!DOCTYPE html>
<html>
<head>
<title>My Products App</title>
</head>
<body>
<h1>KeyCloak Test</h1>
<a href="/products">My products</a></body>
</html>
Un Runner classique Spring Boot
package com.softeam.keycloak.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class KeycloakAppApplication {
public static void main(String[] args) {
SpringApplication.run(KeycloakAppApplication.class, args);
}
}
Remarque : il ne faut pas oublier de modifier le port pour que l’application tourne sur un autre port que le 8080 car Keycloak tourne par défaut sur le même port ou faire le contraire et modifier le fichier de configuration Keycloak sur \standalone\configuration\standalone.xml
<socket-binding name=”http” port=”${jboss.http.port:8080}”/>
Configuration Keycloak
Création d’un domaine/realm Keycloak
Configuration d’un realm
Dans ma configuration, j’ai choisi l’option User registration, Forgot password et Login with email, vous pouvez sélectionner les options les plus convenables pour votre application.
Ajout d’un rôle
Nous avons au moins un rôle pour l’associer à nos utilisateurs.
Ajout d’un client
Comme j’ai déjà précisé, un client correspond à la ressource qui va demander l’authentification à Keycloak, donc finalement l’Api REST de produits que nous avons déjà créé.
Configuration du client
Mapping user to role
Pour associer un utilisateur à un rôle, il est nécessaire de passer par le bloc ‘Role Mappings’ de la vue user.
Côté application Spring BOOT
Après avoir ajouté l’adapter Keycloak pour Spring Boot et le démarreur Keycloak Spring Boot comme dépendances , il reste qu’à fournir une configuration supplémentaire via Spring Boot (application.properties
).
En général, une configuration Keycloak doit se faire via la mise à disposition d’un fichier keycloak.json , dans le cas de Spring Boot, nous passerons directement par applications.properties
keycloak.auth-server-url=http://localhost:8080/auth
keycloak.realm=spring-boot
keycloak.public-client=true
keycloak.resource=products-app
Ensuite, au lieu de passer par le web.xml pour configurer la partie sécurité, il suffit d’ajouter les properties suivantes dans applications.properties et c’est Spring qui va assigner login-method à Keycloak et il va configurer les contraintes de sécurité au moment du démarrage de l’application.
keycloak.security-constraints[0].authRoles[0]=manager
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/products/*
Finalement , je vais modifier le fichier index.html pour ajouter la possibilité de se déconnecter et de gérer son compte Keycloak via notre application web.
En règle générale, pour déconnecter un utilisateur Keycloak, il faut passer par une URL qui ressemble à la suivante :
http://auth-server/auth/realms/{realm-name}/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri
Tandis que pour la gestion de son compte, il faut passer par l’Url suivant :
http://auth-server/auth/realms/{realm-name}/account/
Keycloak fournit un client par défaut nommé “Account” qui permet la gestion d’un compte utilisateur
Notre index.html ressemblera désormais à :
<!DOCTYPE html>
<html>
<head>
<title>My awesome landing page</title>
</head>
<body>
<h1>KeyCloak Test</h1>
<a href="/products">My products</a>
<footer>
<a href=http://localhost:8080/auth/realms/spring-boot/account/ >Gérer mon compte</a>
</footer>
</body>
</html>
Récapitulatif
Résultat
En arrivant sur http://localhost:8081/products, Keycloak va nous proposer de s’authentifier via sa page de login par défaut
Il faut utiliser l’utilisateur que nous avons déjà créé pour se connecter , une fois la connexion est aboutie nous aurions le résultat suivant :
Modifier le thème de la page de login
Toutes les pages fournies par Keycloak comme la page de login, la page d’inscription et la page de gestion de comptes sont modifiables, nous pouvons mettre en place le style CSS qui convient à nos applications, c’est ce que nous allons essayer d’appliquer sur la page de login.
Pour modifier le thème Keycloak, il faut passer par Realm Settings / Thèmes comme suit :
Keycloak propose la liste des thèmes disponibles pour toutes les pages, ainsi que les emails ( eh oui nous pouvons aussi créer nos propres templates de mails 😜)
Par défaut Keycloak propose deux thèmes :
Nous allons voir comment peut-on créer notre propre thème et ainsi le déployer sur Keycloak et l’appliquer à notre domaine/realm.
Let’s go ✌️
Il est recommandé de copier et de modifier un thème existant.
Pour pouvoir modifier le thème et voir les modifications sans redémarrer le serveur Keycloak, vous devez modifier le fichier “standalone.xml” sur votre serveur Keycloak afin de désactiver la mise en cache.
<theme>
<staticMaxAge>-1</staticMaxAge>
<cacheThemes>false</cacheThemes>
<cacheTemplates>false</cacheTemplates>
...
</theme>
Cette manipulation ne doit pas se faire en production car ça peut engendrer des grands problèmes de performance.
Nous commençons par dupliquer le théme ‘keycloak’ en allant sur \themes 👇
J’ai renommé le dossier en ‘product-app’
Nous pouvons vérifier dans la configuration si Keycloak propose déjà notre nouveau thème products-app 👇
Maintenant il faut faire appel à vos compétences en CSS pour créer un style propre pour la page de login et comme j’ai des compétences très modestes en CSS, nous allons faire un exemple très simple.
Pour faire ceci il faut aller sur products-app/login/resources/*
Je vais modifier l’image du fond par exemple :
.login-pf body {
background: url(“../img/img.jpg”) no-repeat center center fixed;
background-size: cover;
}
Je vais également apporter quelques modifications au look des zones de texte et aux boutons, vous pouvez vous amusez en modifiant le fichier styles.css ( n’oubliez pas de nettoyer en cas de duplication 🙏).
Résultat
C’est moche, je sais 👊 le but était uniquement de montrer comment personnaliser les pages Keycloak en créant vos propres thèmes, après à vous de jouer 😄
Le code est disponible sous GitHub.