Files
sshkeyvault/tests/mock-oidc/login.html
T
florian.wildeandClaude Opus 5.5 e89112a761 test: SSH-Testziele und Mock-OIDC fuer Integrationstests (#011)
Bootstrap, Host-Key-Pruefung und spaeteres Ausrollen brauchen echte
sshd-Gegenstellen. Zwei Debian-13-Container (ziel-a, ziel-b) in einem
gemeinsamen Netz bilden frische Hosts vor dem Bootstrap nach: root- und
Passwort-Login sind absichtlich offen, Host-Keys entstehen erst beim
Start, und `hostkeys-tauschen` erlaubt den Test "geaenderter Host-Key
wird abgelehnt" ohne Neuerstellen des Containers.

Die Testhilfen lesen dieselben Adress-Variablen wie die Compose-Datei
und lassen Tests mit Hinweis auf den Startbefehl fehlschlagen, statt
sie still zu ueberspringen - ein uebersprungener Integrationstest sieht
sonst wie ein bestandener aus.

Der Mock-OIDC-Anbieter ersetzt authentik in der Entwicklung (PLAN.md,
Entscheidung 7). Bei interaktivem Login uebernimmt er nur Claims aus dem
Formular, daher belegt eine eigene Login-Seite email, name und groups
vor und laesst die Gruppen frei waehlen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:13:56 +02:00

125 lines
3.8 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Mock-OIDC – Anmeldung (nur Entwicklung)</title>
<style>
body {
font-family: system-ui, sans-serif;
background: #111418;
color: #e6e8eb;
margin: 0;
padding: 2rem 1rem;
}
main {
max-width: 34rem;
margin: 0 auto;
}
h1 {
font-size: 1.3rem;
}
p.hinweis {
color: #f0b429;
font-size: 0.9rem;
}
label {
display: block;
margin: 1rem 0 0.3rem;
font-weight: 600;
}
input,
textarea {
width: 100%;
box-sizing: border-box;
background: #1b2027;
color: inherit;
border: 1px solid #39414d;
border-radius: 6px;
padding: 0.5rem;
font-family: ui-monospace, monospace;
font-size: 0.9rem;
}
.rollen {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
margin-top: 1rem;
}
button {
background: #2a3240;
color: inherit;
border: 1px solid #39414d;
border-radius: 6px;
padding: 0.4rem 0.8rem;
cursor: pointer;
}
button[type="submit"] {
background: #2f6fde;
border-color: #2f6fde;
margin-top: 1rem;
width: 100%;
padding: 0.6rem;
}
</style>
</head>
<body>
<main>
<h1>Mock-OIDC-Anmeldung</h1>
<p class="hinweis">
Nur für die Entwicklung (#011). Benutzername wird zu <code>sub</code>, die Claims unten landen im
ID-Token und unter <code>/userinfo</code>.
</p>
<!-- Ohne action postet das Formular an die /authorize-URL samt Query zurück –
genau das erwartet mock-oauth2-server. -->
<form method="post">
<label for="username">Benutzername (sub)</label>
<input id="username" name="username" required value="admin" autocomplete="off" />
<div class="rollen">
<button type="button" data-rolle="admin">Admin</button>
<button type="button" data-rolle="operator">Operator</button>
<button type="button" data-rolle="reader">Reader</button>
<button type="button" data-rolle="ohne">Ohne Gruppe</button>
</div>
<label for="claims">Claims (JSON, frei änderbar)</label>
<textarea id="claims" name="claims" rows="12"></textarea>
<button type="submit">Anmelden</button>
</form>
</main>
<script>
// Der Mock übernimmt bei interaktivem Login nur die Claims aus diesem Formular
// (tokenCallbacks greifen dann nicht). Deshalb wird hier ein vollständiger
// Standardsatz vorbelegt; Gruppen lassen sich frei ändern.
const gruppen = {
admin: ["sshkv-admins"],
operator: ["sshkv-operators"],
reader: ["sshkv-readers"],
ohne: [],
};
const benutzer = document.getElementById("username");
const claims = document.getElementById("claims");
function fuellen(rolle) {
const name = benutzer.value || rolle;
claims.value = JSON.stringify(
{
email: name + "@sshkv.test",
email_verified: true,
name: name.charAt(0).toUpperCase() + name.slice(1) + " (Mock)",
preferred_username: name,
groups: gruppen[rolle],
},
null,
2,
);
}
document.querySelectorAll("button[data-rolle]").forEach((knopf) => {
knopf.addEventListener("click", () => {
if (knopf.dataset.rolle !== "ohne") benutzer.value = knopf.dataset.rolle;
fuellen(knopf.dataset.rolle);
});
});
fuellen("admin");
</script>
</body>
</html>