Conversation
Reject process_type not matching [A-Za-z0-9_-]{1,63} and audience that is blank, over 512 chars, or contains control characters (400). process_type is concatenated into the SPIFFE ID path and every proof-of-possession message field must be newline-free, so this closes SPIFFE-ID injection and PoP message ambiguity. Adds characterization tests pinning existing fail-closed behaviour: malformed PEM, future-dated and malformed-base64 PoP, and a not-yet-valid instance cert.
Comment on lines
+49
to
+59
| SecurityFilterChain chain = http | ||
| .securityMatcher("/jwt-svid/**") | ||
| .authorizeHttpRequests(auth -> { | ||
| auth.requestMatchers("/**").hasAuthority("uaa.resource"); | ||
| auth.anyRequest().denyAll(); | ||
| }) | ||
| .authenticationManager(clientAuthenticationManager) | ||
| .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) | ||
| .addFilterAt(clientAuthenticationFilter.getFilter(), BasicAuthenticationFilter.class) | ||
| .anonymous(AnonymousConfigurer::disable) | ||
| .csrf(CsrfConfigurer::disable) |
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved proof-of-possession, signing, configuration, validation, and documentation issues block approval.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (6)
Prevent timestamp overflow from bypassing proof freshness checks · New Validate null or blank instance certificates before parsing · New Enforce RSA/RS256 keys for JWT-SVID signing · New Document SPIFFE configuration properties and defaults · New Add REST Docs coverage for the JWT-SVID signing endpoint · New Add integration coverage for JWT-SVID endpoint authentication · New
What changed in this PR
Adds an optional UAA SPIFFE JWT-SVID signing endpoint for authenticated Cloud Foundry workloads, including certificate validation, proof-of-possession checks, and JWT issuance.
Changes:
- Adds protected
/jwt-svid/signrequest and response handling. - Adds SPIFFE configuration, security, identity parsing, and certificate verification.
- Adds proof-of-possession validation and JWT-SVID signing.
- Adds focused unit tests and certificate fixtures.
| File | Description |
|---|---|
server/src/test/java/org/cloudfoundry/identity/uaa/spiffe/SpiffeTestCerts.java |
Provides test certificates and keys. |
server/src/test/java/org/cloudfoundry/identity/uaa/spiffe/SpiffePropertiesTests.java |
Tests configuration defaults. |
server/src/test/java/org/cloudfoundry/identity/uaa/spiffe/SpiffeIdTests.java |
Tests SPIFFE ID formatting. |
server/src/test/java/org/cloudfoundry/identity/uaa/spiffe/SpiffeConfigurationTests.java |
Tests CA parsing. |
server/src/test/java/org/cloudfoundry/identity/uaa/spiffe/ProofOfPossessionVerifierTests.java |
Tests proof-of-possession validation. |
server/src/test/java/org/cloudfoundry/identity/uaa/spiffe/JwtSvidSignerTests.java |
Tests JWT-SVID signing. |
server/src/test/java/org/cloudfoundry/identity/uaa/spiffe/JwtSvidControllerTests.java |
Tests endpoint behavior and validation. |
server/src/test/java/org/cloudfoundry/identity/uaa/spiffe/InstanceIdentityVerifierTests.java |
Tests certificate trust and validity. |
server/src/test/java/org/cloudfoundry/identity/uaa/spiffe/CertificateOuParserTests.java |
Tests certificate OU extraction. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/SpiffeSecurityConfiguration.java |
Protects the signing endpoint. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/SpiffeProperties.java |
Defines SPIFFE configuration. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/SpiffeId.java |
Formats workload SPIFFE IDs. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/SpiffeConfiguration.java |
Parses the configured CA. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/ProofOfPossessionVerifier.java |
Verifies proof-of-possession signatures. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/JwtSvidSigner.java |
Creates signed JWT-SVIDs. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/JwtSvidResponse.java |
Defines signing responses. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/JwtSvidRequest.java |
Defines signing requests. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/JwtSvidController.java |
Implements the signing endpoint. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/InstanceIdentityVerifier.java |
Validates instance certificates. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/CfInstanceIdentity.java |
Stores Cloud Foundry identity attributes. |
server/src/main/java/org/cloudfoundry/identity/uaa/spiffe/CertificateOuParser.java |
Extracts identity values from certificate OUs. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+30
to
+32
| if (Math.abs(Instant.now().getEpochSecond() - timestamp) > properties.popFreshnessSeconds()) { | ||
| return false; | ||
| } |
Comment on lines
+77
to
+90
| private static void validateRequest(JwtSvidRequest request) { | ||
| String processType = request.processType(); | ||
| if (processType == null || !PROCESS_TYPE_PATTERN.matcher(processType).matches()) { | ||
| throw new BadSvidRequestException("process_type must match [A-Za-z0-9_-]{1,63}"); | ||
| } | ||
| String audience = request.audience(); | ||
| if (audience == null || audience.isBlank() | ||
| || audience.length() > MAX_AUDIENCE_LENGTH | ||
| || containsControlCharacter(audience)) { | ||
| throw new BadSvidRequestException( | ||
| "audience must be non-blank, at most " + MAX_AUDIENCE_LENGTH | ||
| + " characters, and free of control characters"); | ||
| } | ||
| } |
Comment on lines
+63
to
+64
| KeyInfo activeKey = keyInfoService.getActiveKey(); | ||
| String svid = JwtHelper.encode(claims, activeKey).getEncoded(); |
Comment on lines
+9
to
+10
| @ConfigurationProperties(prefix = "uaa.spiffe") | ||
| public record SpiffeProperties( |
| this.properties = properties; | ||
| } | ||
|
|
||
| @PostMapping(value = "/jwt-svid/sign", consumes = "application/json", produces = "application/json") |
Comment on lines
+50
to
+54
| .securityMatcher("/jwt-svid/**") | ||
| .authorizeHttpRequests(auth -> { | ||
| auth.requestMatchers("/**").hasAuthority("uaa.resource"); | ||
| auth.anyRequest().denyAll(); | ||
| }) |
Member
This branch has not been deployed
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
Adds a JWT-SVID signing endpoint to UAA so it can act as a SPIFFE identity
server for Cloud Foundry workloads (offline-OIDC federation).
POST /jwt-svid/signauthenticates a SPIFFE Agent (client credentials), verifiesthe caller's CF instance-identity certificate against the configured CA,
parses org/space/app GUIDs from the cert OUs, checks a proof-of-possession
signature for freshness, and mints an RS256 JWT-SVID signed with UAA's active key
and OIDC issuer (so it verifies offline against
/token_keys).Key changes (all under
org.cloudfoundry.identity.uaa.spiffe)JwtSvidController,JwtSvidRequest/JwtSvidResponse,JwtSvidSignerInstanceIdentityVerifier,CertificateOuParser,ProofOfPossessionVerifierSpiffeId,CfInstanceIdentity,SpiffeProperties,SpiffeConfiguration,SpiffeSecurityConfigurationContext
Part of RFC UAA-SPIFFE-001 — UAA as a SPIFFE Identity Server for Cloud Foundry.
Cross-repo dependencies
spiffe-signer— exposesuaa.spiffe.*(trustdomain, instance-identity CA) and the signer client.
spiffe-agent.Status
Draft / POC. End-to-end verified on bosh-lite: a CF app received a valid JWT-SVID
with
cforg/space/app/process_type claims.