mavweb: add in-process auth gate for POST /tools
Add a local PasskeySession that handleTools checks before processing any POST action (enable/disable). If the session hasn't been asserted within the 5-minute TTL, return 403 Forbidden. Changes: - webauthn/session.go: add IsStepUp() convenience method (nil-safe) - webauthn.go: PasskeyHandle holds a *PasskeySession; AssertFinish calls session.Assert() after IPC step-up - main.go: create stepUpSession, pass to handleTools and newPasskeyHandle; handleTools returns 403 if !session.IsStepUp() - handlers_test.go: update TestEnableTool_NoInProcessAuthGate to expect 403; add TestEnableTool_WithAuthGate_RequiresStepUp for the happy path with asserted session; update all 10 call sites
This commit is contained in:
+9
-3
@@ -142,12 +142,14 @@ func main() {
|
||||
// Passkey registration + assertion are the step-up mechanism for
|
||||
// AuthStepUp actions (tool enable). Without -webauthn-origin, these
|
||||
// endpoints return 503 and step-up is unavailable (FloorSession).
|
||||
stepUpSession := webauthn.NewPasskeySession(5 * time.Minute)
|
||||
|
||||
if *pkOrigin != "" && *pkRPID != "" && core != nil {
|
||||
pk, err := newPasskeyHandle(webauthn.Config{
|
||||
Origin: *pkOrigin,
|
||||
RPID: *pkRPID,
|
||||
RPName: "maven",
|
||||
}, core, *pkFile)
|
||||
}, core, *pkFile, stepUpSession)
|
||||
if err != nil {
|
||||
log.Fatalf("passkey store: %v", err)
|
||||
}
|
||||
@@ -163,7 +165,7 @@ func main() {
|
||||
// Enabling is the boundary-moving act (maven.md), so it lives ONLY here,
|
||||
// behind wg+nginx+auth — never the voice/chat path.
|
||||
mux.HandleFunc("/tools", func(w http.ResponseWriter, r *http.Request) {
|
||||
handleTools(w, r, core)
|
||||
handleTools(w, r, core, stepUpSession)
|
||||
})
|
||||
|
||||
srv := &http.Server{Addr: *addr, Handler: mux}
|
||||
@@ -425,7 +427,7 @@ func handleRevert(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI) {
|
||||
// whitespace-split — argv with embedded spaces isn't supported (ponytail: no
|
||||
// shell-word parsing; the box owner controls this input, quote a wrapper script
|
||||
// if an arg needs spaces).
|
||||
func handleTools(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI) {
|
||||
func handleTools(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI, session *webauthn.PasskeySession) {
|
||||
if core == nil {
|
||||
http.Error(w, "tools disabled (no -core)", http.StatusServiceUnavailable)
|
||||
return
|
||||
@@ -433,6 +435,10 @@ func handleTools(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI) {
|
||||
ctx := r.Context()
|
||||
var msg string
|
||||
if r.Method == http.MethodPost {
|
||||
if !session.IsStepUp() {
|
||||
http.Error(w, "step-up required: assert a passkey first", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
action := r.FormValue("action")
|
||||
name := strings.TrimSpace(r.FormValue("name"))
|
||||
switch action {
|
||||
|
||||
Reference in New Issue
Block a user