apereo/cas · warning
No client IP or user-agent was provided. Skipping adaptive…
Error message
No client IP or user-agent was provided. Skipping adaptive authentication policy...
What it means
DefaultAdaptiveAuthenticationPolicy.isAuthenticationRequestAllowed skips all adaptive checks (IP rejection, user-agent rejection, geo/country rejection) and returns true when ClientInfoHolder has no client info or the user-agent string is blank. Adaptive policy is effectively bypassed for that request.
Solutions
- Ensure the client info filter is registered and ordered first so ClientInfoHolder is populated.
- Configure the reverse proxy to forward X-Forwarded-For and User-Agent headers.
- Verify cas.authn.adaptive.policy configuration exists and the request carries a User-Agent.
- If bypass is unacceptable, fail closed by wrapping the policy and rejecting requests with missing client info.
Example fix
// before: filter missing, adaptive policy silently bypassed
// after: register the filter
@Bean
public FilterRegistrationBean<CasClientInfoHttpRequestFilter> clientInfoFilter(
final CasClientInfoHttpRequestFilter filter) {
val reg = new FilterRegistrationBean<>(filter);
reg.setOrder(Ordered.HIGHEST_PRECEDENCE);
return reg;
} Defensive patterns
Strategy: fallback
Validate before calling
if (ClientInfoHolder.getClientInfo() == null || StringUtils.isBlank(request.getHeader("User-Agent"))) {
LOGGER.warn("Client info/user-agent missing — adaptive policy will be skipped");
} Prevention
- Verify the client-info servlet filter is present and highest precedence after proxy/LB changes.
- Monitor for skipped adaptive checks in logs; silent bypass hides policy gaps.
- Fail closed in a wrapper if adaptive enforcement is a hard requirement.
When it happens
Trigger: ClientInfoHolder.getClientInfo() returns null (no ClientInfoFilter/filter servlet not applied, e.g. non-web or mis-ordered filter chain) or the userAgent parameter is blank when the webflow action invokes the policy.
Common situations: Reverse proxy not forwarding X-Forwarded-For so client info is empty; CasClientInfoHttpRequestFilter removed/ordered out; internal calls to the flow (e.g. REST/scripted) without headers; tests invoking the policy directly.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- No ClientInfo could be found. Returning empty ClientInfo…
- Client IP [ ] is rejected for authentication
- User agent [ ] is rejected for authentication
- Client [ ] is rejected for authentication based on country…
- Client IP [ ] is banned
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/5cbce587707cd09b.
Report an issue: GitHub.
Appendix: source
Thrown at core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/adaptive/DefaultAdaptiveAuthenticationPolicy.java:38
* @author Misagh Moayyed
* @since 5.1.0
*/
@Slf4j
@RequiredArgsConstructor
public class DefaultAdaptiveAuthenticationPolicy implements AdaptiveAuthenticationPolicy {
private final GeoLocationService geoLocationService;
private final IPAddressIntelligenceService ipAddressIntelligenceService;
private final AdaptiveAuthenticationProperties adaptiveAuthenticationProperties;
@Override
public boolean isAuthenticationRequestAllowed(final RequestContext requestContext, final String userAgent,
final GeoLocationRequest location) throws Throwable {
val clientInfo = ClientInfoHolder.getClientInfo();
if (clientInfo == null || StringUtils.isBlank(userAgent)) {
LOGGER.warn("No client IP or user-agent was provided. Skipping adaptive authentication policy...");
return true;
}
val clientIp = clientInfo.getClientIpAddress();
if (isIpAddressRejected(requestContext, clientIp)) {
LOGGER.warn("Client IP [{}] is rejected for authentication", clientIp);
return false;
}
if (isUserAgentRejected(userAgent)) {
LOGGER.warn("User agent [{}] is rejected for authentication", userAgent);
return false;
}
LOGGER.debug("User agent [{}] is authorized to proceed", userAgent);
if (this.geoLocationService != null && location != null && StringUtils.isNotBlank(clientIp)
&& StringUtils.isNotBlank(this.adaptiveAuthenticationProperties.getPolicy().getRejectCountries())) {
val loc = this.geoLocationService.locate(clientIp, location);
if (loc != null) {
LOGGER.debug("Determined geolocation for [{}] to be [{}]", clientIp, loc);View on GitHub (pinned to e7288fc434)