Skip to content

Fix: unreachable bootstrap SAML IDP metadata crashes UAA startup#3974

Merged
duanemay merged 4 commits into
developfrom
saml-bootstrap-idp-startup-resilience
Jul 8, 2026
Merged

Fix: unreachable bootstrap SAML IDP metadata crashes UAA startup#3974
duanemay merged 4 commits into
developfrom
saml-bootstrap-idp-startup-resilience

Conversation

@duanemay

@duanemay duanemay commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary

Follow-up to #3971. That PR made SamlRelyingPartyRegistrationRepositoryConfig's bootstrap-YAML SAML IDP loop resolve each provider's metadata via SamlIdentityProviderConfigurator.resolveMetadataXml(), which performs a live HTTP(S) fetch. That call happens while building the RelyingPartyRegistrationBuilder.Params object -- outside the try block that only wraps buildRelyingPartyRegistration(params) -- and it can throw RestClientException (DNS/connect failures) rather than the Saml2Exception the existing catch clause was written for.

Net effect: a bootstrap SAML IDP with a momentarily (or permanently) unreachable metadata URL -- previously logged as an error and skipped, per this loop's own documented intent ("some SAML IDPs might require you to supply the SAML SP metadata first before you can get the SAML IDP metadata") -- now crashes the entire Spring context and prevents UAA from starting.

Reproduced locally via scripts/saml/saml-legacy-uaa.yml's simple.saml.invalid provider, which is deliberately configured with an unreachable metadata URL (http://simplesamlphp.cfapps.io/..., a long-decommissioned Pivotal Web Services demo host) specifically to exercise this "tolerate an unreachable bootstrap IDP" path:

Caused by: java.net.UnknownHostException: simplesamlphp.cfapps.io
...
Factory method 'relyingPartyRegistrationRepository' threw exception with message:
I/O error on GET request for "http://simplesamlphp.cfapps.io:80/saml2/idp/metadata.php"

Change

  • Move the per-provider metadata resolution inside the existing try block in SamlRelyingPartyRegistrationRepositoryConfig.relyingPartyRegistrationRepository().
  • Broaden the catch from Saml2Exception to Exception, since the failure surface now includes RestClientException from the live fetch, in addition to Saml2Exception from buildRelyingPartyRegistration() itself.
  • This restores the pre-Fix: skipSslValidation ignored when fetching SAML IDP metadata during login  #3971 guarantee that a single bad/unreachable bootstrap IDP is logged and skipped rather than taking down UAA startup.

Test plan

  • Added relyingPartyRegistrationRepositoryToleratesUnreachableBootstrapIdpMetadata to SamlRelyingPartyRegistrationRepositoryConfigTest, asserting the bean still builds successfully when a bootstrap IDP's metadata resolution throws ResourceAccessException.
  • Confirmed the new test fails against develop's current HEAD (reproducing the crash) and passes with this fix.
  • Full org.cloudfoundry.identity.uaa.provider.saml.* package: 269/269 passing.

#3971 made SamlRelyingPartyRegistrationRepositoryConfig resolve each
bootstrap-YAML SAML IDP's metadata via
SamlIdentityProviderConfigurator.resolveMetadataXml(), which performs a
live HTTP(S) fetch. That call happened while building the
RelyingPartyRegistrationBuilder.Params object, outside the try block that
only wrapped buildRelyingPartyRegistration(params), and it can throw
RestClientException (DNS/connect failures) rather than the Saml2Exception
the catch clause was written for. An unreachable bootstrap IDP metadata
URL -- previously logged as an error and skipped, matching this loop's
own documented intent ("some SAML IDPs might require you to supply the
SAML SP metadata first before you can get the SAML IDP metadata") -- now
takes down the entire Spring context and prevents UAA from starting.

Move the resolution inside the try block and broaden the catch to
Exception, so a single bad/unreachable bootstrap IDP is logged and
skipped instead of crashing startup, restoring the pre-#3971 resilience
guarantee. Verified against scripts/saml/saml-legacy-uaa.yml's
'simple.saml.invalid' provider, which is deliberately configured with an
unreachable metadata URL to exercise exactly this path.

Add a regression test asserting relyingPartyRegistrationRepository()
still returns successfully when a bootstrap IDP's metadata fetch throws.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 7, 2026 16:12
Catching Exception broadly would also swallow genuine bugs (e.g. an NPE
from a real defect) as a quiet log line instead of surfacing them.
Catch only the exception types this call site can actually throw:
Saml2Exception (buildRelyingPartyRegistration's own parsing failures),
RestClientException (the live metadata fetch: DNS/connect/HTTP
failures), and IllegalStateException (a malformed metadata URI in
resolveMetadataXml).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores UAA’s ability to start successfully when a bootstrap-configured SAML IDP has an unreachable or otherwise failing metadata URL, by ensuring failures during metadata resolution/build are handled as “log and skip” rather than crashing Spring context initialization.

Changes:

  • Moves bootstrap IDP metadata resolution into the existing per-IDP try block so fetch failures are caught and tolerated.
  • Broadens the bootstrap loop error handling to avoid taking down startup when metadata resolution fails.
  • Adds a regression test to ensure the relying-party repository bean still builds when a bootstrap IDP’s metadata resolution throws.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/SamlRelyingPartyRegistrationRepositoryConfig.java Wraps bootstrap IDP metadata resolution + registration build in a single try/catch to prevent startup crashes when one bootstrap IDP is unreachable.
server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/SamlRelyingPartyRegistrationRepositoryConfigTest.java Adds a test ensuring repository creation tolerates an exception thrown during bootstrap IDP metadata resolution.

Address Copilot review comment on #3974: the regression test only
asserted the bean builds and the default registration survives, not
that the bad provider itself was dropped. Assert that looking it up by
its registrationId falls through to DefaultRelyingPartyRegistrationRepository's
generic stub (entityId == the SP's own ENTITY_ID) rather than some
partial/broken registration.

That fallback path calls retrieveKeyManager(), which reads
IdentityZoneHolder's static SAML key manager state -- add the same
IdentityZoneHolder.Initializer setup ConfiguratorRelyingPartyRegistrationRepositoryTest
already uses, since this is the first test in this class to exercise it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…rap IdP

simplesamlphp.cfapps.io was a real (now decommissioned) Pivotal Web
Services demo host that happened to stop resolving, which is what
surfaced the startup-crash bug this PR fixes. Point simple.saml.invalid
at the RFC 2606 reserved .invalid TLD instead, so this fixture's "must
never resolve" intent is guaranteed and documented rather than
incidental.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@duanemay duanemay requested a review from strehle July 7, 2026 17:15
@github-project-automation github-project-automation Bot moved this from Inbox to Pending Merge | Prioritized in Foundational Infrastructure Working Group Jul 8, 2026
@duanemay duanemay merged commit 510fd0b into develop Jul 8, 2026
34 of 43 checks passed
@duanemay duanemay deleted the saml-bootstrap-idp-startup-resilience branch July 8, 2026 13:33
@github-project-automation github-project-automation Bot moved this from Pending Merge | Prioritized to Done in Foundational Infrastructure Working Group Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

3 participants