All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apereo.cas.config.CasPersonDirectoryJdbcConfiguration Maven / Gradle / Ivy

There is a newer version: 7.2.0-RC4
Show newest version
package org.apereo.cas.config;

import org.apereo.cas.authentication.attribute.CaseCanonicalizationMode;
import org.apereo.cas.authentication.principal.attribute.PersonAttributeDao;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.features.CasFeatureModule;
import org.apereo.cas.configuration.model.core.authentication.AttributeRepositoryStates;
import org.apereo.cas.configuration.model.support.jdbc.JdbcPrincipalAttributesProperties;
import org.apereo.cas.configuration.support.JpaBeans;
import org.apereo.cas.jdbc.AbstractJdbcPersonAttributeDao;
import org.apereo.cas.jdbc.MultiRowJdbcPersonAttributeDao;
import org.apereo.cas.jdbc.QueryType;
import org.apereo.cas.jdbc.SingleRowJdbcPersonAttributeDao;
import org.apereo.cas.persondir.PersonDirectoryAttributeRepositoryPlanConfigurer;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.cas.util.function.FunctionUtils;
import org.apereo.cas.util.spring.SpringExpressionLanguageValueResolver;
import org.apereo.cas.util.spring.beans.BeanCondition;
import org.apereo.cas.util.spring.beans.BeanContainer;
import org.apereo.cas.util.spring.beans.BeanSupplier;
import org.apereo.cas.util.spring.boot.ConditionalOnFeatureEnabled;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ScopedProxyMode;
import java.util.ArrayList;
import java.util.Locale;
import java.util.stream.Collectors;

/**
 * This is {@link CasPersonDirectoryJdbcConfiguration}.
 *
 * @author Misagh Moayyed
 * @since 6.4.0
 */
@ConditionalOnClass(JpaBeans.class)
@Slf4j
@ConditionalOnFeatureEnabled(feature = CasFeatureModule.FeatureCatalog.PersonDirectory)
@EnableConfigurationProperties(CasConfigurationProperties.class)
@Configuration(value = "CasPersonDirectoryJdbcConfiguration", proxyBeanMethods = false)
class CasPersonDirectoryJdbcConfiguration {
    private static final BeanCondition CONDITION = BeanCondition.on("cas.authn.attribute-repository.jdbc[0].sql");

    @Configuration(value = "JdbcAttributeRepositoryConfiguration", proxyBeanMethods = false)
    @EnableConfigurationProperties(CasConfigurationProperties.class)
    static class JdbcAttributeRepositoryConfiguration {
        @ConditionalOnMissingBean(name = "jdbcAttributeRepositories")
        @Bean
        @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
        public BeanContainer jdbcAttributeRepositories(
            final ConfigurableApplicationContext applicationContext,
            final CasConfigurationProperties casProperties) {
            return BeanSupplier.of(BeanContainer.class)
                .when(CONDITION.given(applicationContext.getEnvironment()))
                .supply(() -> {
                    val list = new ArrayList();
                    val attrs = casProperties.getAuthn().getAttributeRepository();
                    attrs.getJdbc()
                        .stream()
                        .filter(jdbc -> StringUtils.isNotBlank(jdbc.getSql()) && StringUtils.isNotBlank(jdbc.getUrl()))
                        .forEach(jdbc -> {
                            val jdbcDao = createJdbcPersonAttributeDao(jdbc);
                            FunctionUtils.doIfNotNull(jdbc.getId(), id -> jdbcDao.setId(id));

                            val queryAttributes = CollectionUtils.wrap("username", jdbc.getUsername());
                            queryAttributes.putAll(jdbc.getQueryAttributes());
                            jdbcDao.setQueryAttributeMapping(queryAttributes);

                            val mapping = jdbc.getAttributes();
                            if (mapping != null && !mapping.isEmpty()) {
                                LOGGER.debug("Configured result attribute mapping for [{}] to be [{}]", jdbc.getUrl(), jdbc.getAttributes());
                                jdbcDao.setResultAttributeMapping(mapping);
                            }
                            jdbcDao.setRequireAllQueryAttributes(jdbc.isRequireAllAttributes());

                            val caseMode = CaseCanonicalizationMode.valueOf(jdbc.getCaseCanonicalization().toUpperCase(Locale.ENGLISH));
                            jdbcDao.setUsernameCaseCanonicalizationMode(caseMode);
                            jdbcDao.setDefaultCaseCanonicalizationMode(caseMode);
                            jdbcDao.setQueryType(QueryType.valueOf(jdbc.getQueryType().toUpperCase(Locale.ENGLISH)));
                            jdbcDao.setOrder(jdbc.getOrder());
                            jdbcDao.setEnabled(jdbc.getState() != AttributeRepositoryStates.DISABLED);
                            jdbcDao.putTag(PersonDirectoryAttributeRepositoryPlanConfigurer.class.getSimpleName(),
                                jdbc.getState() == AttributeRepositoryStates.ACTIVE);
                            list.add(jdbcDao);
                        });
                    return BeanContainer.of(list);
                })
                .otherwise(BeanContainer::empty)
                .get();
        }

        private static AbstractJdbcPersonAttributeDao configureJdbcPersonAttributeDao(
            final AbstractJdbcPersonAttributeDao dao, final JdbcPrincipalAttributesProperties jdbc) {

            val attributes = jdbc.getCaseInsensitiveQueryAttributes();
            val results = CollectionUtils.convertDirectedListToMap(attributes);

            dao.setCaseInsensitiveQueryAttributes(results
                .entrySet()
                .stream()
                .map(entry -> Pair.of(entry.getKey(),
                    StringUtils.isBlank(entry.getValue())
                        ? CaseCanonicalizationMode.valueOf(jdbc.getCaseCanonicalization().toUpperCase(Locale.ENGLISH))
                        : CaseCanonicalizationMode.valueOf(entry.getValue().toUpperCase(Locale.ENGLISH))))
                .collect(Collectors.toMap(Pair::getKey, Pair::getValue)));
            return dao;
        }

        private static AbstractJdbcPersonAttributeDao createJdbcPersonAttributeDao(final JdbcPrincipalAttributesProperties jdbc) {
            val url = SpringExpressionLanguageValueResolver.getInstance().resolve(jdbc.getUrl());
            val sql = SpringExpressionLanguageValueResolver.getInstance().resolve(jdbc.getSql());
            if (jdbc.isSingleRow()) {
                LOGGER.debug("Configured single-row JDBC attribute repository for [{}]", url);
                val singleRow = new SingleRowJdbcPersonAttributeDao(JpaBeans.newDataSource(jdbc), sql);
                return configureJdbcPersonAttributeDao(singleRow, jdbc);
            }
            LOGGER.debug("Configured multi-row JDBC attribute repository for [{}]", url);
            val jdbcDao = new MultiRowJdbcPersonAttributeDao(JpaBeans.newDataSource(jdbc), sql);
            LOGGER.debug("Configured multi-row JDBC column mappings for [{}] are [{}]", url, jdbc.getColumnMappings());
            jdbcDao.setNameValueColumnMappings(jdbc.getColumnMappings());
            return configureJdbcPersonAttributeDao(jdbcDao, jdbc);
        }
    }

    @Configuration(value = "JdbcAttributeRepositoryPlanConfiguration", proxyBeanMethods = false)
    @EnableConfigurationProperties(CasConfigurationProperties.class)
    static class JdbcAttributeRepositoryPlanConfiguration {
        @Bean
        @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
        @ConditionalOnMissingBean(name = "jdbcPersonDirectoryAttributeRepositoryPlanConfigurer")
        public PersonDirectoryAttributeRepositoryPlanConfigurer jdbcPersonDirectoryAttributeRepositoryPlanConfigurer(
            final ConfigurableApplicationContext applicationContext,
            @Qualifier("jdbcAttributeRepositories")
            final BeanContainer jdbcAttributeRepositories) {
            return BeanSupplier.of(PersonDirectoryAttributeRepositoryPlanConfigurer.class)
                .when(CONDITION.given(applicationContext.getEnvironment()))
                .supply(() -> plan -> {
                    val results = jdbcAttributeRepositories.toList()
                        .stream()
                        .filter(PersonAttributeDao::isEnabled)
                        .collect(Collectors.toList());
                    plan.registerAttributeRepositories(results);
                })
                .otherwiseProxy()
                .get();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy