You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2023/07/04 09:59:54 UTC
[sling-whiteboard] branch master updated: oidc-rp: rewrite Endpoints as a OidcProviderMetadataRegistry component
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
The following commit(s) were added to refs/heads/master by this push:
new b39b5856 oidc-rp: rewrite Endpoints as a OidcProviderMetadataRegistry component
b39b5856 is described below
commit b39b58568a8c619acddf3f08c7a2d4ecf45d1d82
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Tue Jul 4 12:59:43 2023 +0300
oidc-rp: rewrite Endpoints as a OidcProviderMetadataRegistry component
---
.../sling/servlets/oidc_rp/impl/Endpoints.java | 56 ----------------------
.../servlets/oidc_rp/impl/OidcCallbackServlet.java | 14 +++---
.../oidc_rp/impl/OidcEntryPointServlet.java | 14 +++---
.../oidc_rp/impl/OidcProviderMetadataRegistry.java | 51 ++++++++++++++++++++
4 files changed, 66 insertions(+), 69 deletions(-)
diff --git a/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/Endpoints.java b/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/Endpoints.java
deleted file mode 100644
index 892ca7ab..00000000
--- a/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/Endpoints.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sling.servlets.oidc_rp.impl;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.net.http.HttpResponse.BodyHandlers;
-
-import javax.json.Json;
-import javax.json.JsonObject;
-import javax.json.JsonReader;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-record Endpoints(String authorizationEndpoint, String tokenEndpoint) {
-
- private static final Logger logger = LoggerFactory.getLogger(Endpoints.class);
-
- // TODO - cache endpoints, move to service?
- // TODO - can we reuse code from the Nimbus SDK?
- static Endpoints discover(String base, HttpClient client) throws IOException, InterruptedException {
- logger.info("Initiating discovery request for baseUrl {}", base);
- HttpRequest discoveryRequest = HttpRequest.newBuilder()
- .uri(URI.create(base + "/.well-known/openid-configuration"))
- .build();
-
- HttpResponse<byte[]> response = client.send(discoveryRequest, BodyHandlers.ofByteArray());
- try (JsonReader reader = Json.createReader(new ByteArrayInputStream(response.body()))) {
- JsonObject cfg = reader.readObject();
- String authEndpoint = cfg.getJsonString("authorization_endpoint").getString();
- String tokenEndpoint = cfg.getJsonString("token_endpoint").getString();
- Endpoints ep = new Endpoints(authEndpoint, tokenEndpoint);
- logger.info("Discovered auth_endpoint {} , token_endpoint {}", ep.authorizationEndpoint(), ep.tokenEndpoint());
- return ep;
- }
- }
-}
\ No newline at end of file
diff --git a/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcCallbackServlet.java b/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcCallbackServlet.java
index 5c1e4673..3d15265f 100644
--- a/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcCallbackServlet.java
+++ b/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcCallbackServlet.java
@@ -22,7 +22,6 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
-import java.net.http.HttpClient;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
@@ -58,6 +57,7 @@ import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse;
import com.nimbusds.openid.connect.sdk.AuthenticationResponse;
import com.nimbusds.openid.connect.sdk.AuthenticationResponseParser;
import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
@Component(service = { Servlet.class })
@SlingServletPaths(OidcCallbackServlet.PATH)
@@ -70,15 +70,18 @@ public class OidcCallbackServlet extends SlingAllMethodsServlet {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Map<String, OidcConnection> connections;
private final OidcConnectionPersister persister;
+ private final OidcProviderMetadataRegistry metadataRegistry;
static String getCallbackUri(HttpServletRequest request) {
return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + PATH;
}
@Activate
- public OidcCallbackServlet(@Reference(policyOption = GREEDY) List<OidcConnection> connections, @Reference OidcConnectionPersister persister) {
+ public OidcCallbackServlet(@Reference(policyOption = GREEDY) List<OidcConnection> connections, @Reference OidcConnectionPersister persister,
+ @Reference OidcProviderMetadataRegistry metadataRegistry) {
this.connections = connections.stream()
.collect(Collectors.toMap( OidcConnection::name, Function.identity()));
+ this.metadataRegistry = metadataRegistry;
this.persister = persister;
}
@@ -126,11 +129,10 @@ public class OidcCallbackServlet extends SlingAllMethodsServlet {
AuthorizationCode code = new AuthorizationCode(authCode);
- HttpClient client = HttpClient.newHttpClient();
- Endpoints ep = Endpoints.discover(connection.baseUrl(), client);
+ OIDCProviderMetadata providerMetadata = metadataRegistry.getProviderMetadata(connection.baseUrl());
TokenRequest tokenRequest = new TokenRequest(
- new URI(ep.tokenEndpoint()),
+ providerMetadata.getTokenEndpointURI(),
clientCredentials,
new AuthorizationCodeGrant(code, new URI(getCallbackUri(request)))
);
@@ -163,8 +165,6 @@ public class OidcCallbackServlet extends SlingAllMethodsServlet {
}
} catch (ParseException | URISyntaxException | IOException e) {
throw new ServletException(e);
- } catch (InterruptedException e1) {
- Thread.currentThread().interrupt();
}
}
diff --git a/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcEntryPointServlet.java b/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcEntryPointServlet.java
index f9853b0d..8b67aaf9 100644
--- a/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcEntryPointServlet.java
+++ b/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcEntryPointServlet.java
@@ -23,7 +23,6 @@ import static org.osgi.service.component.annotations.ReferencePolicyOption.GREED
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
-import java.net.http.HttpClient;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@@ -50,6 +49,7 @@ import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.id.State;
import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
import com.nimbusds.openid.connect.sdk.Nonce;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
@Component(service = { Servlet.class })
@SlingServletPaths(OidcEntryPointServlet.PATH)
@@ -62,10 +62,14 @@ public class OidcEntryPointServlet extends SlingAllMethodsServlet {
private final Map<String, OidcConnection> connections;
+ private final OidcProviderMetadataRegistry metadataRegistry;
+
@Activate
- public OidcEntryPointServlet(@Reference(policyOption = GREEDY) List<OidcConnection> connections) {
+ public OidcEntryPointServlet(@Reference(policyOption = GREEDY) List<OidcConnection> connections,
+ @Reference OidcProviderMetadataRegistry metadataRegistry) {
this.connections = connections.stream()
.collect(Collectors.toMap( OidcConnection::name, Function.identity()));
+ this.metadataRegistry = metadataRegistry;
}
@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
@@ -89,7 +93,7 @@ public class OidcEntryPointServlet extends SlingAllMethodsServlet {
throw new ServletException("Misconfigured baseUrl");
try {
- Endpoints ep = Endpoints.discover(connection.baseUrl(), HttpClient.newHttpClient());
+ OIDCProviderMetadata providerMetadata = metadataRegistry.getProviderMetadata(connection.baseUrl());
// The client ID provisioned by the OpenID provider when
// the client was registered
@@ -113,7 +117,7 @@ public class OidcEntryPointServlet extends SlingAllMethodsServlet {
new ResponseType("code"),
new Scope(connection.scopes()),
clientID, callback)
- .endpointURI(new URI(ep.authorizationEndpoint()))
+ .endpointURI(providerMetadata.getAuthorizationEndpointURI())
.state(state)
.nonce(nonce)
.customParameter("access_type", "offline") // request refresh token. TODO - is this Google-specific?
@@ -122,8 +126,6 @@ public class OidcEntryPointServlet extends SlingAllMethodsServlet {
response.sendRedirect(authRequest.toURI().toString());
} catch (URISyntaxException e) {
throw new ServletException(e);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
}
}
}
diff --git a/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcProviderMetadataRegistry.java b/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcProviderMetadataRegistry.java
new file mode 100644
index 00000000..ddc75e87
--- /dev/null
+++ b/org.apache.sling.servlets.oidc-rp/src/main/java/org/apache/sling/servlets/oidc_rp/impl/OidcProviderMetadataRegistry.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.servlets.oidc_rp.impl;
+
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.osgi.service.component.annotations.Component;
+
+import com.nimbusds.oauth2.sdk.GeneralException;
+import com.nimbusds.oauth2.sdk.id.Issuer;
+import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
+
+/**
+ * A registry for provider metadata
+ *
+ * <p>Encapsulates the logic for retrieving the {@link #OIDCProviderMetadata} for a given
+ * connection.</p>
+ *
+ * <p>Maintains a best-effort, unbounded, cache for the metadata, on the assumption that
+ * there will be a small number of OIDC connections configured.</p>
+ */
+@Component(service = OidcProviderMetadataRegistry.class)
+public class OidcProviderMetadataRegistry {
+ private final ConcurrentMap<String, OIDCProviderMetadata> cache = new ConcurrentHashMap<>();
+
+ public OIDCProviderMetadata getProviderMetadata(String base) {
+ return cache.computeIfAbsent(base, s -> {
+ try {
+ return OIDCProviderMetadata.resolve(new Issuer(s));
+ } catch (GeneralException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+}
\ No newline at end of file