apereo/cas · error · AuthenticationException

Authenticated profile does not carry the UMA protection…

Error message

Authenticated profile does not carry the UMA protection scope

What it means

BaseUmaEndpointController.getAuthenticatedProfile reads the authenticated user profile from the Pac4J session store and requires it to hold the requested UMA permission as a role. If the profile lacks that permission, an AuthenticationException is thrown, blocking access to the UMA endpoint. This guards endpoints so only principals with the UMA protection permission proceed.

Solutions

  1. Ensure the access token used includes the UMA protection scope so the profile gains the required role.
  2. Check the profile/authorization mapping so the requiredPermission (e.g. uma_protection) is added as a role.
  3. Re-authenticate to obtain a fresh profile with the correct roles.
  4. Verify the session store (sessionStore config) used by getUmaConfigurationContext matches the one used at login.

Example fix

// before
// profile roles: [] -> AuthenticationException thrown
// after
// request token with scope=uma_protection; profile roles: [uma_protection]
Defensive patterns

Strategy: try-catch

Validate before calling

UserProfile p = OAuth20Utils.getAuthenticatedUserProfile(context, sessionStore);
if (p == null || !p.getRoles().contains("uma_protection")) {
    throw new AuthenticationException("profile lacks UMA permission");
}

Try / catch

try { return getAuthenticatedProfile(request, response, permission); } catch (AuthenticationException e) {
    response.sendError(HttpServletResponse.SC_FORBIDDEN);
    return null;
}

Prevention

When it happens

Trigger: Calling a UMA controller endpoint (resource-set registration, permission, etc.) with a session whose profile does not include the requiredPermission role, e.g. the user authenticated but was never granted the UMA protection scope/role.

Common situations: Direct browser access to UMA endpoints without the token-based profile carrying the role; session store losing profile attributes; misconfigured authorization generator not mapping the uma_protection scope to a role.

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/c646f93ea9e3487b. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-oauth-uma-core/src/main/java/org/apereo/cas/uma/web/controllers/BaseUmaEndpointController.java:50

 */
@Getter
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class BaseUmaEndpointController extends AbstractController {
    /**
     * Json object mapper instance.
     */
    protected static final ObjectMapper MAPPER = JacksonObjectMapperFactory.builder()
        .defaultTypingEnabled(false).build().toObjectMapper();

    private final UmaConfigurationContext umaConfigurationContext;

    protected UserProfile getAuthenticatedProfile(final HttpServletRequest request,
                                                  final HttpServletResponse response,
                                                  final String requiredPermission) {
        val context = new JEEContext(request, response);
        val profile = OAuth20Utils.getAuthenticatedUserProfile(context, getUmaConfigurationContext().getSessionStore());
        if (!profile.getRoles().contains(requiredPermission)) {
            throw new AuthenticationException("Authenticated profile does not carry the UMA protection scope");
        }
        return profile;
    }

    protected MultiValueMap<String, Object> buildResponseEntityErrorModel(final InvalidResourceSetException e) {
        return buildResponseEntityErrorModel(e.getStatus(), e.getMessage());
    }

    protected MultiValueMap<String, Object> buildResponseEntityErrorModel(final HttpStatus code, final String message) {
        return CollectionUtils.asMultiValueMap("code",
            code.value(),
            "message", message);
    }

    protected OAuth20AccessToken resolveAccessToken(final Ticket token) {
        return (OAuth20AccessToken) (token.isStateless() ? umaConfigurationContext.getTicketRegistry().getTicket(token.getId()) : token);
    }

View on GitHub (pinned to e7288fc434)