diff --git a/tp5-bd.md b/tp5-bd.md
new file mode 100644
index 0000000..de7b1a0
--- /dev/null
+++ b/tp5-bd.md
@@ -0,0 +1,139 @@
+# TP 5 : Sécurité des bases de données (12h)
+
+Pour ce TP, nous allons utiliser Docker. Vous pouvez l'installer sur votre machine ou dans une VM quelconque.
+
+Ce TP peut être réalisé dans la VM MI-LXC disponible [ici](https://flesueur.irisa.fr/mi-lxc/images/milxc-debian-amd64-1.4.1.ova) (identique à la première période). Avant de lancer la VM, il peut être nécessaire de diminuer la RAM allouée. Par défaut, la VM a 3GO : si vous avez 4GO sur votre machine physique, il vaut mieux diminuer à 2GO, voire 1.5GO pour la VM (la VM devrait fonctionner de manière correcte toujours).
+
+
+Quelques commandes utiles
+=========================
+
+Dans la console psql :
+* \l lister les bases
+* \dt lister les tables
+* \du (\du+) lister les rôles (utilisateurs/groupes)
+* \z lister les permissions
+* TABLE clients; afficher la table clients
+* \c database; ouvrir la base database
+* La doc de référence : [doc](https://www.postgresql.org/docs/current/index.html)
+
+Démarrage (30 minutes)
+=========
+
+Ici, on va démarrer une base PostgreSQL et faire de premières manipulations. Pour créer et démarrer un docker postgresql :
+
+`docker run --name mypostgres -e POSTGRES_PASSWORD=foo -d postgres`
+
+Ensuite, pour se connecter à la console :
+
+`docker exec -it mypostgres psql -U postgres`
+
+La base est persistente si vous stoppez/redémarrez le docker, mais pas en cas de fausse manip. Prenez des notes au fur et à mesure !
+
+
+Création d'une première base (2 heures)
+============================
+
+Il faut tout d'abord comprendre la notion de rôles (utilisateurs/groupes) et de bases.
+
+Rôles
+-----
+
+La documentation est à lire [ici](https://www.postgresql.org/docs/current/user-manag.html) (jusque 22.2 seulement pour l'instant). Les groupes et les utilisateurs sont des rôles avec des attributs différents. La modification d'un rôle est expliquée [ici](https://www.postgresql.org/docs/current/sql-alterrole.html).
+
+> Créez un utilisateur ayant le droit de se connecter, avec un mot de passe. Puis utilisez ALTER pour changer son mot de passe.
+
+Base
+----
+
+Une base est un ensemble de tables (relations) qui appartient à un utilisateur. La création de base est documentée [ici](https://www.postgresql.org/docs/current/managing-databases.html) (ignorez les parties templates et tablespaces).
+
+> Créez une nouvelle base qui doit appartenir à l'utilisateur que vous avez créé. Puis supprimez-là, récréez-là et utilisez ALTER pour modifier (puis remettre) son propriétaire.
+
+
+Tables
+------
+
+Les tables sont les éléments des bases qui vont contenir les données qui seront requêtées. Pour créer une table, la [doc](https://www.postgresql.org/docs/current/ddl-basics.html). Il faut ensuite la remplir avec [INSERT/UPDATE/DELETE](https://www.postgresql.org/docs/current/dml.html) et la requêter avec [SELECT](https://www.postgresql.org/docs/current/queries.html).
+
+> Créez une table, insérez et modifiez quelques lignes et requêtez-là avec un WHERE simple.
+
+Nous avons maintenant le nécessaire pour explorer les fonctionnalités de sécurité.
+
+Disponibilité (30 minutes)
+=============
+
+Expérimentez le dump et la restauration tel que décrit [ici](https://www.postgresql.org/docs/current/backup-dump.html)
+
+Pour vous connecter en shell sur le docker, `docker exec -it mypostgres bash` (où bash peut évidemment être remplacé par toute commande que vous vouliez taper dans le docker).
+
+> Présentez votre déroulé.
+
+Contrôle d'accès (3 heures)
+================
+
+Pour la confidentialité et l'intégrité, nous allons voir la gestion des comptes et des droits.
+
+<< PAUSE COURS AU TABLEAU >>
+
+Gestion des comptes
+-------------------
+
+Il est maintenant temps de lire la gestion de l'appartenance aux rôles [ici](https://www.postgresql.org/docs/current/role-membership.html).
+
+> Créez quelques utilisateurs, quelques groupes et affectez des utilisateurs aux groupes.
+
+Gestion des droits
+------------------
+
+PostgreSQL permet de régler les droits :
+* des tables : [ici](https://www.postgresql.org/docs/current/ddl-priv.html)
+* des lignes : [ici](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)
+
+La gestion par tables permet la première approche à grain moyen, la gestion par lignes permet ensuite une granularité de contrôle beaucoup plus fine. Les droits sont affectés à des rôles afin de faire du RBAC.
+
+> Sur une table, permettez à un rôle de lire uniquement (SELECT) et à un autre d'écrire.
+
+> Sur des lignes, limitez la lecture à l'utilisateur nommé sur la ligne.
+
+Mise en œuvre (6 heures)
+=============
+
+Bravo ! Vous voilà maintenant responsable de mettre une formidable application en production ! Cette application a été développée avec les dernières technologies à la mode par le stagiaire qui vient de partir (parce que c'était, avant vous, le seul technique de l'organisation).
+
+Cette application est disponible dans le sous-dossier [tp5-files](tp5-files/). Vous pouvez la lancer avec `docker-compose up -d` (en étant placé dans le sous-dossier contenant le docker-compose.yml) et y accéder depuis votre hôte aux URLs `http://localhost/admin/`, `http://localhost/clients/` et `http://localhost/helpdesk/`.
+
+Vous pouvez explorer son code (et son README.txt) dans le sous-dossier [webapp](tp5-files/webapp/). La base initiale est décrite dans [sqlinit.sql](tp5-files/sqlinit/sqlinit.sql), ce qui vous permet de connaître les authentifiants attendus. Pour vous connecter à la base (credentials www/foo) :
+* `docker exec -it postgres psql -U www clientsdb`
+* ou via un navigateur vers `http://localhost:81` (phppgadmin)
+
+Et là, c'est le drame. En regardant `clients/do_login.php`, vous prenez peur pour la mise en production.
+
+> Quel est le problème dans ce fichier ? Retrouvez-vous ce problème ailleurs ? Qu'aurait-il fallu faire à la place ? Exploitez-le !
+
+Malheureusement, la recette a déjà eu lieu et vous n'avez plus la possibilité de faire des modifications au travers de toute l'application. Nous allons explorer 2 voies de défense en profondeur afin de limiter les impacts :
+* Séparation des accès à la BD en 3 utilisateurs distincts admin/helpdesk/client puis restriction des droits sur les tables
+* Séparation des accès à la BD en n utilisateurs distincts appartenant à l'un des 3 rôles puis application de Row-Level security
+
+Segmentation des accès en 3 utilisateurs
+----------------------------------------
+
+Raffinez l'authentification entre l'application et la BD afin de limiter les dégâts potentiels :
+* Créez 3 utilisateurs distincts admin/helpdesk/client au niveau de la BD, qui correspondront aux usages des 3 sous-dossiers de l'application
+* Attribuez leur les droits minimaux nécessaires à chacune des sections de l'application (droits de SELECT, INSERT et UPDATE sur la table clients)
+* Modifiez l'inclusion du `db.inc.php` pour que les fichiers PHP de chaque sous-dossier se connectent à la base avec les credentials adaptés
+
+> Déployez ce modèle et mettez à jour le code PHP en fonction. Vérifiez que certaines exploitations initiales ne fonctionnent plus.
+
+Segmentation des accès en n utilisateurs
+----------------------------------------
+
+Raffinez l'authentification entre l'application et la BD afin de limiter les dégâts potentiels :
+* Un utilisateur de l'application web = un utilisateur de la BD
+* L'authentification sera réalisée directement avec la BD (stockages des authentifiants dans la session PHP)
+* Des rôles (hiérarchiques) pour factoriser la gestion des droits
+* Une sécurité à grain fin au niveau des lignes de tables (Row security)
+
+> Proposez (sur papier) et faîtes valider un modèle RBAC adapté. Déployez ce modèle et mettez à jour le code PHP en fonction. Vérifiez que votre exploitation initiale ne fonctionne plus.
+
+> REMARQUE : En l'absence de row-level security (pas disponible avec MySQL/MariaDB par exemple), un résultat relativement similaire (mais plus complexe à maintenir) aurait pu être obtenu avec l'utilisation de vues.
diff --git a/tp5-files/docker-compose.yml b/tp5-files/docker-compose.yml
new file mode 100644
index 0000000..007d287
--- /dev/null
+++ b/tp5-files/docker-compose.yml
@@ -0,0 +1,37 @@
+version: "3.3"
+
+services:
+ db:
+ image: postgres
+ container_name: postgres
+ #networks:
+ # - postgres
+ environment:
+ - POSTGRES_DB=clientsdb
+ - POSTGRES_PASSWORD=foo
+ - POSTGRES_USER=www
+ ports:
+ - 5432:5432
+ volumes:
+ - ${PWD}/sqlinit:/docker-entrypoint-initdb.d
+ - mydb:/var/lib/postgresql/data
+
+ webapp:
+ build: webapp/
+ image: webapp-image
+ container_name: webapp
+ ports:
+ - 80:80
+ volumes:
+ - ${PWD}/webapp:/var/www/html
+
+ phppgadmin:
+ image: bitnami/phppgadmin
+ container_name: phppgadmin
+ ports:
+ - 81:8080
+ environment:
+ - DATABASE_HOST=postgres
+
+volumes:
+ mydb:
diff --git a/tp5-files/sqlinit/sqlinit.sql b/tp5-files/sqlinit/sqlinit.sql
new file mode 100644
index 0000000..e7fd992
--- /dev/null
+++ b/tp5-files/sqlinit/sqlinit.sql
@@ -0,0 +1,11 @@
+-- CREATE USER www WITH PASSWORD 'foo';
+-- CREATE DATABASE clientsdb OWNER www;
+\c clientsdb
+CREATE TABLE clients (id SERIAL, name varchar(15), password varchar(15), role varchar(15), email varchar(25), comment varchar(5000), message varchar(5000));
+ALTER TABLE clients OWNER TO www;
+INSERT INTO clients( name, password, role) VALUES ('admin', 'admin', 'admin');
+INSERT INTO clients( name, password, role) VALUES ('helpdesk1', 'helpdesk1', 'helpdesk');
+INSERT INTO clients( name, password, role) VALUES ('helpdesk2', 'helpdesk2', 'helpdesk');
+INSERT INTO clients( name, password, role) VALUES ('client1', 'client1', 'client');
+INSERT INTO clients( name, password, role) VALUES ('client2', 'client2', 'client');
+INSERT INTO clients( name, password, role) VALUES ('client3', 'client3', 'client');
diff --git a/tp5-files/webapp/Dockerfile b/tp5-files/webapp/Dockerfile
new file mode 100755
index 0000000..a2dd269
--- /dev/null
+++ b/tp5-files/webapp/Dockerfile
@@ -0,0 +1,3 @@
+FROM php:apache
+
+RUN apt-get update && apt-get install -y libpq-dev && docker-php-ext-install pgsql
diff --git a/tp5-files/webapp/README.txt b/tp5-files/webapp/README.txt
new file mode 100755
index 0000000..639e936
--- /dev/null
+++ b/tp5-files/webapp/README.txt
@@ -0,0 +1,13 @@
+Application web de gestion clientèle.
+
+- admin/ contient le code pour ajouter/supprimer des clients
+- helpdesk/ contient le code pour modifier des clients, lire leur message et le modifier
+- clients/ contient le code permettant à chaque client de voir ses infos et d'envoyer un message au helpdesk
+
+Dans chaque dossier :
+- index.php fournit la page de login
+- do_login.php traite le login, stocke login et pass dans la session PHP puis redirige vers la page d'affichage print_clients.php
+- print_clients.php affiche, selon le cas, la liste + ajout/suppression, la liste + modification ou le compte du client connecté
+- do_*.php traite les actions sur la BD (insertion, suppression, modification) demandées par print_clients.php puis redirige vers print_clients.php
+
+La table utilisée est 'clients' de la base 'clientsdb' avec le compte www/foo.
diff --git a/tp5-files/webapp/admin/do_login.php b/tp5-files/webapp/admin/do_login.php
new file mode 100755
index 0000000..78c28e0
--- /dev/null
+++ b/tp5-files/webapp/admin/do_login.php
@@ -0,0 +1,19 @@
+ 0)
+ header('Location: print_clients.php');
+else
+ print "Authentication failed, $query";
+?>
diff --git a/tp5-files/webapp/admin/do_support.php b/tp5-files/webapp/admin/do_support.php
new file mode 100755
index 0000000..aa6c7f2
--- /dev/null
+++ b/tp5-files/webapp/admin/do_support.php
@@ -0,0 +1,32 @@
+Logout
";
+
+require_once("../db.inc.php");
+
+
+// Gestion des ajouts/suppressions
+if (isset($_POST['name'])) { // Ajout d'un nouveau client
+ $name=$_POST['name'];
+ $email=$_POST['email'];
+ $comment=$_POST['comment'];
+ $password=$_POST['password'];
+ $role=$_POST['role'];
+ $query = "INSERT INTO clients (name, email, comment, password, role) VALUES ('$name','$email','$comment', '$password', '$role')";
+ pg_query($dbconn, $query) or die('Échec de la requête : ' . pg_last_error());
+}
+
+if (isset($_GET['delete'])) { // Suppression d'un client
+ $id = $_GET['delete'];
+ $query = "DELETE FROM clients WHERE id='$id'";
+ pg_query($dbconn, $query) or die('Échec de la requête : ' . pg_last_error());
+}
+
+
+// Ferme la connexion
+pg_close($dbconn);
+
+header('Location: print_clients.php');
+?>
diff --git a/tp5-files/webapp/admin/index.php b/tp5-files/webapp/admin/index.php
new file mode 100755
index 0000000..23b399a
--- /dev/null
+++ b/tp5-files/webapp/admin/index.php
@@ -0,0 +1,17 @@
+
+ session_start();
+ unset($_SESSION['login']);
+ unset($_SESSION['password']);
+?>
+
+
Login Admin
+
+
+
+
+
+
diff --git a/tp5-files/webapp/admin/print_clients.php b/tp5-files/webapp/admin/print_clients.php
new file mode 100755
index 0000000..3694efa
--- /dev/null
+++ b/tp5-files/webapp/admin/print_clients.php
@@ -0,0 +1,45 @@
+Logout
";
+
+require_once("../db.inc.php");
+
+// Affichage de la table des clients
+// Exécution de la requête SQL
+$query = 'SELECT * FROM clients';
+$result = pg_query($dbconn, $query) or die('Échec de la requête : ' . pg_last_error());
+
+// Affichage des résultats en HTML
+echo "Name | Email | Comment | Role | Supprimer | \n";
+while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) {
+ $id=$line['id'];
+ $name=$line['name'];
+ $email=$line['email'];
+ $comment=$line['comment'];
+ $role=$line['role'];
+
+ echo "\t
$name | $email | $comment | $role | \n";
+ echo "\tSupprimer |
\n";
+}
+echo "
\n";
+
+// Libère le résultat
+pg_free_result($result);
+
+// Ferme la connexion
+pg_close($dbconn);
+?>
+
+
+
+
+Ajouter un client :
+
diff --git a/tp5-files/webapp/clients/do_login.php b/tp5-files/webapp/clients/do_login.php
new file mode 100755
index 0000000..d273572
--- /dev/null
+++ b/tp5-files/webapp/clients/do_login.php
@@ -0,0 +1,19 @@
+ 0)
+ header('Location: print_clients.php');
+else
+ print "Authentication failed, $query";
+?>
diff --git a/tp5-files/webapp/clients/do_message.php b/tp5-files/webapp/clients/do_message.php
new file mode 100755
index 0000000..ae53c5b
--- /dev/null
+++ b/tp5-files/webapp/clients/do_message.php
@@ -0,0 +1,19 @@
+
diff --git a/tp5-files/webapp/clients/index.php b/tp5-files/webapp/clients/index.php
new file mode 100755
index 0000000..ef3b3b0
--- /dev/null
+++ b/tp5-files/webapp/clients/index.php
@@ -0,0 +1,17 @@
+
+ session_start();
+ unset($_SESSION['login']);
+ unset($_SESSION['password']);
+?>
+
+Login Client
+
+
+
+
+
+
diff --git a/tp5-files/webapp/clients/print_clients.php b/tp5-files/webapp/clients/print_clients.php
new file mode 100755
index 0000000..6e1ebbb
--- /dev/null
+++ b/tp5-files/webapp/clients/print_clients.php
@@ -0,0 +1,37 @@
+Logout
";
+
+require_once("../db.inc.php");
+
+// Affichage de la table des clients
+// Exécution de la requête SQL
+$login = $_SESSION['login'];
+$query = "SELECT * FROM clients WHERE name='$login'";
+$result = pg_query($dbconn,$query) or die('Échec de la requête : ' . pg_last_error());
+
+// Affichage des résultats en HTML
+echo "Name | Email | Message |
\n";
+while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) {
+ $id=$line['id'];
+ $name=$line['name'];
+ $email=$line['email'];
+ $message=$line['message'];
+
+ echo "\t$name | $email | $message |
\n";
+}
+echo "
\n";
+
+// Libère le résultat
+pg_free_result($result);
+
+// Ferme la connexion
+pg_close($dbconn);
+?>
+
+Envoyer un message :
+
diff --git a/tp5-files/webapp/db.inc.php b/tp5-files/webapp/db.inc.php
new file mode 100755
index 0000000..c7013f0
--- /dev/null
+++ b/tp5-files/webapp/db.inc.php
@@ -0,0 +1,9 @@
+
diff --git a/tp5-files/webapp/helpdesk/do_helpdesk.php b/tp5-files/webapp/helpdesk/do_helpdesk.php
new file mode 100755
index 0000000..e4a494c
--- /dev/null
+++ b/tp5-files/webapp/helpdesk/do_helpdesk.php
@@ -0,0 +1,24 @@
+Logout
";
+
+require_once("../db.inc.php");
+
+// Gestion des modifications
+if (isset($_POST['name'])) { // Modification d'un client existant
+ $name=$_POST['name'];
+ $email=$_POST['email'];
+ $comment=$_POST['comment'];
+ $id=$_POST['id'];
+ $message=$_POST['message'];
+ $query = "UPDATE clients SET name='$name',email='$email',comment='$comment',message='$message' WHERE id='$id'";
+ pg_query($dbconn, $query) or die('Échec de la requête : ' . pg_last_error());
+}
+
+// Ferme la connexion
+pg_close($dbconn);
+
+header('Location: print_clients.php');
+?>
diff --git a/tp5-files/webapp/helpdesk/do_login.php b/tp5-files/webapp/helpdesk/do_login.php
new file mode 100755
index 0000000..fd30d64
--- /dev/null
+++ b/tp5-files/webapp/helpdesk/do_login.php
@@ -0,0 +1,18 @@
+ 0)
+ header('Location: print_clients.php');
+else
+ print "Authentication failed, $query";
+?>
diff --git a/tp5-files/webapp/helpdesk/index.php b/tp5-files/webapp/helpdesk/index.php
new file mode 100755
index 0000000..0dfe467
--- /dev/null
+++ b/tp5-files/webapp/helpdesk/index.php
@@ -0,0 +1,17 @@
+
+ session_start();
+ unset($_SESSION['login']);
+ unset($_SESSION['password']);
+?>
+
+Login Helpdesk
+
+
+
+
+
+
diff --git a/tp5-files/webapp/helpdesk/print_clients.php b/tp5-files/webapp/helpdesk/print_clients.php
new file mode 100755
index 0000000..6992568
--- /dev/null
+++ b/tp5-files/webapp/helpdesk/print_clients.php
@@ -0,0 +1,33 @@
+Logout
";
+
+require_once("../db.inc.php");
+
+// Affichage de la table des clients
+// Exécution de la requête SQL
+$query = 'SELECT * FROM clients';
+$result = pg_query($dbconn, $query) or die('Échec de la requête : ' . pg_last_error());
+
+// Affichage des résultats en HTML
+echo "Name | Email | Comment | Message | Name | Email | Comment | Message | Update |
\n";
+while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) {
+ $id=$line['id'];
+ $name=$line['name'];
+ $email=$line['email'];
+ $comment=$line['comment'];
+ $message=$line['message'];
+
+ echo "\t$name | $email | $comment | $message | \n";
+
+echo "\t
\n";
+}
+echo "
\n";
+
+// Libère le résultat
+pg_free_result($result);
+
+// Ferme la connexion
+pg_close($dbconn);
+?>