{"record":{"id":"77992deaa2412dd9","repo":"apereo/cas","slug":"cannot-authorize-principal-s-to-access-service-s","errorCode":null,"errorMessage":"Cannot authorize principal %s to access service %s, likely due to insufficient permissions","messagePattern":"Cannot authorize principal (.+?) to access service (.+?), likely due to insufficient permissions","errorType":"exception","errorClass":"PrincipalException","httpStatus":null,"severity":"error","filePath":"core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/DefaultRegisteredServicePrincipalAccessStrategyEnforcer.java","lineNumber":40,"sourceCode":"    @Override\n    public Boolean authorize(final PrincipalAccessStrategyContext context) {\n        RegisteredServiceAccessStrategyUtils.ensureServiceAccessIsAllowed(context.getService(), context.getRegisteredService());\n        val serviceId = context.getService() != null ? context.getService().getId() : \"unknown\";\n        LOGGER.trace(\"Checking access strategy for service [{}], requested by [{}] with attributes [{}].\", serviceId, context.getPrincipalId(), context.getPrincipalAttributes());\n        val accessRequest = RegisteredServiceAccessStrategyRequest.builder()\n            .service(context.getService())\n            .principalId(context.getPrincipalId())\n            .attributes(context.getPrincipalAttributes())\n            .registeredService(context.getRegisteredService())\n            .applicationContext(this.applicationContext)\n            .build();\n        if (Unchecked.supplier(() -> !context.getRegisteredService().getAccessStrategy().authorizeRequest(accessRequest)).get()) {\n            LOGGER.warn(\"Cannot grant access to service [{}]; it is not authorized for use by [{}].\", serviceId, context.getPrincipalId());\n            val handlerErrors = new HashMap<String, Throwable>();\n            val message = String.format(\"Cannot authorize principal %s to access service %s, likely due to insufficient permissions\", context.getPrincipalId(), serviceId);\n            val exception = new UnauthorizedServiceForPrincipalException(message, context.getRegisteredService(), context.getPrincipalId(), context.getPrincipalAttributes());\n            handlerErrors.put(UnauthorizedServiceForPrincipalException.class.getSimpleName(), exception);\n            throw new PrincipalException(message, handlerErrors, new HashMap<>());\n        }\n        return true;\n    }\n\n\n}\n","sourceCodeStart":22,"sourceCodeEnd":47,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-services-api/src/main/java/org/apereo/cas/services/DefaultRegisteredServicePrincipalAccessStrategyEnforcer.java#L22-L47","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the service definition's accessStrategy (authorizedUsers / userAttributes) and confirm the principal id and attributes actually satisfy it.","Dump the principal's attributes at authentication time and compare against required attributes — fix the attribute repository or release policy if attributes are absent.","Correct casing: if caseSensitive is true (default), match the authorized users/attributes exactly.","Update the service registry entry (or remove the restrictive accessStrategy) and reload services.","Enable debug logging on RegisteredServiceAccessStrategy enforcers to see exactly which rule rejected the request."],"exampleFix":"// before: service JSON denies principal\n\"accessStrategy\": { \"@class\": \"org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy\", \"serviceAuthorizedUsers\": [\"hostnmaster\"] }\n// after: include the actual principal id\n\"accessStrategy\": { \"@class\": \"org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy\", \"serviceAuthorizedUsers\": [\"hostnmaster\", \"alice\"] }","handlingStrategy":"try-catch","validationCode":"RegisteredService svc = servicesManager.findServiceBy(serviceId);\nRegisteredServiceAccessStrategy s = svc.getAccessStrategy();\nboolean allowed = s.isServiceAccessAllowed(principalId, principalAttributes);\nif (!allowed) { // do not attempt access\n}","typeGuard":null,"tryCatchPattern":"try {\n    boolean ok = enforcer.authorize(context);\n} catch (PrincipalException e) {\n    if (e.getHandlerErrors().containsKey(\"UnauthorizedServiceForPrincipalException\")) {\n        // render access-denied for this principal on this service\n    }\n}","preventionTips":["Keep authorizedUsers/required-attribute lists in service definitions in sync with your user directory.","Remember default case-sensitivity of user/attribute matching.","Verify attribute release policies deliver the attributes the access strategy requires.","Review service definitions after copying between environments."],"tags":["authorization","access-strategy","registered-service","principal"],"backgroundTag":"insufficient-permissions","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}