Quantcast
Channel: Groovy – Publicis Sapient Engineering – Engineering Done Right
Viewing all articles
Browse latest Browse all 76

Grails Spring Security Plugin, la sécurité facile

$
0
0

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 :

grails_tuto_1

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 :

grails_tuto_2

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 :

grails_tuto_3

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 :

grails_tuto_4

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 :

grails_tuto_5

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 :


Viewing all articles
Browse latest Browse all 76

Trending Articles