[java-idp-plugin-oidc-op-oidfed] branch main updated: Initial implementation for the trust mark status metadata cache. WIP.
Henri Mikkonen
henri.mikkonen at iki.fi
Wed Nov 12 14:05:16 UTC 2025
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch main
in repository java-idp-plugin-oidc-op-oidfed.
View the commit online:
https://git.shibboleth.net/view/?p=java-idp-plugin-oidc-op-oidfed.git;a=commit;h=d9cbf84575cb6b20bc9e1d382fe5c19feaf9887c
The following commit(s) were added to refs/heads/main by this push:
new d9cbf84 Initial implementation for the trust mark status metadata cache. WIP.
d9cbf84 is described below
commit d9cbf84575cb6b20bc9e1d382fe5c19feaf9887c
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed Nov 12 16:05:01 2025 +0200
Initial implementation for the trust mark status metadata cache. WIP.
- Extracted resolve entity API fetching strategy's common bits into an abstract class
- Both resolve entity and trust mark status exploit that
- Use container with null response for entity-configuration and resolve-entity
- Avoids warnings by metadata cache -layer when fetching strategy returns null
---
.../messaging/impl/TrustMarkStatusRequest.java | 72 ++++++++
.../messaging/impl/TrustMarkStatusResponse.java | 87 +++++++++
...FederationEndpointResponseFetchingStrategy.java | 194 +++++++++++++++++++++
...ntityConfigurationResponseFetchingStrategy.java | 5 +-
...faultResolveEntityResponseFetchingStrategy.java | 8 +-
...ultResolveEntityTrustChainFetchingStrategy.java | 169 ++++--------------
.../DefaultTrustMarkStatusFetchingStrategy.java | 113 ++++++++++++
...sResponseSignatureValidationFilterStrategy.java | 128 ++++++++++++++
.../oidfed/metadata/NimbusResponseContainer.java | 11 +-
.../metadata/ResolveEntityResponseContainer.java | 3 +-
.../op/oidfed/metadata/TrustMarkCriterion.java | 79 +++++++++
.../metadata/TrustMarkStatusRequestCriterion.java | 80 +++++++++
....java => TrustMarkStatusResponseContainer.java} | 33 ++--
.../META-INF/net.shibboleth.idp/postconfig.xml | 25 ++-
14 files changed, 850 insertions(+), 157 deletions(-)
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkStatusRequest.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkStatusRequest.java
new file mode 100644
index 0000000..65a50bb
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkStatusRequest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed 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 net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl;
+
+import java.net.URI;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.oauth2.sdk.Request;
+import com.nimbusds.oauth2.sdk.http.HTTPRequest;
+
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * Request message to the OpenID federation Trust Mark Status endpoint.
+ */
+public class TrustMarkStatusRequest implements Request {
+
+ /** The endpoint URI of the request. */
+ @Nonnull private final URI endpointUri;
+
+ /** The trust mark JWT for the request. */
+ @Nonnull private final SignedJWT trustMark;
+
+ /**
+ * Constructor.
+ *
+ * @param uri endpoint URI
+ * @param jwt trust mark
+ */
+ public TrustMarkStatusRequest(@Nonnull final URI uri, @Nonnull final SignedJWT jwt) {
+ endpointUri = Constraint.isNotNull(uri, "Endpoint URI cannot be null");
+ trustMark = Constraint.isNotNull(jwt, "Trust Mark JWT cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nonnull
+ public URI getEndpointURI() {
+ return endpointUri;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public HTTPRequest toHTTPRequest() {
+ //TODO
+ return null;
+ }
+
+ /**
+ * Get the trust mark for the request.
+ *
+ * @return trust mark
+ */
+ @Nullable public SignedJWT getTrustMark() {
+ return trustMark;
+ }
+
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkStatusResponse.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkStatusResponse.java
new file mode 100644
index 0000000..fa94f8d
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkStatusResponse.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed 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 net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl;
+
+import javax.annotation.Nonnull;
+
+import com.nimbusds.common.contenttype.ContentType;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.http.HTTPResponse;
+
+import net.shibboleth.shared.logic.ConstraintViolationException;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * Response message to the OpenID federation Trust Mark status endpoint.
+ */
+public class TrustMarkStatusResponse extends AbstractSignedJWTResponse {
+
+ /** The JWT type header. */
+ @Nonnull
+ public static final JOSEObjectType JWT_TYPE_HEADER = new JOSEObjectType("trust-mark-status-response+jwt");
+
+ /** The content type. */
+ @Nonnull public static final ContentType HTTP_RESPONSE_CONTENT_TYPE =
+ new ContentType("application", JWT_TYPE_HEADER.toString());
+
+ /**
+ * Constructor.
+ *
+ * @param statement JWT
+ */
+ public TrustMarkStatusResponse(@Nonnull final SignedJWT statement) {
+ super(statement);
+ }
+
+ /** {@inheritDoc} */
+ protected ContentType getHttpResponseContentType() {
+ return HTTP_RESPONSE_CONTENT_TYPE;
+ }
+
+ /** {@inheritDoc} */
+ protected JOSEObjectType getJWTTypeHeader() {
+ return JWT_TYPE_HEADER;
+ }
+
+ /**
+ * Parses a federation resolve entity success response from the given HTTP response.
+ *
+ * @param httpResponse the HTTP response
+ * @return resolve entity success response
+ * @throws ParseException if HTTP response could not be parsed into resolve entity response
+ */
+ @Nonnull
+ public static TrustMarkStatusResponse parse(@Nonnull final HTTPResponse httpResponse)
+ throws ParseException {
+
+ httpResponse.ensureStatusCode(HTTPResponse.SC_OK);
+ httpResponse.ensureEntityContentType(HTTP_RESPONSE_CONTENT_TYPE);
+ final String content = httpResponse.getContent();
+
+ if (StringSupport.trimOrNull(content) == null) {
+ throw new ParseException("Message body is empty");
+ }
+
+ try {
+ final SignedJWT jwt = SignedJWT.parse(httpResponse.getContent());
+ assert jwt != null;
+ return new TrustMarkStatusResponse(jwt);
+ } catch (final java.text.ParseException | ConstraintViolationException e) {
+ throw new ParseException(e.getMessage(), e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/AbstractFederationEndpointResponseFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/AbstractFederationEndpointResponseFetchingStrategy.java
new file mode 100644
index 0000000..72f05cf
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/AbstractFederationEndpointResponseFetchingStrategy.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed 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 net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.hc.client5.http.classic.HttpClient;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.ProtocolException;
+import org.opensaml.security.httpclient.HttpClientSecurityParameters;
+import org.opensaml.security.httpclient.HttpClientSecuritySupport;
+import org.slf4j.Logger;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nimbusds.oauth2.sdk.Request;
+
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
+
+/**
+ * An abstract base class for fetching strategies related to OpenID Federation endpoints.
+ *
+ * @param <R> request message class sent to the federation endpoint
+ * @param <C> response message container class stored to the metadata cache
+ */
+public abstract class
+ AbstractFederationEndpointResponseFetchingStrategy<R extends Request, C extends NimbusResponseContainer>
+ extends AbstractIdentifiableInitializableComponent implements Function<CriteriaSet, C> {
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(AbstractFederationEndpointResponseFetchingStrategy.class);
+
+ /** HTTP client to use. */
+ @NonnullAfterInit protected HttpClient httpClient;
+
+ /** HTTP client security parameters. */
+ @Nullable private HttpClientSecurityParameters httpClientSecurityParameters;
+
+ /** JSON object mapper used for decoding JSON into Map. */
+ @NonnullAfterInit private ObjectMapper objectMapper;
+
+ /** Strategy to fetch request from the criteria set. */
+ @NonnullAfterInit private Function<CriteriaSet, R> criteriaToRequestStrategy;
+
+ /**
+ * Set the {@link HttpClient} to use.
+ *
+ * @param client HTTP client to use
+ */
+ public void setHttpClient(@Nonnull final HttpClient client) {
+ checkSetterPreconditions();
+ httpClient = Constraint.isNotNull(client, "HttpClient cannot be null");
+ }
+
+ /**
+ * Set the optional client security parameters.
+ *
+ * @param params the new client security parameters
+ */
+ public void setHttpClientSecurityParameters(@Nullable final HttpClientSecurityParameters params) {
+ checkSetterPreconditions();
+ httpClientSecurityParameters = params;
+ }
+
+ /**
+ * Set the strategy to fetch request from the criteria set.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setCriteriaToRequestStrategy(@Nonnull final Function<CriteriaSet, R> strategy) {
+ checkSetterPreconditions();
+ criteriaToRequestStrategy = Constraint.isNotNull(strategy, "Criteria to request strategy cannot be null");
+ }
+
+ /**
+
+ * Set the JSON {@link ObjectMapper} used for decoding JSON into Map.
+ *
+ * @param mapper object mapper
+ */
+ public void setObjectMapper(@Nonnull final ObjectMapper mapper) {
+ checkSetterPreconditions();
+
+ objectMapper = Constraint.isNotNull(mapper, "Object mapper cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+ if (httpClient == null) {
+ throw new ComponentInitializationException("Httpclient cannot be null");
+ }
+ if (objectMapper == null) {
+ throw new ComponentInitializationException("Object mapper cannot be null");
+ }
+ if (criteriaToRequestStrategy == null) {
+ throw new ComponentInitializationException("Criteria to request strategy cannot be null");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nullable
+ public C apply(@Nullable final CriteriaSet criteria) {
+ checkComponentActive();
+ if (criteria == null) {
+ log.error("No criteria set provided");
+ return null;
+ }
+ final R request = criteriaToRequestStrategy.apply(criteria);
+ if (request == null) {
+ log.debug("Could not resolve request from criteria {}", criteria);
+ return null;
+ }
+ final ClassicHttpRequest httpRequest = initializeHttpRequest(criteria, request);
+ if (httpRequest == null) {
+ log.debug("Could not initialize HTTP request from {}", request);
+ return null;
+ }
+ final HttpClientContext httpContext = buildHttpContext(httpRequest);
+ try (final ClassicHttpResponse response = httpClient.executeOpen(null, httpRequest, httpContext)) {
+ final String scheme = httpRequest.getUri().getScheme();
+ assert scheme != null;
+ HttpClientSecuritySupport.checkTLSCredentialEvaluated(httpContext, scheme);
+ return parseHttpResponse(criteria, request, response);
+ } catch (final ProtocolException | URISyntaxException | IOException e) {
+ log.debug("Unable to fetch resolve entity response from URI: {}", request.getEndpointURI(), e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Build the {@link HttpClientContext} instance to be used with {@link #httpClient}.
+ *
+ * @param request the HTTP client request
+ * @return the client context instance
+ */
+ @Nonnull
+ protected HttpClientContext buildHttpContext(@Nonnull final ClassicHttpRequest request) {
+ final HttpClientContext clientContext = HttpClientContext.create();
+ assert clientContext != null;
+ HttpClientSecuritySupport.marshalSecurityParameters(clientContext, httpClientSecurityParameters, false);
+ HttpClientSecuritySupport.addDefaultTLSTrustEngineCriteria(clientContext, request);
+ return clientContext;
+ }
+
+ /**
+ * Initializes the {@link ClassicHttpRequest} to be used with {@link #httpClient}.
+ *
+ * @param criteria criteria set
+ * @param request Nimbus request message
+ * @return the request to be used with {@link #httpClient}
+ */
+ @Nullable protected abstract ClassicHttpRequest initializeHttpRequest(@Nonnull final CriteriaSet criteria,
+ @Nonnull R request);
+
+ /**
+ * Parses the response message container to be stored in the metadata cache.
+ *
+ * @param criteria criteria set
+ * @param request Nimbus request message
+ * @param response the HTTP response obtained from {@link #httpClient}
+ * @return the response message container
+ * @throws ProtocolException if HTTP protocol violation occurs
+ * @throws IOException if generic I/O exception occurs
+ */
+ @Nullable protected abstract C parseHttpResponse(@Nonnull final CriteriaSet criteria, @Nonnull final R request,
+ @Nullable final ClassicHttpResponse response) throws ProtocolException, IOException;
+
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultEntityConfigurationResponseFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultEntityConfigurationResponseFetchingStrategy.java
index 1862386..53e0d30 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultEntityConfigurationResponseFetchingStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultEntityConfigurationResponseFetchingStrategy.java
@@ -14,6 +14,7 @@
package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+import java.time.Instant;
import java.util.function.Function;
import javax.annotation.Nonnull;
@@ -45,8 +46,8 @@ public class DefaultEntityConfigurationResponseFetchingStrategy extends Abstract
}
final NimbusResponseCriterion responseCriterion = criteria.get(NimbusResponseCriterion.class);
if (responseCriterion == null) {
- log.debug("No response criterion given, returning null");
- return null;
+ log.debug("No response criterion given, returning container with a null response expiring now");
+ return new NimbusResponseContainer(null, Instant.now());
}
final ResponseContainerExpirationCriterion expirationCriterion =
criteria.get(ResponseContainerExpirationCriterion.class);
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityResponseFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityResponseFetchingStrategy.java
index 70ba1cc..0cbbd0b 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityResponseFetchingStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityResponseFetchingStrategy.java
@@ -14,6 +14,7 @@
package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+import java.time.Instant;
import java.util.function.Function;
import javax.annotation.Nonnull;
@@ -27,7 +28,8 @@ import net.shibboleth.shared.primitive.LoggerFactory;
import net.shibboleth.shared.resolver.CriteriaSet;
/**
- * Default strategy for fetching resolve entity response container via criteria.
+ * Default strategy for fetching resolve entity response container via criteria. If no {@link NimbusResponseCriterion}
+ * is included in the given criteria, a container with a null response expiring now is returned.
*/
@ThreadSafeAfterInit
public class DefaultResolveEntityResponseFetchingStrategy extends AbstractIdentifiableInitializableComponent
@@ -50,8 +52,8 @@ public class DefaultResolveEntityResponseFetchingStrategy extends AbstractIdenti
}
final NimbusResponseCriterion responseCriterion = criteria.get(NimbusResponseCriterion.class);
if (responseCriterion == null) {
- log.debug("No response criterion given, returning null");
- return null;
+ log.debug("No response criterion given, returning container with a null response expiring now");
+ return new ResolveEntityResponseContainer(null, requestCriterion.getRequest(), Instant.now());
}
final ResponseContainerExpirationCriterion expirationCriterion =
criteria.get(ResponseContainerExpirationCriterion.class);
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityTrustChainFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityTrustChainFetchingStrategy.java
index 9cb323c..b3c2d3b 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityTrustChainFetchingStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityTrustChainFetchingStrategy.java
@@ -20,15 +20,11 @@ import java.net.URISyntaxException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.classic.methods.HttpGet;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.ContentType;
@@ -38,126 +34,44 @@ import org.apache.hc.core5.http.ProtocolException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.net.URIBuilder;
-import org.opensaml.security.httpclient.HttpClientSecurityParameters;
-import org.opensaml.security.httpclient.HttpClientSecuritySupport;
import org.slf4j.Logger;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.ResolveEntityRequest;
import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.ResolveEntityResponse;
-import net.shibboleth.oidc.metadata.cache.MetadataCache;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
-import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
-import net.shibboleth.shared.component.ComponentInitializationException;
-import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
import net.shibboleth.shared.resolver.CriteriaSet;
/**
- * Default strategy for fetching trust chains via resolve entity API for an entity specified in the criteria set.
- * Caches for entity configurations and subordinate statements are exploited for actual fetching of the entity
- * statements. The entity configuration may also be delivered via {@link SubjectEntityStatementCriterion} in the
- * criteria set.
+ * Default strategy for fetching trust chain data via resolve entity API for a request specified in the criteria set.
*/
@ThreadSafeAfterInit
-public class DefaultResolveEntityTrustChainFetchingStrategy extends AbstractIdentifiableInitializableComponent
- implements Function<CriteriaSet, ResolveEntityResponseContainer> {
+public class DefaultResolveEntityTrustChainFetchingStrategy
+ extends AbstractFederationEndpointResponseFetchingStrategy<ResolveEntityRequest, ResolveEntityResponseContainer> {
/** Class logger. */
@Nonnull private Logger log = LoggerFactory.getLogger(DefaultResolveEntityTrustChainFetchingStrategy.class);
- /** Cache containing local copies of trusted trust anchor keys. */
- @NonnullAfterInit private MetadataCache<Map<String, LocalKeyContainer>> localTrustAnchorsCache;
-
- /** HTTP client to use. */
- @NonnullAfterInit protected HttpClient httpClient;
-
- /** HTTP client security parameters. */
- @Nullable private HttpClientSecurityParameters httpClientSecurityParameters;
-
- /** JSON object mapper used for decoding JSON into Map. */
- @NonnullAfterInit private ObjectMapper objectMapper;
-
- /**
- * Set the cache containing local copies of trusted trust anchor keys.
- *
- * @param cache cache containing local copies of trusted trust anchor keys.
- */
- public void setLocalTrustAnchorsCache(@Nonnull final MetadataCache<Map<String, LocalKeyContainer>> cache) {
- checkSetterPreconditions();
- localTrustAnchorsCache = Constraint.isNotNull(cache, "Local Trust Anchor cache cannot be null");
- }
-
- /**
- * Set the {@link HttpClient} to use.
- *
- * @param client HTTP client to use
- */
- public void setHttpClient(@Nonnull final HttpClient client) {
- checkSetterPreconditions();
- httpClient = Constraint.isNotNull(client, "HttpClient cannot be null");
- }
-
- /**
- * Set the optional client security parameters.
- *
- * @param params the new client security parameters
- */
- public void setHttpClientSecurityParameters(@Nullable final HttpClientSecurityParameters params) {
- checkSetterPreconditions();
- httpClientSecurityParameters = params;
- }
/**
-
- * Set the JSON {@link ObjectMapper} used for decoding JSON into Map.
- *
- * @param mapper object mapper
+ * Constructor.
*/
- public void setObjectMapper(@Nonnull final ObjectMapper mapper) {
- checkSetterPreconditions();
-
- objectMapper = Constraint.isNotNull(mapper, "Object mapper cannot be null");
- }
-
- /** {@inheritDoc} */
- @Override
- protected void doInitialize() throws ComponentInitializationException {
- super.doInitialize();
- if (localTrustAnchorsCache == null) {
- throw new ComponentInitializationException("Local Trust Anchor cache cannot be null");
- }
- if (httpClient == null) {
- throw new ComponentInitializationException("Httpclient cannot be null");
- }
- if (objectMapper == null) {
- throw new ComponentInitializationException("Object mapper cannot be null");
- }
+ public DefaultResolveEntityTrustChainFetchingStrategy() {
+ setCriteriaToRequestStrategy(criteria -> {
+ final ResolveEntityRequestCriterion requestCriterion = criteria.get(ResolveEntityRequestCriterion.class);
+ if (requestCriterion == null) {
+ log.debug("No request criterion given, returning null");
+ return null;
+ }
+ return requestCriterion.getRequest();
+ });
}
/** {@inheritDoc} */
- @Override @Nullable
- public ResolveEntityResponseContainer apply(@Nullable final CriteriaSet criteria) {
- checkComponentActive();
- if (criteria == null) {
- return null;
- }
-
- final ResolveEntityRequestCriterion requestCriterion = criteria.get(ResolveEntityRequestCriterion.class);
- if (requestCriterion == null) {
- log.debug("No request criterion given, returning null");
- return null;
- }
- final ResponseContainerExpirationCriterion expirationCriterion =
- criteria.get(ResponseContainerExpirationCriterion.class);
- if (expirationCriterion == null) {
- log.debug("No expiration criterion given, returning null");
- return null;
- }
- final ResolveEntityRequest resolveRequest = requestCriterion.getRequest();
+ @Nullable protected ClassicHttpRequest initializeHttpRequest(@Nonnull final CriteriaSet criteria,
+ @Nonnull ResolveEntityRequest resolveRequest) {
final HttpGet httpRequest = new HttpGet(resolveRequest.getEndpointURI());
final List<NameValuePair> nvps = new ArrayList<>();
nvps.add(new BasicNameValuePair("sub", resolveRequest.getSubject()));
@@ -175,45 +89,34 @@ public class DefaultResolveEntityTrustChainFetchingStrategy extends AbstractIden
log.debug("Using URI {} for fetching resolve entity API response", uri);
httpRequest.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED);
httpRequest.setUri(uri);
+ return httpRequest;
+ }
- final HttpClientContext httpContext = buildHttpContext(httpRequest);
- try (final ClassicHttpResponse response = httpClient.executeOpen(null, httpRequest, httpContext)) {
- final String scheme = httpRequest.getUri().getScheme();
- assert scheme != null;
- HttpClientSecuritySupport.checkTLSCredentialEvaluated(httpContext, scheme);
- if (response != null) {
- final HTTPResponse nimbusResponse = new HTTPResponse(response.getCode());
- nimbusResponse.setContent(EntityUtils.toString(response.getEntity()));
+ /** {@inheritDoc} */
+ @Nullable protected ResolveEntityResponseContainer parseHttpResponse(@Nonnull final CriteriaSet criteria,
+ @Nonnull final ResolveEntityRequest request, @Nullable final ClassicHttpResponse response)
+ throws ProtocolException, IOException {
+ final ResponseContainerExpirationCriterion expirationCriterion =
+ criteria.get(ResponseContainerExpirationCriterion.class);
+ if (expirationCriterion == null) {
+ log.debug("No expiration criterion given, returning null");
+ return null;
+ }
+ if (response != null) {
+ final HTTPResponse nimbusResponse = new HTTPResponse(response.getCode());
+ nimbusResponse.setContent(EntityUtils.toString(response.getEntity()));
+ try {
nimbusResponse.setContentType(response.getEntity().getContentType());
final ResolveEntityResponse resolveResponse = ResolveEntityResponse.parse(nimbusResponse);
final Instant expirationTime = expirationCriterion.getExpirationInstant();
- return new ResolveEntityResponseContainer(resolveResponse, resolveRequest, expirationTime);
- } else {
- log.debug("Unable to fetch resolve entity response from URI: {} (null response)", uri);
- //TODO: cache non-success results?
- return null;
+ return new ResolveEntityResponseContainer(resolveResponse, request, expirationTime);
+ } catch (final ParseException e) {
+ log.warn("Could not parse resolve entity response from URI: {}", request.getEndpointURI(), e);
}
- } catch (final ProtocolException | URISyntaxException | IOException | ParseException e) {
- log.debug("Unable to fetch resolve entity response from URI: {}", uri, e);
+ } else {
+ log.debug("Unable to fetch resolve entity response from URI: {} (null response)", request.getEndpointURI());
}
return null;
-
}
-
- /**
- * Build the {@link HttpClientContext} instance to be used by the HttpClient.
- *
- * @param request the HTTP client request
- * @return the client context instance
- */
- @Nonnull
- protected HttpClientContext buildHttpContext(@Nonnull final ClassicHttpRequest request) {
- final HttpClientContext clientContext = HttpClientContext.create();
- assert clientContext != null;
- HttpClientSecuritySupport.marshalSecurityParameters(clientContext, httpClientSecurityParameters, false);
- HttpClientSecuritySupport.addDefaultTLSTrustEngineCriteria(clientContext, request);
- return clientContext;
- }
-
}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkStatusFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkStatusFetchingStrategy.java
new file mode 100644
index 0000000..55184cc
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkStatusFetchingStrategy.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed 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 net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpHeaders;
+import org.apache.hc.core5.http.NameValuePair;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+import org.apache.hc.core5.http.message.BasicNameValuePair;
+import org.slf4j.Logger;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.http.HTTPResponse;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkStatusRequest;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkStatusResponse;
+import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
+
+/**
+ * Default strategy for fetching trust mark status via Trust Mark STatus API for the request specified in the criteria
+ * set. The status response is stored inside a {@link TrustMarkStatusResponseContainer}.
+ */
+ at ThreadSafeAfterInit
+public class DefaultTrustMarkStatusFetchingStrategy
+ extends AbstractFederationEndpointResponseFetchingStrategy<TrustMarkStatusRequest, TrustMarkStatusResponseContainer> {
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(DefaultTrustMarkStatusFetchingStrategy.class);
+
+ /**
+ * Constructor.
+ */
+ public DefaultTrustMarkStatusFetchingStrategy() {
+ setCriteriaToRequestStrategy(criteria -> {
+ final TrustMarkStatusRequestCriterion requestCriterion =
+ criteria.get(TrustMarkStatusRequestCriterion.class);
+ if (requestCriterion == null) {
+ log.debug("No request criterion given, returning null");
+ return null;
+ }
+ return requestCriterion.getRequest();
+ });
+ }
+
+ /** {@inheritDoc} */
+ @Nullable protected ClassicHttpRequest initializeHttpRequest(@Nonnull final CriteriaSet criteria,
+ @Nonnull TrustMarkStatusRequest request) {
+ final HttpPost httpRequest = new HttpPost(request.getEndpointURI());
+ final List<NameValuePair> nvps = new ArrayList<>();
+ nvps.add(new BasicNameValuePair("trust_mark", request.getTrustMark().serialize()));
+ final UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8);
+ httpRequest.setEntity(urlEncodedFormEntity);
+ httpRequest.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED);
+
+ return httpRequest;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable protected TrustMarkStatusResponseContainer parseHttpResponse(@Nonnull final CriteriaSet criteria,
+ @Nonnull final TrustMarkStatusRequest request, @Nullable final ClassicHttpResponse response)
+ throws ProtocolException, IOException {
+ final ResponseContainerExpirationCriterion expirationCriterion =
+ criteria.get(ResponseContainerExpirationCriterion.class);
+ if (expirationCriterion == null) {
+ log.debug("No expiration criterion given, returning null");
+ return null;
+ }
+ if (response != null) {
+ final HTTPResponse nimbusResponse = new HTTPResponse(response.getCode());
+ nimbusResponse.setContent(EntityUtils.toString(response.getEntity()));
+ try {
+ nimbusResponse.setContentType(response.getEntity().getContentType());
+ final TrustMarkStatusResponse statusResponse = TrustMarkStatusResponse.parse(nimbusResponse);
+ final Instant expirationTime = expirationCriterion.getExpirationInstant();
+ return new TrustMarkStatusResponseContainer(statusResponse, request.getTrustMark(), expirationTime);
+ } catch (final ParseException e) {
+ log.warn("Could not parse resolve entity response from URI: {}", request.getEndpointURI(), e);
+ }
+ } else {
+ log.debug("Unable to fetch resolve entity response from URI: {} (null response)", request.getEndpointURI());
+ }
+
+ return null;
+ }
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy.java
new file mode 100644
index 0000000..bb63f0d
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed 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 net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+
+import java.text.ParseException;
+import java.util.List;
+import java.util.function.BiFunction;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.trust.TrustEngine;
+import org.slf4j.Logger;
+
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.openid.connect.sdk.federation.entities.EntityStatement;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkStatusResponse;
+import net.shibboleth.oidc.metadata.cache.MetadataCache;
+import net.shibboleth.oidc.metadata.cache.MetadataCacheException;
+import net.shibboleth.oidc.metadata.filter.MetadataFilterContext;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
+
+/**
+ * Default signature validating filter for Trust Mark Status response. The signature validation is performed via
+ * configurable {@link TrustEngine}.
+ */
+ at ThreadSafeAfterInit
+public class DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy
+ extends AbstractTrustEngineSignatureValidationComponent
+ implements BiFunction<TrustMarkStatusResponseContainer, MetadataFilterContext, TrustMarkStatusResponseContainer> {
+
+ /** Class logger. */
+ @Nonnull private Logger log =
+ LoggerFactory.getLogger(DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy.class);
+
+ /** Cache used to fetch the issuer entity configuration from. */
+ @NonnullAfterInit private MetadataCache<List<EntityStatement>> trustChainCache;
+
+ /**
+ * Set the cache used to fetch the trust chain for the trust mark issuer from.
+ *
+ * @param cache cache used to fetch the trust chain for the trust mark issuer from
+ */
+ public void setTrustChainCache(@Nonnull final MetadataCache<List<EntityStatement>> cache) {
+ checkSetterPreconditions();
+ trustChainCache = Constraint.isNotNull(cache, "Trust Chain cache cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+ if (trustChainCache == null) {
+ throw new ComponentInitializationException("Trust Chain cache cannot be null");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nullable
+ public TrustMarkStatusResponseContainer apply(@Nullable final TrustMarkStatusResponseContainer response,
+ @Nullable final MetadataFilterContext filterContext) {
+ checkComponentActive();
+ if (response == null) {
+ return null;
+ }
+ if (response.getResponse() instanceof TrustMarkStatusResponse successResponse) {
+ final SignedJWT jwt = successResponse.getJWT();
+ final String entityId;
+ try {
+ entityId = jwt.getJWTClaimsSet().getIssuer();
+ } catch (final ParseException e) {
+ log.error("Could not parse issuer entity ID value from the response", e);
+ return null;
+ }
+ final EntityStatement issuerStatement = fetchIssuerStatement(entityId);
+ if (issuerStatement == null) {
+ return null;
+ }
+ log.trace("Starting signature validation of success response from {}", entityId);
+ final CriteriaSet criteria = new CriteriaSet(new SubjectEntityStatementCriterion(issuerStatement));
+ if (validateJwt(jwt, criteria, entityId)) {
+ return response;
+ }
+ } else {
+ log.trace("Ignoring signature validation for the error response");
+ return response;
+ }
+ return null;
+ }
+
+ /**
+ * Fetch the issuer entity configuration from the trust chain metadata cache.
+ *
+ * @param issuer the issuer entity ID
+ * @return the issuer entity configuration, or null if could not be fetched
+ */
+ @Nullable protected EntityStatement fetchIssuerStatement(@Nonnull final String issuer) {
+ final CriteriaSet criteria = new CriteriaSet(new SubjectEntityIDCriterion(issuer));
+ try {
+ final List<List<EntityStatement>> result = trustChainCache.get(criteria);
+ if (!result.isEmpty() && !result.get(0).isEmpty()) {
+ return result.get(0).get(0);
+ }
+ } catch (final MetadataCacheException e) {
+ log.debug("Error while fetching issuer trust chain for {}", issuer, e);
+ }
+ log.warn("Could not fetch entity configuration for {}", issuer);
+ return null;
+ }
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/NimbusResponseContainer.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/NimbusResponseContainer.java
index 9928613..188c501 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/NimbusResponseContainer.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/NimbusResponseContainer.java
@@ -18,6 +18,7 @@ import java.io.Serializable;
import java.time.Instant;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import com.nimbusds.oauth2.sdk.Response;
@@ -32,7 +33,7 @@ public class NimbusResponseContainer implements Serializable {
private static final long serialVersionUID = 656269369356865370L;
/** Response message. */
- @Nonnull private final Response response;
+ @Nullable private final Response response;
/** Expiration instant for this container. */
@Nonnull private final Instant expiration;
@@ -43,9 +44,9 @@ public class NimbusResponseContainer implements Serializable {
* @param responseMessage response message
* @param expirationInstant expiration instant
*/
- public NimbusResponseContainer(@Nonnull final Response responseMessage,
+ public NimbusResponseContainer(@Nullable final Response responseMessage,
@Nonnull final Instant expirationInstant) {
- response = Constraint.isNotNull(responseMessage, "Response message cannot be null");
+ response = responseMessage;
expiration = Constraint.isNotNull(expirationInstant, "Expiration instant cannot be null");
}
@@ -54,7 +55,7 @@ public class NimbusResponseContainer implements Serializable {
*
* @return response message
*/
- public Response getResponse() {
+ @Nullable public Response getResponse() {
return response;
}
@@ -63,7 +64,7 @@ public class NimbusResponseContainer implements Serializable {
*
* @return expiration instant
*/
- public Instant getExpirationInstant() {
+ @Nonnull public Instant getExpirationInstant() {
return expiration;
}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponseContainer.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponseContainer.java
index 103a436..edeabe8 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponseContainer.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponseContainer.java
@@ -18,6 +18,7 @@ import java.io.Serializable;
import java.time.Instant;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import com.nimbusds.oauth2.sdk.Response;
@@ -42,7 +43,7 @@ public class ResolveEntityResponseContainer extends NimbusResponseContainer impl
* @param requestMessage request message
* @param expirationInstant expiration instant
*/
- public ResolveEntityResponseContainer(@Nonnull final Response responseMessage,
+ public ResolveEntityResponseContainer(@Nullable final Response responseMessage,
@Nonnull final ResolveEntityRequest requestMessage, @Nonnull final Instant expirationInstant) {
super(responseMessage, expirationInstant);
request = Constraint.isNotNull(requestMessage, "Request message cannot be null");
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkCriterion.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkCriterion.java
new file mode 100644
index 0000000..3bc1f5b
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkCriterion.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed 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 net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+
+import java.util.Objects;
+
+import javax.annotation.Nonnull;
+
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.resolver.Criterion;
+
+/**
+ * A {@link Criterion} representing a trust mark.
+ */
+public class TrustMarkCriterion implements Criterion {
+
+ /** The trust mark value. */
+ @Nonnull final SignedJWT value;
+
+ /**
+ * Constructor.
+ *
+ * @param jwt the trust mark value, must not be null
+ */
+ public TrustMarkCriterion(@Nonnull final SignedJWT jwt) {
+ value = Constraint.isNotNull(jwt, "Trust Mark cannot be null");
+ }
+
+ /**
+ * Get the trust mark value.
+ *
+ * @return the trust mar value
+ */
+ @Nonnull public SignedJWT getValue() {
+ return value;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "TrustMarkCriterion [value=" + value.serialize() + "]";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return Objects.hash(value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final TrustMarkCriterion other = (TrustMarkCriterion) obj;
+ return value.serialize().equals(other.value.serialize());
+ }
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusRequestCriterion.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusRequestCriterion.java
new file mode 100644
index 0000000..f33a060
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusRequestCriterion.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed 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 net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+
+import java.util.Objects;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkStatusRequest;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.resolver.Criterion;
+
+/**
+ * A {@link Criterion} representing request message to a Trust Mark Status API.
+ */
+public class TrustMarkStatusRequestCriterion implements Criterion {
+
+ /** The request message. */
+ @Nonnull private final TrustMarkStatusRequest request;
+
+ /**
+ * Constructor.
+ *
+ * @param requestMessage request message, must not be null
+ */
+ public TrustMarkStatusRequestCriterion(@Nonnull final TrustMarkStatusRequest requestMessage) {
+ request = Constraint.isNotNull(requestMessage, "Request cannot be null");
+ }
+
+ /**
+ * Get the request message.
+ *
+ * @return the request message
+ */
+ @Nonnull public TrustMarkStatusRequest getRequest() {
+ return request;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "TrustMarkStatusRequestCriterion [request=" + request + "]";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return Objects.hash(request);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final TrustMarkStatusRequestCriterion other = (TrustMarkStatusRequestCriterion) obj;
+ //TODO: proper equals-check
+ return request.equals(other.request);
+ }
+
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponseContainer.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusResponseContainer.java
similarity index 58%
copy from idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponseContainer.java
copy to idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusResponseContainer.java
index 103a436..3a2652a 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponseContainer.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusResponseContainer.java
@@ -19,33 +19,33 @@ import java.time.Instant;
import javax.annotation.Nonnull;
+import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.oauth2.sdk.Response;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.ResolveEntityRequest;
import net.shibboleth.shared.logic.Constraint;
/**
- * A container class for metadata caches carrying request and response message details related to Resolve Entity API.
+ * A container class for metadata caches carrying request and response message details related to Trust Mark Status API.
*/
-public class ResolveEntityResponseContainer extends NimbusResponseContainer implements Serializable {
+public class TrustMarkStatusResponseContainer extends NimbusResponseContainer implements Serializable {
/** Serial version UID. */
- private static final long serialVersionUID = 756269369356865370L;
+ private static final long serialVersionUID = 756269383556865370L;
- /** Request message. */
- @Nonnull private final ResolveEntityRequest request;
+ /** Trust Mark. */
+ @Nonnull private final SignedJWT trustMark;
/**
* Constructor.
*
* @param responseMessage response message
- * @param requestMessage request message
+ * @param jwt trust mark
* @param expirationInstant expiration instant
*/
- public ResolveEntityResponseContainer(@Nonnull final Response responseMessage,
- @Nonnull final ResolveEntityRequest requestMessage, @Nonnull final Instant expirationInstant) {
+ public TrustMarkStatusResponseContainer(@Nonnull final Response responseMessage,
+ @Nonnull final SignedJWT jwt, @Nonnull final Instant expirationInstant) {
super(responseMessage, expirationInstant);
- request = Constraint.isNotNull(requestMessage, "Request message cannot be null");
+ trustMark = Constraint.isNotNull(jwt, "Trust Mark JWT cannot be null");
}
/**
@@ -53,8 +53,17 @@ public class ResolveEntityResponseContainer extends NimbusResponseContainer impl
*
* @return request message
*/
- public ResolveEntityRequest getRequest() {
- return request;
+ public SignedJWT getTrustMark() {
+ return trustMark;
+ }
+
+ /**
+ * Get response message.
+ *
+ * @return response message
+ */
+ @Nonnull public Response getResponse() {
+ return super.getResponse();
}
}
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index 020249d..ea4b2d8 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -255,7 +255,6 @@
<bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultResolveEntityTrustChainFetchingStrategy"
p:httpClient="#{getObject('shibboleth.oidfed.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
p:httpClientSecurityParameters="#{getObject('shibboleth.oidfed.NonBrowser.HttpClientSecurityParameters')}"
- p:localTrustAnchorsCache-ref="shibboleth.oidfed.LocalTrustAnchorsMetadataCache"
p:objectMapper-ref="shibboleth.oidfed.policy.JSONObjectMapper"/>
</property>
</bean>
@@ -305,6 +304,30 @@
</property>
</bean>
+ <bean id="shibboleth.oidfed.TrustMarkStatusMetadataCacheBuilderSpec"
+ class="net.shibboleth.oidc.metadata.cache.impl.DynamicMetadataCacheBuilderSpec"
+ p:metadataExpirationTimeStrategy-ref="shibboleth.oidfed.DefaultEntityStatementExpirationTimeStrategy"
+ p:minCacheDuration="%{idp.oidfed.cache.trustMarkStatus.maxRefreshDelay:PT60S}"
+ p:maxCacheDuration="%{idp.oidfed.cache.trustMarkStatus.maxRefreshDelay:PT30M}">
+ <property name="identifierExtractionStrategy">
+ <bean parent="shibboleth.Functions.Expression" c:expression="#input?.getRequest().getTrustMark().serialize()"/>
+ </property>
+ <property name="criteriaToIdentifierStrategy">
+ <bean parent="shibboleth.Functions.Expression" c:expression="#input?.get(T(net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.TrustMarkRequestCriterion))?.getRequest().getTrustMark().serialize()"/>
+ </property>
+ <property name="metadataFilterStrategy">
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy"
+ p:trustChainCache-ref="shibboleth.oidfed.TrustChainMetadataCache"
+ p:trustEngine-ref="shibboleth.oidfed.DefaultEntityConfigurationTrustEngine"/>
+ </property>
+ <property name="fetchStrategy">
+ <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultTrustMarkStatusFetchingStrategy"
+ p:httpClient="#{getObject('shibboleth.oidfed.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
+ p:httpClientSecurityParameters="#{getObject('shibboleth.oidfed.NonBrowser.HttpClientSecurityParameters')}"
+ p:objectMapper-ref="shibboleth.oidfed.policy.JSONObjectMapper"/>
+ </property>
+ </bean>
+
<bean id="shibboleth.oidfed.DefaultDelegatedTrustMarkTrustEngine"
class="net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine">
<constructor-arg index="0">
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list