chore: establish local platform baseline
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
package identity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
josejwt "github.com/go-jose/go-jose/v4/jwt"
|
||||
)
|
||||
|
||||
func TestOIDCVerifierAcceptsSignedToken(t *testing.T) {
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
keyID := "test-key"
|
||||
webKey := jose.JSONWebKey{Key: &privateKey.PublicKey, KeyID: keyID, Algorithm: string(jose.RS256), Use: "sig"}
|
||||
keySet := jose.JSONWebKeySet{Keys: []jose.JSONWebKey{webKey}}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
|
||||
writer.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(writer).Encode(keySet)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
issuer := "https://identity.example.test/realms/test"
|
||||
audience := "voice-platform-web"
|
||||
rawToken := signTestToken(t, privateKey, keyID, issuer, audience)
|
||||
verifier := NewOIDCVerifier(context.Background(), issuer, server.URL, audience)
|
||||
principal, err := verifier.Verify(context.Background(), rawToken)
|
||||
if err != nil {
|
||||
t.Fatalf("verify token: %v", err)
|
||||
}
|
||||
if principal.Issuer != issuer || principal.Subject != "user-123" || principal.PreferredUsername != "tester" {
|
||||
t.Fatalf("unexpected principal: %#v", principal)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOIDCVerifierRejectsEmptyAndWrongAudience(t *testing.T) {
|
||||
verifier := &OIDCVerifier{}
|
||||
if _, err := verifier.Verify(context.Background(), ""); err != ErrInvalidToken {
|
||||
t.Fatalf("empty token error = %v", err)
|
||||
}
|
||||
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
keyID := "test-key"
|
||||
keySet := jose.JSONWebKeySet{Keys: []jose.JSONWebKey{{
|
||||
Key: &privateKey.PublicKey, KeyID: keyID, Algorithm: string(jose.RS256), Use: "sig",
|
||||
}}}
|
||||
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
|
||||
_ = json.NewEncoder(writer).Encode(keySet)
|
||||
}))
|
||||
defer server.Close()
|
||||
issuer := "https://identity.example.test/realms/test"
|
||||
verifier = NewOIDCVerifier(context.Background(), issuer, server.URL, "expected-audience")
|
||||
if _, err := verifier.Verify(context.Background(), signTestToken(t, privateKey, keyID, issuer, "wrong-audience")); err != ErrInvalidToken {
|
||||
t.Fatalf("wrong audience error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func signTestToken(t *testing.T, key *rsa.PrivateKey, keyID, issuer, audience string) string {
|
||||
t.Helper()
|
||||
options := (&jose.SignerOptions{}).WithType("JWT").WithHeader("kid", keyID)
|
||||
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.RS256, Key: key}, options)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rawToken, err := josejwt.Signed(signer).
|
||||
Claims(josejwt.Claims{
|
||||
Issuer: issuer, Subject: "user-123", Audience: josejwt.Audience{audience},
|
||||
Expiry: josejwt.NewNumericDate(time.Now().Add(time.Minute)),
|
||||
IssuedAt: josejwt.NewNumericDate(time.Now()),
|
||||
}).
|
||||
Claims(map[string]any{"name": "测试用户", "preferred_username": "tester"}).
|
||||
Serialize()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return rawToken
|
||||
}
|
||||
Reference in New Issue
Block a user