1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.logic.oidc;
20
21 import com.nimbusds.oauth2.sdk.ParseException;
22 import com.nimbusds.oauth2.sdk.id.Issuer;
23 import com.nimbusds.openid.connect.sdk.SubjectType;
24 import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
25 import java.io.IOException;
26 import java.net.URI;
27 import java.net.http.HttpClient;
28 import java.net.http.HttpRequest;
29 import java.net.http.HttpResponse;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Optional;
34 import java.util.function.Function;
35 import java.util.stream.Collectors;
36 import org.apache.syncope.common.lib.to.OIDCC4UIProviderTO;
37 import org.apache.syncope.core.persistence.api.entity.OIDCC4UIProvider;
38 import org.pac4j.core.http.callback.NoParameterCallbackUrlResolver;
39 import org.pac4j.oidc.client.OidcClient;
40 import org.pac4j.oidc.config.OidcConfiguration;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44
45
46
47 public class OIDCClientCache {
48
49 protected static final Logger LOG = LoggerFactory.getLogger(OIDCClientCache.class);
50
51 protected static final Function<String, String> DISCOVERY_URI =
52 issuer -> issuer + "/.well-known/openid-configuration";
53
54 public static void importMetadata(final OIDCC4UIProviderTO opTO)
55 throws IOException, InterruptedException, ParseException {
56
57 String discoveryDocumentURI = DISCOVERY_URI.apply(opTO.getIssuer());
58 HttpResponse<String> response = HttpClient.newBuilder().build().send(
59 HttpRequest.newBuilder(URI.create(discoveryDocumentURI)).GET().build(),
60 HttpResponse.BodyHandlers.ofString());
61
62 OIDCProviderMetadata metadata = OIDCProviderMetadata.parse(response.body());
63
64 opTO.setIssuer(
65 Optional.ofNullable(metadata.getIssuer()).map(Issuer::getValue).orElse(null));
66 opTO.setJwksUri(
67 Optional.ofNullable(metadata.getJWKSetURI()).map(URI::toASCIIString).orElse(null));
68 opTO.setAuthorizationEndpoint(
69 Optional.ofNullable(metadata.getAuthorizationEndpointURI()).map(URI::toASCIIString).orElse(null));
70 opTO.setTokenEndpoint(
71 Optional.ofNullable(metadata.getTokenEndpointURI()).map(URI::toASCIIString).orElse(null));
72 opTO.setUserinfoEndpoint(
73 Optional.ofNullable(metadata.getUserInfoEndpointURI()).map(URI::toASCIIString).orElse(null));
74 opTO.setEndSessionEndpoint(
75 Optional.ofNullable(metadata.getEndSessionEndpointURI()).map(URI::toASCIIString).orElse(null));
76 Optional.ofNullable(metadata.getScopes()).ifPresent(s -> opTO.getScopes().addAll(s.toStringList()));
77 }
78
79 protected final List<OidcClient> cache = Collections.synchronizedList(new ArrayList<>());
80
81 public Optional<OidcClient> get(final String opName) {
82 return cache.stream().filter(c -> opName.equals(c.getName())).findFirst();
83 }
84
85 public OidcClient add(final OIDCC4UIProvider op, final String callbackUrl) {
86 OIDCProviderMetadata metadata = new OIDCProviderMetadata(
87 new Issuer(op.getIssuer()),
88 List.of(SubjectType.PUBLIC),
89 Optional.ofNullable(op.getJwksUri()).map(URI::create).orElse(null));
90 metadata.setAuthorizationEndpointURI(
91 Optional.ofNullable(op.getAuthorizationEndpoint()).map(URI::create).orElse(null));
92 metadata.setTokenEndpointURI(
93 Optional.ofNullable(op.getTokenEndpoint()).map(URI::create).orElse(null));
94 metadata.setUserInfoEndpointURI(
95 Optional.ofNullable(op.getUserinfoEndpoint()).map(URI::create).orElse(null));
96 metadata.setEndSessionEndpointURI(
97 Optional.ofNullable(op.getEndSessionEndpoint()).map(URI::create).orElse(null));
98
99 OidcConfiguration cfg = new OidcConfiguration();
100 cfg.setClientId(op.getClientID());
101 cfg.setSecret(op.getClientSecret());
102 cfg.setProviderMetadata(metadata);
103 cfg.setScope(op.getScopes().stream().collect(Collectors.joining(" ")));
104 cfg.setUseNonce(false);
105 cfg.setLogoutHandler(new NoOpLogoutHandler());
106
107 OidcClient client = new OidcClient(cfg);
108 client.setName(op.getName());
109 client.setCallbackUrlResolver(new NoParameterCallbackUrlResolver());
110 client.setCallbackUrl(callbackUrl);
111 client.init();
112
113 cache.add(client);
114 return client;
115 }
116
117 public boolean removeAll(final String opName) {
118 return cache.removeIf(c -> opName.equals(c.getName()));
119 }
120 }