@Override
    public DuoSecurityAuthenticationResult authenticateInternal(final Credential credential) throws Exception {
        val duoCredential = (DuoSecurityUniversalPromptCredential) credential;
        LOGGER.trace("Exchanging Duo Security authorization code [{}]", credential.getId());

        val principalId = getDuoPrincipalId(duoCredential);
        val client = duoClient.getInstance();
        val result = client.exchangeAuthorizationCodeFor2FAResult(credential.getId(), principalId);
        LOGGER.debug("Validated Duo Security code [{}] with result [{}]", credential.getId(), result);

        val username = StringUtils.defaultIfBlank(result.getPreferred_username(), result.getSub());
        val attributes = new LinkedHashMap<String, List<Object>>();
        if (properties.isCollectDuoAttributes()) {
            attributes.putAll(collectDuoAuthenticationAttributes(result));
            attributes.putAll(collectDuoAuthenticationContextAttributes(result));
            attributes.putAll(collectDuoAuthenticationResultAttributes(result));
        }
        return DuoSecurityAuthenticationResult.builder()
            .success(true)
            .username(username)
            .attributes(attributes)
            .build();
    }
An abstraction that encapsulates interaction with
Duo 2fa authentication service via its universal prompt API.

@author Misagh Moayyed
@since 6.3.0
support/cas-server-support-duo-core/src/main/java/org/apereo/cas/adaptors/duo/authn/UniversalPromptDuoSecurityAuthenticationService.java