Repository navigation
feat(local): one-command local manual-test kit for AS, DC and TP (#254) - #259
Merged
Merged
Conversation
The data_custodian_admin, third_party, third_party_admin and datacustodian clients are development fixtures. They are now seeded only when espi.authserver.seed.demo-clients=true, which the local, dev-mysql, dev-postgresql and testcontainers profiles set. Other profiles start with none of them, matching the production onboarding model: Third Parties register through RFC 7591. - datacustodian (introspection) and data_custodian_admin can instead be provisioned from ESPI_DATACUSTODIAN_CLIENT_SECRET and ESPI_DATACUSTODIAN_ADMIN_CLIENT_SECRET, stored hashed. - With demo seeding off, an existing demo row that still accepts its development secret gets a random secret at startup. - DEPLOYMENT_GUIDE lists the new settings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dev-mysql is the default profile in application.yml, so a deployment that does not set SPRING_PROFILES_ACTIVE would run with demo seeding on. Startup now fails when espi.authserver.seed.demo-clients=true and the issuer host is not localhost, 127.0.0.1 or ::1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…251) Spring Authorization Server only checks that a requested scope is registered for the client, whatever the grant. ESPI keeps customer data and administrative tokens apart, so: - client_credentials cannot be granted an ESPI customer data scope (any FB=... other than the FB=36_40 registration-token renewal scope); - authorization_code cannot be granted an administrative scope (ThirdParty_Admin_Access, DataCustodian_Admin_Access, FB=36_40, authserver.admin, client.create). The client receives invalid_scope at its redirect URI, as Spring does for its own scope check. EspiGrantScopePolicy runs after Spring's default validators on the token and authorization endpoints. Tested with unit tests and a Docker-backed SecurityIntegrationTest case using a client registered for both grants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Data Custodian parses scopes tolerantly (any segment order, trimmed, case-insensitive FB key), so a prefix check on "FB=" could be bypassed with a different spelling, and Upload_Admin_Access was missing from the administrative list. Both rules now fail closed: - client_credentials: only the exact administrative scope strings, including Upload_Admin_Access; - authorization_code: only openid/profile, or a scope that parses like EspiScope to Function Blocks other than the reserved 36 and 40. Unparseable or unknown scopes are rejected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…scripts (#254) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…scripts (#254) - scripts/local/start-all.ps1, stop-all.ps1, smoke.ps1 alongside the Bash versions; both smoke checks pass 25/25 against a fresh start. - docs/LOCAL_TESTING.md: start/check/stop, URLs, logins, the seeded OAuth clients, curl recipes (tokens, introspection, feeds, actuator, RFC 7591 registration), captured ESPI XML, and the open blockers. - .gitattributes keeps *.sh at LF so they run on Windows checkouts. - .local-run/ (script logs) is git-ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… introspection test The GHSA-mh65 test minted a client_credentials token for the placeholder scope FB_1, which the per-grant allowlist now rejects. It requests ThirdParty_Admin_Access instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rant Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #254. One command starts the AS, DC and TP on the
localprofile; one command checks them; a runbook lists every URL, login, client andcurlrecipe.Changes
AS
third_partydemo client: alsoclient_credentials+ThirdParty_Admin_Access, which is the ESPI client access token for the Authorization (and later Bulk, DC: implement ESPI Batch/Bulk API — Third Party client access token only, scoped to its own Authorizations #256) APIs. fix(authserver): restrict each OAuth grant to its own kind of scope (#251) #258 makes sure customer FB scopes can't be obtained that way.espi.authserver.seed.third-party.redirect-uris; the default is unchanged).locallists the TP's real Spring OAuth2 callbacks (:8082/ThirdParty/login/oauth2/code/datacustodian-{monthly,daily}).application-local.yml(DEV ONLY), all overridable by environment variables:admin/admin(bcrypt hash; a passkey is still enrolled at first login);espi_adminandespi_registrardev secrets.SecurityIntegrationTest: the "client not registered for the grant" case uses the per-test authorization_code-only client instead ofthird_party.TP
application-local.yml: the registrations match the AS seed.tp-secreteverywhere.openid/profileare dropped.datacustodian-adminbecomesclient_credentialswithThirdParty_Admin_Access.Scripts in
scripts/local/, Bash and PowerShell versions:start-allbuilds once, starts all three apps, waits for/actuator/healthand prints the URLs; logs go to.local-run/.stop-allstops the apps by port.smokemakes 25 checks: health; four client_credentials tokens;client_credentialsrefused for an FB scope; introspection; all ten DC feeds; the Authorization feed with the TP client access token; 401 without a token; admin actuator on each app.Docs and repo
docs/LOCAL_TESTING.mdis the runbook..gitattributeskeeps*.shat LF..local-run/is git-ignored.Verification (this branch, Windows 11)
scripts/local/stop-all.shstopped the running apps;start-all.sh(with build) brought all three up healthysmoke.sh: 25 passed, 0 failed;smoke.ps1: 25 passed, 0 failedoauth2/authorization/datacustodian-monthly→ AS/oauth2/authorizeaccepted (redirect URI and scope valid) → 302 to/authorize/delegate, which is where AS: unauthenticated /oauth2/authorize redirects to /authorize/delegate without parameters (400); outbound delegation to DC is broken #232 stops the flow todayNot in this PR
These are listed under "Known limitations" in the runbook.
🤖 Generated with Claude Code