mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-15 18:20:35 +00:00
Fix agent-token fallback to reject cross-org tokens and update security contract test
Two test regressions introduced when agent-report tokens were allowed as fallback auth for /api/auto-register: 1. Org mismatch was not checked: a token belonging to org-a could authenticate a request whose context carried org-b. Add an explicit org consistency check before setting authenticated=true in the fallback path. 2. The security regression test assumed only setup tokens could authenticate auto-register. That contract has intentionally changed: agent-report tokens can now authenticate but are restricted to updating existing nodes (403 for new-node attempts). Update the test to assert the actual security boundary.
This commit is contained in:
parent
264c9377a2
commit
9bac3f421d
2 changed files with 21 additions and 11 deletions
|
|
@ -718,12 +718,19 @@ func (h *ConfigHandlers) handleAutoRegister(w http.ResponseWriter, r *http.Reque
|
|||
record, ok := cfg.ValidateAPIToken(apiToken)
|
||||
config.Mu.Unlock()
|
||||
if ok && record != nil && record.HasScope(config.ScopeAgentReport) {
|
||||
authenticated = true
|
||||
r = r.WithContext(context.WithValue(r.Context(), agentAutoRegContextKey{}, true))
|
||||
log.Info().
|
||||
Str("type", req.Type).
|
||||
Str("host", req.Host).
|
||||
Msg("Auto-register authenticated via agent API token (update-only mode)")
|
||||
// Reject cross-org tokens: if the request context has an explicit
|
||||
// non-default org, the token must belong to that same org.
|
||||
requestOrgID := GetOrgID(r.Context())
|
||||
orgMismatch := requestOrgID != "" && requestOrgID != "default" &&
|
||||
record.OrgID != "" && record.OrgID != requestOrgID
|
||||
if !orgMismatch {
|
||||
authenticated = true
|
||||
r = r.WithContext(context.WithValue(r.Context(), agentAutoRegContextKey{}, true))
|
||||
log.Info().
|
||||
Str("type", req.Type).
|
||||
Str("host", req.Host).
|
||||
Msg("Auto-register authenticated via agent API token (update-only mode)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2065,16 +2065,19 @@ func TestAutoRegisterRejectsAgentTokenWithoutSetupToken(t *testing.T) {
|
|||
router := NewRouter(cfg, nil, nil, nil, nil, "1.0.0")
|
||||
router.configHandlers.SetConfig(cfg)
|
||||
|
||||
body := `{"type":"pve","host":"https://192.168.1.1:8006","tokenId":"test@pam!pulse","tokenValue":"secret"}`
|
||||
// Agent-report tokens can authenticate auto-register but are restricted to
|
||||
// updating existing nodes. Attempting to register a brand-new node must
|
||||
// return 403, not succeed.
|
||||
body := `{"type":"pve","host":"https://192.168.1.1:8006","tokenId":"pulse-monitor@pve!pulse-192-168-1-1","tokenValue":"secret","source":"agent","serverName":"newhost"}`
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/auto-register", strings.NewReader(body))
|
||||
req.Header.Set("X-API-Token", rawToken)
|
||||
rec := httptest.NewRecorder()
|
||||
router.Handler().ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("expected 401 when agent API token is provided without a Pulse setup token, got %d", rec.Code)
|
||||
if rec.Code != http.StatusForbidden {
|
||||
t.Fatalf("expected 403 when agent API token is used to register a new node, got %d", rec.Code)
|
||||
}
|
||||
if !strings.Contains(rec.Body.String(), "Pulse setup token required") {
|
||||
t.Fatalf("expected setup-token requirement guidance, got %q", rec.Body.String())
|
||||
if !strings.Contains(rec.Body.String(), "agent token auth permits token updates for existing nodes only") {
|
||||
t.Fatalf("expected agent-token restriction message, got %q", rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue