feat(security-006): split SecurityFilterChain into isolated API-key and JWT chains#12
Merged
hendrikebbers merged 4 commits intomainfrom Apr 28, 2026
Merged
Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nd JWT chains Replace the single SecurityFilterChain that mixed API-key and JWT authentication with two strictly isolated chains: - externalApiFilterChain (@order(1)) scoped to /api/external/**: API-key authentication only; GET/HEAD/OPTIONS allowed via declarative authorizeHttpRequests; all other methods denied at the chain level. - defaultFilterChain (@order(2)) for everything else: JWT/OAuth2 only; X-API-Key header silently ignored. Health and Swagger remain public. ApiKeyAuthenticationFilter is no longer @component (would auto-register on every chain) and no longer enforces HTTP-method authorization — that responsibility moved to the chain configuration. The filter is now constructed via @bean and only added to chain 1 via addFilterBefore. AuthService.getUserInformation() returns UserInformation("UNKNOWN", "UNKNOWN", null, null) for non-JWT principals instead of throwing, so audit logging and similar callers work in API-key contexts. Tracked as a TODO to associate user identity with API keys in a follow-up. Includes tests covering the simplified filter behavior, the new UNKNOWN user fallback in AuthService, and updated SecurityConfigRoleTest constructor signature. Spec: specs/006-split-security-filter-chains/ Closes #11 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…chain documentation
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
Replace the single
SecurityFilterChainthat mixed API-key and JWT authentication with two strictly isolated chains:externalApiFilterChain(@Order(1), scoped to/api/external/**): API-key authentication only. Read-only HTTP methods (GET/HEAD/OPTIONS) are authorized declaratively at the chain level; all other methods are rejected with403 Forbidden. JWT bearer tokens are not evaluated.defaultFilterChain(@Order(2), all other paths): JWT/OAuth2 only. TheX-API-Keyheader is silently ignored. Health and Swagger endpoints remain public.The split makes the security model explicit, enables independent policies per chain, and prepares the library to host its own read-only controllers under
/api/external/.Spec
specs/006-split-security-filter-chains/specs/006-split-security-filter-chains/design.mdspecs/006-split-security-filter-chains/behaviors.mdChanges
SecurityConfignow contributes twoSecurityFilterChainbeans plus anApiKeyAuthenticationFilter@Beanconstructed fromApiKeyDataService.ApiKeyAuthenticationFilterno longer carries@Component(would auto-register on every chain) and no longer enforces HTTP-method authorization. It is a pure authentication adapter — chain-levelauthorizeHttpRequestsenforces read-only access.AuthService.getUserInformation()returnsUserInformation("UNKNOWN", "UNKNOWN", null, null)for non-JWT principals (e.g., API-key requests) instead of throwing, so audit logging and similar callers work in API-key contexts.package-info.javadocumentation updated for the two-chain model.TODO.mdrecords the follow-up to associate user identity with API keys.Test coverage
AuthServiceTestcovers JWT principal happy path, blank-subject error, and the newUNKNOWNuser fallback for API-key and string principals.SecurityConfigRoleTestupdated for the new constructor signature (now takesApiKeyDataService).main— unrelated to this PR.Closes #11
🤖 Generated with Claude Code