]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Add script to handle ssh keys
authorThibault Pelloquin <thibault.pelloquin@gmail.com>
Tue, 19 Oct 2021 21:32:45 +0000 (23:32 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Wed, 20 Oct 2021 18:13:34 +0000 (20:13 +0200)
Work by Thibault

modules/private/websites/tools/tools/landing/ldap_ssh_keys.php [new file with mode: 0644]
nix/sources.json
nixops/secrets

diff --git a/modules/private/websites/tools/tools/landing/ldap_ssh_keys.php b/modules/private/websites/tools/tools/landing/ldap_ssh_keys.php
new file mode 100644 (file)
index 0000000..259e28d
--- /dev/null
@@ -0,0 +1,348 @@
+<!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>
+
+
index 961d378227905178c7b838cff131270a4d4703d4..1a1cf5a85b7c64ec34f97f86148dc7f49fc857ef 100644 (file)
     "webapps-landing": {
         "ref": "gitolite_local/local_changes",
         "repo": "https://git.immae.eu/github/bastienwirtz/homer.git",
-        "rev": "49b6104e9d0059b7990b3dcd53cca664d5cce7af",
+        "rev": "bb60c5b869931f305f15c5bfa9cdb3f68702f01f",
         "type": "git",
         "version": "e0a72b7-local"
     },
index 0b9f489a7e2e01208d4285c26348b4fa09607e1b..39f3c2c33c57df2a502b3cdf45635d0afe272739 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0b9f489a7e2e01208d4285c26348b4fa09607e1b
+Subproject commit 39f3c2c33c57df2a502b3cdf45635d0afe272739