{"record":{"id":"43597cb01de07f43","repo":"apereo/cas","slug":"principal-is-unauthorized-to-authenticate-as","errorCode":null,"errorMessage":"Principal  is unauthorized to authenticate as ","messagePattern":"Principal  is unauthorized to authenticate as ","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-surrogate-core/src/main/java/org/apereo/cas/authentication/SurrogateAuthenticationPostProcessor.java","lineNumber":100,"sourceCode":"                    .build();\n\n                surrogateEligibilityAuditableExecution.execute(surrogateEligibleAudit);\n                return;\n            }\n            LOGGER.error(\"Principal [{}] is unable/unauthorized to authenticate as [{}]\", primaryPrincipal, surrogateUsername);\n            throw new FailedLoginException();\n        } catch (final Exception e) {\n            publishFailureEvent(primaryPrincipal, surrogateUsername);\n            final Map<String, Throwable> map = CollectionUtils.wrap(getClass().getSimpleName(),\n                new SurrogateAuthenticationException(\"Principal \" + primaryPrincipal + \" is unauthorized to authenticate as \" + surrogateUsername));\n\n            val surrogateIneligibleAudit = AuditableContext.builder()\n                .service(transaction.getService())\n                .authentication(authentication)\n                .build();\n\n            surrogateEligibilityAuditableExecution.execute(surrogateIneligibleAudit);\n            throw new AuthenticationException(map);\n        }\n    }\n\n    @Override\n    public boolean supports(final Credential credential) {\n        return credential.getCredentialMetadata().getTrait(SurrogateCredentialTrait.class)\n            .stream()\n            .anyMatch(trait -> StringUtils.isNotBlank(trait.getSurrogateUsername()));\n    }\n\n    private void publishFailureEvent(final Principal principal, final String surrogate) {\n        val clientInfo = ClientInfoHolder.getClientInfo();\n        val event = new CasSurrogateAuthenticationFailureEvent(this, principal, surrogate, clientInfo);\n        publishEvent(event);\n    }\n\n    private void publishSuccessEvent(final Principal principal, final String surrogate) {\n        val clientInfo = ClientInfoHolder.getClientInfo();","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-surrogate-core/src/main/java/org/apereo/cas/authentication/SurrogateAuthenticationPostProcessor.java#L82-L118","documentation":"After confirming the surrogate username is present, SurrogateAuthenticationPostProcessor checks eligibility via the surrogate eligibility auditable execution. When the primary principal is NOT allowed to authenticate as the surrogate user, it executes an ineligible-access audit and throws AuthenticationException whose message is 'Principal <p> is unauthorized to authenticate as <s>'.","triggerScenarios":"Post-processing a surrogate authentication where canImpersonate (or the eligibility source consulted in process()) denies the primary->surrogate mapping, even though the primary credential itself authenticated fine.","commonSituations":"Primary user missing from the surrogate allow-list for the target; LDAP/JSON eligibility source unreachable so lookup yields nothing; service-specific surrogate policy blocking this registered service; attribute release filtering out the evidence attributes.","solutions":["Grant eligibility: add the primary principal to the target account's surrogate list in the configured surrogate source.","Verify the surrogate eligibility source (cas.authn.surrogate.* json/ldap/groovy) is reachable and returns data for this pair.","Check registered-service surrogate policy/attributes aren't filtering out eligibility.","Review the audit trail (surrogateEligibilityAuditableExecution) to see exactly which check denied access."],"exampleFix":"// before: LDAP surrogate filter finds nothing\ncas.authn.surrogate.ldap.search-filter=(&(uid={principal})(surrogateMember={surrogate}))\n// after: also allow members of a surrogate group\ncas.authn.surrogate.ldap.search-filter=(&(objectClass=person)(|(uid={principal})(member={principal})))","handlingStrategy":"validation","validationCode":"// check eligibility before running the full surrogate flow\nboolean eligible = surrogateAuthenticationService.canImpersonate(surrogateUsername, principal, Optional.of(registeredService));\nif (!eligible) { throw new AccessDeniedException(\"Not eligible to authenticate as \" + surrogateUsername); }","typeGuard":null,"tryCatchPattern":"try {\n    processor.process(transaction, result);\n} catch (AuthenticationException e) {\n    // present 'not permitted to impersonate' message and audit reference\n    LOGGER.warn(\"Surrogate eligibility denied: {}\", e.getMessage());\n}","preventionTips":["Review the audit records from surrogateEligibilityAuditableExecution when denials occur","Keep the eligibility source (LDAP/JSON) reachable and monitored","Document the surrogate approval workflow so admins know how to grant access","Test service-specific surrogate policies after registered-service changes"],"tags":["surrogate","impersonation","authorization"],"backgroundTag":"permission-denied","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"}