protected Map<String, List<Object>> retrievePersonAttributes(final String principalId,
                                                                 final Credential credential,
                                                                 final Optional<Principal> currentPrincipal,
                                                                 final Map<String, List<Object>> queryAttributes,
                                                                 final Optional<Service> givenService,
                                                                 final Optional<AuthenticationHandler> handler) throws Throwable {

        queryAttributes.computeIfAbsent("credentialId", __ -> CollectionUtils.wrapList(credential.getId()));
        queryAttributes.computeIfAbsent("credentialClass", __ -> CollectionUtils.wrapList(credential.getClass().getSimpleName()));

        val attributes = new LinkedHashMap<String, List<Object>>();
        currentPrincipal.ifPresent(p -> {
            attributes.putAll(p.getAttributes());
            attributes.put("currentPrincipalId", CollectionUtils.wrap(p.getId()));
        });
        val principal = context.getPrincipalFactory().createPrincipal(principalId, attributes);
        val service = givenService.orElse(null);
        val query = AttributeRepositoryQuery.builder()
            .principal(principal)
            .activeRepositoryIds(context.getActiveAttributeRepositoryIdentifiers())
            .authenticationHandler(handler.orElse(null))
            .service(service)
            .tenant(credential.getTenant())
            .build();

        val repositoryIds = context.getAttributeRepositoryResolver().resolve(query);
        LOGGER.debug("The following attribute repository IDs are resolved: [{}]", repositoryIds);

        val attributeRepository = determineAttributeRepository(query);
        try {
            val attributeFetcher = PrincipalAttributeRepositoryFetcher
                .builder()
                .attributeRepository(attributeRepository)
                .principalId(principalId)
                .activeAttributeRepositoryIdentifiers(repositoryIds)
                .currentPrincipal(currentPrincipal.orElse(null))
                .queryAttributes(queryAttributes)
                .service(service)
                .build();
            return attributeFetcher.retrieve();
        } finally {
            if (attributeRepository instanceof final AggregatingPersonAttributeDao aggregate) {
                val repositories = aggregate.getPersonAttributeDaos();
                for (val repository : repositories) {
                    if (repository.isDisposable() && repository instanceof final DisposableBean db) {
                        db.destroy();
                    }
                }
            }
        }
    }
Resolves principals by querying a data source using the Person Directory API.
The {@link Principal#getAttributes()} are populated by the results of the
query and the principal ID may optionally be set by proving an attribute whose first non-null value is used;
otherwise the credential ID is used for the principal ID.

@author Marvin S. Addison
@since 4.0.0
support/cas-server-support-person-directory-core/src/main/java/org/apereo/cas/authentication/principal/resolvers/PersonDirectoryPrincipalResolver.java