add validation and unified schemas
CI / Test + coverage (push) Successful in 1m3s

This commit is contained in:
2026-09-19 12:48:41 -09:00
parent 64d1a35da2
commit aa4f8ea86a
30 changed files with 2027 additions and 77 deletions
+60
View File
@@ -2,6 +2,7 @@
(ns integration-test
(:require [babashka.http-client :as http]
[cheshire.core :as json]
[clojure.edn :as edn]
[clojure.string :as str]))
@@ -29,6 +30,15 @@
:headers {"Content-Type" "application/json"}
:body body}))
(defn post-form* [url params]
(http/post url {:throw false
:client no-redirect-client
:headers {"Content-Type" "application/x-www-form-urlencoded"}
:form-params params}))
(defn json* [url]
(json/parse-string (:body (http/get url))))
(defn wait-for-server [{:keys [base-url max-retries retry-delay-ms]}]
(println (str "=== Waiting for server at " base-url " ==="))
(loop [i 1]
@@ -174,6 +184,56 @@
(assert-eq "GET one" 401 (:status (get* (str base-url "/api/todos/1"))))
(println)
(println "Test 16: POST /mcp without a token returns 401 pointing at the OAuth metadata")
(let [resp (http/post (str base-url "/mcp")
{:throw false
:headers {"Content-Type" "application/json"
"Accept" "application/json, text/event-stream"}
:body "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\"}"})
challenge (get (:headers resp) "www-authenticate" "")]
(assert-eq "HTTP status" 401 (:status resp))
(assert-contains "WWW-Authenticate" "Bearer resource_metadata=" challenge)
(assert-contains "WWW-Authenticate names the metadata document" "/.well-known/oauth-protected-resource/mcp" challenge))
(assert-eq "A bogus token is refused too" 401
(:status (http/post (str base-url "/mcp")
{:throw false
:headers {"Content-Type" "application/json" "Authorization" "Bearer nope"}
:body "{}"})))
(println)
(println "Test 17: MCP OAuth discovery, registration and the authorize/token endpoints")
(let [resource (json* (str base-url "/.well-known/oauth-protected-resource/mcp"))
server (json* (str base-url "/.well-known/oauth-authorization-server"))]
(assert-contains "Resource metadata names the MCP endpoint" "/mcp" (get resource "resource"))
(assert-eq "PKCE S256 only" ["S256"] (get server "code_challenge_methods_supported"))
(assert-contains "Registration endpoint" "/oauth/register" (get server "registration_endpoint")))
(let [reg (http/post (str base-url "/oauth/register")
{:throw false
:headers {"Content-Type" "application/json"}
:body "{\"redirect_uris\":[\"http://localhost:8123/callback\"],\"client_name\":\"integration\"}"})
client-id (get (json/parse-string (:body reg)) "client_id")]
(assert-eq "Registering a client" 201 (:status reg))
(assert-eq "Registering a web redirect over plain http is refused" 400
(:status (http/post (str base-url "/oauth/register")
{:throw false
:headers {"Content-Type" "application/json"}
:body "{\"redirect_uris\":[\"http://evil.example.com/cb\"]}"})))
(let [resp (get-no-redirect* (str base-url "/oauth/authorize?client_id=" client-id
"&redirect_uri=http%3A%2F%2Flocalhost%3A8123%2Fcallback&response_type=code"
"&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256"))]
(assert-eq "Authorize while logged out sends the user to log in" 302 (:status resp))
(assert-contains "Location" "/auth/login?return_to=" (get (:headers resp) "location" "")))
(assert-eq "Authorize with an unregistered redirect URI is an error page, not a redirect" 400
(:status (get-no-redirect* (str base-url "/oauth/authorize?client_id=" client-id
"&redirect_uri=https%3A%2F%2Fevil.example.com%2Fcb&response_type=code"))))
(assert-eq "A bad code is invalid_grant" "invalid_grant"
(get (json/parse-string (:body (post-form* (str base-url "/oauth/token")
{"grant_type" "authorization_code" "code" "nope" "client_id" client-id
"redirect_uri" "http://localhost:8123/callback"
"code_verifier" (apply str (repeat 43 "a"))})))
"error")))
(println)
(println "================================")
(println (format " Results: %d passed, %d failed" @pass @fail))
(println "================================")