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

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

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

import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.features.CasFeatureModule;
import org.apereo.cas.support.saml.OpenSamlConfigBean;
import org.apereo.cas.support.saml.SamlUtils;
import org.apereo.cas.support.saml.mdui.AbstractMetadataResolverAdapter;
import org.apereo.cas.support.saml.mdui.ChainingMetadataResolverAdapter;
import org.apereo.cas.support.saml.mdui.DynamicMetadataResolverAdapter;
import org.apereo.cas.support.saml.mdui.MetadataResolverAdapter;
import org.apereo.cas.support.saml.mdui.StaticMetadataResolverAdapter;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.cas.util.ResourceUtils;
import org.apereo.cas.util.spring.boot.ConditionalOnFeatureEnabled;

import com.google.common.base.Splitter;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.jooq.lambda.Unchecked;
import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain;
import org.opensaml.saml.metadata.resolver.filter.impl.RequiredValidUntilFilter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfiguration;
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.ScopedProxyMode;
import org.springframework.core.io.Resource;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * This is {@link SamlMetadataUIConfiguration}.
 *
 * @author Misagh Moayyed
 * @since 5.0.0
 */
@EnableConfigurationProperties(CasConfigurationProperties.class)
@Slf4j
@ConditionalOnFeatureEnabled(feature = CasFeatureModule.FeatureCatalog.SAML)
@AutoConfiguration
public class SamlMetadataUIConfiguration {

    private static final String DEFAULT_SEPARATOR = "::";

    private static MetadataResolverAdapter configureAdapter(
        final AbstractMetadataResolverAdapter adapter,
        final ConfigurableApplicationContext applicationContext,
        final CasConfigurationProperties casProperties,
        final OpenSamlConfigBean openSamlConfigBean) {
        val resources = new HashMap();
        val chain = new MetadataFilterChain();
        casProperties.getSamlMetadataUi().getResources()
            .forEach(Unchecked.consumer(r -> configureResource(applicationContext, resources, chain, r, casProperties)));
        adapter.setRequireValidMetadata(casProperties.getSamlMetadataUi().isRequireValidMetadata());
        adapter.setMetadataResources(resources);
        adapter.setConfigBean(openSamlConfigBean);
        return adapter;
    }

    private static void configureResource(
        final ConfigurableApplicationContext applicationContext,
        final Map resources,
        final MetadataFilterChain chain,
        final String resourceArray,
        final CasConfigurationProperties casProperties) {
        val splitArray = org.springframework.util.StringUtils.commaDelimitedListToStringArray(resourceArray);
        Arrays.stream(splitArray).forEach(Unchecked.consumer(entry -> {
            val arr = Splitter.on(DEFAULT_SEPARATOR).splitToList(entry);
            val metadataFile = arr.getFirst();
            val signingKey = arr.size() > 1 ? arr.get(1) : null;
            val filters = new ArrayList();
            if (casProperties.getSamlMetadataUi().getMaxValidity() > 0) {
                val filter = new RequiredValidUntilFilter();
                filter.setMaxValidityInterval(Duration.ofSeconds(casProperties.getSamlMetadataUi().getMaxValidity()));
                filter.initialize();
                filters.add(filter);
            }
            var addResource = true;
            if (StringUtils.isNotBlank(signingKey)) {
                val sigFilter = SamlUtils.buildSignatureValidationFilter(applicationContext, signingKey);
                if (sigFilter != null) {
                    sigFilter.setRequireSignedRoot(casProperties.getSamlMetadataUi().isRequireSignedRoot());
                    sigFilter.initialize();
                    filters.add(sigFilter);
                } else {
                    LOGGER.warn("Failed to locate the signing key [{}] for [{}]", signingKey, metadataFile);
                    addResource = false;
                }
            }
            chain.setFilters(filters);
            val resource = applicationContext.getResource(metadataFile);
            if (addResource && ResourceUtils.doesResourceExist(resource)) {
                resources.put(resource, chain);
            } else {
                LOGGER.warn("Skipping metadata [{}]; Either the resource cannot be retrieved or its signing key is missing", metadataFile);
            }
        }));
    }

    @ConditionalOnMissingBean(name = "chainingSamlMetadataUIMetadataResolverAdapter")
    @Bean
    @RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
    public MetadataResolverAdapter chainingSamlMetadataUIMetadataResolverAdapter(
        final CasConfigurationProperties casProperties,
        final ConfigurableApplicationContext applicationContext,
        @Qualifier(OpenSamlConfigBean.DEFAULT_BEAN_NAME)
        final OpenSamlConfigBean openSamlConfigBean) {
        val staticAdapter = new StaticMetadataResolverAdapter();
        configureAdapter(staticAdapter, applicationContext, casProperties, openSamlConfigBean);
        staticAdapter.buildMetadataResolverAggregate();

        val dynaAdapter = new DynamicMetadataResolverAdapter();
        configureAdapter(dynaAdapter, applicationContext, casProperties, openSamlConfigBean);
        return new ChainingMetadataResolverAdapter(CollectionUtils.wrapSet(staticAdapter, dynaAdapter));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy