apereo/cas · error · InsufficientAuthenticationException
Unable to grant access to
Error message
Unable to grant access to %s
What it means
Thrown by palantirUserDetailsService when the authenticated CAS assertion does not contain the configured required attribute with a value matching the configured regex (casAuthentication.requiredAttributeName / requiredAttributeValue). CAS Palantir support gates access on this attribute before granting authorities. If no attribute value matches, the user is rejected with an Spring Security InsufficientAuthenticationException and access is denied.
Solutions
- Log the assertion attributes (the warn line prints the attribute name and pattern) and verify the attribute is actually present on the assertion; fix the attribute release/source if missing.
- Correct cas.authn.palantir.required-attribute-name to the exact attribute key returned by the attribute repository.
- Loosen or correct cas.authn.palantir.required-attribute-value regex (it is compiled with RegexUtils.createPattern, full Java regex semantics).
- Test the regex against real attribute values using a Java regex tester before deploying.
Example fix
// before cas.authn.palantir.required-attribute-name=memberOf cas.authn.palantir.required-attribute-value=^CN=palantir-users.* // after cas.authn.palantir.required-attribute-name=groups cas.authn.palantir.required-attribute-value=CN=palantir-users
Defensive patterns
Strategy: validation
Validate before calling
// Verify the assertion carries the required attribute before login
Map<String, Object> attrs = assertion.getAttributes();
Pattern p = Pattern.compile(requiredAttributeValue);
boolean ok = attrs.getOrDefault(requiredAttributeName, List.of()).stream()
.anyMatch(v -> p.matcher(v.toString()).find());
if (!ok) { throw new IllegalStateException("Missing required attribute " + requiredAttributeName); } Try / catch
try { authManager.authenticate(token); } catch (InsufficientAuthenticationException e) { LOGGER.warn("Palantir access denied: {}", e.getMessage()); throw new AccessDeniedException("access denied"); } Prevention
- Confirm attribute release policies include the required attribute for all intended users.
- Test required-attribute-value regexes against real production attribute values.
- Log assertion attributes in a staging environment before tightening the filter.
When it happens
Trigger: A user logs in via the Palantir integration and the assertion's attribute named by cas.authn.palantir[0].required-attribute-name is missing, or none of its values matches the regex cas.authn.palantir[0].required-attribute-value.
Common situations: Attribute not released by the identity provider or attribute repository policy; wrong attribute name configured (case/scope mismatch like uid vs login); regex too strict (e.g. expecting an exact group name but attribute contains extra whitespace or different casing); attribute populated only for some users.
Related errors
- No user can be accepted because none is defined
- Multiple principal values are not allowed: [principalAttr]
- Principal resolution handled by
- Authentication has failed because LDAP password policy…
- Authentication handler is disabled
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/970e1601f0c6fe05.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-palantir/src/main/java/org/apereo/cas/config/CasPalantirCasAuthenticationConfiguration.java:132
@Bean
@ConditionalOnMissingBean(name = "palantirUserDetailsService")
public AuthenticationUserDetailsService palantirUserDetailsService(
final CasConfigurationProperties casProperties) {
return (AuthenticationUserDetailsService<CasAssertionAuthenticationToken>) token -> {
val assertion = token.getAssertion();
val attributes = assertion.getPrincipal().getAttributes();
val username = assertion.getPrincipal().getName();
val casAuthentication = casProperties.getPalantir().getCasAuthentication();
val requiredAttributeName = casAuthentication.getRequiredAttributeName();
val requiredAttributeValue = RegexUtils.createPattern(casAuthentication.getRequiredAttributeValue());
val requiredAttributeValues = CollectionUtils.toCollection(attributes.get(requiredAttributeName));
if (requiredAttributeValues.stream().noneMatch(value -> RegexUtils.find(requiredAttributeValue, value.toString()))) {
LOGGER.warn("Required attribute [{}] with value [{}] is not found in the CAS assertion for user [{}]",
requiredAttributeName, requiredAttributeValue.pattern(), username);
throw new InsufficientAuthenticationException("Unable to grant access to %s".formatted(username));
}
val authorities = CollectionUtils.toCollection(attributes.get("role"))
.stream()
.map(role -> Strings.CI.startsWith(role.toString(), "ROLE_") ? role.toString() : "ROLE_" + role)
.map(String::toUpperCase)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username, "N/A", authorities);
};
}
@Bean
@ConditionalOnMissingBean(name = "palantirTicketValidator")
public TicketValidator palantirTicketValidator(
@Qualifier(WebApplicationService.BEAN_NAME_FACTORY)
final ServiceFactory<WebApplicationService> webApplicationServiceFactory,View on GitHub (pinned to e7288fc434)