Improve gateway auth middleware to use internal auth context

Enforce GATEWAY_API_KEY in Makefile E2E test target Fix gateway E2E test
payload reading to use io.ReadAll Remove deprecated multi-node test
targets and cleanup Makefile comments
This commit is contained in:
anonpenguin 2025-08-23 11:14:11 +03:00
parent 895f1d5dff
commit 03b3b38967
3 changed files with 33 additions and 54 deletions

View File

@ -5,9 +5,15 @@ test:
@echo Running tests...
go test -v $(TEST)
# Gateway-focused E2E tests assume gateway and nodes are already running
# Configure via env:
# GATEWAY_BASE_URL (default http://127.0.0.1:8080)
# GATEWAY_API_KEY (required for auth-protected routes)
.PHONY: test-e2e
test-e2e:
@echo Running E2E tests...
@echo "Running gateway E2E tests (HTTP/WS only)..."
@echo "Base URL: $${GATEWAY_BASE_URL:-http://127.0.0.1:8080}"
@test -n "$$GATEWAY_API_KEY" || (echo "GATEWAY_API_KEY must be set" && exit 1)
go test -v -tags e2e ./e2e
# Network - Distributed P2P Database System
@ -37,11 +43,6 @@ clean:
rm -rf data/
@echo "Clean complete!"
# Run tests
test:
@echo "Running tests..."
go test -v ./...
# Run bootstrap node (auto-selects identity and data dir)
run-node:
@echo "Starting bootstrap node with config..."
@ -151,30 +152,6 @@ dev-setup: deps
@mkdir -p data/test-bootstrap data/test-node1 data/test-node2
@echo "Development setup complete!"
# Multi-node testing
test-multinode: build
@echo "🧪 Starting comprehensive multi-node test..."
@chmod +x scripts/test-multinode.sh
@./scripts/test-multinode.sh
test-peer-discovery: build
@echo "🔍 Testing peer discovery (requires running nodes)..."
@echo "Connected peers:"
@./bin/network-cli peers --timeout 10s
test-replication: build
@echo "🔄 Testing data replication (requires running nodes)..."
@./bin/network-cli storage put "replication:test:$$(date +%s)" "Test data - $$(date)"
@sleep 2
@echo "Retrieving replicated data:"
@./bin/network-cli storage list replication:test:
test-consensus: build
@echo "🗄️ Testing database consensus (requires running nodes)..."
@./bin/network-cli query "CREATE TABLE IF NOT EXISTS consensus_test (id INTEGER PRIMARY KEY, test_data TEXT, timestamp TEXT)"
@./bin/network-cli query "INSERT INTO consensus_test (test_data, timestamp) VALUES ('Makefile test', '$$(date)')"
@./bin/network-cli query "SELECT * FROM consensus_test ORDER BY id DESC LIMIT 5"
# Start development cluster (requires multiple terminals)
dev-cluster:
@echo "To start a development cluster, run these commands in separate terminals:"

View File

@ -3,11 +3,11 @@
package e2e
import (
"context"
"crypto/rand"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
@ -111,11 +111,10 @@ func TestGateway_Storage_PutGetListExistsDelete(t *testing.T) {
if err != nil { t.Fatalf("get do: %v", err) }
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { t.Fatalf("get status: %d", resp.StatusCode) }
got := make([]byte, len(payload))
n, _ := resp.Body.Read(got)
if n == 0 || string(got[:n]) != string(payload[:n]) {
t.Fatalf("payload mismatch: want %q got %q", string(payload), string(got[:n]))
}
got, _ := io.ReadAll(resp.Body)
if string(got) != string(payload) {
t.Fatalf("payload mismatch: want %q got %q", string(payload), string(got))
}
}
// LIST (prefix)

View File

@ -9,6 +9,7 @@ import (
"strings"
"time"
"git.debros.io/DeBros/network/pkg/client"
"git.debros.io/DeBros/network/pkg/logging"
"git.debros.io/DeBros/network/pkg/storage"
"go.uber.org/zap"
@ -95,12 +96,13 @@ func (g *Gateway) authMiddleware(next http.Handler) http.Handler {
return
}
// Look up API key in DB and derive namespace
db := g.client.Database()
ctx := r.Context()
// Join to namespaces to resolve name in one query
q := "SELECT namespaces.name FROM api_keys JOIN namespaces ON api_keys.namespace_id = namespaces.id WHERE api_keys.key = ? LIMIT 1"
res, err := db.Query(ctx, q, key)
// Look up API key in DB and derive namespace
db := g.client.Database()
// Use internal auth for DB validation (auth not established yet)
internalCtx := client.WithInternalAuth(r.Context())
// Join to namespaces to resolve name in one query
q := "SELECT namespaces.name FROM api_keys JOIN namespaces ON api_keys.namespace_id = namespaces.id WHERE api_keys.key = ? LIMIT 1"
res, err := db.Query(internalCtx, q, key)
if err != nil || res == nil || res.Count == 0 || len(res.Rows) == 0 || len(res.Rows[0]) == 0 {
w.Header().Set("WWW-Authenticate", "Bearer error=\"invalid_token\"")
writeError(w, http.StatusUnauthorized, "invalid API key")
@ -121,10 +123,10 @@ func (g *Gateway) authMiddleware(next http.Handler) http.Handler {
return
}
// Attach auth metadata to context for downstream use
ctx = context.WithValue(ctx, ctxKeyAPIKey, key)
ctx = storage.WithNamespace(ctx, ns)
next.ServeHTTP(w, r.WithContext(ctx))
// Attach auth metadata to context for downstream use
reqCtx := context.WithValue(r.Context(), ctxKeyAPIKey, key)
reqCtx = storage.WithNamespace(reqCtx, ns)
next.ServeHTTP(w, r.WithContext(reqCtx))
})
}
@ -224,22 +226,23 @@ func (g *Gateway) authorizationMiddleware(next http.Handler) http.Handler {
return
}
// Check ownership in DB
db := g.client.Database()
// Ensure namespace exists and get id
if _, err := db.Query(ctx, "INSERT OR IGNORE INTO namespaces(name) VALUES (?)", ns); err != nil {
// Check ownership in DB using internal auth context
db := g.client.Database()
internalCtx := client.WithInternalAuth(ctx)
// Ensure namespace exists and get id
if _, err := db.Query(internalCtx, "INSERT OR IGNORE INTO namespaces(name) VALUES (?)", ns); err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
nres, err := db.Query(ctx, "SELECT id FROM namespaces WHERE name = ? LIMIT 1", ns)
nres, err := db.Query(internalCtx, "SELECT id FROM namespaces WHERE name = ? LIMIT 1", ns)
if err != nil || nres == nil || nres.Count == 0 || len(nres.Rows) == 0 || len(nres.Rows[0]) == 0 {
writeError(w, http.StatusForbidden, "namespace not found")
return
}
nsID := nres.Rows[0][0]
q := "SELECT 1 FROM namespace_ownership WHERE namespace_id = ? AND owner_type = ? AND owner_id = ? LIMIT 1"
res, err := db.Query(ctx, q, nsID, ownerType, ownerID)
q := "SELECT 1 FROM namespace_ownership WHERE namespace_id = ? AND owner_type = ? AND owner_id = ? LIMIT 1"
res, err := db.Query(internalCtx, q, nsID, ownerType, ownerID)
if err != nil || res == nil || res.Count == 0 {
writeError(w, http.StatusForbidden, "forbidden: not an owner of namespace")
return