All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apereo.cas.config.YubiKeyAuthenticationEventExecutionPlanConfiguration Maven / Gradle / Ivy
package org.apereo.cas.config;
import org.apereo.cas.adaptors.yubikey.AcceptAllYubiKeyAccountValidator;
import org.apereo.cas.adaptors.yubikey.DefaultYubiKeyAccountValidator;
import org.apereo.cas.adaptors.yubikey.DenyAllYubiKeyAccountValidator;
import org.apereo.cas.adaptors.yubikey.YubiKeyAccount;
import org.apereo.cas.adaptors.yubikey.YubiKeyAccountRegistry;
import org.apereo.cas.adaptors.yubikey.YubiKeyAccountValidator;
import org.apereo.cas.adaptors.yubikey.YubiKeyAuthenticationHandler;
import org.apereo.cas.adaptors.yubikey.YubiKeyCredential;
import org.apereo.cas.adaptors.yubikey.YubiKeyMultifactorAuthenticationProvider;
import org.apereo.cas.adaptors.yubikey.YubiKeyMultifactorAuthenticatorDeviceManager;
import org.apereo.cas.adaptors.yubikey.YubiKeyRegisteredDevice;
import org.apereo.cas.adaptors.yubikey.registry.JsonYubiKeyAccountRegistry;
import org.apereo.cas.adaptors.yubikey.registry.OpenYubiKeyAccountRegistry;
import org.apereo.cas.adaptors.yubikey.registry.PermissiveYubiKeyAccountRegistry;
import org.apereo.cas.adaptors.yubikey.registry.RestfulYubiKeyAccountRegistry;
import org.apereo.cas.adaptors.yubikey.registry.YubiKeyAccountRegistryEndpoint;
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
import org.apereo.cas.authentication.AuthenticationHandler;
import org.apereo.cas.authentication.AuthenticationMetaDataPopulator;
import org.apereo.cas.authentication.MultifactorAuthenticationFailureModeEvaluator;
import org.apereo.cas.authentication.MultifactorAuthenticationProvider;
import org.apereo.cas.authentication.bypass.MultifactorAuthenticationProviderBypassEvaluator;
import org.apereo.cas.authentication.device.MultifactorAuthenticationDeviceManager;
import org.apereo.cas.authentication.handler.ByCredentialTypeAuthenticationHandlerResolver;
import org.apereo.cas.authentication.metadata.AuthenticationContextAttributeMetaDataPopulator;
import org.apereo.cas.authentication.metadata.MultifactorAuthenticationProviderMetadataPopulator;
import org.apereo.cas.authentication.principal.PrincipalFactory;
import org.apereo.cas.authentication.principal.PrincipalFactoryUtils;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.features.CasFeatureModule;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.util.ResourceUtils;
import org.apereo.cas.util.crypto.CipherExecutor;
import org.apereo.cas.util.http.HttpClient;
import org.apereo.cas.util.spring.SpringExpressionLanguageValueResolver;
import org.apereo.cas.util.spring.boot.ConditionalOnFeatureEnabled;
import com.yubico.client.v2.YubicoClient;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
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.time.Clock;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* This is {@link YubiKeyAuthenticationEventExecutionPlanConfiguration}.
*
* @author Misagh Moayyed
* @author Dmitriy Kopylenko
* @since 5.1.0
*/
@EnableConfigurationProperties(CasConfigurationProperties.class)
@Slf4j
@ConditionalOnFeatureEnabled(feature = CasFeatureModule.FeatureCatalog.YubiKey)
@Configuration(value = "YubiKeyAuthenticationEventExecutionPlanConfiguration", proxyBeanMethods = false)
class YubiKeyAuthenticationEventExecutionPlanConfiguration {
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
@ConditionalOnMissingBean(name = "yubikeyMultifactorProviderAuthenticationMetadataPopulator")
public AuthenticationMetaDataPopulator yubikeyMultifactorProviderAuthenticationMetadataPopulator(
@Qualifier(ServicesManager.BEAN_NAME) final ServicesManager servicesManager,
final CasConfigurationProperties casProperties,
@Qualifier("yubikeyMultifactorAuthenticationProvider") final ObjectProvider yubikeyMultifactorAuthenticationProvider) {
val authenticationContextAttribute = casProperties.getAuthn().getMfa().getCore().getAuthenticationContextAttribute();
return new MultifactorAuthenticationProviderMetadataPopulator(authenticationContextAttribute,
yubikeyMultifactorAuthenticationProvider, servicesManager);
}
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
@ConditionalOnMissingBean(name = "yubikeyAuthenticationMetaDataPopulator")
public AuthenticationMetaDataPopulator yubikeyAuthenticationMetaDataPopulator(
final CasConfigurationProperties casProperties,
@Qualifier("yubikeyAuthenticationHandler") final AuthenticationHandler yubikeyAuthenticationHandler,
@Qualifier("yubikeyMultifactorAuthenticationProvider") final MultifactorAuthenticationProvider yubikeyMultifactorAuthenticationProvider) {
val authenticationContextAttribute = casProperties.getAuthn().getMfa().getCore().getAuthenticationContextAttribute();
return new AuthenticationContextAttributeMetaDataPopulator(authenticationContextAttribute,
yubikeyAuthenticationHandler, yubikeyMultifactorAuthenticationProvider.getId());
}
@ConditionalOnMissingBean(name = "yubikeyPrincipalFactory")
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public PrincipalFactory yubikeyPrincipalFactory() {
return PrincipalFactoryUtils.newPrincipalFactory();
}
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
@Bean
@ConditionalOnMissingBean(name = "yubicoClient")
public YubicoClient yubicoClient(final CasConfigurationProperties casProperties) {
val yubi = casProperties.getAuthn().getMfa().getYubikey();
val client = YubicoClient.getClient(yubi.getClientId(), yubi.getSecretKey());
if (!yubi.getApiUrls().isEmpty()) {
val urls = yubi.getApiUrls().toArray(ArrayUtils.EMPTY_STRING_ARRAY);
client.setWsapiUrls(urls);
}
return client;
}
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
@ConditionalOnMissingBean(name = "yubikeyAuthenticationHandler")
public AuthenticationHandler yubikeyAuthenticationHandler(
final CasConfigurationProperties casProperties,
@Qualifier("yubikeyPrincipalFactory") final PrincipalFactory yubikeyPrincipalFactory,
@Qualifier("yubicoClient") final YubicoClient yubicoClient,
@Qualifier("yubiKeyAccountRegistry") final YubiKeyAccountRegistry yubiKeyAccountRegistry,
@Qualifier("yubikeyMultifactorAuthenticationProvider") final ObjectProvider multifactorAuthenticationProvider,
@Qualifier(ServicesManager.BEAN_NAME) final ServicesManager servicesManager) {
val yubi = casProperties.getAuthn().getMfa().getYubikey();
return new YubiKeyAuthenticationHandler(yubi.getName(), servicesManager,
yubikeyPrincipalFactory, yubicoClient, yubiKeyAccountRegistry,
yubi.getOrder(), multifactorAuthenticationProvider);
}
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
@ConditionalOnMissingBean(name = "yubiKeyAccountValidator")
public YubiKeyAccountValidator yubiKeyAccountValidator(
final CasConfigurationProperties casProperties,
@Qualifier("yubicoClient") final YubicoClient yubicoClient) {
val yubi = casProperties.getAuthn().getMfa().getYubikey();
return switch (yubi.getValidator()) {
case SKIP -> new AcceptAllYubiKeyAccountValidator();
case REJECT -> new DenyAllYubiKeyAccountValidator();
case VERIFY -> new DefaultYubiKeyAccountValidator(yubicoClient);
};
}
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
@ConditionalOnMissingBean(name = "yubiKeyAccountRegistry")
public YubiKeyAccountRegistry yubiKeyAccountRegistry(
final CasConfigurationProperties casProperties,
@Qualifier("yubiKeyAccountValidator")
final YubiKeyAccountValidator yubiKeyAccountValidator,
@Qualifier("yubicoClient")
final YubicoClient yubicoClient,
@Qualifier("yubikeyAccountCipherExecutor")
final CipherExecutor yubikeyAccountCipherExecutor) throws Exception {
val yubi = casProperties.getAuthn().getMfa().getYubikey();
if (StringUtils.isNotBlank(yubi.getJsonFile())) {
val jsonResource = ResourceUtils.getRawResourceFrom(SpringExpressionLanguageValueResolver.getInstance().resolve(yubi.getJsonFile()));
LOGGER.debug("Using JSON resource [{}] as the YubiKey account registry", jsonResource);
val registry = new JsonYubiKeyAccountRegistry(jsonResource, yubiKeyAccountValidator);
registry.setCipherExecutor(yubikeyAccountCipherExecutor);
return registry;
}
if (StringUtils.isNotBlank(yubi.getRest().getUrl())) {
LOGGER.debug("Using REST API resource [{}] as the YubiKey account registry", yubi.getRest().getUrl());
val registry = new RestfulYubiKeyAccountRegistry(yubi.getRest(), yubiKeyAccountValidator);
registry.setCipherExecutor(yubikeyAccountCipherExecutor);
return registry;
}
if (yubi.getAllowedDevices() != null && !yubi.getAllowedDevices().isEmpty()) {
LOGGER.debug("Using statically-defined devices for [{}] as the YubiKey account registry",
yubi.getAllowedDevices().keySet());
val map = (Map) yubi.getAllowedDevices()
.entrySet()
.stream()
.map(entry -> YubiKeyAccount.builder().id(System.currentTimeMillis()).username(entry.getKey())
.devices(List.of(YubiKeyRegisteredDevice.builder().publicId(entry.getValue())
.name(UUID.randomUUID().toString())
.registrationDate(ZonedDateTime.now(Clock.systemUTC()))
.build()))
.build()).collect(Collectors.toMap(YubiKeyAccount::getUsername, Function.identity()));
val registry = new PermissiveYubiKeyAccountRegistry(map, yubiKeyAccountValidator);
registry.setCipherExecutor(CipherExecutor.noOpOfSerializableToString());
return registry;
}
LOGGER.warn("All credentials are considered eligible for YubiKey authentication. "
+ "Consider providing an account registry implementation via [{}]",
YubiKeyAccountRegistry.class.getName());
val registry = new OpenYubiKeyAccountRegistry(yubiKeyAccountValidator);
registry.setCipherExecutor(yubikeyAccountCipherExecutor);
return registry;
}
@Bean
@ConditionalOnAvailableEndpoint
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public YubiKeyAccountRegistryEndpoint yubiKeyAccountRegistryEndpoint(
final CasConfigurationProperties casProperties,
final ConfigurableApplicationContext applicationContext,
@Qualifier("yubiKeyAccountRegistry") final ObjectProvider yubiKeyAccountRegistry) {
return new YubiKeyAccountRegistryEndpoint(casProperties, applicationContext, yubiKeyAccountRegistry);
}
@ConditionalOnMissingBean(name = "yubikeyMultifactorAuthenticationProvider")
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public MultifactorAuthenticationProvider yubikeyMultifactorAuthenticationProvider(
@Qualifier("yubiKeyMultifactorAuthenticatorDeviceManager") final MultifactorAuthenticationDeviceManager yubiKeyMultifactorAuthenticatorDeviceManager,
final CasConfigurationProperties casProperties,
@Qualifier("yubicoClient") final YubicoClient yubicoClient,
@Qualifier(HttpClient.BEAN_NAME_HTTPCLIENT) final HttpClient httpClient,
@Qualifier("yubikeyBypassEvaluator") final MultifactorAuthenticationProviderBypassEvaluator yubikeyBypassEvaluator,
@Qualifier("failureModeEvaluator") final MultifactorAuthenticationFailureModeEvaluator failureModeEvaluator) {
val yubi = casProperties.getAuthn().getMfa().getYubikey();
val provider = new YubiKeyMultifactorAuthenticationProvider(yubicoClient, httpClient);
provider.setBypassEvaluator(yubikeyBypassEvaluator);
provider.setFailureMode(yubi.getFailureMode());
provider.setFailureModeEvaluator(failureModeEvaluator);
provider.setOrder(yubi.getRank());
provider.setId(yubi.getId());
provider.setDeviceManager(yubiKeyMultifactorAuthenticatorDeviceManager);
return provider;
}
@ConditionalOnMissingBean(name = "yubiKeyMultifactorAuthenticatorDeviceManager")
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public MultifactorAuthenticationDeviceManager yubiKeyMultifactorAuthenticatorDeviceManager(
@Qualifier("yubiKeyAccountRegistry") final YubiKeyAccountRegistry yubiKeyAccountRegistry) {
return new YubiKeyMultifactorAuthenticatorDeviceManager(yubiKeyAccountRegistry);
}
@ConditionalOnMissingBean(name = "yubikeyAuthenticationEventExecutionPlanConfigurer")
@Bean
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public AuthenticationEventExecutionPlanConfigurer yubikeyAuthenticationEventExecutionPlanConfigurer(
final CasConfigurationProperties casProperties,
@Qualifier("yubikeyMultifactorProviderAuthenticationMetadataPopulator") final AuthenticationMetaDataPopulator yubikeyMultifactorProviderAuthenticationMetadataPopulator,
@Qualifier("yubikeyAuthenticationHandler") final AuthenticationHandler yubikeyAuthenticationHandler,
@Qualifier("yubikeyAuthenticationMetaDataPopulator") final AuthenticationMetaDataPopulator yubikeyAuthenticationMetaDataPopulator) {
return plan -> {
val yubi = casProperties.getAuthn().getMfa().getYubikey();
if (yubi.getClientId() > 0 && StringUtils.isNotBlank(yubi.getSecretKey())) {
plan.registerAuthenticationHandler(yubikeyAuthenticationHandler);
plan.registerAuthenticationMetadataPopulator(yubikeyAuthenticationMetaDataPopulator);
plan.registerAuthenticationMetadataPopulator(yubikeyMultifactorProviderAuthenticationMetadataPopulator);
plan.registerAuthenticationHandlerResolver(new ByCredentialTypeAuthenticationHandlerResolver(YubiKeyCredential.class));
}
};
}
}