mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-21 05:58:13 +02:00
API interne pour la façade Rust : clé de pilotage à la demande
Lot 2 de la migration : la façade va authentifier elle-même ses routes /api/*. La clé de pilotage vit dans la base bbolt, verrouillée par ce process ; la façade la demande donc à GET /internal/v1/auth, à chaque requête — un changement de clé prend effet tout de suite, comme avant. La réponse contient un secret, d'où trois verrous : route branchée uniquement sur l'écoute TCP directe (le tunnel du relais sert le mux nu), jeton tiré au hasard par la façade à chaque démarrage et exigé en temps constant, 404 sans rien révéler sinon. Base illisible : 503, la façade fermera l'accès plutôt que de l'ouvrir. Spec du lot 2 jointe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4b859c4eb6
commit
a99d988e70
4 files changed
+233
-1
No files matched your search
@@ -0,0 +1,75 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const jetonTest = "0123456789abcdef0123456789abcdef"
|
||||
|
||||
func appelInterne(t *testing.T, path, jeton string) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
suite := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("mux"))
|
||||
})
|
||||
r := httptest.NewRequest("GET", path, nil)
|
||||
if jeton != "" {
|
||||
r.Header.Set(internalTokenHeader, jeton)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
withInternalAPI(suite).ServeHTTP(w, r)
|
||||
return w
|
||||
}
|
||||
|
||||
func TestAPIInterneFermeeSansJeton(t *testing.T) {
|
||||
t.Setenv(internalTokenEnv, "")
|
||||
if w := appelInterne(t, "/internal/v1/auth", jetonTest); w.Code != 404 {
|
||||
t.Fatalf("sans jeton configuré : %d, attendu 404", w.Code)
|
||||
}
|
||||
// Jeton configuré mais trop court : API désactivée, même avec le bon.
|
||||
t.Setenv(internalTokenEnv, "court")
|
||||
if w := appelInterne(t, "/internal/v1/auth", "court"); w.Code != 404 {
|
||||
t.Fatalf("jeton trop court : %d, attendu 404", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIInterneRefuseMauvaisJeton(t *testing.T) {
|
||||
t.Setenv(internalTokenEnv, jetonTest)
|
||||
for _, j := range []string{"", "x", strings.ToUpper(jetonTest)} {
|
||||
if w := appelInterne(t, "/internal/v1/auth", j); w.Code != 404 {
|
||||
t.Fatalf("jeton %q : %d, attendu 404", j, w.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIInterneAuth(t *testing.T) {
|
||||
testHome(t)
|
||||
t.Setenv(internalTokenEnv, jetonTest)
|
||||
if err := putStr(bkState, "web_key", "loki-web-secret"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w := appelInterne(t, "/internal/v1/auth", jetonTest)
|
||||
if w.Code != 200 {
|
||||
t.Fatalf("code %d : %s", w.Code, w.Body.String())
|
||||
}
|
||||
var got map[string]string
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got["web_key"] != "loki-web-secret" || got["version"] != Version {
|
||||
t.Fatalf("réponse : %+v", got)
|
||||
}
|
||||
if w := appelInterne(t, "/internal/v1/autre", jetonTest); w.Code != 404 {
|
||||
t.Fatalf("route inconnue : %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIInterneLaisseLeResteAuMux(t *testing.T) {
|
||||
t.Setenv(internalTokenEnv, jetonTest)
|
||||
if w := appelInterne(t, "/api/ping", ""); w.Body.String() != "mux" {
|
||||
t.Fatalf("relais au mux : %q", w.Body.String())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user