package org.apereo.cas.config; import net.shibboleth.ext.spring.resource.ResourceHelper; import org.apereo.cas.authentication.AuthenticationSystemSupport; import org.apereo.cas.authentication.principal.ServiceFactory; import org.apereo.cas.authentication.principal.WebApplicationService; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.configuration.model.support.saml.idp.SamlIdPProperties; import org.apereo.cas.logout.SingleLogoutServiceLogoutUrlBuilder; import org.apereo.cas.services.ServicesManager; import org.apereo.cas.support.saml.OpenSamlConfigBean; import org.apereo.cas.support.saml.services.SamlIdPSingleLogoutServiceLogoutUrlBuilder; import org.apereo.cas.support.saml.services.idp.metadata.cache.ChainingMetadataResolverCacheLoader; import org.apereo.cas.support.saml.services.idp.metadata.cache.DefaultSamlRegisteredServiceCachingMetadataResolver; import org.apereo.cas.support.saml.services.idp.metadata.cache.SamlRegisteredServiceCachingMetadataResolver; import org.apereo.cas.support.saml.web.idp.metadata.SamlIdpMetadataAndCertificatesGenerationService; import org.apereo.cas.support.saml.web.idp.metadata.SamlMetadataController; import org.apereo.cas.support.saml.web.idp.metadata.TemplatedMetadataAndCertificatesGenerationService; import org.apereo.cas.support.saml.web.idp.profile.ECPProfileHandlerController; import org.apereo.cas.support.saml.web.idp.profile.IdPInitiatedProfileHandlerController; import org.apereo.cas.support.saml.web.idp.profile.builders.AuthnContextClassRefBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.DefaultAuthnContextClassRefBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.SamlProfileObjectBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.SamlProfileSamlAssertionBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.SamlProfileSamlAttributeStatementBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.SamlProfileSamlAuthNStatementBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.SamlProfileSamlConditionsBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.SamlProfileSamlNameIdBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.SamlProfileSamlSubjectBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.enc.BaseSamlObjectSigner; import org.apereo.cas.support.saml.web.idp.profile.builders.enc.SamlAttributeEncoder; import org.apereo.cas.support.saml.web.idp.profile.builders.enc.SamlIdPObjectSignatureValidator; import org.apereo.cas.support.saml.web.idp.profile.builders.enc.SamlObjectEncrypter; import org.apereo.cas.support.saml.web.idp.profile.builders.enc.SamlObjectSignatureValidator; import org.apereo.cas.support.saml.web.idp.profile.builders.response.SamlProfileSaml2ResponseBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.response.SamlProfileSamlSoap11FaultResponseBuilder; import org.apereo.cas.support.saml.web.idp.profile.builders.response.SamlProfileSamlSoap11ResponseBuilder; import org.apereo.cas.support.saml.web.idp.profile.slo.SLOPostProfileHandlerController; import org.apereo.cas.support.saml.web.idp.profile.slo.SLORedirectProfileHandlerController; import org.apereo.cas.support.saml.web.idp.profile.sso.SSOPostProfileCallbackHandlerController; import org.apereo.cas.support.saml.web.idp.profile.sso.SSOPostProfileHandlerController; import org.apereo.cas.util.http.HttpClient; import org.opensaml.saml.metadata.resolver.MetadataResolver; import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver; import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.AttributeStatement; import org.opensaml.saml.saml2.core.AuthnStatement; import org.opensaml.saml.saml2.core.Conditions; import org.opensaml.saml.saml2.core.NameID; import org.opensaml.saml.saml2.ecp.Response; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; 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.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.FileSystemResource; import org.springframework.ui.velocity.VelocityEngineFactory; import javax.net.ssl.HostnameVerifier; /** * The {@link SamlIdPConfiguration}. * * @author Misagh Moayyed * @since 5.0.0 */ @Configuration("samlIdPConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) public class SamlIdPConfiguration { @Autowired private CasConfigurationProperties casProperties; @Autowired @Qualifier("hostnameVerifier") private HostnameVerifier hostnameVerifier; @Autowired @Qualifier("servicesManager") private ServicesManager servicesManager; @Autowired @Qualifier("noRedirectHttpClient") private HttpClient httpClient; @Autowired @Qualifier("shibboleth.OpenSAMLConfig") private OpenSamlConfigBean openSamlConfigBean; @Autowired @Qualifier("shibboleth.VelocityEngine") private VelocityEngineFactory velocityEngineFactory; @Autowired @Qualifier("webApplicationServiceFactory") private ServiceFactory<WebApplicationService> webApplicationServiceFactory; @Autowired @Qualifier("defaultAuthenticationSystemSupport") private AuthenticationSystemSupport authenticationSystemSupport; @Bean public SingleLogoutServiceLogoutUrlBuilder singleLogoutServiceLogoutUrlBuilder() { return new SamlIdPSingleLogoutServiceLogoutUrlBuilder(servicesManager, defaultSamlRegisteredServiceCachingMetadataResolver()); } @ConditionalOnMissingBean(name = "chainingMetadataResolverCacheLoader") @Bean @RefreshScope public ChainingMetadataResolverCacheLoader chainingMetadataResolverCacheLoader() { return new ChainingMetadataResolverCacheLoader( openSamlConfigBean, httpClient ); } @ConditionalOnMissingBean(name = "defaultSamlRegisteredServiceCachingMetadataResolver") @Bean @RefreshScope public SamlRegisteredServiceCachingMetadataResolver defaultSamlRegisteredServiceCachingMetadataResolver() { return new DefaultSamlRegisteredServiceCachingMetadataResolver( casProperties.getAuthn().getSamlIdp().getMetadata().getCacheExpirationMinutes(), chainingMetadataResolverCacheLoader() ); } @ConditionalOnMissingBean(name = "samlProfileSamlResponseBuilder") @Bean @RefreshScope public SamlProfileObjectBuilder<org.opensaml.saml.saml2.core.Response> samlProfileSamlResponseBuilder() { return new SamlProfileSaml2ResponseBuilder( openSamlConfigBean, samlObjectSigner(), velocityEngineFactory, samlProfileSamlAssertionBuilder(), samlObjectEncrypter()); } @ConditionalOnMissingBean(name = "samlProfileSamlSubjectBuilder") @Bean @RefreshScope public SamlProfileSamlSubjectBuilder samlProfileSamlSubjectBuilder() { return new SamlProfileSamlSubjectBuilder(openSamlConfigBean, samlProfileSamlNameIdBuilder(), casProperties.getAuthn().getSamlIdp().getResponse().getSkewAllowance()); } @ConditionalOnMissingBean(name = "samlObjectEncrypter") @Bean @RefreshScope public SamlObjectEncrypter samlObjectEncrypter() { final SamlIdPProperties.Algorithms algs = casProperties.getAuthn().getSamlIdp().getAlgs(); return new SamlObjectEncrypter(algs.getOverrideDataEncryptionAlgorithms(), algs.getOverrideKeyEncryptionAlgorithms(), algs.getOverrideBlackListedEncryptionAlgorithms(), algs.getOverrideWhiteListedAlgorithms()); } @ConditionalOnMissingBean(name = "samlObjectSigner") @Bean @RefreshScope public BaseSamlObjectSigner samlObjectSigner() { final SamlIdPProperties.Algorithms algs = casProperties.getAuthn().getSamlIdp().getAlgs(); return new BaseSamlObjectSigner( algs.getOverrideSignatureReferenceDigestMethods(), algs.getOverrideSignatureAlgorithms(), algs.getOverrideBlackListedSignatureSigningAlgorithms(), algs.getOverrideWhiteListedSignatureSigningAlgorithms()); } @ConditionalOnMissingBean(name = "shibbolethIdpMetadataAndCertificatesGenerationService") @Bean public SamlIdpMetadataAndCertificatesGenerationService shibbolethIdpMetadataAndCertificatesGenerationService() { return new TemplatedMetadataAndCertificatesGenerationService(); } @ConditionalOnMissingBean(name = "samlProfileSamlSoap11FaultResponseBuilder") @Bean @RefreshScope public SamlProfileObjectBuilder<Response> samlProfileSamlSoap11FaultResponseBuilder() { return new SamlProfileSamlSoap11FaultResponseBuilder( openSamlConfigBean, samlObjectSigner(), velocityEngineFactory, samlProfileSamlAssertionBuilder(), samlProfileSamlResponseBuilder(), samlObjectEncrypter()); } @ConditionalOnMissingBean(name = "samlProfileSamlSoap11ResponseBuilder") @Bean @RefreshScope public SamlProfileObjectBuilder<Response> samlProfileSamlSoap11ResponseBuilder() { return new SamlProfileSamlSoap11ResponseBuilder( openSamlConfigBean, samlObjectSigner(), velocityEngineFactory, samlProfileSamlAssertionBuilder(), samlProfileSamlResponseBuilder(), samlObjectEncrypter()); } @ConditionalOnMissingBean(name = "samlProfileSamlNameIdBuilder") @Bean @RefreshScope public SamlProfileObjectBuilder<NameID> samlProfileSamlNameIdBuilder() { return new SamlProfileSamlNameIdBuilder(openSamlConfigBean); } @ConditionalOnMissingBean(name = "samlProfileSamlConditionsBuilder") @Bean @RefreshScope public SamlProfileObjectBuilder<Conditions> samlProfileSamlConditionsBuilder() { return new SamlProfileSamlConditionsBuilder(openSamlConfigBean); } @ConditionalOnMissingBean(name = "defaultAuthnContextClassRefBuilder") @Bean @RefreshScope public AuthnContextClassRefBuilder defaultAuthnContextClassRefBuilder() { return new DefaultAuthnContextClassRefBuilder(); } @ConditionalOnMissingBean(name = "samlProfileSamlAssertionBuilder") @Bean @RefreshScope public SamlProfileObjectBuilder<Assertion> samlProfileSamlAssertionBuilder() { return new SamlProfileSamlAssertionBuilder(openSamlConfigBean, samlProfileSamlAuthNStatementBuilder(), samlProfileSamlAttributeStatementBuilder(), samlProfileSamlSubjectBuilder(), samlProfileSamlConditionsBuilder(), samlObjectSigner()); } @ConditionalOnMissingBean(name = "samlProfileSamlAuthNStatementBuilder") @Bean @RefreshScope public SamlProfileObjectBuilder<AuthnStatement> samlProfileSamlAuthNStatementBuilder() { return new SamlProfileSamlAuthNStatementBuilder(openSamlConfigBean, defaultAuthnContextClassRefBuilder()); } @ConditionalOnMissingBean(name = "samlProfileSamlAttributeStatementBuilder") @Bean @RefreshScope public SamlProfileObjectBuilder<AttributeStatement> samlProfileSamlAttributeStatementBuilder() { return new SamlProfileSamlAttributeStatementBuilder(openSamlConfigBean, new SamlAttributeEncoder()); } @ConditionalOnMissingBean(name = "samlIdPObjectSignatureValidator") @Bean public SamlObjectSignatureValidator samlIdPObjectSignatureValidator() { final SamlIdPProperties.Algorithms algs = casProperties.getAuthn().getSamlIdp().getAlgs(); return new SamlIdPObjectSignatureValidator( algs.getOverrideSignatureReferenceDigestMethods(), algs.getOverrideSignatureAlgorithms(), algs.getOverrideBlackListedSignatureSigningAlgorithms(), algs.getOverrideWhiteListedSignatureSigningAlgorithms(), casSamlIdPMetadataResolver() ); } @ConditionalOnMissingBean(name = "samlObjectSignatureValidator") @Bean public SamlObjectSignatureValidator samlObjectSignatureValidator() { final SamlIdPProperties.Algorithms algs = casProperties.getAuthn().getSamlIdp().getAlgs(); return new SamlObjectSignatureValidator( algs.getOverrideSignatureReferenceDigestMethods(), algs.getOverrideSignatureAlgorithms(), algs.getOverrideBlackListedSignatureSigningAlgorithms(), algs.getOverrideWhiteListedSignatureSigningAlgorithms() ); } @Bean @RefreshScope public SSOPostProfileHandlerController ssoPostProfileHandlerController() { return new SSOPostProfileHandlerController( samlObjectSigner(), openSamlConfigBean.getParserPool(), authenticationSystemSupport, servicesManager, webApplicationServiceFactory, defaultSamlRegisteredServiceCachingMetadataResolver(), openSamlConfigBean, samlProfileSamlResponseBuilder(), casProperties.getAuthn().getSamlIdp().getAuthenticationContextClassMappings(), casProperties.getServer().getPrefix(), casProperties.getServer().getName(), casProperties.getAuthn().getMfa().getRequestParameter(), casProperties.getServer().getLoginUrl(), casProperties.getServer().getLogoutUrl(), casProperties.getAuthn().getSamlIdp().getLogout().isForceSignedLogoutRequests(), casProperties.getAuthn().getSamlIdp().getLogout().isSingleLogoutCallbacksDisabled(), samlObjectSignatureValidator()); } @Bean @RefreshScope public SLORedirectProfileHandlerController sloRedirectProfileHandlerController() { final SamlIdPProperties idp = casProperties.getAuthn().getSamlIdp(); return new SLORedirectProfileHandlerController( samlObjectSigner(), openSamlConfigBean.getParserPool(), authenticationSystemSupport, servicesManager, webApplicationServiceFactory, defaultSamlRegisteredServiceCachingMetadataResolver(), openSamlConfigBean, samlProfileSamlResponseBuilder(), casProperties.getAuthn().getSamlIdp().getAuthenticationContextClassMappings(), casProperties.getServer().getPrefix(), casProperties.getServer().getName(), casProperties.getAuthn().getMfa().getRequestParameter(), casProperties.getServer().getLoginUrl(), casProperties.getServer().getLogoutUrl(), idp.getLogout().isForceSignedLogoutRequests(), idp.getLogout().isSingleLogoutCallbacksDisabled(), samlObjectSignatureValidator()); } @Bean @RefreshScope public SLOPostProfileHandlerController sloPostProfileHandlerController() { final SamlIdPProperties idp = casProperties.getAuthn().getSamlIdp(); return new SLOPostProfileHandlerController( samlObjectSigner(), openSamlConfigBean.getParserPool(), authenticationSystemSupport, servicesManager, webApplicationServiceFactory, defaultSamlRegisteredServiceCachingMetadataResolver(), openSamlConfigBean, samlProfileSamlResponseBuilder(), casProperties.getAuthn().getSamlIdp().getAuthenticationContextClassMappings(), casProperties.getServer().getPrefix(), casProperties.getServer().getName(), casProperties.getAuthn().getMfa().getRequestParameter(), casProperties.getServer().getLoginUrl(), casProperties.getServer().getLogoutUrl(), idp.getLogout().isForceSignedLogoutRequests(), idp.getLogout().isSingleLogoutCallbacksDisabled(), samlObjectSignatureValidator()); } @Bean @RefreshScope public IdPInitiatedProfileHandlerController idPInitiatedSamlProfileHandlerController() { final SamlIdPProperties idp = casProperties.getAuthn().getSamlIdp(); return new IdPInitiatedProfileHandlerController( samlObjectSigner(), openSamlConfigBean.getParserPool(), authenticationSystemSupport, servicesManager, webApplicationServiceFactory, defaultSamlRegisteredServiceCachingMetadataResolver(), openSamlConfigBean, samlProfileSamlResponseBuilder(), idp.getAuthenticationContextClassMappings(), casProperties.getServer().getPrefix(), casProperties.getServer().getName(), casProperties.getAuthn().getMfa().getRequestParameter(), casProperties.getServer().getLoginUrl(), casProperties.getServer().getLogoutUrl(), idp.getLogout().isForceSignedLogoutRequests(), idp.getLogout().isSingleLogoutCallbacksDisabled(), samlIdPObjectSignatureValidator()); } @Bean @RefreshScope public SSOPostProfileCallbackHandlerController ssoPostProfileCallbackHandlerController() { final SamlIdPProperties idp = casProperties.getAuthn().getSamlIdp(); return new SSOPostProfileCallbackHandlerController( samlObjectSigner(), openSamlConfigBean.getParserPool(), authenticationSystemSupport, servicesManager, webApplicationServiceFactory, defaultSamlRegisteredServiceCachingMetadataResolver(), openSamlConfigBean, samlProfileSamlResponseBuilder(), idp.getAuthenticationContextClassMappings(), casProperties.getServer().getPrefix(), casProperties.getServer().getName(), casProperties.getAuthn().getMfa().getRequestParameter(), casProperties.getServer().getLoginUrl(), casProperties.getServer().getLogoutUrl(), idp.getLogout().isForceSignedLogoutRequests(), idp.getLogout().isSingleLogoutCallbacksDisabled(), samlObjectSignatureValidator(), this.hostnameVerifier); } @Bean @RefreshScope public ECPProfileHandlerController ecpProfileHandlerController() { final SamlIdPProperties idp = casProperties.getAuthn().getSamlIdp(); return new ECPProfileHandlerController(samlObjectSigner(), openSamlConfigBean.getParserPool(), authenticationSystemSupport, servicesManager, webApplicationServiceFactory, defaultSamlRegisteredServiceCachingMetadataResolver(), openSamlConfigBean, samlProfileSamlSoap11ResponseBuilder(), samlProfileSamlSoap11FaultResponseBuilder(), idp.getAuthenticationContextClassMappings(), casProperties.getServer().getPrefix(), casProperties.getServer().getName(), casProperties.getAuthn().getMfa().getRequestParameter(), casProperties.getServer().getLoginUrl(), casProperties.getServer().getLogoutUrl(), idp.getLogout().isForceSignedLogoutRequests(), idp.getLogout().isSingleLogoutCallbacksDisabled(), samlObjectSignatureValidator()); } @Bean public MetadataResolver casSamlIdPMetadataResolver() { try { final SamlIdPProperties idp = casProperties.getAuthn().getSamlIdp(); final ResourceBackedMetadataResolver resolver = new ResourceBackedMetadataResolver( ResourceHelper.of(new FileSystemResource(idp.getMetadata().getMetadataFile()))); resolver.setParserPool(this.openSamlConfigBean.getParserPool()); resolver.setFailFastInitialization(idp.getMetadata().isFailFast()); resolver.setRequireValidMetadata(idp.getMetadata().isRequireValidMetadata()); resolver.setId(idp.getEntityId()); resolver.initialize(); return resolver; } catch (final Exception e) { throw new BeanCreationException(e.getMessage(), e); } } @Bean @RefreshScope public SamlMetadataController samlMetadataController() { return new SamlMetadataController(shibbolethIdpMetadataAndCertificatesGenerationService()); } }