Le monde Grails a le vent en poupe ces temps-ci. Bien avant le printemps on peut voir fleurir des dizaines de tutoriaux sur le net pour prendre l’outil en main et créer sa première application. Mais un simple « Getting started » ne suffit pas toujours à bien prendre la mesure de la puissance de Grails.
Je vous propose donc un petit tutoriel pour mettre en place une gestion des utilisateurs, avec gestion des rôles, filtres URL/Rôles, formulaire de souscription de compte. Pour cela, nous allons nous appuyer sur le Spring Security Plugin de Grails. C’est une étape incontournable de la création d’application, et nous allons pouvoir constater à quel point l’utilisation de Grails booste la productivité.
Béni soit le scaffolding
Commençons par créer l’application BookStore
qui nous servira de base, ainsi qu’une classe de domaine Book
.
grails create-app BookStore cd BookStore grail create-domain-class fr.xebia.bookstore.common.Book
Apportons quelques modifications à notre classe pour qu’elle soit un peu plus parlante dans la suite des exemples :
grails-app/domain/fr/xebia/bookstore/common/Book.groovy
package fr.xebia.bookstore.common class Book { String titre String auteur Date premierePublication static constraints = { titre(nullable:false) auteur(nullable:false) } }
Maintenant nous générons le CRUD autour de notre classe Book
.
grails generate-all fr.xebia.bookstore.common.Book
Installation du plugin Spring Security. Pas de panique, acegi
est toujours le nom du plugin, c’est un héritage de l’histoire
grails install-plugin acegi
Creation des classes de domaines pour la gestion de la sécurité, Utilisateur, roles et mapping de security et génération des managers associés
grails create-auth-domains fr.xebia.bookstore.security.User fr.xebia.bookstore.security.Role fr.xebia.bookstore.security.RequestMap grails generate-manager
Maintenant nous générons les composants nécessaires à la souscription d’un compte par un internaute.
grails generate-registration
A ce stade, nous disposons des contrôleurs suivants (et des vues qui vont avec) :
- CaptchaController : permet de générer des images captcha pour éviter que des robots ne viennent créer des comptes utilisateurs
- fr.xebia.bookstore.common.BookController : CRUD de gestion de la classe
Book
- LoginController : Contrôleur de connexion
- LogoutController : Contrôleur de déconnexion
- RegisterController : Contrôleur d’enregistrement d’un compte utilisateur par un internaute
- RequestMapController : CRUD de gestion des règles de sécurité
- RoleController : CRUD de gestion des rôles
- UserController : CRUD de gestion des utilisateurs, destiné à notre espace d’administration
On peut déjà démarrer l’application avec un grails run-app
et voir ce que ça donne :

Configuration et sécurisation
Cela fait déjà beaucoup de matières à exploiter en un temps relativement court. Mais en l’état c’est encore un peu brut de fonderie pour ressembler à une vraie application. Nous allons donc faire un peu de configuration et de rangement autour de tout ce code parachuté par Grails. Pour atteindre notre objectif, nous allons maintenant procéder à la sécurisation des écrans de :
- CRUD complet des utilisateurs
- CRUD complet des rôles
- CRUD complet des mappings de sécurité
- Création de
Book
Tout est déjà en place pour cela grâce au code que nous avons généré. Commençons par utiliser le RoleController
pour créer un rôle utilisateur et un rôle administrateur :

Maintenant que nous avons des rôles, il faut créer un compte utilisateur avec le rôle ROLE_ADMIN pour éviter de se retrouver bloqué quand on posera les mappings de sécurité. Cette fois, c’est du coté des écrans du UserController
que ça se passe :

Et pour finir, on pose des mappings de sécurité sur les URL qui nous intéressent, avec la liste des rôles autorisés à accéder. Pour cela, nous utilisons le RequestMapController
:

Et voilà ! Notre application répond déjà mieux à nos attentes en terme de sécurité :
- tout le monde peut voir la liste des
Book
présents en base. - seuls les utilisateur ayant le rôle ROLE_USER ou ROLE_ADMIN peuvent insérer de nouveaux
Book
- seuls les utilisateur ayant le rôle ROLE_ADMIN peuvent créer des utilisateurs, des rôles et modifier les règles de sécurité
Si un utilisateur non authentifié tente d’accéder à une URL protégée, il sera automatiquement redirigé vers un écran de login avant d’accéder à la page désirée.
Adaptations de confort
Par défaut, une application Grails utilise HSQLDB et démarre avec une base vierge à chaque lancement. Nous allons donc changer cela pour intégrer directement à chaque démarrage les rôles, mappings de sécurité et un compte administrateur :
grails-app/conf/BootStrap.groovy
import fr.xebia.bookstore.security.User import fr.xebia.bookstore.security.Role import fr.xebia.bookstore.security.RequestMap class BootStrap { def authenticateService def init = { servletContext -> def roleAdmin = new Role(authority: 'ROLE_ADMIN', description: 'Administrateur').save() def roleUser = new Role(authority: 'ROLE_USER', description: 'Utilisateur').save() def userAdmin = new User(username: 'admin', userRealName: 'ATTAN Charles', passwd: authenticateService.encodePassword('admin'), enabled: true, email: 'admin@bookstore.fr') userAdmin.addToAuthorities(roleAdmin) userAdmin.save() def protectBookCreation = new RequestMap(url: '/book/create*', configAttribute: 'ROLE_ADMIN,ROLE_USER').save() def protectUserManaging = new RequestMap(url: '/user/*', configAttribute: 'ROLE_ADMIN').save() def protectRoleManaging = new RequestMap(url: '/role/*', configAttribute: 'ROLE_ADMIN').save() def protectSecurityMappingManaging = new RequestMap(url: '/requestMap/*', configAttribute: 'ROLE_ADMIN').save() } def destroy = { } }
Voilà, au prochain démarrage nous retrouverons toutes nos chères données directement en base. Ensuite, nous pouvons nous attaquer à l’enregistrement des internautes en tant qu’utilisateur standard. Par défaut, le formulaire lié au RegisterController
crée des utilisateurs sans rôle, ce qui ne nous convient pas du tout. De plus, comme il serait agréable pour les nouveaux utilisateurs de recevoir un mail de confirmation de leur inscription, on va le mettre en place dans la foulée :
grails-app/conf/SecurityConfig.groovy
security { active = true loginUserDomainClass = "fr.xebia.bookstore.security.User" authorityDomainClass = "fr.xebia.bookstore.security.Role" requestMapClass = "fr.xebia.bookstore.security.RequestMap" defaultRole = 'ROLE_USER' // Role par defaut des nouveaux utilisateurs useMail = true // specifie d'envoyer un mail à l'enregistrement d'un compte mailHost = 'localhost' // serveur d'envoi de mails mailProtocol = 'smtp' // nom du protocole JavaMail mailFrom = 'no.reply@bookstore.fr' // adresse de l'envoyeur du mail mailPort = 25 // port de connexion au serveur de mail }
Avec ces modifications, tous les internautes qui créeront des comptes par le formulaire obtiendrons le rôle ROLE_USER et recevront un mail comme ceci :

Si vous souhaitez adapter un peu le format du mail, le code associé est situé vers la ligne 170 du code de RegisterController
:
extrait de grails-app/controllers/RegisterController.groovy
[...] if (config.security.useMail) { String emailContent = """You have signed up for an account at: ${request.scheme}://${request.serverName}:${request.serverPort}${request.contextPath} Here are the details of your account: ------------------------------------- LoginName: ${person.username} Email: ${person.email} Full Name: ${person.userRealName} Password: ${params.passwd} """ def email = [ to: [person.email], // 'to' expects a List, NOT a single email address subject: "[${request.contextPath}] Account Signed Up", text: emailContent // 'text' is the email body ] emailerService.sendEmails([email]) } [...]
Et voilà comment en quelques minutes on peut avoir une application, basique certes… mais sécurisée !
Pour aller plus loin
Le plugin Grails Spring Security possède de nombreuses autres options. Je n’ai développé ici que la stratégie de stockage des règles de sécurité dans la base, mais il est également possible de les définir directement dans le fichier SecurityConfig
, ou par annotations des méthodes des contrôleurs.
On peut appuyer la sécurité sur OpenID, LDAP, CAS, NTLM ou même utiliser une connexion FaceBook Connect. On peut changer l’algorithme de cryptage des mots de passe, les possibilités sont assez étendues.
Et si vraiment Spring Security ne vous convient pas, il existe d’autres solutions de sécurité à base de plugins comme Shiro ou Stark, qui feront peut-être l’objet d’autres articles dans le futur.
Conclusion
L’utilisation du plugin Grails Spring Security permet de mettre le pied à l’étrier très rapidement, en s’appuyant sur un standard des frameworks de sécurité en Java. J’ai personnellement beaucoup apprécié la simplicité de prise en main et les exemples fournis dans la documentation officielle. Je vous invite d’ailleurs à la parcourir, elle contient d’autres tutoriels notamment pour l’utilisation de OpenID et LDAP.
Nota Bene : Cet article est fortement inspiré de celui-ci, mais il méritait des précisions à mon goût.
Ressources :