Date de première publication : 2012/06/07
Objectif et contexte
L'objectif de cet exercice est d'ajouter une sécurité sur notre application web. Comme le sujet est vaste, complexe et toujours glissant, nous n'allons voir que les bases. Comme cela, vous n'aurez pas l'impression malsaine que votre application est blindée.
- Java SE 7 u3
- Java EE 6 u3
- Netbeans 7.1.2
- Glassfish 3.1.2
- Mojarra (JSF) 2.1.6
Mise en place d'une base d'utilisateurs
La première chose à faire est de créer une base d'utilisateurs : identifiant, rôle, mot de passe.
(O) Services > Servers > Glassfish Server (BD) View Domain Admin Console
Configuration > server-config > Sécurité > Domaines (realms) > file
(B) Gérer les utilisateurs (B) Nouveau
et saisir les informations suivantes :
- identifiant
- groupe (s)
- mot de passe à confirmer
Revenir au niveau Sécurité et cocher :
Mise en correspondance par défaut des principaux avec des rôles
(Role Mapping Enable)
On associera plus tard les identifiants (Principal) ou les groupes à des rôles utilisateur.
Authentification BASIC
Configuration
On va placer les informations de sécurité dans le fichier de déploiement web.xml
.
Cela peut se faire directement en XML mais on peut aussi utiliser l'interface graphique de Netbeans.
- Aller dans l'onglet (O) security
- Développer Login configuration
- cocher BASIC
- Realm name : file, spécifier le nomo du domaine
- Développer Security Role
- (B) Add
- Role name : Registered
- (B) Add Security Constraint
- URL Pattern : /faces/protect/*, /protect/*
- All HTTP methods
- Cocher Enable Authentication Constraint
- Role name : Registered
On suppose que les fichiers à protéger sont dans le répertoire protect
de web
Attention : sous Glassfish, les noms de rôle commencent obligatoirement par une majuscule
Il faut maintenant associer rôle et utilisateur ou groupe. Cela se fait en éditant le descripteur de déploiement de Glassfish :
glassfish-web.xml
(Ce fichier était nommé sun-web.xml
dans les versions antérieures à la 3.0)
Si ce fichier n'est pas présent, il faut le créer avec la manipulation suivante :
(N) New file (O) Glassfish > Glassfish descriptor
Il faut maintenant éditer la section Security du fichier
Développer Registered ou le créer comme Security Role Name puis préciser les ou les Principal (Groupes).
Pages protégées
Si le fichier ajout.xhtml
se trouve dans le répertoire /protect
,
vous pouvez constater qu'il est protégé
en tapant son url : XXXXX/faces/protect/ajout.xhtml
Mais comment accédez à la page par un lien ?
On utilise souvent la balise commandButton avec l'attribut action. Mais si vous essayez, vous allez constater que la page s'affiche et que la protection
Déconnexion
Le mécanisme d'authentification BASIC n'est pas fait pour la déconnexion. Envoyer une erreur 401 ne marche pas tout le temps. Le meilleur moyen est de fermer le navigateur.
Authentification par formulaire
C'est très similaire à ce que l'on vient de faire. Il suffit de changer le paramétrage du fichier de déploiement. Dans la section Security, cocher FORM et donner le nom d'une page web de connexion et le nom d'une page Web en cas d'erreur de connexion.
Si vos pages sont des pages facelets, il faut penser à la résolution de nom. Par exemple : /faces/login.xhtml
.
La page de connexion doit comporter les éléments suivants :
<form method="post" action="j_security_check">
<h:panelGrid columns="2">
<h:outputLabel for="j_username">Identifiant :</h:outputLabel>
<h:inputText id="j_username"/>
<h:outputLabel for="j_password">Mot de passe :</h:outputLabel>
<h:inputSecret id="j_password" />
</h:panelGrid>
<h:commandButton value="Se connecter" />
</form>
Notez bien que l'on ne peut pas utiliser de formulaire JSF, cela ne marcherait pas.
Le tutorial propose page 748 une autre méthode assez sympathique également. Il faut écrire un formulaire (JSF)
paramétré par les attributs login
et mdp
. L'action à réaliser est la suivante :
public void login() {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
try {
request.login(login, mdp);
context.addMessage(null, new FacesMessage("Et hop, reconnu"));
} catch (ServletException e) {
// Handle unknown username/password in request.login().
context.addMessage(null, new FacesMessage("Unknown login "+e.getMessage()));
// éventuellement log.log(Level.SEVERE, "Failed to logout user!", e);
// avec private static Logger log = Logger.getLogger(AuthBackingBean.class.getName());
}
}
Cette méthode est pratique :
- pour avoir une zone de l'écran qui affiche la connexion ou le nom de l'utilisateur.
- utiliser le mécanisme d'affichage des erreurs de JSF
- d'avoir des informations que la connexion sans regarder les logs.
- Si
login() renvoie une chaine de caractère, on peut choisir la page en fonction d'une éventuelle erreur.
Maintenant pour gérer une déconnexion, c'est beaucoup plus facile, il suffit d'invalider la session ou d'utiliser logout()
.
Voilà c'est tout pour cette découverte de la sécurisation. Prochaine étape : JAAS et sécurisation par base de données.