Java EE / Spring

Master e-services 2015

View the Project on GitHub gdufrene/java_ee_spring-14

Persistance.

Il y a fort longtemps dans une galaxie lointaine ... lorsque l'on souhaitait accéder à une base de données relationnelle, on utilisait un drivers spécifique pour LA base de données visée et on écrivait du code SQL spécifique (car le SQL n'était pas encore très standardisé). On utilisait également des opérations spécifiques du drivers.

JDBC

Puis est arrivé JDBC ... une abstraction java permettant de standardiser un peu les méthodes qui manipulent ces bases. JDBC est une spécification : des interfaces et des objets disponibles dans le package java.sql.

Il reste nécessaire d'avoir le drivers de la base de données compatible JDBC, mais vous devriez être capable de changer de drivers (et donc de base de données) sans avoir à modifier trop de choses dans votre code.

Initialiser une base SQL

Nous allons tester JDBC avec une base minimaliste nommée "sqlite".
sqlite est fourni avec votre distribution linux, et souvent avec Mac OS x. Sous windows vous pouvez télécharger cette archive contenant une version pré-compilée.
C'est une base de données relationnelle "classique" qui a au moins trois avantages :

Commençons par créer une table et mettons y quelques données...
Placez-vous dans votre répertoire tomcat/webapps/tp1/WEB-INF
lancez sqlite avec la commande sqlite3 data.db

Créez une table "member" avec les colonnes "nom", "prenom", "email", "pwd".
Insérer le membre : Dufrene, Guillaume, -mon email-, test

create table member(
  nom    varchar(80),
  prenom varchar(80),
  email  varchar(100),
  pwd    varchar(45)
);
insert into member values( "Dufrene", "Guillaume", "xxEMAILxx", "test");

Connexion et requête d'une base

A partir de maintenant nous allons séparer les sources java et les classes.
Créez un répertoire "src" dans tomcat/webapps/tp1/WEB-INF
Créer un répertoire "jdbc" dans src
Utilisez cette interface et cette implémentation incomplète comme base de travail
pour récupérer ces sources facilement ... (dans WEB-INF/src/jdbc)

wget http://gdufrene.github.io/java_ee_spring-14/files/tp2/ITestJDBC.java
wget http://gdufrene.github.io/java_ee_spring-14/files/tp2/TestJDBC.java

Pour manipuler les données présentes dans sqlite, nous aurons besoin d'un drivers implémentant les spécification JDBC : sqlite-jdbc-3.8.11.2.jar.
Cette librairie fournie la classe java "org.sqlite.JDBC" qui est le drivers à utiliser.

Compilons ce petit objet qui se connecte à la base.
En vous plaçant dans "WEB-INF" :
javac -sourcepath src -d classes src/jdbc/TestJDBC.java
L'option "sourcepath" permet d'indiquer où trouver les fichiers sources nécessaire à la compilation. L'option "d" indique l'endroit où les fichiers class seront compilés.
Essayons de d'exécuter. Il sera nécessaire de rentre le drivers sqlite-jdbc accessible à l'exécution (dans le classpath)
java -cp lib/sqlite-jdbc-3.8.11.2.jar:classes jdbc.TestJDBC
L'option "cp" permet de spécifiez les endroits ou se trouve les class nécessaire, à la compilation, ou à l'exécution. Il peut contenir des répertoires ou des fichiers jar. Le classpath est séparé par ":" sous linux/mac et par ";" sous windows.
pour le moment vous devriez obtenir :

Test du mot de passe
 ==> false

Implémentez correctement la classe TestJDBC pour vérifier la correspondance d'un mail et d'un mot de passe.

Tester votre opération checkPasswordBasic
Attention le fichier check.jar a été mis à jour, pensez à télécharger la nouvelle version
Exécutons le check, en mettant dans le classpath votre implémentation de TestJDBC, et la librairie sqlite-jdbc et mettre en paramètre "check-jdbc1".
Cette ligne suppose que "check.jar" soit contenu dans "WEB-INF", adapter la ligne de code si ce n'est pas le cas.
java -cp classes:check.jar:lib/sqlite-jdbc-3.8.11.2.jar tool.Check check-jdbc1

Selon la manière dont vous avez implémenté votre fonction, il est possible de contourner la vérification du mot de passe ou non. Si c'est le cas (dernier test) votre code est sensible à de l'injection SQL.
Que se passe-t-il si je passe la chaîne de caractère ' OR '1' = '1 dans les deux paramètres email et mot de passe ?
Trouvez un moyen de corriger ce problème.

Améliorons notre code

Stocker un mot de passe en clair dans une base de données c'est mal !
Cela ne respecte pas la confidentialité et expose vos utilisateurs à un vol potentiel de leur mot de passe.
Une bonne pratique est de réaliser un "Hash" du mot de passe avant de l'insérer en base de données. Lors de la vérification du mot de passe, il faut comparer le hash en base avec le hash du mot de passe proposé.
La fonction de hash "SHA1" peut être utilisée pour ce faire.

Selon l'interface ITestJDBC, implémentez les fonction :
» exists pour vérifier si un utilisateur existe ou non.
» addMember pour insérer la une nouvelle personne dont le mot de passe sera "hashé" par la fonction SHA1.
» checkPasswordWithSum qui vérifie le mot de passe d'un utilisateur par la fonction SHA1.
Voici un exemple de code pour obtenir un "SHA1" en java, utilisant MessageDigest.

private static String sha1(String password) {
  MessageDigest md = null;
  try {
      md = MessageDigest.getInstance("SHA-1");
  } catch(NoSuchAlgorithmException e) {
      e.printStackTrace();
      return "*****";
  } 
  byte[] sha1sum = md.digest(password.getBytes());
  StringBuffer sb = new StringBuffer();
  for( int i = 0; i < sha1sum.length; i++ ) sb.append( String.format("%02x", sha1sum[i]) );
  return sb.toString();
}
Tester vos opérations pour la 2e partie
java -cp classes:check.jar:lib/sqlite-jdbc-3.8.11.2.jar tool.Check check-jdbc2

Mettre à jour votre git

Il est temps de mettre à jour votre repository de sources.
Il n'est pas souhaitable de commiter les fichiers jar, ceux-ci peuvent être retrouvés facilement.
Ecrire une règle dans votre ".gitignore" pour ne pas inclure les fichiers .jar ainsi que les fichiers .db (base sqlite)
Ajouter le ".gitignore" pour le prochain commit. git add .gitignore
Ajouter tous les nouveaux fichiers à votre commit git add .
Vérifier le contenu de votre prochain commit git status
Enlever éventuellement les fichiers superflues git rm --cached xxFILExx
Commitez votre travail et mettez un message pertinent git ci -m "TP2-JDBC" "Poussez" votre travail sur le serveur git push

En environnement de travail, avant de pousser ou de commencer à travailler en début de journée il convient généralement de "Tirer" les modifications de code réalisées par vos collègues.
git pull
Si des conflits surviennent, visualisez les fichiers en conflit avec git status, modifiez les pour conserver le code nécessaire, puis ajoutez les pour un prochain commit qui résoudra le conflit.
Lorsque vous avez corrigé et ajouté tous les fichiers en conflit, il faut faire de nouveau un commit et un push.

Configurer eclipse pour travailler efficacement

Nous allons configurer l'IDE Eclipse pour travailler de manière plus efficace.
Eclipse est un outil vous faciliter la vie, vous devez comprendre son fonctionnement et savoir vous en passer si nécessaire.

Voici les actions essentielles à savoir pour le cadre de ce TP.
... (demo)

... (/demo)

Réaliser un écran d'authentification

Nous allons utiliser les classes écrites à l'instant et les utiliser dans des JSP / Servlet afin de permettre à des membres de s'inscrire ou de s'identifier.
Nous allons utiliser Bootstrap afin de donner rapidement un style sympa à nos pages.
Il faudra sans doute modifier votre "DAO" TestJDBC pour charger le fichier "data.db" ailleurs que dans le répertoire courant, interprété comme le répertoire dans lequel vous êtes au moment de lancer tomcat. Ce pourrait ne pas etre pratique d'avoir ce fichier dans le "/bin" de tomcat, et ce ne semble pas être une super idée de le laisser dans le "/WEB-INF" de votre contexte.
Trouver un endroit pertinent pour le mettre et proposez un moyen simple de configurer le chemin où se trouve ce fichier.

  1. Télécharger ce fichier html et ce fichier de style. Mettez-les dans à la racine de votre contexte web (webapps/tp1).
  2. Modifiez le login.html pour en faire une JSP.
  3. Créez une servlet "AuthControl" branchée sur l'url "/auth" qui vérifiera que le mail et le mot de passe correspondent à un utilisateur.
  4. Il faudra modifier l'attribut "action" de votre formulaire html pour diriger la requête post vers votre servlet.
  5. Utilisez les paramètre "email" et "password" pour valider ou non l'authentification.
  6. Si ce c'est bon, on utilisera la méthode "sendRedirect" de l'objet HttpServletResponse pour diriger l'utilisateur vers une page de bienvenue.
  7. Si le login / mot de passe ne correspondent pas, ré-afficher la JSP de login avec un message d'erreur.
    On pourra utiliser dans ce cas l'objet RequestDispatcher qui permet de déléguer le traitement d'une requête à une autre servlet (ou une autre JSP).
    req.getRequestDispatcher("/login.jsp").forward(req, resp);
  8. Le message d'erreur doit être dans une div dont la classe css est "alert alert-danger" voir cet extrait de documentation.
    Pour passer une variable (ou un paramètre java) à votre servlet (le message d'erreur par exemple) vous pouvez utiliser la méthode "setAttribute" de l'objet request. Dans votre JSP vous pourrez récupérer cette variable avec la méthode associée "getAttribute".
  9. lorsqu'une erreur survient on souhaiterait que le champ email conserve le contenu saisi par l'utilisateur lors de l'essai précédant.
Attention : sendRedirect ou forward n'arrête pas le traitement de la méthode java. Si vous souhaitez ne pas continuer le traitement de l'opération vous devez explicitement faire un "return" avec cette opération.

Exemple de formulaire d'identification.


Formulaire d'inscription

Selon le même principe Vous allez réaliser un formulaire d'inscription.
Voici les étapes principales

  1. Créer une page JSP (register.jsp) pour le formulaire d'inscription.
    les champs du formulaire seront nommés : firstname, lastname, email, password.
  2. Créer une servlet ("/signin") qui récupère les paramètres.
  3. vérifier la validité des paramètres dans votre servlet
  4. Gestion des erreurs : ré-afficher le formulaire avec les champs en erreur (class has-error).
  5. Si tout est Ok, enregistrer l'utilisateur et rediriger l'utilisateur vers une page de confirmation.


Exemple de formulaire d'enregistrement.
Ici, le mail saisi existe déjà, un message d'erreur l'indique et le champ est mis en évidence.


Tester votre authentification et inscription
java -cp classes:check.jar:lib/sqlite-jdbc-3.8.11.2.jar tool.Check check-auth

Lorsque vous êtes satisfait du résultat mettre à jour le git.
Indiquez dans votre message de commit "TP2-Auth".

Envoyer des mails avec JavaMail

( autonomie )

Essayez de mettre en place l'envoie d'un e-mail de confirmation lors de l'inscription d'un membre.
Ce membre devra confirmer son inscription en cliquant sur le lien reçu par email.
Le compte ne sera pas actif tant que le membre n'aura pas cliqué sur le lien, c'est à dire que lorsque le membre essai de s'identifier alors qu'il n'a pas validé son inscription on lui affiche un message d'erreur et on l'invite à valider son email.
Lorsqu'une personne active son compte, envoyez lui un mail de bienvenue et mettre l'administrateur en copie.
Si j'ai oublié mon mot de passe, un lien sur la page d'identification m'amène à un formulaire où je peux renseigner mon adresse email, je reçoit un mail me permettant de mettre un nouveau mot de passe.

Il vous faudra utiliser l'API "javamail".
Depuis l'université il vous sera possible d'utiliser le SMTP et votre compte mail "univ-lille1".
N'hésitez pas à consultez la documentation du CRI et les tutoriaux disponibles.

Lorsque vous avez terminé ce cas d'usage, faîtes valider votre travail lors d'un TP encadré pour valider.

  - Ajouter les dépendances à tomcat
  - Configurer et utiliser javamail
  - Envoyer un mail de validation
  - Envoyer un mail de confirmation d'inscription
  - Envoyer un mail en cas d'oublie de mot de passe