package org.apereo.cas.adaptors.jdbc.config; import org.apache.commons.lang3.StringUtils; import org.apereo.cas.adaptors.jdbc.BindModeSearchDatabaseAuthenticationHandler; import org.apereo.cas.adaptors.jdbc.QueryAndEncodeDatabaseAuthenticationHandler; import org.apereo.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler; import org.apereo.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler; import org.apereo.cas.authentication.AuthenticationEventExecutionPlan; import org.apereo.cas.authentication.AuthenticationHandler; import org.apereo.cas.authentication.principal.DefaultPrincipalFactory; import org.apereo.cas.authentication.principal.PrincipalFactory; import org.apereo.cas.authentication.principal.PrincipalResolver; import org.apereo.cas.authentication.support.password.PasswordPolicyConfiguration; import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer; import org.apereo.cas.configuration.CasConfigurationProperties; import org.apereo.cas.configuration.model.support.jdbc.JdbcAuthenticationProperties; import org.apereo.cas.configuration.support.Beans; import org.apereo.cas.services.ServicesManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 java.util.Collection; import java.util.HashSet; import java.util.Map; /** * This is {@link CasJdbcAuthenticationConfiguration}. * * @author Misagh Moayyed * @since 5.0.0 */ @Configuration("CasJdbcAuthenticationConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) public class CasJdbcAuthenticationConfiguration { private static final Logger LOGGER = LoggerFactory.getLogger(CasJdbcAuthenticationConfiguration.class); @Autowired(required = false) @Qualifier("queryAndEncodePasswordPolicyConfiguration") private PasswordPolicyConfiguration queryAndEncodePasswordPolicyConfiguration; @Autowired(required = false) @Qualifier("searchModePasswordPolicyConfiguration") private PasswordPolicyConfiguration searchModePasswordPolicyConfiguration; @Autowired(required = false) @Qualifier("queryPasswordPolicyConfiguration") private PasswordPolicyConfiguration queryPasswordPolicyConfiguration; @Autowired(required = false) @Qualifier("bindSearchPasswordPolicyConfiguration") private PasswordPolicyConfiguration bindSearchPasswordPolicyConfiguration; @Autowired @Qualifier("servicesManager") private ServicesManager servicesManager; @Autowired private CasConfigurationProperties casProperties; @ConditionalOnMissingBean(name = "jdbcAuthenticationHandlers") @Bean @RefreshScope public Collection<AuthenticationHandler> jdbcAuthenticationHandlers() { final Collection<AuthenticationHandler> handlers = new HashSet<>(); final JdbcAuthenticationProperties jdbc = casProperties.getAuthn().getJdbc(); jdbc.getBind().forEach(b -> handlers.add(bindModeSearchDatabaseAuthenticationHandler(b))); jdbc.getEncode().forEach(b -> handlers.add(queryAndEncodeDatabaseAuthenticationHandler(b))); jdbc.getQuery().forEach(b -> handlers.add(queryDatabaseAuthenticationHandler(b))); jdbc.getSearch().forEach(b -> handlers.add(searchModeSearchDatabaseAuthenticationHandler(b))); return handlers; } private AuthenticationHandler bindModeSearchDatabaseAuthenticationHandler(final JdbcAuthenticationProperties.Bind b) { final BindModeSearchDatabaseAuthenticationHandler h = new BindModeSearchDatabaseAuthenticationHandler(b.getName(), servicesManager, jdbcPrincipalFactory(), b.getOrder(), Beans.newDataSource(b)); h.setPasswordEncoder(Beans.newPasswordEncoder(b.getPasswordEncoder())); h.setPrincipalNameTransformer(Beans.newPrincipalNameTransformer(b.getPrincipalTransformation())); if (bindSearchPasswordPolicyConfiguration != null) { h.setPasswordPolicyConfiguration(bindSearchPasswordPolicyConfiguration); } h.setPrincipalNameTransformer(Beans.newPrincipalNameTransformer(b.getPrincipalTransformation())); if (StringUtils.isNotBlank(b.getCredentialCriteria())) { h.setCredentialSelectionPredicate(Beans.newCredentialSelectionPredicate(b.getCredentialCriteria())); } LOGGER.debug("Created authentication handler [{}] to handle database url at [{}]", h.getName(), b.getUrl()); return h; } private AuthenticationHandler queryAndEncodeDatabaseAuthenticationHandler(final JdbcAuthenticationProperties.Encode b) { final QueryAndEncodeDatabaseAuthenticationHandler h = new QueryAndEncodeDatabaseAuthenticationHandler(b.getName(), servicesManager, jdbcPrincipalFactory(), b.getOrder(), Beans.newDataSource(b), b.getAlgorithmName(), b.getSql(), b.getPasswordFieldName(), b.getSaltFieldName(), b.getExpiredFieldName(), b.getDisabledFieldName(), b.getNumberOfIterationsFieldName(), b.getNumberOfIterations(), b.getStaticSalt()); h.setPasswordEncoder(Beans.newPasswordEncoder(b.getPasswordEncoder())); h.setPrincipalNameTransformer(Beans.newPrincipalNameTransformer(b.getPrincipalTransformation())); if (queryAndEncodePasswordPolicyConfiguration != null) { h.setPasswordPolicyConfiguration(queryAndEncodePasswordPolicyConfiguration); } h.setPrincipalNameTransformer(Beans.newPrincipalNameTransformer(b.getPrincipalTransformation())); if (StringUtils.isNotBlank(b.getCredentialCriteria())) { h.setCredentialSelectionPredicate(Beans.newCredentialSelectionPredicate(b.getCredentialCriteria())); } LOGGER.debug("Created authentication handler [{}] to handle database url at [{}]", h.getName(), b.getUrl()); return h; } private AuthenticationHandler queryDatabaseAuthenticationHandler(final JdbcAuthenticationProperties.Query b) { final Map<String, String> attributes = Beans.transformPrincipalAttributesListIntoMap(b.getPrincipalAttributeList()); LOGGER.debug("Created and mapped principal attributes [{}] for [{}]...", attributes, b.getUrl()); final QueryDatabaseAuthenticationHandler h = new QueryDatabaseAuthenticationHandler(b.getName(), servicesManager, jdbcPrincipalFactory(), b.getOrder(), Beans.newDataSource(b), b.getSql(), b.getFieldPassword(), b.getFieldExpired(), b.getFieldDisabled(), attributes); h.setPasswordEncoder(Beans.newPasswordEncoder(b.getPasswordEncoder())); h.setPrincipalNameTransformer(Beans.newPrincipalNameTransformer(b.getPrincipalTransformation())); if (queryPasswordPolicyConfiguration != null) { h.setPasswordPolicyConfiguration(queryPasswordPolicyConfiguration); } h.setPrincipalNameTransformer(Beans.newPrincipalNameTransformer(b.getPrincipalTransformation())); if (StringUtils.isNotBlank(b.getCredentialCriteria())) { h.setCredentialSelectionPredicate(Beans.newCredentialSelectionPredicate(b.getCredentialCriteria())); } LOGGER.debug("Created authentication handler [{}] to handle database url at [{}]", h.getName(), b.getUrl()); return h; } private AuthenticationHandler searchModeSearchDatabaseAuthenticationHandler(final JdbcAuthenticationProperties.Search b) { final SearchModeSearchDatabaseAuthenticationHandler h = new SearchModeSearchDatabaseAuthenticationHandler(b.getName(), servicesManager, jdbcPrincipalFactory(), b.getOrder(), Beans.newDataSource(b), b.getFieldUser(), b.getFieldPassword(), b.getTableUsers()); h.setPasswordEncoder(Beans.newPasswordEncoder(b.getPasswordEncoder())); h.setPrincipalNameTransformer(Beans.newPrincipalNameTransformer(b.getPrincipalTransformation())); h.setPrincipalNameTransformer(Beans.newPrincipalNameTransformer(b.getPrincipalTransformation())); if (searchModePasswordPolicyConfiguration != null) { h.setPasswordPolicyConfiguration(searchModePasswordPolicyConfiguration); } if (StringUtils.isNotBlank(b.getCredentialCriteria())) { h.setCredentialSelectionPredicate(Beans.newCredentialSelectionPredicate(b.getCredentialCriteria())); } LOGGER.debug("Created authentication handler [{}] to handle database url at [{}]", h.getName(), b.getUrl()); return h; } @ConditionalOnMissingBean(name = "jdbcPrincipalFactory") @Bean @RefreshScope public PrincipalFactory jdbcPrincipalFactory() { return new DefaultPrincipalFactory(); } /** * The type Jdbc authentication event execution plan configuration. */ @Configuration("jdbcAuthenticationEventExecutionPlanConfiguration") @EnableConfigurationProperties(CasConfigurationProperties.class) public class JdbcAuthenticationEventExecutionPlanConfiguration implements AuthenticationEventExecutionPlanConfigurer { @Autowired @Qualifier("personDirectoryPrincipalResolver") private PrincipalResolver personDirectoryPrincipalResolver; @Override public void configureAuthenticationExecutionPlan(final AuthenticationEventExecutionPlan plan) { jdbcAuthenticationHandlers().forEach(h -> plan.registerAuthenticationHandlerWithPrincipalResolver(h, personDirectoryPrincipalResolver)); } } }