apereo/cas · error · PrincipalException

Cannot authorize principal

Error message

Cannot authorize principal %s to access service %s, likely due to insufficient permissions

What it means

The registered service's RegisteredServiceAccessStrategy (authorizeRequest) denied the request for this specific principal, so CAS refuses to let the principal access the service. An UnauthorizedServiceForPrincipalException is wrapped in a PrincipalException carrying the handler error, which the authentication/protocol layer turns into an unauthorized-service response.

Solutions

  1. Inspect the service definition's accessStrategy (authorizedUsers / userAttributes) and confirm the principal id and attributes actually satisfy it.
  2. Dump the principal's attributes at authentication time and compare against required attributes — fix the attribute repository or release policy if attributes are absent.
  3. Correct casing: if caseSensitive is true (default), match the authorized users/attributes exactly.
  4. Update the service registry entry (or remove the restrictive accessStrategy) and reload services.
  5. Enable debug logging on RegisteredServiceAccessStrategy enforcers to see exactly which rule rejected the request.

Example fix

// before: service JSON denies principal
"accessStrategy": { "@class": "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", "serviceAuthorizedUsers": ["hostnmaster"] }
// after: include the actual principal id
"accessStrategy": { "@class": "org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy", "serviceAuthorizedUsers": ["hostnmaster", "alice"] }
Defensive patterns

Strategy: try-catch

Validate before calling

RegisteredService svc = servicesManager.findServiceBy(serviceId);
RegisteredServiceAccessStrategy s = svc.getAccessStrategy();
boolean allowed = s.isServiceAccessAllowed(principalId, principalAttributes);
if (!allowed) { // do not attempt access
}

Try / catch

try {
    boolean ok = enforcer.authorize(context);
} catch (PrincipalException e) {
    if (e.getHandlerErrors().containsKey("UnauthorizedServiceForPrincipalException")) {
        // render access-denied for this principal on this service
    }
}

Prevention

When it happens

Trigger: Calling authorize during access-strategy enforcement when the service's access strategy evaluates false for this principal — e.g. serviceAuthorizedUsers/authorizedUsers does not list the principal, required principal attributes (userAttributes) don't match the principal's actual attributes, or a delegated authorizeRequest rule (caseSensitive, rejects users) fails.

Common situations: Service JSON/registry entry lists the wrong username or the pattern is case-mismatched; required attribute missing from the principal because the attribute repository changed or wasn't released; users moved between LDAP groups; copied a service definition that names another environment's test users.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/DefaultRegisteredServicePrincipalAccessStrategyEnforcer.java:40

    @Override
    public Boolean authorize(final PrincipalAccessStrategyContext context) {
        RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(context.getService(), context.getRegisteredService());
        val serviceId = context.getService() != null ? context.getService().getId() : "unknown";
        LOGGER.trace("Checking access strategy for service [{}], requested by [{}] with attributes [{}].", serviceId, context.getPrincipalId(), context.getPrincipalAttributes());
        val accessRequest = RegisteredServiceAccessStrategyRequest.builder()
            .service(context.getService())
            .principalId(context.getPrincipalId())
            .attributes(context.getPrincipalAttributes())
            .registeredService(context.getRegisteredService())
            .applicationContext(this.applicationContext)
            .build();
        if (Unchecked.supplier(() -> !context.getRegisteredService().getAccessStrategy().authorizeRequest(accessRequest)).get()) {
            LOGGER.warn("Cannot grant access to service [{}]; it is not authorized for use by [{}].", serviceId, context.getPrincipalId());
            val handlerErrors = new HashMap<String, Throwable>();
            val message = String.format("Cannot authorize principal %s to access service %s, likely due to insufficient permissions", context.getPrincipalId(), serviceId);
            val exception = new UnauthorizedServiceForPrincipalException(message, context.getRegisteredService(), context.getPrincipalId(), context.getPrincipalAttributes());
            handlerErrors.put(UnauthorizedServiceForPrincipalException.class.getSimpleName(), exception);
            throw new PrincipalException(message, handlerErrors, new HashMap<>());
        }
        return true;
    }


}

View on GitHub (pinned to e7288fc434)