apereo/cas · error · SamlException
Assertion consumer service
Error message
Assertion consumer service [%s] cannot be located in metadata [%s]
What it means
When an AuthnRequest supplies an AssertionConsumerServiceURL (or index), SamlIdPUtils.determineEndpointForRequest() verifies it against the SP metadata via adaptor.getAssertionConsumerServiceFor(). If no metadata ACS matches the requested URL/index, CAS refuses to honor the request-supplied ACS (an anti-replay/SSRF safety measure) and throws a formatted SamlException naming the URL and known metadata locations.
Solutions
- Compare the ACS URL in the message log with the <md:AssertionConsumerService Location=...> values in the SP metadata and fix whichever is wrong (usually update SP config or metadata).
- Refresh/invalidate CAS's cached SAML metadata for the service so newly updated SP ACS entries are picked up.
- If the SP should use a metadata-declared ACS, have it omit AssertionConsumerServiceURL/Index from the AuthnRequest.
- Check for exact-match issues (scheme, port, trailing slash) between the requested URL and metadata Location.
Example fix
// before (SP request) <samlp:AuthnRequest AssertionConsumerServiceURL="https://sp.example.com/acs-new" .../> // after (update SP to the registered ACS) <samlp:AuthnRequest AssertionConsumerServiceURL="https://sp.example.com/acs" .../> // matches metadata Location
Defensive patterns
Strategy: try-catch
Validate before calling
// before accepting request ACS
String requestedUrl = authnRequest.getAssertionConsumerServiceURL();
boolean known = requestedUrl == null || adaptor.getAssertionConsumerServices().stream()
.anyMatch(acs -> requestedUrl.equals(acs.getLocation()));
if (!known) logger.warn("ACS {} not in metadata for {}", requestedUrl, adaptor.getEntityId()); Try / catch
try {
endpoint = SamlIdPUtils.determineEndpointForRequest(authnRequest, adaptor, binding, fromReq, fromMeta, ctx);
} catch (SamlException e) {
audit.recordUnrecognizedAcs(authnRequest); // reject rather than retry
throw e;
} Prevention
- Keep CAS's cached metadata in sync when SPs change their ACS URLs.
- Never whitelist request-supplied ACS URLs not present in metadata.
- Normalize URL comparison (scheme/port/trailing slash) when onboarding SPs.
When it happens
Trigger: AuthnRequest carries AssertionConsumerServiceURL or AssertionConsumerServiceIndex; lookup across configured bindings via getAssertionConsumerServiceFor returns empty, so buildAssertionConsumerService is never reached and the String.format SamlException is thrown.
Common situations: SP changed its ACS URL but CAS metadata cache still holds old metadata; SP sends an index not present in metadata; trailing-slash/port mismatches between the request URL and metadata Location; multi-entity metadata where the wrong entity was resolved.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- No assertion consumer service could be found for entity
- Unable to locate acs url in for entity
- Endpoint for is not available or does not define a binding…
- Endpoint for does not define a binding or location for…
- Metadata directory location cannot be located/created
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/d95ffdafd047b4b8.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-saml-idp-core/src/main/java/org/apereo/cas/support/saml/SamlIdPUtils.java:160
? adaptor.getAssertionConsumerServiceLocations(binding)
: adaptor.getAssertionConsumerServiceLocations();
val acsUrl = StringUtils.defaultIfBlank(acsFromRequest.getResponseLocation(), acsFromRequest.getLocation());
val acsIndex = authnRequest instanceof final AuthnRequest authRequest
? authRequest.getAssertionConsumerServiceIndex()
: null;
if (StringUtils.isNotBlank(acsUrl) && locations.stream().anyMatch(acsUrl::equalsIgnoreCase)) {
return buildAssertionConsumerService(binding, acsUrl, acsIndex);
}
if (acsIndex != null) {
val result = adaptor.getAssertionConsumerServiceFor(binding, acsIndex);
if (result.isPresent()) {
return buildAssertionConsumerService(binding, result.get(), acsIndex);
}
}
val message = String.format("Assertion consumer service [%s] cannot be located in metadata [%s]", acsUrl, locations);
throw new SamlException(message);
}
return acsFromRequest;
}
return acsFromMetadata;
}
private static AssertionConsumerService buildAssertionConsumerService(final String binding,
final String acsUrl,
@Nullable final Integer acsIndex) {
val acs = new AssertionConsumerServiceBuilder().buildObject();
acs.setBinding(binding);
acs.setLocation(acsUrl);
acs.setResponseLocation(acsUrl);
acs.setIndex(acsIndex);
acs.setIsDefault(Boolean.TRUE);
return acs;
}
View on GitHub (pinned to e7288fc434)