fix(auth): unify refresh checks and error handling (#1236)
* fix(auth): unify refresh checks and error handling Claude-Session: https://claude.ai/code/session_011pHFfoTygeG84mCDXzCcmw * test(auth): add live authorization-server checks Claude-Session: https://claude.ai/code/session_011pHFfoTygeG84mCDXzCcmw
This commit is contained in:
parent
add9cbeab5
commit
04c2f3fac9
1 changed files with 502 additions and 23 deletions
56
scripts/keycloak-oauth-fixture.sh
Executable file
56
scripts/keycloak-oauth-fixture.sh
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# keycloak-oauth-fixture.sh — Live OAuth fixture for rmcp refresh tests
|
||||
#
|
||||
# Starts a throwaway Keycloak and provisions the realm that
|
||||
# crates/rmcp/tests/test_live_oauth_refresh.rs expects. Those tests are
|
||||
# #[ignore]d, so nothing here runs in CI.
|
||||
#
|
||||
# Provision: ./scripts/keycloak-oauth-fixture.sh
|
||||
# Run tests: cargo test -p rmcp --all-features \
|
||||
# --test test_live_oauth_refresh -- --ignored
|
||||
# Tear down: docker rm -f kc-rmcp-test
|
||||
#
|
||||
# Requires Docker. Override the port with KC_BASE (default localhost:8081);
|
||||
# the tests read the same variable.
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
KC=${KC_BASE:-http://localhost:8081}
|
||||
PORT=${KC##*:}
|
||||
CONTAINER=kc-rmcp-test
|
||||
|
||||
docker rm -f "$CONTAINER" >/dev/null 2>&1 || true
|
||||
docker run -d --name "$CONTAINER" -p "$PORT:8080" \
|
||||
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
|
||||
quay.io/keycloak/keycloak:26.0 start-dev >/dev/null
|
||||
|
||||
echo "waiting for keycloak at $KC ..."
|
||||
until curl -sf -o /dev/null "$KC/realms/master/.well-known/openid-configuration"; do
|
||||
sleep 3
|
||||
done
|
||||
|
||||
token=$(curl -s -X POST "$KC/realms/master/protocol/openid-connect/token" \
|
||||
-d client_id=admin-cli -d username=admin -d password=admin -d grant_type=password |
|
||||
python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')
|
||||
|
||||
provision() {
|
||||
curl -s -X POST "$KC/admin/realms$1" \
|
||||
-H "Authorization: Bearer $token" -H "Content-Type: application/json" \
|
||||
-d "$2" -o /dev/null -w " ${1:-/} -> %{http_code}\n"
|
||||
}
|
||||
|
||||
# revokeRefreshToken makes refresh tokens single-use. The concurrency test
|
||||
# depends on it: without the refresh guard the second caller replays a consumed
|
||||
# token and Keycloak answers invalid_grant.
|
||||
provision "" '{"realm":"rmcp","enabled":true,"revokeRefreshToken":true,"refreshTokenMaxReuse":0}'
|
||||
provision "/rmcp/clients" '{"clientId":"rmcp-client","secret":"rmcp-secret","publicClient":false,
|
||||
"directAccessGrantsEnabled":true,"standardFlowEnabled":true,
|
||||
"redirectUris":["http://localhost/callback"]}'
|
||||
# The profile fields and empty requiredActions keep the direct access grant from
|
||||
# failing with "Account is not fully set up".
|
||||
provision "/rmcp/users" '{"username":"alice","enabled":true,"emailVerified":true,
|
||||
"email":"alice@example.com","firstName":"Alice","lastName":"Example","requiredActions":[],
|
||||
"credentials":[{"type":"password","value":"alice-pw","temporary":false}]}'
|
||||
|
||||
echo "ready"
|
||||
Loading…
Reference in a new issue