<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<title>ImmaeEu Account</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://assets.immae.eu/skeleton/2.0.4/skeleton.min.css" integrity="sha256-2YQRJMXD7pIAPHiXr0s+vlRWA7GYJEK0ARns7k2sbHY=" crossorigin="anonymous" />
<style type="text/css">
body {
font-family: Verdana,Arial,Courier New;
margin: auto;
}
table#ssh_keys_list textarea {
width: 100%;
height: 100%;
}
table#ssh_keys_list tbody tr.sshkeyrow {
height: 130px;
}
table#ssh_keys_list tbody tr.headrow th {
border-bottom: 0px !important;
padding-bottom: 0px !important;
}
table#ssh_keys_list tbody tr.mainrow td:not(.delete-button) {
border-bottom: 0px !important;
padding-bottom: 0px !important;
}
table#ssh_keys_list td.sshkey {
min-width: 600px;
height: 100%;
padding-top: 0px !important;
}
table#ssh_keys_list td.comment {
min-width: 160px;
}
</style>
</head>
<body>
<div class="container">
<h1>Gestion des clés SSH</h1>
<?php
$connection = NULL;
session_start();
// Liste des applications gérées
const apps = [
'git',
'pub',
'ftp',
'ssh',
'forward',
];
function checkSshKey($sshKey)
{
$exploded = explode(' ', $sshKey);
if (count($exploded) != 2) {
return false;
}
if (!in_array($exploded[0], array('ssh-rsa', 'ssh-ed25519'))) {
return false;
}
$decoded = base64_decode($exploded[1], true);
if ($decoded === FALSE) {
return false;
}
$decoded = preg_replace("/[^\w\-]/","", (string) $decoded);
if (substr($decoded, 0, strlen($exploded[0])) !== $exploded[0]) {
return false;
}
return true;
}
function isUserLogged()
{
return (isset($_SESSION["login"]) && doConnect() !== NULL);
}
function doConnect()
{
global $connection;
$server = "ldaps://ldap.immae.eu";
if ($connection === NULL) {
$connection = ldap_connect($server);
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3);
if (isset($_SESSION["user_dn"]) && isset($_SESSION["password"])) {
if (ldap_bind($connection, $_SESSION["user_dn"], $_SESSION["password"]) === false) {
$connection = NULL;
unset($_SESSION["user_dn"]);
unset($_SESSION["password"]);
unset($_SESSION["login"]);
}
}
}
return $connection;
}
function checkLogin($user, $password)
{
$con = doConnect();
$user_dn = "uid=$user,ou=users,dc=immae,dc=eu";
if (ldap_bind($con, $user_dn, $password) === false) {
return false;
}
$_SESSION["user_dn"] = $user_dn;
$_SESSION["password"] = $password;
$user_search = ldap_search($con,"dc=immae,dc=eu","(uid=$user)");
$auth_entry = ldap_first_entry($con, $user_search);
return true;
}
function getLdapInfo()
{
$con = doConnect();
if (!isset($_SESSION["user_dn"])) {
$sortieLdap = [];
} else {
$user_read = ldap_read($con, $_SESSION["user_dn"], "(objectclass=*)", array("uid","immaeSshKey"));
$user_entry = ldap_first_entry($con, $user_read);
$sortieLdap = ldap_get_values($con, $user_entry, "immaeSshKey");
unset($sortieLdap["count"]);
}
$keys = [];
foreach ($sortieLdap as $line) {
$exploded = explode(' ', $line);
$apps = explode('|', $exploded[0]);
$publicKey = $exploded[1] . ' ' . $exploded[2];
unset($exploded[0]);
unset($exploded[1]);
unset($exploded[2]);
$comment = implode(' ', $exploded);
$keys[] = [
'apps' => $apps,
'public_key' => $publicKey,
'comment' => $comment,
];
}
return $keys;
}
function pushLdapInfos($keys)
{
$con = doConnect();
if (!isset($_SESSION["user_dn"]))
return false;
return ldap_mod_replace($con, $_SESSION["user_dn"], array("immaeSshKey" => $keys));
}
// Script
if (isset($_POST['deconnexion'])) {
$_SESSION = [];
}
if (isset($_POST['sauvegarder'])) {
$editedKeys = [];
$errors = false;
$keysToSave = [];
foreach($_POST['keys'] as $id => $key) {
$editedKeys[$id] = $key;
if (!checkSshKey($key['public_key'])) {
$editedKeys[$id]['error'] = true;
$errors = true;
}
if (!isset($key['apps'])) {
$editedKeys[$id]['apps'] = $key['apps'] = [];
}
foreach ($key['apps'] as $app) {
if (!in_array($app, apps)) {
die("integrity");
}
}
if (!isset($editedKeys[$id]['error']) || $editedKeys[$id]['error'] !== true) {
$keysToSave[] = implode('|', $key['apps']) . ' ' . $key['public_key'] . ' ' . $key['comment'];
}
}
if (!$errors) {
$successSave = pushLdapInfos($keysToSave);
}
}
$loginErrors = "";
if (isset($_POST['login'])) {
if (empty($_POST['username']) || empty($_POST['password'])) {
$loginErrors = "Le nom d'utilisateur et le mot de passe sont requis.";
} elseif (!checkLogin($_POST['username'], $_POST['password'])) {
$loginErrors = "Identifiants incorrects.";
} else {
$_SESSION['login'] = $_POST['username'];
}
}
if (isUserLogged()) :
$keys = isset($editedKeys) ? $editedKeys : getLdapInfo();
?>
<p>Connecté en tant que <b><?= $_SESSION['login']; ?></b></p>
<form method="post">
<input type="submit" name="deconnexion" value="Déconnexion">
</form>
<?php if (isset($successSave) && $successSave === true) : ?>
<p style="color: green;">Clés enregistrées avec succès.</p>
<?php endif; ?>
<form method="post">
<table id="ssh_keys_list">
<tbody>
<?php
foreach ($keys as $id => $sshKey) :
?>
<tr class="headrow">
<th>Description</th>
<?php foreach (apps as $app) : ?>
<th><?= $app ?></th>
<?php endforeach; ?>
<th></th>
</tr>
<tr class="mainrow">
<td class="comment"><textarea name="keys[<?= $id ?>][comment]"><?= $sshKey['comment'] ?></textarea></td>
<?php
foreach (apps as $app) :
$checked = in_array($app, $sshKey['apps']);
?>
<td><input type="checkbox" name="keys[<?= $id ?>][apps][]" value="<?= $app ?>"<?= $checked ? ' checked' : '' ?>></td>
<?php endforeach; ?>
<td class="delete-button" rowspan="2"><button class="delete">Suppr.</button></td>
</tr>
<tr class="sshkeyrow">
<td colspan="<?php echo 1+count(apps); ?>" class="sshkey"><textarea name="keys[<?= $id ?>][public_key]" <?php if (isset($sshKey['error']) && $sshKey['error'] === true) :?>style="color: red"<?php endif; ?>><?= $sshKey['public_key'] ?></textarea></td>
</tr>
<?php
endforeach;
?>
</tbody>
</table>
<button id="add">Ajouter</button>
<hr>
<input type="submit" value="Sauvegarder" name="sauvegarder">
</form>
<script>
function deleteLine(element) {
element.addEventListener('click', function(e) {
e.preventDefault();
e.target.closest('tr').remove();
}, false);
}
var suppr = document.getElementsByClassName('delete');
var add = document.getElementById('add');
var list = document.querySelector('#ssh_keys_list > tbody');
for (var i = 0; i < suppr.length; i++) {
deleteLine(suppr[i]);
}
add.addEventListener('click', function (e) {
e.preventDefault();
i++;
var newLine = `
<tr class="headrow">
<th>Description</th>
<?php foreach (apps as $app) : ?>
<th><?= $app ?></th>
<?php endforeach; ?>
<th></th>
</tr>
<tr class="mainrow">
<td class="comment"><textarea name="keys[${i}][comment]"></textarea></td>
`;
<?php
foreach (apps as $app) :
?>
newLine += `<td><input type="checkbox" name="keys[${i}][apps][]" value="<?= $app ?>"></td>`;
<?php endforeach; ?>
newLine += `<td class="delete-button" rowspan="2"><button class="delete" id="delete-${i}">Suppr.</button></td>
</tr>`;
newLine += `<tr class="sshkeyrow">
<td colspan="<?php echo 1+count(apps); ?>" class="sshkey"><textarea name="keys[$[i}][public_key]"></textarea></td>
</tr>`;
list.insertAdjacentHTML('beforeend', newLine);
deleteLine(document.getElementById("delete-" + i));
}, false)
</script>
<?php
else:
?>
<form action="" method="post">
<h2>Login</h2>
<?php
if (!empty($loginErrors)):
?>
<p style="color: red;"><?= $loginErrors; ?></p>
<?php
endif;
?>
<label for="username">Utilisateur :</label>
<input type="text" id="username" name="username"/>
<label for="password">Mot de passe :</label>
<input type="password" id="password" name="password"/>
<input type="submit" value="OK" name="login" />
</form>
<?php
endif;
?>
</div>
</body>
</html>