configureOAuth20Client(Collection)   B
last analyzed

Complexity

Conditions 3

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
c 0
b 0
f 0
cc 3
rs 8.8571
1
package org.apereo.cas.support.pac4j.config.support.authentication;
2
3
import com.github.scribejava.core.model.Verb;
4
import com.nimbusds.jose.JWSAlgorithm;
5
import org.apache.commons.lang3.StringUtils;
6
import org.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;
7
import org.apereo.cas.authentication.AuthenticationHandler;
8
import org.apereo.cas.authentication.AuthenticationMetaDataPopulator;
9
import org.apereo.cas.authentication.principal.DefaultPrincipalFactory;
10
import org.apereo.cas.authentication.principal.PrincipalFactory;
11
import org.apereo.cas.authentication.principal.PrincipalResolver;
12
import org.apereo.cas.configuration.CasConfigurationProperties;
13
import org.apereo.cas.configuration.model.support.pac4j.Pac4jProperties;
14
import org.apereo.cas.services.ServicesManager;
15
import org.apereo.cas.support.pac4j.authentication.ClientAuthenticationMetaDataPopulator;
16
import org.apereo.cas.support.pac4j.authentication.handler.support.ClientAuthenticationHandler;
17
import org.apereo.cas.support.pac4j.web.flow.SAML2ClientLogoutAction;
18
import org.pac4j.cas.client.CasClient;
19
import org.pac4j.cas.config.CasConfiguration;
20
import org.pac4j.cas.config.CasProtocol;
21
import org.pac4j.core.client.BaseClient;
22
import org.pac4j.core.client.Clients;
23
import org.pac4j.oauth.client.BitbucketClient;
24
import org.pac4j.oauth.client.DropBoxClient;
25
import org.pac4j.oauth.client.FacebookClient;
26
import org.pac4j.oauth.client.FoursquareClient;
27
import org.pac4j.oauth.client.GenericOAuth20Client;
28
import org.pac4j.oauth.client.GitHubClient;
29
import org.pac4j.oauth.client.Google2Client;
30
import org.pac4j.oauth.client.LinkedIn2Client;
31
import org.pac4j.oauth.client.OrcidClient;
32
import org.pac4j.oauth.client.PayPalClient;
33
import org.pac4j.oauth.client.TwitterClient;
34
import org.pac4j.oauth.client.WindowsLiveClient;
35
import org.pac4j.oauth.client.WordPressClient;
36
import org.pac4j.oauth.client.YahooClient;
37
import org.pac4j.oidc.client.AzureAdClient;
38
import org.pac4j.oidc.client.GoogleOidcClient;
39
import org.pac4j.oidc.client.KeycloakOidcClient;
40
import org.pac4j.oidc.client.OidcClient;
41
import org.pac4j.oidc.config.OidcConfiguration;
42
import org.pac4j.saml.client.SAML2Client;
43
import org.pac4j.saml.client.SAML2ClientConfiguration;
44
import org.slf4j.Logger;
45
import org.slf4j.LoggerFactory;
46
import org.springframework.beans.factory.annotation.Autowired;
47
import org.springframework.beans.factory.annotation.Qualifier;
48
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
49
import org.springframework.boot.context.properties.EnableConfigurationProperties;
50
import org.springframework.cloud.context.config.annotation.RefreshScope;
51
import org.springframework.context.annotation.Bean;
52
import org.springframework.context.annotation.Configuration;
53
import org.springframework.webflow.execution.Action;
54
55
import java.util.ArrayList;
56
import java.util.Collection;
57
import java.util.LinkedHashSet;
58
import java.util.Set;
59
import java.util.concurrent.atomic.AtomicInteger;
60
61
/**
62
 * This is {@link Pac4jAuthenticationEventExecutionPlanConfiguration}.
63
 *
64
 * @author Misagh Moayyed
65
 * @author Dmitriy Kopylenko
66
 * @since 5.1.0
67
 */
68
@Configuration("pac4jAuthenticationEventExecutionPlanConfiguration")
69
@EnableConfigurationProperties(CasConfigurationProperties.class)
70
public class Pac4jAuthenticationEventExecutionPlanConfiguration {
71
    private static final Logger LOGGER = LoggerFactory.getLogger(Pac4jAuthenticationEventExecutionPlanConfiguration.class);
72
73
    @Autowired
74
    private CasConfigurationProperties casProperties;
75
76
    @Autowired
77
    @Qualifier("servicesManager")
78
    private ServicesManager servicesManager;
79
80
    @Autowired
81
    @Qualifier("personDirectoryPrincipalResolver")
82
    private PrincipalResolver personDirectoryPrincipalResolver;
83
84
    private void configureGithubClient(final Collection<BaseClient> properties) {
85
        final Pac4jProperties.Github github = casProperties.getAuthn().getPac4j().getGithub();
86
        if (StringUtils.isNotBlank(github.getId()) && StringUtils.isNotBlank(github.getSecret())) {
87
            final GitHubClient client = new GitHubClient(github.getId(), github.getSecret());
88
            setClientName(client, github.getClientName());
89
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
90
            properties.add(client);
91
        }
92
    }
93
94
    private void configureDropboxClient(final Collection<BaseClient> properties) {
95
        final Pac4jProperties.Dropbox db = casProperties.getAuthn().getPac4j().getDropbox();
96
        if (StringUtils.isNotBlank(db.getId()) && StringUtils.isNotBlank(db.getSecret())) {
97
            final DropBoxClient client = new DropBoxClient(db.getId(), db.getSecret());
98
            setClientName(client, db.getClientName());
99
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
100
            properties.add(client);
101
        }
102
    }
103
104
    private void configureOrcidClient(final Collection<BaseClient> properties) {
105
        final Pac4jProperties.Orcid db = casProperties.getAuthn().getPac4j().getOrcid();
106
        if (StringUtils.isNotBlank(db.getId()) && StringUtils.isNotBlank(db.getSecret())) {
107
            final OrcidClient client = new OrcidClient(db.getId(), db.getSecret());
108
            setClientName(client, db.getClientName());
109
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
110
            properties.add(client);
111
        }
112
    }
113
114
    private void configureWindowsLiveClient(final Collection<BaseClient> properties) {
115
        final Pac4jProperties.WindowsLive live = casProperties.getAuthn().getPac4j().getWindowsLive();
116
        if (StringUtils.isNotBlank(live.getId()) && StringUtils.isNotBlank(live.getSecret())) {
117
            final WindowsLiveClient client = new WindowsLiveClient(live.getId(), live.getSecret());
118
            setClientName(client, live.getClientName());
119
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
120
            properties.add(client);
121
        }
122
    }
123
124
    private void configureYahooClient(final Collection<BaseClient> properties) {
125
        final Pac4jProperties.Yahoo yahoo = casProperties.getAuthn().getPac4j().getYahoo();
126
        if (StringUtils.isNotBlank(yahoo.getId()) && StringUtils.isNotBlank(yahoo.getSecret())) {
127
            final YahooClient client = new YahooClient(yahoo.getId(), yahoo.getSecret());
128
            setClientName(client, yahoo.getClientName());
129
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
130
            properties.add(client);
131
        }
132
    }
133
134
    private void configureFoursquareClient(final Collection<BaseClient> properties) {
135
        final Pac4jProperties.Foursquare foursquare = casProperties.getAuthn().getPac4j().getFoursquare();
136
        if (StringUtils.isNotBlank(foursquare.getId()) && StringUtils.isNotBlank(foursquare.getSecret())) {
137
            final FoursquareClient client = new FoursquareClient(foursquare.getId(), foursquare.getSecret());
138
            setClientName(client, foursquare.getClientName());
139
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
140
            properties.add(client);
141
        }
142
    }
143
144
    private void configureGoogleClient(final Collection<BaseClient> properties) {
145
        final Pac4jProperties.Google google = casProperties.getAuthn().getPac4j().getGoogle();
146
        final Google2Client client = new Google2Client(google.getId(), google.getSecret());
147
        if (StringUtils.isNotBlank(google.getId()) && StringUtils.isNotBlank(google.getSecret())) {
148
            setClientName(client, google.getClientName());
149
            if (StringUtils.isNotBlank(google.getScope())) {
150
                client.setScope(Google2Client.Google2Scope.valueOf(google.getScope().toUpperCase()));
151
            }
152
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
153
            properties.add(client);
154
        }
155
    }
156
157
    private void configureFacebookClient(final Collection<BaseClient> properties) {
158
        final Pac4jProperties.Facebook fb = casProperties.getAuthn().getPac4j().getFacebook();
159
        if (StringUtils.isNotBlank(fb.getId()) && StringUtils.isNotBlank(fb.getSecret())) {
160
            final FacebookClient client = new FacebookClient(fb.getId(), fb.getSecret());
161
            setClientName(client, fb.getClientName());
162
            if (StringUtils.isNotBlank(fb.getScope())) {
163
                client.setScope(fb.getScope());
164
            }
165
166
            if (StringUtils.isNotBlank(fb.getFields())) {
167
                client.setFields(fb.getFields());
168
            }
169
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
170
            properties.add(client);
171
        }
172
    }
173
174
    private void configureLinkedInClient(final Collection<BaseClient> properties) {
175
        final Pac4jProperties.LinkedIn ln = casProperties.getAuthn().getPac4j().getLinkedIn();
176
        if (StringUtils.isNotBlank(ln.getId()) && StringUtils.isNotBlank(ln.getSecret())) {
177
            final LinkedIn2Client client = new LinkedIn2Client(ln.getId(), ln.getSecret());
178
            setClientName(client, ln.getClientName());
179
            if (StringUtils.isNotBlank(ln.getScope())) {
180
                client.setScope(ln.getScope());
181
            }
182
183
            if (StringUtils.isNotBlank(ln.getFields())) {
184
                client.setFields(ln.getFields());
185
            }
186
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
187
            properties.add(client);
188
        }
189
    }
190
191
    private void configureTwitterClient(final Collection<BaseClient> properties) {
192
        final Pac4jProperties.Twitter twitter = casProperties.getAuthn().getPac4j().getTwitter();
193
        if (StringUtils.isNotBlank(twitter.getId()) && StringUtils.isNotBlank(twitter.getSecret())) {
194
            final TwitterClient client = new TwitterClient(twitter.getId(), twitter.getSecret());
195
            setClientName(client, twitter.getClientName());
196
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
197
            properties.add(client);
198
        }
199
    }
200
201
    private void configureWordpressClient(final Collection<BaseClient> properties) {
202
        final Pac4jProperties.Wordpress wp = casProperties.getAuthn().getPac4j().getWordpress();
203
        if (StringUtils.isNotBlank(wp.getId()) && StringUtils.isNotBlank(wp.getSecret())) {
204
            final WordPressClient client = new WordPressClient(wp.getId(), wp.getSecret());
205
            setClientName(client, wp.getClientName());
206
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
207
            properties.add(client);
208
        }
209
    }
210
211
    private void configureBitbucketClient(final Collection<BaseClient> properties) {
212
        final Pac4jProperties.Bitbucket bb = casProperties.getAuthn().getPac4j().getBitbucket();
213
        if (StringUtils.isNotBlank(bb.getId()) && StringUtils.isNotBlank(bb.getSecret())) {
214
            final BitbucketClient client = new BitbucketClient(bb.getId(), bb.getSecret());
215
            setClientName(client, bb.getClientName());
216
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
217
            properties.add(client);
218
        }
219
    }
220
221
    private void configurePaypalClient(final Collection<BaseClient> properties) {
222
        final Pac4jProperties.Paypal paypal = casProperties.getAuthn().getPac4j().getPaypal();
223
        if (StringUtils.isNotBlank(paypal.getId()) && StringUtils.isNotBlank(paypal.getSecret())) {
224
            final PayPalClient client = new PayPalClient(paypal.getId(), paypal.getSecret());
225
            setClientName(client, paypal.getClientName());
226
            LOGGER.debug("Created client [{}] with identifier [{}]", client.getName(), client.getKey());
227
            properties.add(client);
228
        }
229
    }
230
231
    private void setClientName(final BaseClient client, final String clientName) {
232
        if (StringUtils.isNotBlank(clientName)) {
233
            client.setName(clientName);
234
        }
235
    }
236
237
    private void configureCasClient(final Collection<BaseClient> properties) {
238
        final AtomicInteger index = new AtomicInteger();
239
        casProperties.getAuthn().getPac4j().getCas()
240
                .stream()
241
                .filter(cas -> StringUtils.isNotBlank(cas.getLoginUrl()))
242
                .forEach(cas -> {
243
                    final CasConfiguration cfg = new CasConfiguration(cas.getLoginUrl(), CasProtocol.valueOf(cas.getProtocol()));
244
                    final CasClient client = new CasClient(cfg);
245
                    final int count = index.intValue();
246
                    if (StringUtils.isNotBlank(cas.getClientName())) {
247
                        client.setName(cas.getClientName());
248
                    } else if (count > 0) {
249
                        client.setName(client.getClass().getSimpleName() + count);
250
                    }
251
                    index.incrementAndGet();
252
                    LOGGER.debug("Created client [{}]", client);
253
                    properties.add(client);
254
                });
255
    }
256
257
    private void configureSamlClient(final Collection<BaseClient> properties) {
258
        final AtomicInteger index = new AtomicInteger();
259
        casProperties.getAuthn().getPac4j().getSaml()
260
                .stream()
261
                .filter(saml -> StringUtils.isNotBlank(saml.getKeystorePath()) && StringUtils.isNotBlank(saml.getIdentityProviderMetadataPath()))
262
                .forEach(saml -> {
263
                    final SAML2ClientConfiguration cfg = new SAML2ClientConfiguration(saml.getKeystorePath(), saml.getKeystorePassword(),
264
                            saml.getPrivateKeyPassword(), saml.getIdentityProviderMetadataPath());
265
                    cfg.setMaximumAuthenticationLifetime(saml.getMaximumAuthenticationLifetime());
266
                    cfg.setServiceProviderEntityId(saml.getServiceProviderEntityId());
267
                    cfg.setServiceProviderMetadataPath(saml.getServiceProviderMetadataPath());
268
                    cfg.setDestinationBindingType(saml.getDestinationBinding());
269
                    cfg.setForceAuth(saml.isForceAuth());
270
                    cfg.setPassive(saml.isPassive());
271
                    cfg.setWantsAssertionsSigned(saml.isWantsAssertionsSigned());
272
273
                    if (StringUtils.isNotBlank(saml.getAuthnContextClassRef())) {
274
                        cfg.setComparisonType(saml.getAuthnContextComparisonType().toUpperCase());
275
                        cfg.setAuthnContextClassRef(saml.getAuthnContextClassRef());
276
                    }
277
                    if (StringUtils.isNotBlank(saml.getKeystoreAlias())) {
278
                        cfg.setKeystoreAlias(saml.getKeystoreAlias());
279
                    }
280
                    if (StringUtils.isNotBlank(saml.getNameIdPolicyFormat())) {
281
                        cfg.setNameIdPolicyFormat(saml.getNameIdPolicyFormat());
282
                    }
283
                    final SAML2Client client = new SAML2Client(cfg);
284
285
                    final int count = index.intValue();
286
                    if (saml.getClientName() != null) {
287
                        client.setName(saml.getClientName());
288
                    } else if (count > 0) {
289
                        client.setName(client.getClass().getSimpleName() + count);
290
                    }
291
292
                    index.incrementAndGet();
293
                    LOGGER.debug("Created client [{}]", client);
294
                    properties.add(client);
295
                });
296
    }
297
298
    private void configureOAuth20Client(final Collection<BaseClient> properties) {
299
        final AtomicInteger index = new AtomicInteger();
300
        casProperties.getAuthn().getPac4j().getOauth2()
301
                .stream()
302
                .filter(oauth -> StringUtils.isNotBlank(oauth.getId()) && StringUtils.isNotBlank(oauth.getSecret()))
303
                .forEach(oauth -> {
304
                    final GenericOAuth20Client client = new GenericOAuth20Client();
305
                    client.setKey(oauth.getId());
306
                    client.setSecret(oauth.getSecret());
307
                    client.setProfileAttrs(oauth.getProfileAttrs());
308
                    client.setProfileNodePath(oauth.getProfilePath());
309
                    client.setProfileUrl(oauth.getProfileUrl());
310
                    client.setProfileVerb(Verb.valueOf(oauth.getProfileVerb().toUpperCase()));
311
                    client.setTokenUrl(oauth.getTokenUrl());
312
                    client.setAuthUrl(oauth.getAuthUrl());
313
                    client.setCustomParams(oauth.getCustomParams());
314
                    final int count = index.intValue();
315
                    if (StringUtils.isNotBlank(oauth.getClientName())) {
316
                        client.setName(oauth.getClientName());
317
                    } else if (count > 0) {
318
                        client.setName(client.getClass().getSimpleName() + count);
319
                    }
320
                    index.incrementAndGet();
321
                    LOGGER.debug("Created client [{}]", client);
322
                    properties.add(client);
323
                });
324
    }
325
326
    private void configureOidcClient(final Collection<BaseClient> properties) {
327
        final AtomicInteger index = new AtomicInteger();
328
        casProperties.getAuthn().getPac4j().getOidc()
329
                .stream()
330
                .filter(oidc -> StringUtils.isNotBlank(oidc.getId()) && StringUtils.isNotBlank(oidc.getSecret()))
331
                .forEach(oidc -> {
332
333
                    final OidcConfiguration cfg = new OidcConfiguration();
334
                    if (StringUtils.isNotBlank(oidc.getScope())) {
335
                        cfg.setScope(oidc.getScope());
336
                    }
337
                    cfg.setUseNonce(oidc.isUseNonce());
338
                    cfg.setSecret(oidc.getSecret());
339
                    cfg.setClientId(oidc.getId());
340
341
                    if (StringUtils.isNotBlank(oidc.getPreferredJwsAlgorithm())) {
342
                        cfg.setPreferredJwsAlgorithm(JWSAlgorithm.parse(oidc.getPreferredJwsAlgorithm().toUpperCase()));
343
                    }
344
                    cfg.setMaxClockSkew(oidc.getMaxClockSkew());
345
                    cfg.setDiscoveryURI(oidc.getDiscoveryUri());
346
                    cfg.setCustomParams(oidc.getCustomParams());
347
348
                    final OidcClient client;
349
                    switch (oidc.getType().toUpperCase()) {
350
                        case "GOOGLE":
351
                            client = new GoogleOidcClient(cfg);
352
                            break;
353
                        case "AZURE":
354
                            client = new AzureAdClient(cfg);
355
                            break;
356
                        case "KEYCLOAK":
357
                            client = new KeycloakOidcClient(cfg);
358
                            break;
359
                        case "GENERIC":
360
                        default:
361
                            client = new OidcClient(cfg);
362
                            break;
363
                    }
364
                    final int count = index.intValue();
365
                    if (StringUtils.isNotBlank(oidc.getClientName())) {
366
                        client.setName(oidc.getClientName());
367
                    } else if (count > 0) {
368
                        client.setName(client.getClass().getSimpleName() + count);
369
                    }
370
                    index.incrementAndGet();
371
                    LOGGER.debug("Created client [{}]", client);
372
                    properties.add(client);
373
                });
374
    }
375
376
    @RefreshScope
377
    @Bean
378
    public Clients builtClients() {
379
        final Set<BaseClient> clients = new LinkedHashSet<>();
380
381
        configureCasClient(clients);
382
        configureFacebookClient(clients);
383
        configureOidcClient(clients);
384
        configureOAuth20Client(clients);
385
        configureSamlClient(clients);
386
        configureTwitterClient(clients);
387
        configureDropboxClient(clients);
388
        configureFoursquareClient(clients);
389
        configureGithubClient(clients);
390
        configureGoogleClient(clients);
391
        configureWindowsLiveClient(clients);
392
        configureYahooClient(clients);
393
        configureLinkedInClient(clients);
394
        configurePaypalClient(clients);
395
        configureWordpressClient(clients);
396
        configureBitbucketClient(clients);
397
        configureOrcidClient(clients);
398
399
        LOGGER.debug("The following clients are built: [{}]", clients);
400
        if (clients.isEmpty()) {
401
            LOGGER.warn("No delegated authentication clients are defined/configured");
402
        }
403
404
        LOGGER.info("Located and prepared [{}] delegated authentication client(s)", clients.size());
405
        return new Clients(casProperties.getServer().getLoginUrl(), new ArrayList<>(clients));
406
    }
407
408
    @ConditionalOnMissingBean(name = "clientPrincipalFactory")
409
    @Bean
410
    public PrincipalFactory clientPrincipalFactory() {
411
        return new DefaultPrincipalFactory();
412
    }
413
414
    @ConditionalOnMissingBean(name = "clientAuthenticationMetaDataPopulator")
415
    @Bean
416
    public AuthenticationMetaDataPopulator clientAuthenticationMetaDataPopulator() {
417
        return new ClientAuthenticationMetaDataPopulator();
418
    }
419
420
    @ConditionalOnMissingBean(name = "saml2ClientLogoutAction")
421
    @Bean
422
    public Action saml2ClientLogoutAction() {
423
        return new SAML2ClientLogoutAction(builtClients());
424
    }
425
426
    @RefreshScope
427
    @Bean
428
    @ConditionalOnMissingBean(name = "clientAuthenticationHandler")
429
    public AuthenticationHandler clientAuthenticationHandler() {
430
        final Pac4jProperties pac4j = casProperties.getAuthn().getPac4j();
431
        final ClientAuthenticationHandler h = new ClientAuthenticationHandler(pac4j.getName(), servicesManager,
432
                clientPrincipalFactory(), builtClients());
433
        h.setTypedIdUsed(pac4j.isTypedIdUsed());
434
        return h;
435
    }
436
437
    @ConditionalOnMissingBean(name = "pac4jAuthenticationEventExecutionPlanConfigurer")
438
    @Bean
439
    public AuthenticationEventExecutionPlanConfigurer pac4jAuthenticationEventExecutionPlanConfigurer() {
440
        return plan -> {
441
            if (!builtClients().findAllClients().isEmpty()) {
442
                LOGGER.info("Registering delegated authentication clients...");
443
                plan.registerAuthenticationHandlerWithPrincipalResolver(clientAuthenticationHandler(), personDirectoryPrincipalResolver);
444
                plan.registerMetadataPopulator(clientAuthenticationMetaDataPopulator());
445
            }
446
        };
447
    }
448
}
449