Files
CosmicClash/server/workload/jwt_test.go
T
2026-09-01 09:57:33 +01:00

67 lines
2.8 KiB
Go

package workload
import (
"encoding/base64"
"encoding/json"
"strings"
"testing"
"time"
"github.com/cosmic-clash/cosmic-clash/server/domain"
)
func binding() domain.WorkloadBinding {
return domain.WorkloadBinding{Issuer: "https://issuer", Audience: "cosmic-result", Namespace: "games", ServiceAcct: "match-server", PodUID: "pod-1", GameServerUID: "gs-1", AllocationID: "allocation-1", MatchID: "match-1", ServerID: "server-1"}
}
func tokenFor(t *testing.T, alg string, claims map[string]any) string {
t.Helper()
header, _ := json.Marshal(map[string]string{"alg": alg, "typ": "JWT"})
payload, _ := json.Marshal(claims)
encode := func(value []byte) string { return base64.RawURLEncoding.EncodeToString(value) }
return encode(header) + "." + encode(payload) + "." + encode([]byte("signature"))
}
func validClaims() map[string]any {
return map[string]any{"iss": "https://issuer", "aud": "cosmic-result", "iat": float64(999), "exp": float64(1001), "namespace": "games", "service_account": "match-server", "pod_uid": "pod-1", "gameserver_uid": "gs-1", "allocation_id": "allocation-1", "match_id": "match-1", "server_id": "server-1"}
}
func TestParseAndValidateVerifiesJWTBeforeReturningBinding(t *testing.T) {
token := tokenFor(t, "RS256", validClaims())
wantSigning := strings.Join(strings.Split(token, ".")[:2], ".")
got, err := ParseAndValidate(token, binding(), func(signingInput, signature []byte) bool {
return string(signingInput) == wantSigning && string(signature) == "signature"
}, time.Unix(1000, 0))
if err != nil || got != binding() {
t.Fatalf("binding=%+v err=%v", got, err)
}
}
func TestParseAndValidateRejectsUnsignedMalformedAndMutatedTokens(t *testing.T) {
cases := []string{tokenFor(t, "none", validClaims()), tokenFor(t, "RS256", validClaims())[:10], tokenFor(t, "RS256", validClaims())}
for i, token := range cases {
_, err := ParseAndValidate(token, binding(), func([]byte, []byte) bool { return i != 2 }, time.Unix(1000, 0))
if err == nil {
t.Fatalf("case %d accepted", i)
}
}
claims := validClaims()
claims["server_id"] = "other"
if _, err := ParseAndValidate(tokenFor(t, "RS256", claims), binding(), func([]byte, []byte) bool { return true }, time.Unix(1000, 0)); err == nil {
t.Fatal("mutated binding accepted")
}
}
func TestParseAndValidateRejectsBoundaryExpiryAndMultiAudience(t *testing.T) {
claims := validClaims()
claims["exp"] = float64(1000)
if _, err := ParseAndValidate(tokenFor(t, "RS256", claims), binding(), func([]byte, []byte) bool { return true }, time.Unix(1000, 0)); err == nil {
t.Fatal("expiry boundary accepted")
}
claims = validClaims()
claims["aud"] = []string{"other", "cosmic-result"}
if _, err := ParseAndValidate(tokenFor(t, "RS256", claims), binding(), func([]byte, []byte) bool { return true }, time.Unix(1000, 0)); err == nil {
t.Fatal("ambiguous audience accepted")
}
}