Exercice PL/SQL - Sécurité des bases de données
Sujet :
Contexte :
Une entreprise souhaite contrôler l'accès aux informations sensibles. Chaque employé appartient à une filière
et a un chef.
Un employé ne peut consulter les données que de ses subordonnés appartenant à sa propre filière.
Tables disponibles :
1. EMPLOYE :
- id_employe NUMBER PRIMARY KEY
- nom VARCHAR2(50)
- id_chef NUMBER
- filiere VARCHAR2(30)
2. LOG_SECURITE :
- id_log NUMBER PRIMARY KEY
- id_employe NUMBER
- message VARCHAR2(200)
- date_log DATE
Consignes :
Écris un bloc PL/SQL qui :
1. Utilise un curseur pour parcourir tous les employés.
2. Récupère pour chacun d'eux les informations sur leur chef (nom et filière).
3. Vérifie si l'employé et son chef appartiennent à la même filière.
4. Si oui, affiche les noms de l'employé et de son chef.
5. Si non, enregistre une tentative d'accès non autorisée dans la table LOG_SECURITE.
6. Gère les exceptions NO_DATA_FOUND et OTHERS.
Solution :
SET SERVEROUTPUT ON;
DECLARE
CURSOR c_emp IS
SELECT id_employe, nom, id_chef, filiere FROM EMPLOYE;
v_id_employe EMPLOYE.id_employe%TYPE;
v_nom_employe [Link]%TYPE;
v_id_chef EMPLOYE.id_chef%TYPE;
v_filiere_emp [Link]%TYPE;
v_nom_chef [Link]%TYPE;
v_filiere_chef [Link]%TYPE;
BEGIN
FOR emp_rec IN c_emp LOOP
BEGIN
v_id_employe := emp_rec.id_employe;
v_nom_employe := emp_rec.nom;
v_id_chef := emp_rec.id_chef;
v_filiere_emp := emp_rec.filiere;
IF v_id_chef IS NULL THEN
CONTINUE;
END IF;
SELECT nom, filiere INTO v_nom_chef, v_filiere_chef
FROM EMPLOYE
WHERE id_employe = v_id_chef;
IF v_filiere_emp = v_filiere_chef THEN
DBMS_OUTPUT.PUT_LINE('[OK] Employé : ' || v_nom_employe || ' | Chef : ' ||
v_nom_chef);
ELSE
INSERT INTO LOG_SECURITE (id_log, id_employe, message, date_log)
VALUES (
LOG_SECURITE_SEQ.NEXTVAL,
v_id_employe,
'Tentative non autorisée : ' || v_nom_employe || ' -> Chef : ' || v_nom_chef,
SYSDATE
);
DBMS_OUTPUT.PUT_LINE('[REFUS] Accès interdit pour ' || v_nom_employe || ' (chef : ' ||
v_nom_chef || ')');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('[AVERTISSEMENT] Chef introuvable pour ' || v_nom_employe);
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('[ERREUR] Erreur inconnue : ' || SQLERRM);
END;
END LOOP;
END;
/
-- Séquence (si elle n'existe pas) :
-- CREATE SEQUENCE LOG_SECURITE_SEQ START WITH 1 INCREMENT BY 1;