display attempts to admin
This commit is contained in:
22
css/dataTables.css
Normal file
22
css/dataTables.css
Normal file
File diff suppressed because one or more lines are too long
73
database.php
Normal file
73
database.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
|
||||
function GetDbConnection(): ?PDO
|
||||
{
|
||||
$host = 'localhost'; // ou l'adresse IP du serveur MariaDB
|
||||
$dbname = 'ldap'; // nom de votre base de donn<6E>es
|
||||
$username = 'root'; // nom d'utilisateur MariaDB
|
||||
$password = '4321'; // mot de passe pour l'utilisateur
|
||||
try {
|
||||
// Cr<43>ation d'une instance PDO pour la connexion <20> la base de donn<6E>es
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
|
||||
// Configuration du mode d'erreur de PDO pour les exceptions
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
return $pdo;
|
||||
} catch (PDOException $e) {
|
||||
echo "Échec de la connexion : " . $e->getMessage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
class AuthAttempt
|
||||
{
|
||||
public string $username;
|
||||
public string $status;
|
||||
public string $timestamp;
|
||||
public string $ip_address;
|
||||
|
||||
public function __construct(
|
||||
string $username,
|
||||
string $status,
|
||||
string $ip_address,
|
||||
string $timestamp = "",
|
||||
) {
|
||||
$this->username = $username;
|
||||
$this->status = $status;
|
||||
$this->ip_address = $ip_address;
|
||||
$this->timestamp = $timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
function InsertLine(AuthAttempt $attempt)
|
||||
{
|
||||
$table_name = "authentification_attempts";
|
||||
$pdo = GetDbConnection();
|
||||
|
||||
$query = $pdo->prepare("INSERT INTO $table_name(`username`, `status`, `ip_address`) VALUES (:user, :status, :ip);");
|
||||
|
||||
$query->bindValue(":user", $attempt->username, PDO::PARAM_STR);
|
||||
$query->bindValue(":status", $attempt->status, PDO::PARAM_STR);
|
||||
$query->bindValue(":ip", $attempt->ip_address, PDO::PARAM_STR);
|
||||
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
function GetLines() : array {
|
||||
$table_name = "authentification_attempts";
|
||||
$pdo = GetDbConnection();
|
||||
|
||||
$query = $pdo->prepare("SELECT * FROM $table_name;");
|
||||
|
||||
$query->execute();
|
||||
|
||||
$lines = $query->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach($lines as $line) {
|
||||
array_push($result, new AuthAttempt($line["username"], $line["status"], $line["ip_address"], $line["timestamp"]));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
15
db_test.php
15
db_test.php
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
$host = 'localhost'; // ou l'adresse IP du serveur MariaDB
|
||||
$dbname = 'mysql'; // nom de votre base de donn<6E>es
|
||||
$username = 'root'; // nom d'utilisateur MariaDB
|
||||
$password = '4321'; // mot de passe pour l'utilisateur
|
||||
try {
|
||||
// Cr<43>ation d'une instance PDO pour la connexion <20> la base de donn<6E>es
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
|
||||
// Configuration du mode d'erreur de PDO pour les exceptions
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
echo "Connexion réussie <20> MariaDB avec PDO!";
|
||||
} catch (PDOException $e) {
|
||||
echo "<EFBFBD>chec de la connexion : " . $e->getMessage();
|
||||
}
|
||||
?>
|
||||
36
js/datatables.min.js
vendored
Normal file
36
js/datatables.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
245
lang/fr.json
Normal file
245
lang/fr.json
Normal file
@@ -0,0 +1,245 @@
|
||||
{
|
||||
"emptyTable": "Aucune donnée disponible dans le tableau",
|
||||
"loadingRecords": "Chargement...",
|
||||
"processing": "Traitement...",
|
||||
"select": {
|
||||
"rows": {
|
||||
"_": "%d lignes sélectionnées",
|
||||
"1": "1 ligne sélectionnée"
|
||||
},
|
||||
"cells": {
|
||||
"1": "1 cellule sélectionnée",
|
||||
"_": "%d cellules sélectionnées"
|
||||
},
|
||||
"columns": {
|
||||
"1": "1 colonne sélectionnée",
|
||||
"_": "%d colonnes sélectionnées"
|
||||
}
|
||||
},
|
||||
"autoFill": {
|
||||
"cancel": "Annuler",
|
||||
"fill": "Remplir toutes les cellules avec <i>%d<\/i>",
|
||||
"fillHorizontal": "Remplir les cellules horizontalement",
|
||||
"fillVertical": "Remplir les cellules verticalement"
|
||||
},
|
||||
"searchBuilder": {
|
||||
"conditions": {
|
||||
"date": {
|
||||
"after": "Après le",
|
||||
"before": "Avant le",
|
||||
"between": "Entre",
|
||||
"empty": "Vide",
|
||||
"not": "Différent de",
|
||||
"notBetween": "Pas entre",
|
||||
"notEmpty": "Non vide",
|
||||
"equals": "Égal à"
|
||||
},
|
||||
"number": {
|
||||
"between": "Entre",
|
||||
"empty": "Vide",
|
||||
"gt": "Supérieur à",
|
||||
"gte": "Supérieur ou égal à",
|
||||
"lt": "Inférieur à",
|
||||
"lte": "Inférieur ou égal à",
|
||||
"not": "Différent de",
|
||||
"notBetween": "Pas entre",
|
||||
"notEmpty": "Non vide",
|
||||
"equals": "Égal à"
|
||||
},
|
||||
"string": {
|
||||
"contains": "Contient",
|
||||
"empty": "Vide",
|
||||
"endsWith": "Se termine par",
|
||||
"not": "Différent de",
|
||||
"notEmpty": "Non vide",
|
||||
"startsWith": "Commence par",
|
||||
"equals": "Égal à",
|
||||
"notContains": "Ne contient pas",
|
||||
"notEndsWith": "Ne termine pas par",
|
||||
"notStartsWith": "Ne commence pas par"
|
||||
},
|
||||
"array": {
|
||||
"empty": "Vide",
|
||||
"contains": "Contient",
|
||||
"not": "Différent de",
|
||||
"notEmpty": "Non vide",
|
||||
"without": "Sans",
|
||||
"equals": "Égal à"
|
||||
}
|
||||
},
|
||||
"add": "Ajouter une condition",
|
||||
"button": {
|
||||
"0": "Recherche avancée",
|
||||
"_": "Recherche avancée (%d)"
|
||||
},
|
||||
"clearAll": "Effacer tout",
|
||||
"condition": "Condition",
|
||||
"data": "Donnée",
|
||||
"deleteTitle": "Supprimer la règle de filtrage",
|
||||
"logicAnd": "Et",
|
||||
"logicOr": "Ou",
|
||||
"title": {
|
||||
"0": "Recherche avancée",
|
||||
"_": "Recherche avancée (%d)"
|
||||
},
|
||||
"value": "Valeur",
|
||||
"leftTitle": "Désindenter le critère",
|
||||
"rightTitle": "Indenter le critère"
|
||||
},
|
||||
"searchPanes": {
|
||||
"clearMessage": "Effacer tout",
|
||||
"count": "{total}",
|
||||
"title": "Filtres actifs - %d",
|
||||
"collapse": {
|
||||
"0": "Volet de recherche",
|
||||
"_": "Volet de recherche (%d)"
|
||||
},
|
||||
"countFiltered": "{shown} ({total})",
|
||||
"emptyPanes": "Pas de volet de recherche",
|
||||
"loadMessage": "Chargement du volet de recherche...",
|
||||
"collapseMessage": "Réduire tout",
|
||||
"showMessage": "Montrer tout"
|
||||
},
|
||||
"buttons": {
|
||||
"collection": "Collection",
|
||||
"colvis": "Visibilité colonnes",
|
||||
"colvisRestore": "Rétablir visibilité",
|
||||
"copy": "Copier",
|
||||
"copySuccess": {
|
||||
"1": "1 ligne copiée dans le presse-papier",
|
||||
"_": "%d lignes copiées dans le presse-papier"
|
||||
},
|
||||
"copyTitle": "Copier dans le presse-papier",
|
||||
"csv": "CSV",
|
||||
"excel": "Excel",
|
||||
"pageLength": {
|
||||
"-1": "Afficher toutes les lignes",
|
||||
"_": "Afficher %d lignes",
|
||||
"1": "Afficher 1 ligne"
|
||||
},
|
||||
"pdf": "PDF",
|
||||
"print": "Imprimer",
|
||||
"copyKeys": "Appuyez sur ctrl ou u2318 + C pour copier les données du tableau dans votre presse-papier.",
|
||||
"createState": "Créer un état",
|
||||
"removeAllStates": "Supprimer tous les états",
|
||||
"removeState": "Supprimer",
|
||||
"renameState": "Renommer",
|
||||
"savedStates": "États sauvegardés",
|
||||
"stateRestore": "État %d",
|
||||
"updateState": "Mettre à jour"
|
||||
},
|
||||
"decimal": ",",
|
||||
"datetime": {
|
||||
"previous": "Précédent",
|
||||
"next": "Suivant",
|
||||
"hours": "Heures",
|
||||
"minutes": "Minutes",
|
||||
"seconds": "Secondes",
|
||||
"unknown": "-",
|
||||
"amPm": [
|
||||
"am",
|
||||
"pm"
|
||||
],
|
||||
"months": {
|
||||
"0": "Janvier",
|
||||
"2": "Mars",
|
||||
"3": "Avril",
|
||||
"4": "Mai",
|
||||
"5": "Juin",
|
||||
"6": "Juillet",
|
||||
"8": "Septembre",
|
||||
"9": "Octobre",
|
||||
"10": "Novembre",
|
||||
"1": "Février",
|
||||
"11": "Décembre",
|
||||
"7": "Août"
|
||||
},
|
||||
"weekdays": [
|
||||
"Dim",
|
||||
"Lun",
|
||||
"Mar",
|
||||
"Mer",
|
||||
"Jeu",
|
||||
"Ven",
|
||||
"Sam"
|
||||
]
|
||||
},
|
||||
"editor": {
|
||||
"close": "Fermer",
|
||||
"create": {
|
||||
"title": "Créer une nouvelle entrée",
|
||||
"button": "Nouveau",
|
||||
"submit": "Créer"
|
||||
},
|
||||
"edit": {
|
||||
"button": "Editer",
|
||||
"title": "Editer Entrée",
|
||||
"submit": "Mettre à jour"
|
||||
},
|
||||
"remove": {
|
||||
"button": "Supprimer",
|
||||
"title": "Supprimer",
|
||||
"submit": "Supprimer",
|
||||
"confirm": {
|
||||
"_": "Êtes-vous sûr de vouloir supprimer %d lignes ?",
|
||||
"1": "Êtes-vous sûr de vouloir supprimer 1 ligne ?"
|
||||
}
|
||||
},
|
||||
"multi": {
|
||||
"title": "Valeurs multiples",
|
||||
"info": "Les éléments sélectionnés contiennent différentes valeurs pour cette entrée. Pour modifier et définir tous les éléments de cette entrée à la même valeur, cliquez ou tapez ici, sinon ils conserveront leurs valeurs individuelles.",
|
||||
"restore": "Annuler les modifications",
|
||||
"noMulti": "Ce champ peut être modifié individuellement, mais ne fait pas partie d'un groupe. "
|
||||
},
|
||||
"error": {
|
||||
"system": "Une erreur système s'est produite (<a target=\"\\\" rel=\"nofollow\" href=\"\\\">Plus d'information<\/a>)."
|
||||
}
|
||||
},
|
||||
"stateRestore": {
|
||||
"removeSubmit": "Supprimer",
|
||||
"creationModal": {
|
||||
"button": "Créer",
|
||||
"order": "Tri",
|
||||
"paging": "Pagination",
|
||||
"scroller": "Position du défilement",
|
||||
"search": "Recherche",
|
||||
"select": "Sélection",
|
||||
"columns": {
|
||||
"search": "Recherche par colonne",
|
||||
"visible": "Visibilité des colonnes"
|
||||
},
|
||||
"name": "Nom :",
|
||||
"searchBuilder": "Recherche avancée",
|
||||
"title": "Créer un nouvel état",
|
||||
"toggleLabel": "Inclus :"
|
||||
},
|
||||
"renameButton": "Renommer",
|
||||
"duplicateError": "Il existe déjà un état avec ce nom.",
|
||||
"emptyError": "Le nom ne peut pas être vide.",
|
||||
"emptyStates": "Aucun état sauvegardé",
|
||||
"removeConfirm": "Voulez vous vraiment supprimer %s ?",
|
||||
"removeError": "Échec de la suppression de l'état.",
|
||||
"removeJoiner": "et",
|
||||
"removeTitle": "Supprimer l'état",
|
||||
"renameLabel": "Nouveau nom pour %s :",
|
||||
"renameTitle": "Renommer l'état"
|
||||
},
|
||||
"info": "Affichage de _START_ à _END_ sur _TOTAL_ entrées",
|
||||
"infoEmpty": "Affichage de 0 à 0 sur 0 entrées",
|
||||
"infoFiltered": "(filtrées depuis un total de _MAX_ entrées)",
|
||||
"lengthMenu": "Afficher _MENU_ entrées",
|
||||
"paginate": {
|
||||
"first": "Première",
|
||||
"last": "Dernière",
|
||||
"next": "Suivante",
|
||||
"previous": "Précédente"
|
||||
},
|
||||
"zeroRecords": "Aucune entrée correspondante trouvée",
|
||||
"aria": {
|
||||
"sortAscending": " : activer pour trier la colonne par ordre croissant",
|
||||
"sortDescending": " : activer pour trier la colonne par ordre décroissant"
|
||||
},
|
||||
"infoThousands": " ",
|
||||
"search": "Rechercher :",
|
||||
"thousands": " "
|
||||
}
|
||||
20
ldap.php
20
ldap.php
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
require_once "database.php";
|
||||
|
||||
$ldap_domain_name = "woodywood";
|
||||
|
||||
$handle = ldap_connect("ldap://$ldap_domain_name.local");
|
||||
@@ -18,15 +20,25 @@ class UserInfo
|
||||
}
|
||||
}
|
||||
|
||||
function LdapConnect(string $domain, string $username, string $password, ?array $controls): LDAP\Result|false
|
||||
function LdapConnect(string $domain, string $username, string $password): LDAP\Result|false
|
||||
{
|
||||
global $handle;
|
||||
$bind = ldap_bind_ext($handle, $username . '@' . $domain, $password, $controls);
|
||||
LogConnection();
|
||||
$bind = ldap_bind_ext($handle, $username . '@' . $domain, $password);
|
||||
return $bind;
|
||||
}
|
||||
|
||||
function LogConnection() {}
|
||||
function LdapIsConnected(string $domain, string $username, string $password) {
|
||||
global $handle;
|
||||
$result = LdapConnect($domain, $username, $password);
|
||||
ldap_parse_result($handle, $result, $error_code, $matched_dn, $error_message, $referrals, $controls);
|
||||
$success = $error_code == 0;
|
||||
LogConnection($username, $success);
|
||||
return $success;
|
||||
}
|
||||
|
||||
function LogConnection(string $username, bool $success) {
|
||||
InsertLine(new AuthAttempt($username, $success ? "success" : "failure", $_SERVER['REMOTE_ADDR']));
|
||||
}
|
||||
|
||||
function LdapConnectAndBind()
|
||||
{
|
||||
|
||||
@@ -11,12 +11,9 @@ $password = rtrim($_POST["password"]);
|
||||
|
||||
require_once "ldap.php";
|
||||
|
||||
$result = LdapConnect($domain, $user, $password, []);
|
||||
$result = LdapIsConnected($domain, $user, $password, []);
|
||||
|
||||
ldap_parse_result($handle, $result, $error_code, $matched_dn, $error_message, $referrals, $controls);
|
||||
|
||||
|
||||
if ($error_code != 0) {
|
||||
if (!$result) {
|
||||
require_once "templates/login_failed.html";
|
||||
exit;
|
||||
}
|
||||
@@ -29,5 +26,4 @@ $body = PrintLoginInfo($info);
|
||||
|
||||
require_once "templates/login_success.html.php";
|
||||
|
||||
// TODO: Mettre les tentatives dans la db
|
||||
// TODO: ldaps
|
||||
@@ -6,6 +6,8 @@
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="../css/index.css">
|
||||
<link rel="stylesheet" href="../css/main.css">
|
||||
<!-- Datatables CSS -->
|
||||
<link rel="stylesheet" href="../css/dataTables.css">
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
$admin_account = "Administrateur";
|
||||
|
||||
function PrintListFirsts(string $title, array $liste): string
|
||||
{
|
||||
$result = '<div class="list-group-item"><h5>' . $title . '</h5>';
|
||||
@@ -13,7 +15,11 @@ function PrintListFirsts(string $title, array $liste): string
|
||||
|
||||
function PrintLoginInfo($info)
|
||||
{
|
||||
global $admin_account;
|
||||
$body = '<h2 class="text-center pt-3">Bienvenue ' . $info->fullName . " !</h2>";
|
||||
if ($info->fullName == $admin_account) {
|
||||
return $body .= PrintAdminInterface();
|
||||
}
|
||||
$body .= '<div class="list-group ">';
|
||||
foreach ($info->ous as $ou) {
|
||||
$body .= '<div class="list-group-item"><h3>' . $ou . "</h3>";
|
||||
@@ -22,8 +28,48 @@ function PrintLoginInfo($info)
|
||||
$body .= PrintListFirsts("Groupes", LdapGetGroupsInOU($ou));
|
||||
$body .= "</div>";
|
||||
$body .= "</div>";
|
||||
|
||||
}
|
||||
$body .= "</div>";
|
||||
return $body;
|
||||
}
|
||||
|
||||
function translateSuccess(string $success) {
|
||||
return $success == "success" ? "Succès" : "Échec";
|
||||
}
|
||||
|
||||
function PrintAdminInterface(): string
|
||||
{
|
||||
$auth_attempts = GetLines();
|
||||
$body = '<h5 class="text-center">Historique des connexions</h5>';
|
||||
$body .= '<table id="attempts" class="table table-striped table-bordered">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th scope="col">Utilisateur</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Date</th>
|
||||
<th scope="col">Adresse IP</th>
|
||||
</tr>
|
||||
</thead>';
|
||||
foreach ($auth_attempts as $attempt) {
|
||||
$body .= '<tr>';
|
||||
$body .= '<td>' . $attempt->username . '</td>';
|
||||
$body .= '<td>' . translateSuccess($attempt->status) . '</td>';
|
||||
$body .= '<td>' . $attempt->timestamp . '</td>';
|
||||
$body .= '<td>' . $attempt->ip_address . '</td>';
|
||||
$body .= '</tr>';
|
||||
}
|
||||
$body .= "</table>";
|
||||
$body .= '
|
||||
<script src="/js/datatables.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
let table = new DataTable("#attempts", {
|
||||
language: {
|
||||
url: "/lang/fr.json",
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
';
|
||||
return $body;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user