apereo/cas · warning

Client [ ] is rejected for authentication based on country…

Error message

Client [{}] is rejected for authentication based on country location

What it means

DefaultAdaptiveAuthenticationPolicy rejects an authentication request because the client's resolved geolocation country appears in cas.authn.adaptive.policy.reject-countries. This is a WARN log plus a 'false' return from isAuthenticationRequestAllowed, which the adaptive policy engine turns into an authentication block. It means geo-location data matched a deliberately configured blacklist.

Solutions

  1. Remove the client's country from cas.authn.adaptive.policy.reject-countries, or have the user disable their VPN/proxy
  2. Verify the geoIP database (MaxMind) is current and correctly located; update or fix cas.geo-location settings
  3. If blanket country blocking is unintended, remove/reduce the reject-countries entry or disable the adaptive policy feature

Example fix

// before
cas.authn.adaptive.policy.reject-countries=DE,FR
// after
cas.authn.adaptive.policy.reject-countries=
Defensive patterns

Strategy: validation

Validate before calling

if (policy != null && policy.getRejectCountries() != null && geoService.locate(clientIp, null) != null) { /* check country not in rejectCountries before calling */ }

Type guard

boolean isCountryAllowed(GeoLocationService svc, String ip, List<String> rejected) { var loc = svc.locate(ip, null); return loc == null || rejected == null || !rejected.contains(loc.getCountry()); }

Prevention

When it happens

Trigger: Authentication attempt whose client IP resolves via geoLocationService.locate() to a country listed in adaptiveAuthenticationProperties.getPolicy().getRejectCountries().

Common situations: Users behind VPNs/proxies exiting in a blocked country; misconfigured reject-countries list accidentally including the users' own country; stale or wrong GeoLite2 database attributing the wrong country; server-side NAT making all clients appear from one region.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/7ea4c27e8bbb3d8b. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/adaptive/DefaultAdaptiveAuthenticationPolicy.java:58

        }
        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);
                if (isGeoLocationCountryRejected(loc)) {
                    LOGGER.warn("Client [{}] is rejected for authentication based on country location", clientIp);
                    return false;
                }
            } else {
                LOGGER.info("Could not determine geolocation for [{}]", clientIp);
            }
        }
        LOGGER.debug("Adaptive authentication policy has authorized client [{}] to proceed.", clientIp);
        return true;
    }

    private boolean isGeoLocationCountryRejected(final GeoLocationResponse finalLoc) {
        val rejectCountries = this.adaptiveAuthenticationProperties.getPolicy().getRejectCountries();
        return StringUtils.isNotBlank(rejectCountries)
               && RegexUtils.find(rejectCountries, finalLoc.build());
    }

    private boolean isUserAgentRejected(final String userAgent) {
        val rejectBrowsers = this.adaptiveAuthenticationProperties.getPolicy().getRejectBrowsers();

View on GitHub (pinned to e7288fc434)