org.apereo.cas.pac4j.web.DelegatedClientOidcBuilder Maven / Gradle / Ivy
package org.apereo.cas.pac4j.web;
import org.apereo.cas.authentication.CasSSLContext;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.configuration.model.support.pac4j.oidc.BasePac4jOidcClientProperties;
import org.apereo.cas.configuration.model.support.pac4j.oidc.Pac4jOidcClientProperties;
import org.apereo.cas.configuration.support.Beans;
import org.apereo.cas.support.pac4j.authentication.clients.ConfigurableDelegatedClient;
import org.apereo.cas.support.pac4j.authentication.clients.ConfigurableDelegatedClientBuilder;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.cas.util.ResourceUtils;
import org.apereo.cas.util.crypto.PrivateKeyFactoryBean;
import org.apereo.cas.util.function.FunctionUtils;
import org.apereo.cas.util.spring.SpringExpressionLanguageValueResolver;
import com.github.scribejava.core.model.Verb;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.pac4j.oauth.client.BitbucketClient;
import org.pac4j.oauth.client.DropBoxClient;
import org.pac4j.oauth.client.FacebookClient;
import org.pac4j.oauth.client.FoursquareClient;
import org.pac4j.oauth.client.GenericOAuth20Client;
import org.pac4j.oauth.client.GitHubClient;
import org.pac4j.oauth.client.Google2Client;
import org.pac4j.oauth.client.HiOrgServerClient;
import org.pac4j.oauth.client.LinkedIn2Client;
import org.pac4j.oauth.client.PayPalClient;
import org.pac4j.oauth.client.TwitterClient;
import org.pac4j.oauth.client.WindowsLiveClient;
import org.pac4j.oauth.client.WordPressClient;
import org.pac4j.oauth.client.YahooClient;
import org.pac4j.oidc.client.AppleClient;
import org.pac4j.oidc.client.AzureAd2Client;
import org.pac4j.oidc.client.GoogleOidcClient;
import org.pac4j.oidc.client.KeycloakOidcClient;
import org.pac4j.oidc.client.OidcClient;
import org.pac4j.oidc.config.AppleOidcConfiguration;
import org.pac4j.oidc.config.AzureAd2OidcConfiguration;
import org.pac4j.oidc.config.KeycloakOidcConfiguration;
import org.pac4j.oidc.config.OidcConfiguration;
import java.security.interfaces.ECPrivateKey;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* This is {@link DelegatedClientOidcBuilder}.
*
* @author Misagh Moayyed
* @since 7.1.0
*/
@RequiredArgsConstructor
@Slf4j
public class DelegatedClientOidcBuilder implements ConfigurableDelegatedClientBuilder {
private final CasSSLContext casSslContext;
@Override
public List build(final CasConfigurationProperties casProperties) throws Exception {
val newClients = new ArrayList();
newClients.addAll(buildFacebookIdentityProviders(casProperties));
newClients.addAll(buildOidcIdentityProviders(casProperties));
newClients.addAll(buildOAuth20IdentityProviders(casProperties));
newClients.addAll(buildTwitterIdentityProviders(casProperties));
newClients.addAll(buildDropBoxIdentityProviders(casProperties));
newClients.addAll(buildFoursquareIdentityProviders(casProperties));
newClients.addAll(buildGitHubIdentityProviders(casProperties));
newClients.addAll(buildGoogleIdentityProviders(casProperties));
newClients.addAll(buildWindowsLiveIdentityProviders(casProperties));
newClients.addAll(buildYahooIdentityProviders(casProperties));
newClients.addAll(buildLinkedInIdentityProviders(casProperties));
newClients.addAll(buildPaypalIdentityProviders(casProperties));
newClients.addAll(buildWordpressIdentityProviders(casProperties));
newClients.addAll(buildBitBucketIdentityProviders(casProperties));
newClients.addAll(buildHiOrgServerIdentityProviders(casProperties));
return newClients;
}
protected Collection buildFoursquareIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val foursquare = pac4jProperties.getFoursquare();
if (foursquare.isEnabled() && StringUtils.isNotBlank(foursquare.getId()) && StringUtils.isNotBlank(foursquare.getSecret())) {
val client = new FoursquareClient(foursquare.getId(), foursquare.getSecret());
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, foursquare));
}
return List.of();
}
protected Collection buildGoogleIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val google = pac4jProperties.getGoogle();
if (google.isEnabled() && StringUtils.isNotBlank(google.getId()) && StringUtils.isNotBlank(google.getSecret())) {
val client = new Google2Client(google.getId(), google.getSecret());
if (StringUtils.isNotBlank(google.getScope())) {
client.setScope(Google2Client.Google2Scope.valueOf(google.getScope().toUpperCase(Locale.ENGLISH)));
}
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, google));
}
return List.of();
}
protected Collection buildFacebookIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val fb = pac4jProperties.getFacebook();
if (fb.isEnabled() && StringUtils.isNotBlank(fb.getId()) && StringUtils.isNotBlank(fb.getSecret())) {
val client = new FacebookClient(fb.getId(), fb.getSecret());
FunctionUtils.doIfNotBlank(fb.getScope(), __ -> client.setScope(fb.getScope()));
FunctionUtils.doIfNotBlank(fb.getFields(), __ -> client.setFields(fb.getFields()));
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, fb));
}
return List.of();
}
protected Collection buildLinkedInIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val ln = pac4jProperties.getLinkedIn();
if (ln.isEnabled() && StringUtils.isNotBlank(ln.getId()) && StringUtils.isNotBlank(ln.getSecret())) {
val client = new LinkedIn2Client(ln.getId(), ln.getSecret());
FunctionUtils.doIfNotBlank(ln.getScope(), __ -> client.setScope(ln.getScope()));
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, ln));
}
return List.of();
}
protected Collection buildGitHubIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val github = pac4jProperties.getGithub();
if (github.isEnabled() && StringUtils.isNotBlank(github.getId()) && StringUtils.isNotBlank(github.getSecret())) {
val client = new GitHubClient(github.getId(), github.getSecret());
FunctionUtils.doIfNotBlank(github.getScope(), __ -> client.setScope(github.getScope()));
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, github));
}
return List.of();
}
protected Collection buildDropBoxIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val db = pac4jProperties.getDropbox();
if (db.isEnabled() && StringUtils.isNotBlank(db.getId()) && StringUtils.isNotBlank(db.getSecret())) {
val client = new DropBoxClient(db.getId(), db.getSecret());
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, db));
}
return List.of();
}
protected Collection buildWindowsLiveIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val live = pac4jProperties.getWindowsLive();
if (live.isEnabled() && StringUtils.isNotBlank(live.getId()) && StringUtils.isNotBlank(live.getSecret())) {
val client = new WindowsLiveClient(live.getId(), live.getSecret());
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, live));
}
return List.of();
}
protected Collection buildYahooIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val yahoo = pac4jProperties.getYahoo();
if (yahoo.isEnabled() && StringUtils.isNotBlank(yahoo.getId()) && StringUtils.isNotBlank(yahoo.getSecret())) {
val client = new YahooClient(yahoo.getId(), yahoo.getSecret());
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, yahoo));
}
return List.of();
}
protected Collection buildHiOrgServerIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val hiOrgServer = pac4jProperties.getHiOrgServer();
if (hiOrgServer.isEnabled() && StringUtils.isNotBlank(hiOrgServer.getId()) && StringUtils.isNotBlank(hiOrgServer.getSecret())) {
val client = new HiOrgServerClient(hiOrgServer.getId(), hiOrgServer.getSecret());
if (StringUtils.isNotBlank(hiOrgServer.getScope())) {
client.getConfiguration().setScope(hiOrgServer.getScope());
}
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, hiOrgServer));
}
return List.of();
}
protected Collection buildOAuth20IdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
return pac4jProperties
.getOauth2()
.stream()
.filter(oauth -> oauth.isEnabled()
&& StringUtils.isNotBlank(oauth.getId())
&& StringUtils.isNotBlank(oauth.getSecret()))
.map(oauth -> {
val client = new GenericOAuth20Client();
client.setProfileId(StringUtils.defaultIfBlank(oauth.getPrincipalIdAttribute(), pac4jProperties.getCore().getPrincipalIdAttribute()));
client.setKey(SpringExpressionLanguageValueResolver.getInstance().resolve(oauth.getId()));
client.setSecret(SpringExpressionLanguageValueResolver.getInstance().resolve(oauth.getSecret()));
client.setProfileAttrs(oauth.getProfileAttrs());
client.setProfileUrl(oauth.getProfileUrl());
client.setProfileVerb(Verb.valueOf(oauth.getProfileVerb().toUpperCase(Locale.ENGLISH)));
client.setTokenUrl(oauth.getTokenUrl());
client.setAuthUrl(oauth.getAuthUrl());
client.setScope(oauth.getScope());
client.setCustomParams(oauth.getCustomParams());
client.setWithState(oauth.isWithState());
FunctionUtils.doIfNotBlank(oauth.getClientAuthenticationMethod(), client::setClientAuthenticationMethod);
client.getConfiguration().setResponseType(oauth.getResponseType());
LOGGER.debug("Created client [{}]", client);
return new ConfigurableDelegatedClient(client, oauth);
})
.collect(Collectors.toList());
}
protected Collection buildOidcIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
return pac4jProperties
.getOidc()
.stream()
.map(this::getOidcClientFrom)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
protected Collection buildWordpressIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val wp = pac4jProperties.getWordpress();
if (wp.isEnabled() && StringUtils.isNotBlank(wp.getId()) && StringUtils.isNotBlank(wp.getSecret())) {
val client = new WordPressClient(wp.getId(), wp.getSecret());
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, wp));
}
return List.of();
}
protected Collection buildTwitterIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val twitter = pac4jProperties.getTwitter();
if (twitter.isEnabled() && StringUtils.isNotBlank(twitter.getId()) && StringUtils.isNotBlank(twitter.getSecret())) {
val client = new TwitterClient(twitter.getId(), twitter.getSecret(), twitter.isIncludeEmail());
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, twitter));
}
return List.of();
}
private ConfigurableDelegatedClient getOidcClientFrom(final Pac4jOidcClientProperties clientProperties) {
val resolver = SpringExpressionLanguageValueResolver.getInstance();
if (clientProperties.getAzure().isEnabled() && StringUtils.isNotBlank(clientProperties.getAzure().getId())) {
LOGGER.debug("Building OpenID Connect client for Azure AD...");
val azure = getOidcConfigurationForClient(clientProperties.getAzure(), AzureAd2OidcConfiguration.class);
azure.setTenant(resolver.resolve(clientProperties.getAzure().getTenant()));
val cfg = new AzureAd2OidcConfiguration(azure);
return new ConfigurableDelegatedClient(new AzureAd2Client(cfg), clientProperties.getAzure());
}
if (clientProperties.getGoogle().isEnabled() && StringUtils.isNotBlank(clientProperties.getGoogle().getId())) {
LOGGER.debug("Building OpenID Connect client for Google...");
val cfg = getOidcConfigurationForClient(clientProperties.getGoogle(), OidcConfiguration.class);
return new ConfigurableDelegatedClient(new GoogleOidcClient(cfg), clientProperties.getGoogle());
}
if (clientProperties.getKeycloak().isEnabled() && StringUtils.isNotBlank(clientProperties.getKeycloak().getId())) {
LOGGER.debug("Building OpenID Connect client for KeyCloak...");
val cfg = getOidcConfigurationForClient(clientProperties.getKeycloak(), KeycloakOidcConfiguration.class);
cfg.setRealm(resolver.resolve(clientProperties.getKeycloak().getRealm()));
cfg.setBaseUri(resolver.resolve(clientProperties.getKeycloak().getBaseUri()));
return new ConfigurableDelegatedClient(new KeycloakOidcClient(cfg), clientProperties.getKeycloak());
}
if (clientProperties.getApple().isEnabled() && StringUtils.isNotBlank(clientProperties.getApple().getPrivateKey())) {
LOGGER.debug("Building OpenID Connect client for Apple...");
val cfg = getOidcConfigurationForClient(clientProperties.getApple(), AppleOidcConfiguration.class);
FunctionUtils.doUnchecked(__ -> {
val factory = new PrivateKeyFactoryBean();
factory.setAlgorithm("EC");
factory.setSingleton(false);
factory.setLocation(ResourceUtils.getResourceFrom(clientProperties.getApple().getPrivateKey()));
cfg.setPrivateKey((ECPrivateKey) factory.getObject());
});
cfg.setPrivateKeyID(clientProperties.getApple().getPrivateKeyId());
cfg.setTeamID(clientProperties.getApple().getTeamId());
cfg.setTimeout(Beans.newDuration(clientProperties.getApple().getTimeout()));
return new ConfigurableDelegatedClient(new AppleClient(cfg), clientProperties.getApple());
}
if (clientProperties.getGeneric().isEnabled()) {
LOGGER.debug("Building generic OpenID Connect client...");
val generic = getOidcConfigurationForClient(clientProperties.getGeneric(), OidcConfiguration.class);
return new ConfigurableDelegatedClient(new OidcClient(generic), clientProperties.getGeneric());
}
return null;
}
protected Collection buildPaypalIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val paypal = pac4jProperties.getPaypal();
if (paypal.isEnabled() && StringUtils.isNotBlank(paypal.getId()) && StringUtils.isNotBlank(paypal.getSecret())) {
val client = new PayPalClient(paypal.getId(), paypal.getSecret());
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, paypal));
}
return List.of();
}
private T getOidcConfigurationForClient(final BasePac4jOidcClientProperties oidc,
final Class clazz) {
val resolver = SpringExpressionLanguageValueResolver.getInstance();
val cfg = FunctionUtils.doUnchecked(() -> clazz.getDeclaredConstructor().newInstance());
FunctionUtils.doIfNotBlank(oidc.getScope(), __ -> cfg.setScope(resolver.resolve(oidc.getScope())));
cfg.setUseNonce(oidc.isUseNonce());
cfg.setDisablePkce(oidc.isDisablePkce());
cfg.setSecret(resolver.resolve(oidc.getSecret()));
cfg.setClientId(resolver.resolve(oidc.getId()));
cfg.setReadTimeout((int) Beans.newDuration(oidc.getReadTimeout()).toMillis());
cfg.setConnectTimeout((int) Beans.newDuration(oidc.getConnectTimeout()).toMillis());
if (StringUtils.isNotBlank(oidc.getPreferredJwsAlgorithm())) {
cfg.setPreferredJwsAlgorithm(JWSAlgorithm.parse(oidc.getPreferredJwsAlgorithm().toUpperCase(Locale.ENGLISH)));
}
cfg.setMaxClockSkew(Long.valueOf(Beans.newDuration(oidc.getMaxClockSkew()).toSeconds()).intValue());
cfg.setDiscoveryURI(oidc.getDiscoveryUri());
cfg.setCustomParams(oidc.getCustomParams());
cfg.setLogoutUrl(oidc.getLogoutUrl());
cfg.setAllowUnsignedIdTokens(oidc.isAllowUnsignedIdTokens());
cfg.setIncludeAccessTokenClaimsInProfile(oidc.isIncludeAccessTokenClaims());
cfg.setExpireSessionWithToken(oidc.isExpireSessionWithToken());
cfg.setLogoutValidation(oidc.isValidateLogoutToken());
FunctionUtils.doIfNotBlank(oidc.getSupportedClientAuthenticationMethods(), methods -> {
val clientMethods = org.springframework.util.StringUtils.commaDelimitedListToSet(methods)
.stream()
.map(ClientAuthenticationMethod::parse)
.collect(Collectors.toSet());
cfg.setSupportedClientAuthenticationMethods(clientMethods);
});
FunctionUtils.doIfNotBlank(oidc.getClientAuthenticationMethod(),
method -> cfg.setClientAuthenticationMethod(ClientAuthenticationMethod.parse(method)));
if (StringUtils.isNotBlank(oidc.getTokenExpirationAdvance())) {
cfg.setTokenExpirationAdvance((int) Beans.newDuration(oidc.getTokenExpirationAdvance()).toSeconds());
}
FunctionUtils.doIfNotBlank(oidc.getResponseMode(), __ -> cfg.setResponseMode(oidc.getResponseMode()));
FunctionUtils.doIfNotBlank(oidc.getResponseType(), __ -> cfg.setResponseType(oidc.getResponseType()));
if (!oidc.getMappedClaims().isEmpty()) {
cfg.setMappedClaims(CollectionUtils.convertDirectedListToMap(oidc.getMappedClaims()));
}
cfg.setSslSocketFactory(casSslContext.getSslContext().getSocketFactory());
cfg.setHostnameVerifier(casSslContext.getHostnameVerifier());
return cfg;
}
protected Collection buildBitBucketIdentityProviders(final CasConfigurationProperties casProperties) {
val pac4jProperties = casProperties.getAuthn().getPac4j();
val bitbucket = pac4jProperties.getBitbucket();
if (bitbucket.isEnabled() && StringUtils.isNotBlank(bitbucket.getId()) && StringUtils.isNotBlank(bitbucket.getSecret())) {
val client = new BitbucketClient(bitbucket.getId(), bitbucket.getSecret());
LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
return List.of(new ConfigurableDelegatedClient(client, bitbucket));
}
return List.of();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy