apereo/cas · warning
Attribute query ticket
Error message
Attribute query ticket [{}] has either expired, or it is linked to a single sign-on session that is no longer valid and has now expired What it means
This warning is logged when a SAML 2.0 Attribute Query request references an attribute query ticket that is absent from the ticket registry or has expired (a query ticket is also expired when its linked SSO session expires). The controller then throws InvalidTicketException and the Attribute Query profile request fails.
Solutions
- Verify SP attribute query timing is within the SamlAttributeQueryTicket TTL and the SSO session is still alive (check cas.authn.saml-idp.core attribute-query ticket expiration settings).
- Inspect the ticket registry (cas-management/actuator endpoints or registry backend) to confirm the ticket exists and has not been evicted.
- Ensure all CAS nodes share the same ticket registry when running a cluster.
- Increase cas.authn.saml-idp.ticket.attribute-query.time-to-kill-in-seconds and underlying SSO/TGT expiration if queries legitimately arrive late.
- Debug the id derivation: same NameID value and SP entity id must be used; confirm the SP is not resending modified NameIDs.
Example fix
// before (cas.properties) cas.authn.saml-idp.ticket.attribute-query.time-to-kill-in-seconds=30 // after cas.authn.saml-idp.ticket.attribute-query.time-to-kill-in-seconds=300
Defensive patterns
Strategy: validation
Validate before calling
var ticket = ticketRegistry.getTicket(id, SamlAttributeQueryTicket.class);
if (ticket == null || ticket.isExpired()) {
throw new InvalidTicketException(id);
} Try / catch
try {
attributeQueryService.handleQuery(request);
} catch (InvalidTicketException e) {
LOGGER.warn("Attribute query ticket expired: {}", e.getMessage());
// respond with SAML error status
} Prevention
- Keep SP attribute query timing well within the ticket TTL and SSO session lifetime.
- Use a shared, persistent ticket registry in clustered deployments.
- Monitor ticket registry eviction rates.
- Alert on frequent InvalidTicketException from the attribute query endpoint.
When it happens
Trigger: A SAML SP sends an AttributeQuery whose NameID and entity ID hash to a SamlAttributeQueryTicket id, but the ticket was already consumed/expired via TTL/TGT-SSO expiry, ticket registry was flushed/evicted, or the SP sends a stale/cached query.
Common situations: Ticket registry cleaned by a shared cache (Redis/Hazelcast/Memcached) eviction policy; attribute queries sent long after SSO login; clock skew or aggressive SamlAttributeQueryTicket TTLs; SP caches ticket ids across restarts; clustering with a registry not shared between CAS nodes.
Related errors
- SAML2 attribute query profile is not enabled
- No Certificates provided
- Public and private keys do not match
- Configuration element indicated an entityCertificate, but…
- Could not decode provided Entity Certificate file
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/874b863a02d58f9e.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-saml-idp-web/src/main/java/org/apereo/cas/support/saml/web/idp/profile/query/SamlIdPSaml2AttributeQueryProfileHandlerController.java:82
}
val ctx = decodeSoapRequest(request);
val query = (AttributeQuery) ctx.getMessage();
try {
val issuer = Objects.requireNonNull(query).getIssuer().getValue();
val registeredService = verifySamlRegisteredService(issuer, request);
val adaptor = getSamlMetadataFacadeFor(registeredService, query);
val facade = adaptor.orElseThrow(() -> UnauthorizedServiceException.denied("Cannot find metadata linked to %s".formatted(issuer)));
verifyAuthenticationContextSignature(ctx, request, query, facade, registeredService);
val nameIdValue = determineNameIdForQuery(query, registeredService, facade);
val factory = (SamlAttributeQueryTicketFactory) getConfigurationContext().getTicketFactory()
.get(SamlAttributeQueryTicket.class);
val id = factory.createTicketIdFor(nameIdValue, facade.getEntityId());
LOGGER.debug("Created ticket id for attribute query [{}]", id);
val ticket = getConfigurationContext().getTicketRegistry().getTicket(id, SamlAttributeQueryTicket.class);
if (ticket == null || ticket.isExpired()) {
LOGGER.warn("Attribute query ticket [{}] has either expired, or it is linked to "
+ "a single sign-on session that is no longer valid and has now expired", id);
throw new InvalidTicketException(id);
}
val authentication = ticket.getAuthentication();
val principal = resolvePrincipalForAttributeQuery(authentication, registeredService);
val releasePolicyContext = RegisteredServiceAttributeReleasePolicyContext.builder()
.registeredService(registeredService)
.applicationContext(getConfigurationContext().getOpenSamlConfigBean().getApplicationContext())
.service(ticket.getService())
.principal(principal)
.build();
val principalAttributes = registeredService.getAttributeReleasePolicy().getConsentableAttributes(releasePolicyContext);
LOGGER.debug("Initial consentable principal attributes are [{}]", principalAttributes);
val authenticationAttributes = getConfigurationContext().getAuthenticationAttributeReleasePolicy()
.getAuthenticationAttributesForRelease(authentication, null, Map.of(), registeredService);View on GitHub (pinned to e7288fc434)