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:
kami
2026-07-05 11:55:44 +04:00
parent c225ba37b2
commit 5afff001c3
5 changed files with 79 additions and 31 deletions
+9 -1
View File
@@ -8,6 +8,7 @@ import (
"net/http"
"time"
"github.com/kami/maven/internal/auth"
"github.com/kami/maven/internal/ipc"
"github.com/kami/maven/internal/webauthn"
)
@@ -29,6 +30,7 @@ type PasskeyHandle struct {
rp *webauthn.RP
assertFn assertIPC // *ipc.Client when connected; nil ⇒ no step-up IPC
store *credentialStore
session *webauthn.PasskeySession
}
type localCred struct {
@@ -36,7 +38,7 @@ type localCred struct {
SignCount int64
}
func newPasskeyHandle(cfg webauthn.Config, core ipc.CoreAPI, storePath string) (*PasskeyHandle, error) {
func newPasskeyHandle(cfg webauthn.Config, core ipc.CoreAPI, storePath string, session *webauthn.PasskeySession) (*PasskeyHandle, error) {
var af assertIPC
if c, ok := core.(assertIPC); ok {
af = c
@@ -49,6 +51,7 @@ func newPasskeyHandle(cfg webauthn.Config, core ipc.CoreAPI, storePath string) (
rp: webauthn.NewRP(cfg),
assertFn: af,
store: store,
session: session,
}, nil
}
@@ -190,6 +193,11 @@ func (h *PasskeyHandle) AssertFinish(w http.ResponseWriter, r *http.Request) {
}
}
// Assert the in-process session so the POST /tools handler sees step-up.
if h.session != nil {
h.session.Assert(r.Context(), auth.Scope{})
}
log.Printf("webauthn: asserted credential %s", credID)
json.NewEncoder(w).Encode(map[string]string{"credential_id": credID})
}