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>
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
<!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>
|
||||
Reference in New Issue
Block a user