Files
go-otel/internal/auth/oidc_test.go
T
mats 21f04d696b
Build and Publish / Metadata (push) Successful in 2s
Build and Publish / BuildAndDeployAmd64 (push) Successful in 58s
more otel
2026-09-18 20:51:37 +00:00

166 lines
4.6 KiB
Go

package auth
import (
"context"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
)
func TestAudienceUnmarshal(t *testing.T) {
var a1 Audience
if err := json.Unmarshal([]byte(`"single-aud"`), &a1); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !a1.Contains("single-aud") || a1.Contains("other") {
t.Fatalf("unexpected audience content: %v", a1)
}
var a2 Audience
if err := json.Unmarshal([]byte(`["aud1", "aud2"]`), &a2); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !a2.Contains("aud1") || !a2.Contains("aud2") || a2.Contains("aud3") {
t.Fatalf("unexpected audience content: %v", a2)
}
}
func TestVerifyToken(t *testing.T) {
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatalf("failed to generate RSA key: %v", err)
}
auth := &OidcAuth{
issuer: "https://test.issuer",
client: "test-client",
keys: map[string]*rsa.PublicKey{
"key-1": &privKey.PublicKey,
},
fetched: time.Now(),
}
// Helper to mint test token
mintToken := func(kid string, claims IDClaims) string {
headerJSON, _ := json.Marshal(map[string]string{
"kid": kid,
"alg": "RS256",
})
claimsJSON, _ := json.Marshal(claims)
headerB64 := base64.RawURLEncoding.EncodeToString(headerJSON)
payloadB64 := base64.RawURLEncoding.EncodeToString(claimsJSON)
sum := sha256.Sum256([]byte(headerB64 + "." + payloadB64))
sig, _ := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, sum[:])
sigB64 := base64.RawURLEncoding.EncodeToString(sig)
return headerB64 + "." + payloadB64 + "." + sigB64
}
// Valid token
validToken := mintToken("key-1", IDClaims{
Iss: "https://test.issuer",
Sub: "user-123",
Aud: Audience{"test-client"},
Exp: time.Now().Add(time.Hour).Unix(),
})
claims, err := auth.VerifyToken(context.Background(), validToken)
if err != nil {
t.Fatalf("expected valid token to pass, got: %v", err)
}
if claims.Sub != "user-123" {
t.Fatalf("expected sub user-123, got %s", claims.Sub)
}
// Expired token
expiredToken := mintToken("key-1", IDClaims{
Iss: "https://test.issuer",
Sub: "user-123",
Aud: Audience{"test-client"},
Exp: time.Now().Add(-time.Hour).Unix(),
})
if _, err := auth.VerifyToken(context.Background(), expiredToken); err == nil {
t.Fatalf("expected expired token to fail")
}
// Wrong audience
wrongAudToken := mintToken("key-1", IDClaims{
Iss: "https://test.issuer",
Sub: "user-123",
Aud: Audience{"other-client"},
Exp: time.Now().Add(time.Hour).Unix(),
})
if _, err := auth.VerifyToken(context.Background(), wrongAudToken); err == nil {
t.Fatalf("expected wrong audience to fail")
}
// Wrong issuer
wrongIssToken := mintToken("key-1", IDClaims{
Iss: "https://wrong.issuer",
Sub: "user-123",
Aud: Audience{"test-client"},
Exp: time.Now().Add(time.Hour).Unix(),
})
if _, err := auth.VerifyToken(context.Background(), wrongIssToken); err == nil {
t.Fatalf("expected wrong issuer to fail")
}
}
func TestRequireAuthMiddleware(t *testing.T) {
auth := &OidcAuth{
issuer: "https://test.issuer",
client: "test-client",
ingestKey: "secret-key",
agentToken: "agent-secret",
}
handler := auth.RequireAuth(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
}))
// 1. Unauthenticated request -> 401
req := httptest.NewRequest("GET", "/api/history", nil)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusUnauthorized {
t.Fatalf("expected 401 for unauthenticated request, got %d", rec.Code)
}
// 2. Ingest key in header -> 200
reqKey := httptest.NewRequest("GET", "/api/history", nil)
reqKey.Header.Set("X-Otel-Ingest-Key", "secret-key")
recKey := httptest.NewRecorder()
handler.ServeHTTP(recKey, reqKey)
if recKey.Code != http.StatusOK {
t.Fatalf("expected 200 with valid ingest key, got %d", recKey.Code)
}
// 3. Dedicated service token in a header -> 200
reqAgent := httptest.NewRequest("GET", "/api/history", nil)
reqAgent.Header.Set("X-Otel-Agent-Token", "agent-secret")
recAgent := httptest.NewRecorder()
handler.ServeHTTP(recAgent, reqAgent)
if recAgent.Code != http.StatusOK {
t.Fatalf("expected 200 with valid agent token, got %d", recAgent.Code)
}
// 4. X-Auth-User from upstream ingress -> 200
reqAuthUser := httptest.NewRequest("GET", "/api/history", nil)
reqAuthUser.Header.Set("X-Auth-User", "mats@tornberg.me")
recAuthUser := httptest.NewRecorder()
handler.ServeHTTP(recAuthUser, reqAuthUser)
if recAuthUser.Code != http.StatusOK {
t.Fatalf("expected 200 with X-Auth-User, got %d", recAuthUser.Code)
}
}