@Override
    public void process(final AuthenticationBuilder builder, final AuthenticationTransaction transaction) throws Throwable {
        val authentication = builder.build();
        val principal = authentication.getPrincipal();

        if (!(principal instanceof final SurrogatePrincipal primaryPrincipal)) {
            LOGGER.trace("Provided principal is one intended for surrogate authentication");
            return;
        }
        val primaryCredential = transaction.getPrimaryCredential();
        if (primaryCredential.isEmpty()) {
            throw new AuthenticationException("Unable to determine primary credentials");
        }
        val surrogateUsername = primaryCredential.get().getCredentialMetadata()
            .getTrait(SurrogateCredentialTrait.class)
            .map(SurrogateCredentialTrait::getSurrogateUsername)
            .orElseThrow(() -> new AuthenticationException("Unable to determine surrogate credential"));

        try {
            if (StringUtils.isBlank(surrogateUsername)) {
                LOGGER.error("No surrogate username was specified as part of the credential");
                throw new CredentialNotFoundException("Missing surrogate username in credential");
            }
            LOGGER.debug("Authenticated [{}] will be checked for surrogate eligibility next for [{}]...", primaryPrincipal, surrogateUsername);
            if (transaction.getService() != null) {
                val svc = servicesManager.findServiceBy(transaction.getService());

                val serviceAccessAudit = AuditableContext.builder()
                    .service(transaction.getService())
                    .authentication(authentication)
                    .registeredService(svc)
                    .build();

                val accessResult = registeredServiceAccessStrategyEnforcer.execute(serviceAccessAudit);
                accessResult.throwExceptionIfNeeded();
            }

            if (surrogateAuthenticationService.canImpersonate(surrogateUsername, primaryPrincipal.getPrimary(), Optional.ofNullable(transaction.getService()))) {
                LOGGER.debug("Principal [{}] is authorized to authenticate as [{}]", primaryPrincipal, surrogateUsername);
                publishSuccessEvent(primaryPrincipal, surrogateUsername);

                val surrogateEligibleAudit = AuditableContext.builder()
                    .service(transaction.getService())
                    .authentication(authentication)
                    .properties(CollectionUtils.wrap("targetUserId", surrogateUsername, "eligible", Boolean.TRUE))
                    .build();

                surrogateEligibilityAuditableExecution.execute(surrogateEligibleAudit);
                return;
            }
            LOGGER.error("Principal [{}] is unable/unauthorized to authenticate as [{}]", primaryPrincipal, surrogateUsername);
            throw new FailedLoginException();
        } catch (final Exception e) {
            publishFailureEvent(primaryPrincipal, surrogateUsername);
            final Map<String, Throwable> map = CollectionUtils.wrap(getClass().getSimpleName(),
                new SurrogateAuthenticationException("Principal " + primaryPrincipal + " is unauthorized to authenticate as " + surrogateUsername));

            val surrogateIneligibleAudit = AuditableContext.builder()
                .service(transaction.getService())
                .authentication(authentication)
                .build();

            surrogateEligibilityAuditableExecution.execute(surrogateIneligibleAudit);
            throw new AuthenticationException(map);
        }
    }
This is {@link SurrogateAuthenticationPostProcessor}.

@author Misagh Moayyed
@since 5.2.0
support/cas-server-support-surrogate-core/src/main/java/org/apereo/cas/authentication/SurrogateAuthenticationPostProcessor.java