Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA. Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb, Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming, Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office (Collabora/OnlyOffice). Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort) sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
91 lines
2.6 KiB
Go
91 lines
2.6 KiB
Go
package auth
|
||
|
||
import (
|
||
"context"
|
||
"os"
|
||
"testing"
|
||
|
||
"github.com/jackc/pgx/v5/pgxpool"
|
||
)
|
||
|
||
// Prüft den Fall, der beim Einschalten von OIDC über eine bestehende
|
||
// Installation entscheidet: Wird das vorhandene Konto verbunden – oder entsteht
|
||
// daneben ein zweites, leeres?
|
||
//
|
||
// Läuft nur mit TEST_DSN gegen eine echte Datenbank; ohne wird übersprungen,
|
||
// damit `go test ./...` überall grün bleibt.
|
||
func TestGetOrCreateByOIDC_Linking(t *testing.T) {
|
||
dsn := os.Getenv("TEST_DSN")
|
||
if dsn == "" {
|
||
t.Skip("TEST_DSN nicht gesetzt")
|
||
}
|
||
ctx := context.Background()
|
||
pool, err := pgxpool.New(ctx, dsn)
|
||
if err != nil {
|
||
t.Fatalf("verbinden: %v", err)
|
||
}
|
||
defer pool.Close()
|
||
s := NewStore(pool)
|
||
|
||
// Aufräumen, auch wenn der Test scheitert.
|
||
cleanup := func() {
|
||
_, _ = pool.Exec(ctx, `DELETE FROM users WHERE username LIKE 'linkprobe%'`)
|
||
}
|
||
cleanup()
|
||
defer cleanup()
|
||
|
||
hash, _ := HashPassword("irrelevant-aber-gueltig")
|
||
if _, err := pool.Exec(ctx,
|
||
`INSERT INTO users (username, display_name, password, is_admin)
|
||
VALUES ('linkprobe', 'Link Probe', $1, true)`, hash); err != nil {
|
||
t.Fatalf("konto anlegen: %v", err)
|
||
}
|
||
|
||
t.Run("ohne Verknüpfung entsteht ein zweites Konto", func(t *testing.T) {
|
||
u, err := s.GetOrCreateByOIDC(ctx, "sub-A", "linkprobe", "Link Probe", false)
|
||
if err != nil {
|
||
t.Fatalf("aufruf: %v", err)
|
||
}
|
||
if u.Username == "linkprobe" {
|
||
t.Fatal("erwartet: ein neues Konto mit abgewandeltem Namen")
|
||
}
|
||
if u.IsAdmin {
|
||
t.Error("ein neu angelegtes Konto darf keine Adminrechte erben")
|
||
}
|
||
_, _ = pool.Exec(ctx, `DELETE FROM users WHERE oidc_sub = 'sub-A'`)
|
||
})
|
||
|
||
t.Run("mit Verknüpfung bleibt das bestehende Konto", func(t *testing.T) {
|
||
u, err := s.GetOrCreateByOIDC(ctx, "sub-B", "linkprobe", "Link Probe", true)
|
||
if err != nil {
|
||
t.Fatalf("aufruf: %v", err)
|
||
}
|
||
if u.Username != "linkprobe" {
|
||
t.Fatalf("erwartet linkprobe, bekam %q", u.Username)
|
||
}
|
||
if !u.IsAdmin {
|
||
t.Error("Adminrecht des bestehenden Kontos ging verloren")
|
||
}
|
||
if !u.IsOIDC {
|
||
t.Error("Konto sollte jetzt als OIDC-Konto gelten")
|
||
}
|
||
})
|
||
|
||
t.Run("erneutes Anmelden findet dasselbe Konto", func(t *testing.T) {
|
||
u, err := s.GetOrCreateByOIDC(ctx, "sub-B", "linkprobe", "Link Probe", true)
|
||
if err != nil || u.Username != "linkprobe" {
|
||
t.Fatalf("wiederholte Anmeldung: %v / %+v", err, u)
|
||
}
|
||
})
|
||
|
||
t.Run("fremde Identität übernimmt ein gebundenes Konto nicht", func(t *testing.T) {
|
||
u, err := s.GetOrCreateByOIDC(ctx, "sub-FREMD", "linkprobe", "Angreifer", true)
|
||
if err != nil {
|
||
t.Fatalf("aufruf: %v", err)
|
||
}
|
||
if u.Username == "linkprobe" {
|
||
t.Fatal("ein bereits gebundenes Konto wurde übernommen – das darf nie passieren")
|
||
}
|
||
})
|
||
}
|