apereo/cas · error · UnauthorizedSsoServiceException

Service [ ] is not allowed to use SSO.

Error message

Service [{}] is not allowed to use SSO.

What it means

DefaultSecurityTokenServiceTokenFetcher resolved the service but ServicesManager returned no WSFederationRegisteredService, or the service's access strategy disallows SSO; in that case it logs this warning and throws UnauthorizedSsoServiceException. The relying party is not permitted to participate in single sign-on token issuance.

Solutions

  1. Register the relying party as a WSFederationRegisteredService whose serviceId matches the requesting service URL
  2. Enable SSO access on the service's access strategy (isServiceAccessAllowed) and check enabled/valid dates
  3. Verify the resolved service id actually matches the registered service pattern (compare logged resolved id)
  4. Reload/publish service registry changes so ServicesManager sees the updated definition

Example fix

// before (access strategy blocks SSO)
"accessStrategy": { "@class": "...DefaultRegisteredServiceAccessStrategy", "enabled": true, "ssoEnabled": false }
// after
"accessStrategy": { "@class": "...DefaultRegisteredServiceAccessStrategy", "enabled": true, "ssoEnabled": true }
Defensive patterns

Strategy: validation

Validate before calling

var rp = servicesManager.findServiceBy(service, WSFederationRegisteredService.class);
if (rp == null || !rp.getAccessStrategy().isServiceAccessAllowed(rp, service)) { /* SSO token fetch will be denied */ }

Try / catch

try { token = tokenFetcher.fetch(service, principalId); }
catch (UnauthorizedSsoServiceException e) { /* register/enable the service for SSO */ }

Prevention

When it happens

Trigger: fetch(service, principalId): servicesManager.findServiceBy(resolvedService, WSFederationRegisteredService.class) returns null, or rp.getAccessStrategy().isServiceAccessAllowed(rp, service) returns false.

Common situations: Service not registered in CAS (or registered as a plain service, not WS-Federation type); service disabled/unauthorized via access strategy (expired start/end date, blacklisted principal); selectionStrategy resolved an unexpected service; case/scheme mismatch in serviceId so nothing matched.

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

Appendix: source

Thrown at support/cas-server-support-ws-sts-api/src/main/java/org/apereo/cas/authentication/DefaultSecurityTokenServiceTokenFetcher.java:42

@RequiredArgsConstructor
@ToString(callSuper = true)
public class DefaultSecurityTokenServiceTokenFetcher implements SecurityTokenServiceTokenFetcher {
    private final ServicesManager servicesManager;

    private final AuthenticationServiceSelectionStrategy selectionStrategy;

    private final CipherExecutor<String, String> credentialCipherExecutor;

    private final SecurityTokenServiceClientBuilder clientBuilder;

    @Override
    public Optional<SecurityToken> fetch(final Service service, final String principalId) throws Throwable {
        val resolvedService = selectionStrategy.resolveServiceFrom(service);
        LOGGER.debug("Resolved service as [{}]", resolvedService);
        if (resolvedService != null) {
            val rp = servicesManager.findServiceBy(resolvedService, WSFederationRegisteredService.class);
            if (rp == null || !rp.getAccessStrategy().isServiceAccessAllowed(rp, service)) {
                LOGGER.warn("Service [{}] is not allowed to use SSO.", rp);
                throw new UnauthorizedSsoServiceException();
            }
            LOGGER.debug("Building security token service client for registered service [{}]", rp);
            val sts = clientBuilder.buildClientForSecurityTokenRequests(rp);
            return Optional.ofNullable(invokeSecurityTokenServiceForToken(rp, sts, principalId));
        }
        return Optional.empty();
    }

    private SecurityToken invokeSecurityTokenServiceForToken(final WSFederationRegisteredService rp,
                                                             final SecurityTokenServiceClient sts,
                                                             final String principalId) {

        try {
            val properties = sts.getProperties();
            properties.put(SecurityConstants.USERNAME, principalId);
            val uid = credentialCipherExecutor.encode(principalId);
            properties.put(SecurityConstants.PASSWORD, uid);

View on GitHub (pinned to e7288fc434)