feat: enforce OIDC session introspection
This commit is contained in:
@@ -104,6 +104,55 @@ func TestOIDCVerifierRejectsMissingOrMismatchedSecurityClaims(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOIDCVerifierFailsClosedWhenIntrospectionMarksSessionInactive(t *testing.T) {
|
||||
key, _ := rsa.GenerateKey(rand.Reader, 2048)
|
||||
active := true
|
||||
var issuer string
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
|
||||
switch request.URL.Path {
|
||||
case "/.well-known/openid-configuration":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"issuer": issuer, "jwks_uri": issuer + "/jwks",
|
||||
"introspection_endpoint": issuer + "/introspect",
|
||||
})
|
||||
case "/jwks":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"keys": []any{rsaJWK("rsa-key", &key.PublicKey)}})
|
||||
case "/introspect":
|
||||
clientID, clientSecret, ok := request.BasicAuth()
|
||||
if !ok || clientID != "gateway-api" || clientSecret != "introspection-secret" {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
if err := request.ParseForm(); err != nil || request.Form.Get("token") == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"active": active})
|
||||
default:
|
||||
http.NotFound(w, request)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
issuer = server.URL
|
||||
verifier, err := NewOIDCVerifier(OIDCConfig{
|
||||
Issuer: issuer, Audience: "gateway-api", TenantID: "tenant-1", RolePrefix: "gateway.",
|
||||
RequiredScopes: []string{"gateway.access"}, HTTPClient: server.Client(),
|
||||
IntrospectionEnabled: true, IntrospectionClientID: "gateway-api",
|
||||
IntrospectionClientSecret: "introspection-secret",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
raw := signedOIDCToken(t, issuer, "rsa-key", jwt.SigningMethodRS256, key, nil)
|
||||
if _, err := verifier.Verify(context.Background(), raw); err != nil {
|
||||
t.Fatalf("active token rejected: %v", err)
|
||||
}
|
||||
active = false
|
||||
if _, err := verifier.Verify(context.Background(), raw); err == nil {
|
||||
t.Fatal("inactive token was accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func signedOIDCToken(t *testing.T, issuer, kid string, method jwt.SigningMethod, key any, mutate func(jwt.MapClaims)) string {
|
||||
t.Helper()
|
||||
now := time.Now()
|
||||
|
||||
Reference in New Issue
Block a user