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:
sysops
2026-08-28 23:34:36 +02:00
parent f0139c889a
commit f627caaacb
19 changed files with 1407 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
package auth
import (
"encoding/json"
"net/http"
"gitea.perlbach24.de/scripte/nexarch/internal/user"
)
// ChangePasswordHandler stellt die Passwortaenderung fuer den bereits
// angemeldeten Benutzer bereit (IAM-08 Akzeptanzkriterium 2). Getrennt von
// Handler (Login/Logout), weil hier zusaetzlich der TenantUserStore fuer das
// Aktualisieren des Hashes gebraucht wird.
type ChangePasswordHandler struct {
users *user.TenantUserStore
}
func NewChangePasswordHandler(users *user.TenantUserStore) *ChangePasswordHandler {
return &ChangePasswordHandler{users: users}
}
type changePasswordRequest struct {
CurrentPassword string `json:"current_password"`
NewPassword string `json:"new_password"`
}
// ChangePassword verlangt das aktuelle Passwort, bevor ein neues gesetzt wird
// — ohne diese Pruefung koennte ein gekapertes, noch gueltiges Session-Cookie
// allein zur vollstaendigen Kontoübernahme reichen (Passwort setzen, alte
// Session unbrauchbar machen). Muss hinter RequireAuth haengen.
func (h *ChangePasswordHandler) ChangePassword(w http.ResponseWriter, r *http.Request) {
claims, ok := ClaimsFromContext(r.Context())
if !ok {
http.Error(w, "nicht angemeldet", http.StatusUnauthorized)
return
}
var req changePasswordRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "ungueltige Anfrage", http.StatusBadRequest)
return
}
creds, err := h.users.GetByIDForAuth(r.Context(), claims.UserID)
if err != nil {
http.Error(w, "Aktuelles Passwort oder neues Passwort ungültig.", http.StatusBadRequest)
return
}
if !VerifyPassword(creds.PasswordHash, req.CurrentPassword) {
http.Error(w, "Aktuelles Passwort oder neues Passwort ungültig.", http.StatusBadRequest)
return
}
newHash, err := HashPassword(req.NewPassword)
if err != nil {
http.Error(w, "Aktuelles Passwort oder neues Passwort ungültig.", http.StatusBadRequest)
return
}
if err := h.users.SetPasswordHash(r.Context(), claims.UserID, newHash); err != nil {
http.Error(w, "Passwort konnte nicht gespeichert werden.", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}