SERVLET TP 5 Description Réalisation

Transcription

SERVLET TP 5 Description Réalisation
SERVLET TP 5
L'objectif de ce TP est de maîtriser:
• le développement d’une tag lib personnalisée,
• le développement d’un servlet de login.
Description
L’objectif est de programmer un servlet qui va contrôler l’accès à une page JSP. L’idée ici est de ne pas
utiliser les possibilités offertes par le serveur d’application (rôles, realm, <security-constraint>, ou
<login-config>,…) mais de programmer la gestion des utilisateurs et des accès à certaines ressources de l’application. Cette façon de procéder est intéressante lorsque l’on souhaite être indépendant
d’un serveur d’application (portabilité afin d’être indépendant de Glassfish ou Tomcat par exemple),
ou bien lorsque l’on souhaite un contrôle individuel sur les accès. Bien sûr, cela représente en contrepartie plus de travail, et cela ne s’avère donc intéressant que si vos besoins sont ceux présentés.
Le deuxième aspect de ce TP est d’aborder la programmation de tags personnalisés. Vous allez programmer deux tags qui seront utilisés dans les pages JSP qui contrôleront les accès.
Le scénario est le suivant. On désire accéder à la page pageProtegee.jsp. Un login est demandé à
l’utilisateur (figure 1). Si l’utilisateur est inconnu, ou le mot de passe incorrect, une nouvelle authentification est demandée (figures 2 et 3). Si l’authentification est valide, alors la page protégée est affichée
à l’utilisateur.
!
Figure 1. Demande de login.!
!
!
!
Figure 2. Erreur (redirection vers le login) .
!
Figure 3. Ré-authentification.!
!
!
!
Figure 4. Accès à la page protégée.
Réalisation
Pour réaliser cette application, on va coder les éléments suivants:
• un servlet d’authentification,
• les pages JSP de login, d’erreur, et la page protégée,
• deux tags liés à la gestion de la sécurité: un pour forcer le login, l’autre pour afficher les messages
d’échec,
• un bean pour gérer les utilisateurs (version simplifiée ici car non reliée à un SBGD !).
La structure de l’application est la suivante:
Cette page est
protégée par
l'inclusion de ce tag
Lorsque le formulaire est soumis,
ce servlet est invoqué
Premièrement, le tag ForceLogin présent dans la page JSP recherche si l’attribut qui identifie l’utilisateur existe dans le contexte de la page (session scope). Si l’utilisateur existe dans la session (cela signifie
qu’il s’est préalablement identifié), le tag ne fait rien (l’évaluation de la page continue), sinon le tag
redirige vers la page de login (spécifiée en utilisant l’attribut de session page-login) et arrête l’évaluation de la page.
Si le login échoue, le contrôle est redirigé vers la page d’erreur. L’attribut page-erreur est optionnel.
S’il n’est pas instancié, la page de login est à nouveau affichée.
Lorsque le login est validé, l’utilisateur est identifié, puis créé et son identification est placée dans le
contexte de la session, et la suite de la page après le tag ForceLogin est évalué.
La page de login soumet le formulaire au servlet Authentification. Si le servlet arrive à authentifier
l’utilisateur (nom et mot de passe), il redirige la requête vers la page protégée. Dans le cas contraire, il
redirige la requête vers la page d’erreur (si elle est définie), ou vers la page de login (sinon).
Pour gérer les utilisateurs, on simule une base de données. La base de données est une instance de
UtilisateursBD, et les utilisateurs sont des instances de Utilisateur.
Le servlet d’authentification récupère le nom et le mot de passe à partir de la requête (issue du formulaire) et tente d’obtenir une référence vers un utilisateur correspondant dans la base de données. Si
l’utilisateur existe (et que le mot de passe est valide), les attributs de session générés par le servlet et le
tag ForceLogin sont supprimés de la session, et la requête est redirigée vers la page protégée. Si l’utilisateur n’est pas dans la base, un attribut de session erreur-login est positionné et la requête propagée à la page de gestion des erreurs (si elle est définit), ou à la page de login (sinon).
Voici des fragments de code pour vous aider.
ForceLogin.java
// si l’utilisateur est dans le contexte de la page, on évalue la page
// sinon on définit les attributs page-login, page-erreur et page-protegee
// et on transmet la requête à la page de login
public class ForceLogin extends TagSupport {
private String pageLogin, pageErreur;
public void setPageLogin(String pl) {
this.pageLogin = pl;
}
public void setPageErreur(String pe) {
this.pageErreur = pe;
}
public int doEndTag() throws JspException {
! // on récupère la session à partir du contexte de la page
!
// on récupère l’URL de la page protégée grâce à la requête
!
// si l’utilisateur n’est pas connu dans la session
!
// ! alors on va à la page login
!
// sinon on évalue la page
}
public void release() {
!
// on efface les pages de login et d’erreur
}
}
AfficheErreurs.java
public class AfficheErreurs extends TagSupport {
public int doStartTag() throws JspException {
! // on récupère la valeur de l’attribut erreur-login défini dans le
!
// contexte session
!
// si elle est différente de null
!
//! alors il y a une erreur et on affiche l’erreur dans le contexte
!
// on arrête d’évaluer la page
}
}
Authentification.java
public class Authentification extends HttpServlet {
private UtilisateursBD loginBD;
!
!
!
!
!
!
!
!
!
!
!
!
!
!
public void init(ServletConfig config) throws ServletException{
super.init(config);
loginBD = new UtilisateursBD();
}
public void service(HttpServletRequest req, HttpServletResponse res)
!
throws IOException, ServletException {
// on récupère la session à partir de la requête, sinon on la crée
// on récupère le nom de l’utilisateur et son mot de passe
//
dans la session
// on vérifie qu’il existe dans la base
// si c’est ok
// ! alors on récupère la page protégée dans la session
//! et on supprime les attributs d’échec/erreur
//! on place l’utilisateur dans la session et on redirige vers la
//! page protégée
// sinon
// ! on positionne les attributs page-login, page-erreur et
// ! erreur-login
// ! on redirige vers la page d’erreur (ou la page de login)
}
}
erreur.jsp
<html><head><title>Erreur login</title></head>
<!-- ici on insère la taglib -->
<body>
<font size='4' color='red'>
Echec de la connexion:<p>
<securite:afficheErreurs/></p></font>
Cliquer <a href='login.jsp'>ici</a> pour r&eacute;ssayer.
</body>
</html>
login.jsp
<html><head><title>Page de login</title></head>
<!-- ici on insère la taglib -->
<body>
<font size='4' color='red'><securite:afficheErreurs/></font>
<p><font size='5' color='blue'>Veuillez vous authentifier</font><hr>
<!-- formulaire avec action vers le servlet !-->
<!-- champ pour le nom !!
!
!
! -->
<!-- et champ pour le mot de passe!!
!
-->
</p>
</body>
</html>
pageProtegee.jsp
<html><head><title>Page prot&eacute;g&eacute;e</title></head>
<!-- ici on insère la taglib -->
<body>
<securite:forceLogin pageLogin='/login.jsp' pageErreur='/erreur.jsp'/>
<jsp:useBean id='utilisateur' type='beans.Utilisateur' scope='session'/>
Ceci est une page prot&eacute;g&eacute;e. Bienvenue
!
<%= utilisateur.getNomUtilisateur() %>.
</body>
</html>
Utilisateur.java
package beans;
public class Utilisateur implements java.io.Serializable {
private final String nomUtilisateur, mdp, msg;
!
// un bean pour gérer les utilisateurs
!
// et pour tester que le login et le mot de passe sont ok
}
UtilisateursBD.java
package beans;
import java.util.*;
public class UtilisateursBD implements java.io.Serializable {
private Vector utilisateurs = new Vector();
private Utilisateur[] listeUtilisateurs = {
new Utilisateur("olivier", "zimboum", "vide"),
};
public UtilisateursBD() {
for(int i=0; i < listeUtilisateurs.length; ++i)
utilisateurs.add(listeUtilisateurs[i]);
}
public void ajoutUtilisateur(String nom, String mdp, String msg) {
utilisateurs.add(new Utilisateur(nom, mdp, msg));
}
public Utilisateur getUtilisateur(String nom, String mdp) {
Iterator it = utilisateurs.iterator();
Utilisateur bean;
synchronized(utilisateurs) {
while(it.hasNext()) {
bean = (Utilisateur)it.next();
if(bean.equals(nom, mdp))
return bean;
}
}
return null;
}
}