IAM-08: benutzerprofil-login-oberflaeche (login+2fa/passwort-reset/profil-backend-handler + web/account next.js-frontend auf shl-01)
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package authtoken
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// fakeNotifier zeichnet auf, ob/mit welchem Token benachrichtigt wurde —
|
||||
// ersetzt LogNotifier im Test, damit der Test pruefen kann, OB ein Token
|
||||
// erzeugt wurde, ohne die HTTP-Antwort danach zu unterscheiden
|
||||
// (Akzeptanzkriterium 3: die Antwort selbst bleibt in beiden Faellen gleich).
|
||||
type fakeNotifier struct {
|
||||
calls []string // e-mail-adressen, fuer die notifiziert wurde
|
||||
}
|
||||
|
||||
func (f *fakeNotifier) NotifyPasswordReset(_ context.Context, email, _ string) error {
|
||||
f.calls = append(f.calls, email)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Akzeptanzkriterium 3 + Pruefung 1: Antwort ist IDENTISCH, egal ob die
|
||||
// E-Mail-Adresse existiert — nur intern (Notifier-Aufruf) unterscheidet sich.
|
||||
func TestRequestReset_SameResponseRegardlessOfExistence(t *testing.T) {
|
||||
tokens, users, userID, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
_ = userID
|
||||
|
||||
u, err := users.Get(context.Background(), userID)
|
||||
if err != nil {
|
||||
t.Fatalf("benutzer laden: %v", err)
|
||||
}
|
||||
|
||||
notifier := &fakeNotifier{}
|
||||
h := NewHandler(tokens, users, notifier)
|
||||
|
||||
// Fall 1: existierende E-Mail.
|
||||
body1, _ := json.Marshal(requestResetRequest{Email: u.Email})
|
||||
req1 := httptest.NewRequest(http.MethodPost, "/auth/password-reset/request", bytes.NewReader(body1))
|
||||
rec1 := httptest.NewRecorder()
|
||||
h.RequestReset(rec1, req1)
|
||||
|
||||
// Fall 2: nicht existierende E-Mail.
|
||||
body2, _ := json.Marshal(requestResetRequest{Email: "gibt-es-nicht@example.com"})
|
||||
req2 := httptest.NewRequest(http.MethodPost, "/auth/password-reset/request", bytes.NewReader(body2))
|
||||
rec2 := httptest.NewRecorder()
|
||||
h.RequestReset(rec2, req2)
|
||||
|
||||
if rec1.Code != rec2.Code {
|
||||
t.Fatalf("status codes unterscheiden sich: %d vs %d — verraet Konto-Existenz", rec1.Code, rec2.Code)
|
||||
}
|
||||
if rec1.Body.String() != rec2.Body.String() {
|
||||
t.Fatalf("antwort-body unterscheidet sich: %q vs %q — verraet Konto-Existenz", rec1.Body.String(), rec2.Body.String())
|
||||
}
|
||||
|
||||
// Intern wurde aber nur fuer die existierende Adresse tatsaechlich benachrichtigt.
|
||||
if len(notifier.calls) != 1 || notifier.calls[0] != u.Email {
|
||||
t.Fatalf("erwartet genau 1 benachrichtigung fuer %q, habe %v", u.Email, notifier.calls)
|
||||
}
|
||||
}
|
||||
|
||||
// Akzeptanzkriterium 3: vollstaendiger Reset-Flow ueber HTTP.
|
||||
func TestCompleteReset_Works(t *testing.T) {
|
||||
tokens, users, userID, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
ctx := context.Background()
|
||||
|
||||
token, err := tokens.Create(ctx, userID, PurposeReset, ResetTokenTTL)
|
||||
if err != nil {
|
||||
t.Fatalf("token erzeugen: %v", err)
|
||||
}
|
||||
|
||||
h := NewHandler(tokens, users, &fakeNotifier{})
|
||||
body, _ := json.Marshal(completeResetRequest{Token: token, NewPassword: "neues-sicheres-passwort"})
|
||||
req := httptest.NewRequest(http.MethodPost, "/auth/password-reset/complete", bytes.NewReader(body))
|
||||
rec := httptest.NewRecorder()
|
||||
h.CompleteReset(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200, body: %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
// Token ist jetzt verbraucht — zweiter Versuch schlaegt fehl.
|
||||
body2, _ := json.Marshal(completeResetRequest{Token: token, NewPassword: "noch-ein-passwort"})
|
||||
req2 := httptest.NewRequest(http.MethodPost, "/auth/password-reset/complete", bytes.NewReader(body2))
|
||||
rec2 := httptest.NewRecorder()
|
||||
h.CompleteReset(rec2, req2)
|
||||
if rec2.Code != http.StatusBadRequest {
|
||||
t.Fatalf("wiederverwendung: status = %d, want 400", rec2.Code)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user