Three modules on Spring Boot 4.1.1 with Spring Authorization Server 7.1.1: the provider
itself, a relying party, and an API that trusts its tokens. Client registration, PKCE,
a custom consent page and token customisation, with profiles that make each failure
reproducible.
Every claim is backed by captured output in docs/output/as-*.txt, regenerated by
authorization-server/scripts/run-all.sh. Notable findings, verified against the jars:
- OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(HttpSecurity) was deleted
in 7.0, and both configuration classes moved into spring-security-config
- ClientSettings.requireProofKey flipped from false to true, on the authorization server
(1.5.8 -> 7.1.1) and on the OAuth2 client (6.5.1 -> 7.1.1)
- requireProofKey(false) does not make PKCE optional for a public client; the code
verifier is that client's only authentication at the token endpoint
- MediaTypeRequestMatcher(TEXT_HTML) matches Accept: */*, so the token endpoint answers
API callers with 302 -> /login unless setIgnoredMediaTypes(ALL) is called
Also renames the repository to spring-auth-demo and cross-links the new chapter set from
the existing documentation.
64 lines
2.6 KiB
Bash
Executable File
64 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# The simplest grant, and what the token customiser does and does not add to it.
|
|
set -u
|
|
cd "$(dirname "$0")/.."
|
|
. scripts/lib.sh
|
|
OUT="../docs/output/${1:-as-client-credentials}.txt"
|
|
mkdir -p ../docs/output
|
|
{
|
|
section "POST /oauth2/token grant_type=client_credentials"
|
|
echo "\$ curl -su demo-service:service-secret -d grant_type=client_credentials \\"
|
|
echo " -d scope=orders.read $AS/oauth2/token"
|
|
RESP=$(curl -s -u demo-service:service-secret \
|
|
-d grant_type=client_credentials -d scope=orders.read \
|
|
"$AS/oauth2/token")
|
|
echo "$RESP" | python3 -m json.tool
|
|
|
|
TOKEN=$(echo "$RESP" | python3 -c 'import sys,json;print(json.load(sys.stdin).get("access_token",""))')
|
|
if [ -z "$TOKEN" ]; then echo "no access token - stopping"; exit 1; fi
|
|
|
|
case "$TOKEN" in
|
|
*.*.*)
|
|
section "JOSE header"
|
|
jwt_header "$TOKEN"
|
|
section "Claims"
|
|
jwt_payload "$TOKEN"
|
|
;;
|
|
*)
|
|
section "Not a JWT"
|
|
echo "The access token is an opaque reference: $TOKEN"
|
|
echo "Length ${#TOKEN}. It carries no claims; the resource server must introspect it."
|
|
section "POST /oauth2/introspect"
|
|
curl -s -u demo-service:service-secret -d "token=$TOKEN" \
|
|
"$AS/oauth2/introspect" | python3 -m json.tool
|
|
;;
|
|
esac
|
|
|
|
section "Wrong secret"
|
|
echo "\$ curl -si -u demo-service:WRONG -d grant_type=client_credentials $AS/oauth2/token"
|
|
curl -s -i -u demo-service:WRONG -d grant_type=client_credentials \
|
|
"$AS/oauth2/token" | sed -n '1p;/^WWW-Authenticate/p;/^{/p'
|
|
|
|
section "A grant the client is not registered for"
|
|
echo "\$ curl -si -u demo-service:service-secret -d grant_type=authorization_code -d code=x $AS/oauth2/token"
|
|
curl -s -i -u demo-service:service-secret -d grant_type=authorization_code -d code=x \
|
|
"$AS/oauth2/token" | sed -n '1p;/^{/p'
|
|
|
|
section "A scope the client is not registered for"
|
|
echo "\$ curl -s -u demo-service:service-secret -d grant_type=client_credentials -d scope=orders.write $AS/oauth2/token"
|
|
curl -s -u demo-service:service-secret -d grant_type=client_credentials -d scope=orders.write \
|
|
"$AS/oauth2/token"
|
|
echo
|
|
|
|
section "Calling the resource server with the token"
|
|
for path in /public /api/orders /api/admin; do
|
|
CODE=$(curl -s -o /tmp/rsbody -w '%{http_code}' -H "Authorization: Bearer $TOKEN" "$RS$path")
|
|
WWW=$(curl -s -D - -o /dev/null -H "Authorization: Bearer $TOKEN" "$RS$path" | grep -i '^WWW-Authenticate' || true)
|
|
echo "GET $path -> $CODE"
|
|
[ -n "$WWW" ] && echo " $WWW"
|
|
head -c 400 /tmp/rsbody; echo
|
|
done
|
|
} > "$OUT" 2>&1
|
|
sed -i 's/[[:space:]]*$//' "$OUT"
|
|
echo "wrote $OUT"
|