{"record":{"id":"d95ffdafd047b4b8","repo":"apereo/cas","slug":"assertion-consumer-service-s-cannot-be-located","errorCode":null,"errorMessage":"Assertion consumer service [%s] cannot be located in metadata [%s]","messagePattern":"Assertion consumer service \\[(.+?)\\] cannot be located in metadata \\[(.+?)\\]","errorType":"exception","errorClass":"SamlException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-saml-idp-core/src/main/java/org/apereo/cas/support/saml/SamlIdPUtils.java","lineNumber":160,"sourceCode":"                    ? adaptor.getAssertionConsumerServiceLocations(binding)\n                    : adaptor.getAssertionConsumerServiceLocations();\n                val acsUrl = StringUtils.defaultIfBlank(acsFromRequest.getResponseLocation(), acsFromRequest.getLocation());\n                val acsIndex = authnRequest instanceof final AuthnRequest authRequest\n                    ? authRequest.getAssertionConsumerServiceIndex()\n                    : null;\n\n                if (StringUtils.isNotBlank(acsUrl) && locations.stream().anyMatch(acsUrl::equalsIgnoreCase)) {\n                    return buildAssertionConsumerService(binding, acsUrl, acsIndex);\n                }\n\n                if (acsIndex != null) {\n                    val result = adaptor.getAssertionConsumerServiceFor(binding, acsIndex);\n                    if (result.isPresent()) {\n                        return buildAssertionConsumerService(binding, result.get(), acsIndex);\n                    }\n                }\n                val message = String.format(\"Assertion consumer service [%s] cannot be located in metadata [%s]\", acsUrl, locations);\n                throw new SamlException(message);\n            }\n            return acsFromRequest;\n        }\n        return acsFromMetadata;\n    }\n\n    private static AssertionConsumerService buildAssertionConsumerService(final String binding,\n                                                                          final String acsUrl,\n                                                                          @Nullable final Integer acsIndex) {\n        val acs = new AssertionConsumerServiceBuilder().buildObject();\n        acs.setBinding(binding);\n        acs.setLocation(acsUrl);\n        acs.setResponseLocation(acsUrl);\n        acs.setIndex(acsIndex);\n        acs.setIsDefault(Boolean.TRUE);\n        return acs;\n    }\n","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-saml-idp-core/src/main/java/org/apereo/cas/support/saml/SamlIdPUtils.java#L142-L178","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (SP request)\n<samlp:AuthnRequest AssertionConsumerServiceURL=\"https://sp.example.com/acs-new\" .../>\n// after (update SP to the registered ACS)\n<samlp:AuthnRequest AssertionConsumerServiceURL=\"https://sp.example.com/acs\" .../>  // matches metadata Location","handlingStrategy":"try-catch","validationCode":"// before accepting request ACS\nString requestedUrl = authnRequest.getAssertionConsumerServiceURL();\nboolean known = requestedUrl == null || adaptor.getAssertionConsumerServices().stream()\n    .anyMatch(acs -> requestedUrl.equals(acs.getLocation()));\nif (!known) logger.warn(\"ACS {} not in metadata for {}\", requestedUrl, adaptor.getEntityId());","typeGuard":null,"tryCatchPattern":"try {\n    endpoint = SamlIdPUtils.determineEndpointForRequest(authnRequest, adaptor, binding, fromReq, fromMeta, ctx);\n} catch (SamlException e) {\n    audit.recordUnrecognizedAcs(authnRequest); // reject rather than retry\n    throw e;\n}","preventionTips":["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."],"tags":["saml","idp","acs","metadata-mismatch","authn-request"],"backgroundTag":"record-not-found","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}