[java-idp-plugin-oidc-op-oidfed] 02/02: Refactoring for metadata caches related to remote entity resolver and trust marks.

Codeberg noreply at shibboleth.net
Wed Dec 17 13:47:19 UTC 2025


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch dev/CACHE-REFACTOR
in repository java-idp-plugin-oidc-op-oidfed.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-oidc-op-oidfed/commit/154625d98fe5a81200139fdec1833629326f04f9

commit 154625d98fe5a81200139fdec1833629326f04f9
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed Dec 17 15:46:45 2025 +0200

    Refactoring for metadata caches related to remote entity resolver and trust marks.
    
    - Harmonised them with the caches related to other fetched entity statements
      - Request/Response are not using Nimbus interfaces anymore
      - Syntax validation via Jackson object mapper
      - Content validation during metadata filtering
---
 .../op/oidfed/metadata/ResolveEntityResponse.java  |  60 ++++++
 .../metadata/ResolveEntityResponsePayload.java     |  86 ++++++++
 .../plugin/oidc/op/oidfed/metadata/TrustMark.java  |  60 ++++++
 .../oidc/op/oidfed/metadata/TrustMarkPayload.java  | 126 ++++++++++++
 .../oidc/op/oidfed/metadata/TrustMarkStatus.java   |  60 ++++++
 .../op/oidfed/metadata/TrustMarkStatusPayload.java |  80 ++++++++
 .../oidfed/messaging/impl/TrustMarkResponse.java   |  87 --------
 .../messaging/impl/TrustMarkStatusRequest.java     |  72 -------
 .../messaging/impl/TrustMarkStatusResponse.java    |  87 --------
 ...FederationEndpointResponseFetchingStrategy.java | 194 ------------------
 ...yResponseSignatureValidationFilterStrategy.java | 129 ------------
 ...ultResolveEntityTrustChainFetchingStrategy.java | 122 ------------
 .../metadata/DefaultTrustMarkFetchingStrategy.java | 114 -----------
 ...kResponseSignatureValidationFilterStrategy.java | 129 ------------
 .../DefaultTrustMarkStatusFetchingStrategy.java    | 113 -----------
 .../op/oidfed/metadata/EntityStatementHelper.java  |   8 +-
 .../metadata/TrustMarkResponseContainer.java       |  75 -------
 .../metadata/TrustMarkStatusResponseContainer.java |  69 -------
 ...EntityStatementContentValidationCondition.java} |  21 +-
 ...atementValidationCriteriaSetLookupFunction.java | 113 +++++++++++
 ...ultResolveEntityTrustChainFetchingStrategy.java | 134 +++++++++++++
 ...emoteResolveEntityCacheContainerIdentifier.java | 143 +++++++++++++
 ...moteResolveEntityCacheIdentifierCriterion.java} |  34 ++--
 .../RemoteResolveEntityResponseContainer.java      |  69 +++++++
 .../cache/tm/DefaultTrustMarkFetchingStrategy.java | 130 ++++++++++++
 .../tm/DefaultTrustMarkStatusFetchingStrategy.java | 129 ++++++++++++
 ...stMarkValidationCriteriaSetLookupFunction.java} |  83 ++++----
 .../cache/tm/RemoteTrustMarkContainer.java         |  68 +++++++
 .../cache/tm/RemoteTrustMarkStatusContainer.java   |  68 +++++++
 .../cache/tm/TrustMarkCacheIdentifier.java}        |  57 +++---
 .../tm/TrustMarkIdentifierCriterion.java}          |  33 ++-
 .../cache/tm/TrustMarkStatusCacheIdentifier.java   | 103 ++++++++++
 .../tm/TrustMarkStatusIdentifierCriterion.java}    |  34 ++--
 ...efaultSubordinateStatementFetchingStrategy.java |  19 +-
 ...inateStatementSignatureValidationCondition.java | 116 -----------
 .../oidfed/profile/impl/CallResolveEntityApi.java  |  52 ++---
 ...TrustMarkFromMetadataCacheFetchingFunction.java |  27 +--
 .../META-INF/net.shibboleth.idp/postconfig.xml     | 221 +++++++++++++++++----
 .../oidfed/metadata-lookup-ext-oidfed-beans.xml    |   2 +-
 .../idp/flows/oidfed/register/register-beans.xml   |   2 +-
 .../oidfed/resolve-entity/resolve-entity-beans.xml |   2 +-
 .../flow/oidfed/EntityConfigurationFlowTest.java   |   5 +-
 42 files changed, 1796 insertions(+), 1540 deletions(-)

diff --git a/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponse.java b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponse.java
new file mode 100644
index 0000000..57d2cec
--- /dev/null
+++ b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponse.java
@@ -0,0 +1,60 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.shared.logic.ConstraintViolationException;
+
+/**
+ * A wrapper class extending {@link EntityStatement} with parsed claims related to resolve entity response.
+ */
+public class ResolveEntityResponse extends EntityStatement {
+
+    /**
+     * Constructor.
+     *
+     * @param signedJwt entity configuration
+     * @param payload entity configuration payload
+     * @throws ConstraintViolationException if the payload syntax/content is not expected
+     */
+    protected ResolveEntityResponse(@Nonnull final SignedJWT signedJwt,
+            @Nonnull final ResolveEntityResponsePayload payload) 
+        throws ConstraintViolationException {
+        super(signedJwt, payload);
+    }
+
+    /**
+     * Parse an {@link ResolveEntityResponse} from the given JWT by using the given object mapper.
+     * 
+     * @param jwt entity statement JWT
+     * @param objectMapper object mapper capable of parsing JWT payload
+     * @return entity configuration
+     * @throws JsonProcessingException if the payload could not be parsed
+     */
+    @Nonnull public static ResolveEntityResponse parse(@Nonnull final SignedJWT jwt,
+            @Nonnull final ObjectMapper objectMapper) throws JsonProcessingException {
+        final JavaType objectType = objectMapper.constructType(ResolveEntityResponsePayload.class);
+        final ResolveEntityResponsePayload result = objectMapper.readValue(jwt.getPayload().toString(), objectType);
+        assert result != null;
+        return new ResolveEntityResponse(jwt, result);
+    }
+    
+}
diff --git a/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponsePayload.java b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponsePayload.java
new file mode 100644
index 0000000..a3f7d5b
--- /dev/null
+++ b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ResolveEntityResponsePayload.java
@@ -0,0 +1,86 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+/**
+ * Resolve Entity response payload claims as defined by the OpenID Federation 1.0 Section 8.3.2.
+ */
+public class ResolveEntityResponsePayload extends EntityStatementPayload {
+
+    /** An array containing the sequence of Entity Statements that compose the Trust Chain. */
+    @JsonProperty("trust_chain") private List<String> trustChain;
+
+    /** An array of Trust Marks. */
+    @JsonProperty("trust_marks") private List<Map<String,String>> trustMarks;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("iss", getIssuer())
+                .add("sub", getSubject())
+                .add("iat", getIssuedAt())
+                .add("exp", getExpiration())
+                .add("metadata", getMetadata())
+                .add("trust_chain", getTrustChain())
+                .add("trust_marks", getTrustMarks())
+                .add("customClaims", getCustomClaims()).toString();
+    }
+
+    /**
+     * Get the array containing the sequence of Entity Statements that compose the Trust Chain.
+     * 
+     * @return trust chain
+     */
+    @Nullable public List<String> getTrustChain() {
+        return trustChain;
+    }
+
+    /**
+     * Set the array containing the sequence of Entity Statements that compose the Trust Chain.
+     * 
+     * @param chain trust chain
+     */
+    public void setTrustAnchorHints(final @Nullable List<String> chain) {
+       trustChain = chain;
+    }
+
+    /**
+     * Get the array of Trust Marks.
+     * 
+     * @return trust marks
+     */
+    @Nullable public List<Map<String, String>> getTrustMarks() {
+        return trustMarks;
+    }
+
+    /**
+     * Set the array of Trust Marks.
+     * 
+     * @param marks trust marks
+     */
+    public void setTrustMarks(@Nullable List<Map<String, String>> marks) {
+        trustMarks = marks;
+    }
+}
diff --git a/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMark.java b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMark.java
new file mode 100644
index 0000000..3a476f5
--- /dev/null
+++ b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMark.java
@@ -0,0 +1,60 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.shared.logic.ConstraintViolationException;
+
+/**
+ * A wrapper class extending {@link EntityStatement} with parsed claims related to trust mark.
+ */
+public class TrustMark extends EntityStatement {
+
+    /**
+     * Constructor.
+     *
+     * @param signedJwt entity configuration
+     * @param payload entity configuration payload
+     * @throws ConstraintViolationException if the payload syntax/content is not expected
+     */
+    protected TrustMark(@Nonnull final SignedJWT signedJwt,
+            @Nonnull final TrustMarkPayload payload) 
+        throws ConstraintViolationException {
+        super(signedJwt, payload);
+    }
+
+    /**
+     * Parse an {@link TrustMark} from the given JWT by using the given object mapper.
+     * 
+     * @param jwt entity statement JWT
+     * @param objectMapper object mapper capable of parsing JWT payload
+     * @return entity configuration
+     * @throws JsonProcessingException if the payload could not be parsed
+     */
+    @Nonnull public static TrustMark parse(@Nonnull final SignedJWT jwt,
+            @Nonnull final ObjectMapper objectMapper) throws JsonProcessingException {
+        final JavaType objectType = objectMapper.constructType(TrustMarkPayload.class);
+        final TrustMarkPayload result = objectMapper.readValue(jwt.getPayload().toString(), objectType);
+        assert result != null;
+        return new TrustMark(jwt, result);
+    }
+    
+}
diff --git a/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkPayload.java b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkPayload.java
new file mode 100644
index 0000000..5413bc7
--- /dev/null
+++ b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkPayload.java
@@ -0,0 +1,126 @@
+/*
+ * 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 javax.annotation.Nullable;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+/**
+ * Trust Mark payload claims as defined by the OpenID Federation 1.0 Section 7.1.
+ */
+public class TrustMarkPayload extends EntityStatementPayload {
+
+    /** An identifier of the type of the Trust Mark. */
+    @JsonProperty("trust_mark_type") private String trustMarkType;
+
+    /** A URL that references a logo for the issued Trust Mark. */
+    @JsonProperty("logo_uri") private String logoUri;
+
+    /** A URL referring to human-readable information about the issuance of the Trust Mark. */
+    @JsonProperty("ref") private String reference;
+
+    /** A Trust Mark delegation JWT. */
+    @JsonProperty("delegation") private String delegation;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("iss", getIssuer())
+                .add("sub", getSubject())
+                .add("iat", getIssuedAt())
+                .add("exp", getExpiration())
+                .add("trust_mark_type", trustMarkType)
+                .add("logo_uri", logoUri)
+                .add("ref", reference)
+                .add("delegation", delegation)
+                .add("customClaims", getCustomClaims()).toString();
+    }
+
+    /**
+     * Get the identifier of the type of the Trust Mark.
+     * 
+     * @return trust mark type
+     */
+    @Nullable public String getTrustMarkType() {
+        return trustMarkType;
+    }
+
+    /**
+     * Set the identifier of the type of the Trust Mark.
+     * 
+     * @param type trust mark type
+     */
+    public void setTrustMarkType(@Nullable final String type) {
+        trustMarkType = type;
+    }
+
+    /**
+     * Get the URL that references a logo for the issued Trust Mark.
+     * 
+     * @return logo URL
+     */
+    @Nullable public String getLogoUri() {
+        return logoUri;
+    }
+
+    /**
+     * Set the URL that references a logo for the issued Trust Mark.
+     * 
+     * @param url logo URL
+     */
+    public void setLogoUri(@Nullable final String url) {
+       logoUri = url;
+    }
+
+    /**
+     * Get the URL referring to human-readable information about the issuance of the Trust Mark.
+     * 
+     * @return reference URL
+     */
+    @Nullable public String getReference() {
+        return reference;
+    }
+
+    /**
+     * Set the URL referring to human-readable information about the issuance of the Trust Mark.
+     * 
+     * @param ref reference URL
+     */
+    public void setReference(@Nullable final String ref) {
+        reference = ref;
+    }
+
+    /**
+     * Get the Trust Mark delegation JWT.
+     * 
+     * @return delegation JWT
+     */
+    @Nullable public String getDelegation() {
+        return delegation;
+    }
+
+    /**
+     * Set the Trust Mark delegation JWT.
+     * 
+     * @param jwt delegation JWT
+     */
+    public void setDelegation(@Nullable final String jwt) {
+        delegation = jwt;
+    }
+}
diff --git a/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatus.java b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatus.java
new file mode 100644
index 0000000..8c566ad
--- /dev/null
+++ b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatus.java
@@ -0,0 +1,60 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.shared.logic.ConstraintViolationException;
+
+/**
+ * A wrapper class extending {@link EntityStatement} with parsed claims related to trust mark status.
+ */
+public class TrustMarkStatus extends EntityStatement {
+
+    /**
+     * Constructor.
+     *
+     * @param signedJwt entity configuration
+     * @param payload entity configuration payload
+     * @throws ConstraintViolationException if the payload syntax/content is not expected
+     */
+    protected TrustMarkStatus(@Nonnull final SignedJWT signedJwt,
+            @Nonnull final TrustMarkStatusPayload payload) 
+        throws ConstraintViolationException {
+        super(signedJwt, payload);
+    }
+
+    /**
+     * Parse an {@link TrustMarkStatus} from the given JWT by using the given object mapper.
+     * 
+     * @param jwt entity statement JWT
+     * @param objectMapper object mapper capable of parsing JWT payload
+     * @return entity configuration
+     * @throws JsonProcessingException if the payload could not be parsed
+     */
+    @Nonnull public static TrustMarkStatus parse(@Nonnull final SignedJWT jwt,
+            @Nonnull final ObjectMapper objectMapper) throws JsonProcessingException {
+        final JavaType objectType = objectMapper.constructType(TrustMarkStatusPayload.class);
+        final TrustMarkStatusPayload result = objectMapper.readValue(jwt.getPayload().toString(), objectType);
+        assert result != null;
+        return new TrustMarkStatus(jwt, result);
+    }
+    
+}
diff --git a/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusPayload.java b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusPayload.java
new file mode 100644
index 0000000..8dd182d
--- /dev/null
+++ b/idp-oidfed-op-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusPayload.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 javax.annotation.Nullable;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+
+/**
+ * Trust Mark Status payload claims as defined by the OpenID Federation 1.0 Section 8.4.2.
+ */
+public class TrustMarkStatusPayload extends EntityStatementPayload {
+
+    /** A Trust Mark. */
+    @JsonProperty("trust_mark") private String trustMark;
+
+    /** A status indicator for the Trust Mark. */
+    @JsonProperty("status") private String status;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("iss", getIssuer())
+                .add("iat", getIssuedAt())
+                .add("trust_mark", trustMark)
+                .add("status", status)
+                .add("customClaims", getCustomClaims()).toString();
+    }
+
+    /**
+     * Get the Trust Mark.
+     * 
+     * @return trust mark
+     */
+    @Nullable public String getTrustMark() {
+        return trustMark;
+    }
+
+    /**
+     * Set the Trust Mark.
+     * 
+     * @param mark trust mark
+     */
+    public void setTrustMark(@Nullable final String mark) {
+        trustMark = mark;
+    }
+
+    /**
+     * Get the status indicator for the Trust Mark.
+     * 
+     * @return status
+     */
+    @Nullable public String getStatus() {
+        return status;
+    }
+
+    /**
+     * Set the status indicator for the Trust Mark.
+     * 
+     * @param value status
+     */
+    public void setStatus(@Nullable final String value) {
+        status = value;
+    }
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkResponse.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkResponse.java
deleted file mode 100644
index c132acb..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkResponse.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 endpoint.
- */
-public class TrustMarkResponse extends AbstractSignedJWTResponse {
-
-    /** The JWT type header. */
-    @Nonnull
-    public static final JOSEObjectType JWT_TYPE_HEADER = new JOSEObjectType("trust-mark+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 TrustMarkResponse(@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 trust mark 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 trust mark response
-     */
-    @Nonnull
-    public static TrustMarkResponse 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 TrustMarkResponse(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/messaging/impl/TrustMarkStatusRequest.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkStatusRequest.java
deleted file mode 100644
index 65a50bb..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkStatusRequest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 9951d1f..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkStatusResponse.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 trust mark status success response from the given HTTP response.
-     *
-     * @param httpResponse the HTTP response
-     * @return trust mark status success response
-     * @throws ParseException if HTTP response could not be parsed into trust mark status 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
deleted file mode 100644
index 72f05cf..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/AbstractFederationEndpointResponseFetchingStrategy.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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/DefaultResolveEntityResponseSignatureValidationFilterStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityResponseSignatureValidationFilterStrategy.java
deleted file mode 100644
index c7b1d33..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityResponseSignatureValidationFilterStrategy.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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 net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.ResolveEntityResponse;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.RemoteEntityConfigurationContainer;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.SubjectEntityStatementCriterion;
-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 resolve entity response. The signature validation is performed via
- * configurable {@link TrustEngine}.
- */
- at ThreadSafeAfterInit
-public class DefaultResolveEntityResponseSignatureValidationFilterStrategy
-    extends AbstractTrustEngineSignatureValidationComponent
-    implements BiFunction<ResolveEntityResponseContainer, MetadataFilterContext, ResolveEntityResponseContainer> {
-
-    /** Class logger. */
-    @Nonnull private Logger log =
-            LoggerFactory.getLogger(DefaultResolveEntityResponseSignatureValidationFilterStrategy.class);
-
-    /** Cache used to fetch the issuer entity configuration from. */
-    @NonnullAfterInit private MetadataCache<RemoteEntityConfigurationContainer> entityConfigurationCache;
-
-    /**
-     * Set the cache used to fetch the issuer entity configuration from.
-     * 
-     * @param cache cache used to fetch the issuer entity configuration from
-     */
-    public void setEntityConfigurationCache(@Nonnull final MetadataCache<RemoteEntityConfigurationContainer> cache) {
-        checkSetterPreconditions();
-        entityConfigurationCache = Constraint.isNotNull(cache, "Entity Configuration cache cannot be null");
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void doInitialize() throws ComponentInitializationException {
-        super.doInitialize();
-        if (entityConfigurationCache == null) {
-            throw new ComponentInitializationException("Entity Configuration cache cannot be null");
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override @Nullable
-    public ResolveEntityResponseContainer apply(@Nullable final ResolveEntityResponseContainer response,
-            @Nullable final MetadataFilterContext filterContext) {
-        checkComponentActive();
-        if (response == null) {
-            return null;
-        }
-        if (response.getResponse() instanceof ResolveEntityResponse 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 signagure validation for the error response");
-            return response;
-        }
-        return null;
-    }
-
-    /**
-     * Fetch the issuer entity configuration from the 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<RemoteEntityConfigurationContainer> result = entityConfigurationCache.get(criteria);
-            if (!result.isEmpty()) {
-                return result.get(0).getEntityStatement();
-            }
-        } catch (final MetadataCacheException e) {
-            log.debug("Error while fetching issuer entity configuration 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/DefaultResolveEntityTrustChainFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityTrustChainFetchingStrategy.java
deleted file mode 100644
index b3c2d3b..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultResolveEntityTrustChainFetchingStrategy.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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.URI;
-import java.net.URISyntaxException;
-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.HttpGet;
-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.apache.hc.core5.net.URIBuilder;
-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.ResolveEntityRequest;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.ResolveEntityResponse;
-import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
-import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.shared.resolver.CriteriaSet;
-
-/**
- * Default strategy for fetching trust chain data via resolve entity API for a request specified in the criteria set.
- */
- at ThreadSafeAfterInit
-public class DefaultResolveEntityTrustChainFetchingStrategy
-    extends AbstractFederationEndpointResponseFetchingStrategy<ResolveEntityRequest, ResolveEntityResponseContainer> {
-
-    /** Class logger. */
-    @Nonnull private Logger log = LoggerFactory.getLogger(DefaultResolveEntityTrustChainFetchingStrategy.class);
-
-    /**
-     * Constructor.
-     */
-    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} */
-    @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()));
-        resolveRequest.getTrustAnchors()
-            .forEach(trustAnchor -> nvps.add(new BasicNameValuePair("trust_anchor", trustAnchor)));
-        resolveRequest.getEntityTypes()
-            .forEach(entityType -> nvps.add(new BasicNameValuePair("entity_type", entityType)));
-        final URI uri;
-        try {
-            uri = new URIBuilder(httpRequest.getUri()).addParameters(nvps).build();
-        } catch (final URISyntaxException e) {
-            log.error("Could not build endpoint URI for the resolve entity request", e);
-            return null;
-        }
-        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;
-    }
-
-    /** {@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, request, 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/DefaultTrustMarkFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkFetchingStrategy.java
deleted file mode 100644
index 890d024..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkFetchingStrategy.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.URI;
-import java.net.URISyntaxException;
-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.HttpGet;
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.ClassicHttpResponse;
-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.apache.hc.core5.net.URIBuilder;
-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.TrustMarkRequest;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkResponse;
-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 via Trust Mark API for the request specified in the criteria set. The
- * response is stored inside a {@link TrustMarkResponseContainer}.
- */
- at ThreadSafeAfterInit
-public class DefaultTrustMarkFetchingStrategy
-    extends AbstractFederationEndpointResponseFetchingStrategy<TrustMarkRequest, TrustMarkResponseContainer> {
-
-    /** Class logger. */
-    @Nonnull private Logger log = LoggerFactory.getLogger(DefaultTrustMarkFetchingStrategy.class);
-
-    /**
-     * Constructor.
-     */
-    public DefaultTrustMarkFetchingStrategy() {
-        setCriteriaToRequestStrategy(criteria -> {
-            final TrustMarkRequestCriterion requestCriterion = criteria.get(TrustMarkRequestCriterion.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 TrustMarkRequest request) {
-        final HttpGet httpRequest = new HttpGet(request.getEndpointURI());
-        final List<NameValuePair> nvps = new ArrayList<>();
-        nvps.add(new BasicNameValuePair("trust_mark_type", request.getTrustMarkType()));
-        nvps.add(new BasicNameValuePair("sub", request.getSubject()));
-        try {
-            final URI uri = new URIBuilder(httpRequest.getUri()).addParameters(nvps).build();
-            httpRequest.setUri(uri);
-        } catch (final URISyntaxException e) {
-            log.error("Could not create URI with the given parameters {}", request, e);
-        }
-        return httpRequest;
-    }
-
-    /** {@inheritDoc} */
-    @Nullable protected TrustMarkResponseContainer parseHttpResponse(@Nonnull final CriteriaSet criteria,
-            @Nonnull final TrustMarkRequest 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 TrustMarkResponse parsedResponse = TrustMarkResponse.parse(nimbusResponse);
-                final Instant expirationTime = expirationCriterion.getExpirationInstant();
-                return new TrustMarkResponseContainer(parsedResponse, request, parsedResponse.getJWT(), 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/DefaultTrustMarkResponseSignatureValidationFilterStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkResponseSignatureValidationFilterStrategy.java
deleted file mode 100644
index 3520d8b..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkResponseSignatureValidationFilterStrategy.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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 net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkResponse;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.RemoteTrustChainsContainer;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.SubjectEntityStatementCriterion;
-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 response. The signature validation is performed via
- * configurable {@link TrustEngine}.
- */
- at ThreadSafeAfterInit
-public class DefaultTrustMarkResponseSignatureValidationFilterStrategy
-    extends AbstractTrustEngineSignatureValidationComponent
-    implements BiFunction<TrustMarkResponseContainer, MetadataFilterContext, TrustMarkResponseContainer> {
-
-    /** Class logger. */
-    @Nonnull private Logger log =
-            LoggerFactory.getLogger(DefaultTrustMarkResponseSignatureValidationFilterStrategy.class);
-
-    /** Cache used to fetch the issuer entity configuration from. */
-    @NonnullAfterInit private MetadataCache<RemoteTrustChainsContainer> 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<RemoteTrustChainsContainer> 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 TrustMarkResponseContainer apply(@Nullable final TrustMarkResponseContainer response,
-            @Nullable final MetadataFilterContext filterContext) {
-        checkComponentActive();
-        if (response == null) {
-            return null;
-        }
-        if (response.getResponse() instanceof TrustMarkResponse 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<RemoteTrustChainsContainer> result = trustChainCache.get(criteria);
-            if (!result.isEmpty() && !result.get(0).getTrustChains().isEmpty()) {
-                return result.get(0).getTrustChains().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/DefaultTrustMarkStatusFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkStatusFetchingStrategy.java
deleted file mode 100644
index 55184cc..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkStatusFetchingStrategy.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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/EntityStatementHelper.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/EntityStatementHelper.java
index 46d2aa4..7caa686 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/EntityStatementHelper.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/EntityStatementHelper.java
@@ -15,7 +15,6 @@
 package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
 
 import java.net.URI;
-import java.time.Instant;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -166,15 +165,12 @@ public class EntityStatementHelper {
      * @param cache metadata cache used for fetching the entity configuration
      * @param entityId entity ID of the entity
      * @param endpointId the endpoint ID
-     * @param expiration expiration passed to the entity configuration cache
      * @return endpoint URI
      */
     @Nullable public static URI fetchEndpointUriFromFederationEntity(
             @Nonnull MetadataCache<RemoteEntityConfigurationContainer> cache,
-            @Nonnull final String entityId, @Nonnull final String endpointId,
-            @Nonnull final Instant expiration) {
-        final CriteriaSet criteria = new CriteriaSet(new SubjectEntityIDCriterion(entityId),
-                new ResponseContainerExpirationCriterion(expiration));
+            @Nonnull final String entityId, @Nonnull final String endpointId) {
+        final CriteriaSet criteria = new CriteriaSet(new SubjectEntityIDCriterion(entityId));
         try {
             final List<RemoteEntityConfigurationContainer> result = cache.get(criteria);
             if (!result.isEmpty()) {
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkResponseContainer.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkResponseContainer.java
deleted file mode 100644
index 755b8fc..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkResponseContainer.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.Serializable;
-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.TrustMarkRequest;
-import net.shibboleth.shared.logic.Constraint;
-
-/**
- * A container class for metadata caches carrying request and response message details related to Trust Mark API.
- */
-public class TrustMarkResponseContainer extends NimbusResponseContainer implements Serializable {
-
-    /** Serial version UID. */
-    private static final long serialVersionUID = 756269383556865370L;
-
-    /** Request message used for obtaining the Trust Mark. */
-    @Nonnull private final TrustMarkRequest 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 TrustMarkResponseContainer(@Nonnull final Response responseMessage,
-            @Nonnull final TrustMarkRequest requestMessage, @Nonnull final SignedJWT jwt,
-            @Nonnull final Instant expirationInstant) {
-        super(responseMessage, expirationInstant);
-        request = Constraint.isNotNull(requestMessage, "Request nessage cannot be null");
-        trustMark = Constraint.isNotNull(jwt, "Trust Mark JWT cannot be null");
-    }
-
-    /**
-     * Get request message.
-     * 
-     * @return request message
-     */
-    public TrustMarkRequest getRequestMessage() {
-        return request;
-    }
-    
-    /**
-     * Get trust mark.
-     * 
-     * @return trust mark
-     */
-    public SignedJWT getTrustMark() {
-        return trustMark;
-    }
-}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusResponseContainer.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusResponseContainer.java
deleted file mode 100644
index 3a2652a..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusResponseContainer.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.Serializable;
-import java.time.Instant;
-
-import javax.annotation.Nonnull;
-
-import com.nimbusds.jwt.SignedJWT;
-import com.nimbusds.oauth2.sdk.Response;
-
-import net.shibboleth.shared.logic.Constraint;
-
-/**
- * A container class for metadata caches carrying request and response message details related to Trust Mark Status API.
- */
-public class TrustMarkStatusResponseContainer extends NimbusResponseContainer implements Serializable {
-
-    /** Serial version UID. */
-    private static final long serialVersionUID = 756269383556865370L;
-
-    /** Trust Mark. */
-    @Nonnull private final SignedJWT trustMark;
-
-    /**
-     * Constructor.
-     *
-     * @param responseMessage response message
-     * @param jwt trust mark
-     * @param expirationInstant expiration instant
-     */
-    public TrustMarkStatusResponseContainer(@Nonnull final Response responseMessage,
-            @Nonnull final SignedJWT jwt, @Nonnull final Instant expirationInstant) {
-        super(responseMessage, expirationInstant);
-        trustMark = Constraint.isNotNull(jwt, "Trust Mark JWT cannot be null");
-    }
-
-    /**
-     * Get request message.
-     * 
-     * @return request message
-     */
-    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/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ec/DefaultEntityConfigurationContentValidationCondition.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultEntityStatementContentValidationCondition.java
similarity index 83%
rename from idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ec/DefaultEntityConfigurationContentValidationCondition.java
rename to idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultEntityStatementContentValidationCondition.java
index 21f03d5..f357f51 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ec/DefaultEntityConfigurationContentValidationCondition.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultEntityStatementContentValidationCondition.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ec;
+package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache;
 
 import java.text.ParseException;
 import java.util.function.BiPredicate;
@@ -23,9 +23,9 @@ import javax.annotation.Nullable;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 
+import com.nimbusds.jwt.JWTClaimsSet;
+
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.BaseExpirableEntityStatementContainer;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.RemoteEntityConfigurationContainer;
 import net.shibboleth.oidc.jwt.claims.ClaimsValidator;
 import net.shibboleth.oidc.jwt.claims.JWTValidationException;
 import net.shibboleth.oidc.metadata.filter.MetadataFilterContext;
@@ -36,19 +36,19 @@ import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
- * Default content validating filter for entity configuration. Verifies that the 
- * {@link RemoteEntityConfigurationContainer#getEntityId()} matches with the subject of the entity configuration and
- * validates the claims via configurable claims validator. Note that the {@link ProfileRequestContext} is not fed to
+ * Default content validating filter for entity statement. Verifies that the 
+ * {@link RemoteEntityConfigurationContainer#getEntityId()} matches with the subject of the entity statement and
+ * validates the claims via configurable claims validator. Note that an empty {@link ProfileRequestContext} is fed to
  * the claims validator.
  */
 @ThreadSafeAfterInit
-public class DefaultEntityConfigurationContentValidationCondition
+public class DefaultEntityStatementContentValidationCondition
     extends AbstractIdentifiableInitializableComponent
     implements BiPredicate<BaseExpirableEntityStatementContainer, MetadataFilterContext>  {
 
     /** Class logger. */
     @Nonnull private Logger log =
-            LoggerFactory.getLogger(DefaultEntityConfigurationContentValidationCondition.class);
+            LoggerFactory.getLogger(DefaultEntityStatementContentValidationCondition.class);
 
     /** The claims validator to use for validating the entity statement claims. */
     @NonnullAfterInit private ClaimsValidator claimsValidator;
@@ -74,6 +74,7 @@ public class DefaultEntityConfigurationContentValidationCondition
         }
 
         final EntityStatement statement = responseContainer.getEntityStatement();
+        assert statement != null;
         if (!responseContainer.getEntityId().equals(statement.getParsedPayload().getSubject())) {
             log.warn("Entity statement subject {} does not match with the requested entity ID {}",
                     statement.getParsedPayload().getSubject(), responseContainer.getEntityId());
@@ -81,7 +82,9 @@ public class DefaultEntityConfigurationContentValidationCondition
         }
 
         try {
-            claimsValidator.validate(statement.getJwt().getJWTClaimsSet(), null);
+            final JWTClaimsSet claimsSet = statement.getJwt().getJWTClaimsSet();
+            assert claimsSet != null;
+            claimsValidator.validate(claimsSet, new ProfileRequestContext());
         } catch (final JWTValidationException | ParseException e) {
             log.warn("Claims validation failed for entity statement {}", responseContainer.getEntityId(), e);
             return false;
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultEntityStatementValidationCriteriaSetLookupFunction.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultEntityStatementValidationCriteriaSetLookupFunction.java
new file mode 100644
index 0000000..d4075d5
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/DefaultEntityStatementValidationCriteriaSetLookupFunction.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.cache;
+
+import java.util.List;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubjectEntityIDCriterion;
+import net.shibboleth.oidc.metadata.cache.MetadataCache;
+import net.shibboleth.oidc.metadata.cache.MetadataCacheException;
+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 criteria set lookup strategy for {@link BaseExpirableEntityStatementContainer}.
+ */
+ at ThreadSafeAfterInit
+public class DefaultEntityStatementValidationCriteriaSetLookupFunction
+    extends AbstractIdentifiableInitializableComponent
+    implements Function<BaseExpirableEntityStatementContainer, CriteriaSet> {
+
+    /** Class logger. */
+    @Nonnull
+    private Logger log = LoggerFactory.getLogger(DefaultEntityStatementValidationCriteriaSetLookupFunction.class);
+
+    /** Metadata cache used for fetching issuer entity configuration. */
+    @NonnullAfterInit private MetadataCache<RemoteEntityConfigurationContainer> entityConfigurationCache;
+
+    /**
+     * Set the metadata cache used for fetching issuer entity configuration.
+     * 
+     * @param cache entity configuration cache
+     */
+    public void setEntityConfigurationCache(@Nonnull final MetadataCache<RemoteEntityConfigurationContainer> cache) {
+        checkSetterPreconditions();
+        entityConfigurationCache = Constraint.isNotNull(cache, "Entity configuration cache cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        if (entityConfigurationCache == null) {
+            throw new ComponentInitializationException("Trust Engine cannot be null");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable
+    public CriteriaSet apply(@Nullable final BaseExpirableEntityStatementContainer metadataContainer) {
+        if (metadataContainer == null || metadataContainer.getEntityStatement() == null) {
+            log.debug("Entity statement is not found from the container, returning null");
+            return null;
+        }
+        final EntityStatement statement = metadataContainer.getEntityStatement();
+        assert statement != null;
+        final SubjectEntityStatementCriterion subjectCriterion = new SubjectEntityStatementCriterion(statement);
+        final IssuerEntityStatementCriterion issuerCriterion = getIssuerCriterion(statement);
+        if (issuerCriterion == null) {
+            log.debug("Issuer statement could not be fetched, returning null");
+            return null;
+        }
+        return new CriteriaSet(subjectCriterion, issuerCriterion);
+    }
+
+    /**
+     * Fetch the issuer entity configuration from the metadata cache and initialize the criterion.
+     * 
+     * @param statement the entity statement whose issuer is fetched
+     * @return the issuer entity configuration, or null if could not be fetched
+     */
+    @Nullable protected IssuerEntityStatementCriterion getIssuerCriterion(
+            @Nonnull final EntityStatement statement) {
+        final String issuer = statement.getIssuer();
+        final CriteriaSet criteria = new CriteriaSet(new SubjectEntityIDCriterion(issuer));
+        try {
+            final List<RemoteEntityConfigurationContainer> result = entityConfigurationCache.get(criteria);
+            if (!result.isEmpty()) {
+                final EntityStatement issuerStatement = result.get(0).getEntityStatement();
+                if (issuerStatement != null) {
+                    return new IssuerEntityStatementCriterion(issuerStatement);
+                }
+            }
+        } catch (final MetadataCacheException e) {
+            log.debug("Error while fetching issuer entity configuration 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/cache/remoteresolver/DefaultResolveEntityTrustChainFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remoteresolver/DefaultResolveEntityTrustChainFetchingStrategy.java
new file mode 100644
index 0000000..29fcc1e
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remoteresolver/DefaultResolveEntityTrustChainFetchingStrategy.java
@@ -0,0 +1,134 @@
+/*
+ * 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.cache.remoteresolver;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+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.HttpGet;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+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.apache.hc.core5.net.URIBuilder;
+import org.slf4j.Logger;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResolveEntityResponse;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.AbstractFederationEndpointResponseFetchingStrategy;
+import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
+import net.shibboleth.shared.logic.ConstraintViolationException;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
+
+/**
+ * Default strategy for fetching trust chain data via resolve entity API for a request specified in the criteria set.
+ */
+ at ThreadSafeAfterInit
+public class DefaultResolveEntityTrustChainFetchingStrategy
+    extends AbstractFederationEndpointResponseFetchingStrategy
+        <RemoteResolveEntityCacheContainerIdentifier, RemoteResolveEntityResponseContainer> {
+
+    /** The JWT type header. */
+    @Nonnull
+    public static final JOSEObjectType JWT_TYPE_HEADER = new JOSEObjectType("resolve-response+jwt");
+
+    /** The HTTP response content type. */
+    @Nonnull public static final String HTTP_RESPONSE_CONTENT_TYPE = "application/" + JWT_TYPE_HEADER.toString();
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(DefaultResolveEntityTrustChainFetchingStrategy.class);
+
+    /**
+     * Constructor.
+     */
+    public DefaultResolveEntityTrustChainFetchingStrategy() {
+        setCriteriaToRequestDataStrategy(criteria -> {
+            final RemoteResolveEntityCacheIdentifierCriterion identifierCriterion =
+                    criteria.get(RemoteResolveEntityCacheIdentifierCriterion.class);
+            if (identifierCriterion == null) {
+                log.debug("No identifier criterion given, returning null");
+                return null;
+            }
+            return identifierCriterion.getIdentifier();
+        });
+    }
+
+    /** {@inheritDoc} */
+    @Nullable protected ClassicHttpRequest initializeHttpRequest(@Nonnull final CriteriaSet criteria,
+            @Nonnull RemoteResolveEntityCacheContainerIdentifier identifier) {
+        final HttpGet httpRequest = new HttpGet(identifier.getEndpoint());
+        final List<NameValuePair> nvps = new ArrayList<>();
+        nvps.add(new BasicNameValuePair("sub", identifier.getSubject()));
+        identifier.getTrustAnchors().forEach(anchor -> nvps.add(new BasicNameValuePair("trust_anchor", anchor)));
+        identifier.getEntityTypes().forEach(type -> nvps.add(new BasicNameValuePair("entity_type", type)));
+        try {
+            final URI uri = new URIBuilder(httpRequest.getUri()).addParameters(nvps).build();
+            httpRequest.setUri(uri);
+        } catch (final URISyntaxException e) {
+            log.error("Could not create URI with the given parameters {}", identifier, e);
+        }
+        return httpRequest;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable protected RemoteResolveEntityResponseContainer parseHttpResponse(@Nonnull final CriteriaSet criteria,
+            @Nonnull final RemoteResolveEntityCacheContainerIdentifier identifier,
+            @Nullable final ClassicHttpResponse response, @Nonnull final Instant validExpiration,
+            @Nonnull final Instant invalidExpiration)
+                    throws ProtocolException, IOException {
+        if (response != null) {
+            if (!HTTP_RESPONSE_CONTENT_TYPE.equals(response.getEntity().getContentType())) {
+                log.warn("Unexpected content type: {}", response.getEntity().getContentType());
+                return new RemoteResolveEntityResponseContainer(identifier, null, validExpiration, invalidExpiration);
+            }
+
+            try {
+                final SignedJWT jwt = SignedJWT.parse(EntityUtils.toString(response.getEntity()));
+                if (!JWT_TYPE_HEADER.equals(jwt.getHeader().getType())) {
+                    log.warn("Unexpected JWT type header {}", jwt.getHeader().getType());
+                    return new RemoteResolveEntityResponseContainer(identifier, null, validExpiration,
+                            invalidExpiration);
+                }
+                assert objectMapper != null;
+                final ResolveEntityResponse resolveEntity = ResolveEntityResponse.parse(jwt, objectMapper);
+                return new RemoteResolveEntityResponseContainer(
+                        identifier, resolveEntity, validExpiration, invalidExpiration);
+            } catch (final JsonProcessingException e) {
+                log.warn("Could not deserialize entity statement payload from the response", e);
+            } catch (final ConstraintViolationException e) {
+                log.warn("Parsed entity configuration claims did not pass syntax validation", e);
+            } catch (java.text.ParseException e) {
+                log.warn("Could not parse JWT from the response", e);
+            }
+        } else {
+            log.debug("Unable to fetch resolve entity response: {} (null response)", identifier.getEndpoint());
+        }
+
+        return new RemoteResolveEntityResponseContainer(identifier, null, validExpiration, invalidExpiration);
+    }
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remoteresolver/RemoteResolveEntityCacheContainerIdentifier.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remoteresolver/RemoteResolveEntityCacheContainerIdentifier.java
new file mode 100644
index 0000000..9e00ca9
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remoteresolver/RemoteResolveEntityCacheContainerIdentifier.java
@@ -0,0 +1,143 @@
+/*
+ * 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.cache.remoteresolver;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Objects;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.base.MoreObjects;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * Default identifier for trust mark within {@link RemoteResolveEntityResponseContainer}.
+ */
+public class RemoteResolveEntityCacheContainerIdentifier implements Serializable {
+
+    /** Serial version UID. */
+    private static final long serialVersionUID = -4143516153785776493L;
+
+    /** The endpoint URI of the request. */
+    @Nonnull @NotEmpty private final String endpoint;
+
+    /** The requested subject. */
+    @Nonnull @NotEmpty private final String subject;
+
+    /** The requested trust anchors. */
+    @Nonnull @NotEmpty private final List<String> trustAnchors;
+
+    /** The requested entity types to resolve. */
+    @Nonnull private final List<String> entityTypes;
+
+    /**
+     * 
+     * Constructor.
+     *
+     * @param uri endpoint URI
+     * @param sub subject
+     * @param anchors trust anchors
+     * @param types optional entity types
+     */
+    public RemoteResolveEntityCacheContainerIdentifier(@Nonnull final String uri,
+                  @Nonnull @NotEmpty final String sub,
+                  @Nonnull @NotEmpty final List<String> anchors,
+                  @Nullable final List<String>  types) {
+        endpoint = Constraint.isNotEmpty(uri, "Endpoint URI cannot be null");
+        subject = Constraint.isNotNull(sub, "Subject cannot be empty");
+        Constraint.isNotEmpty(anchors, "Trust anchors cannot be empty");
+        trustAnchors = anchors;
+        entityTypes = types == null ? CollectionSupport.emptyList() : CollectionSupport.copyToList(types);
+    }
+
+    /**
+     * Returns the requested subject.
+     *
+     * @return The subject.
+     */
+    @Nonnull @NotEmpty public String getSubject() {
+        return subject;
+    }
+
+    /**
+     * Returns the requested trust anchor.
+     *
+     * @return The trust anchor.
+     */
+    @Nonnull @NotEmpty public List<String> getTrustAnchors() {
+        return trustAnchors;
+    }
+
+    /**
+     * Returns the requested entity type to resolve.
+     *
+     * @return The entity type to resolve.
+     */
+    @Nonnull public List<String> getEntityTypes() {
+        return entityTypes;
+    }
+
+    /**
+     * Get the endpoint for the request.
+     * 
+     * @return endpoint
+     */
+    @Nonnull @NotEmpty public String getEndpoint() {
+        return endpoint;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("subject", getSubject())
+                .add("trustAnchors", getTrustAnchors())
+                .add("entityTypes", getEntityTypes())
+                .add("endpoint", getEndpoint())
+                .toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return Objects.hash(endpoint, subject, trustAnchors, entityTypes);
+    }
+
+    /** {@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 RemoteResolveEntityCacheContainerIdentifier other = (RemoteResolveEntityCacheContainerIdentifier) obj;
+        return endpoint.equals(other.endpoint) && subject.equals(other.subject)
+                && trustAnchors.containsAll(other.trustAnchors) && other.trustAnchors.containsAll(trustAnchors)
+                && entityTypes.containsAll(other.entityTypes) && other.entityTypes.containsAll(entityTypes);
+
+    }
+
+}
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/cache/remoteresolver/RemoteResolveEntityCacheIdentifierCriterion.java
similarity index 53%
copy from idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusRequestCriterion.java
copy to idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remoteresolver/RemoteResolveEntityCacheIdentifierCriterion.java
index f33a060..04da259 100644
--- 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/cache/remoteresolver/RemoteResolveEntityCacheIdentifierCriterion.java
@@ -12,52 +12,51 @@
  * limitations under the License.
  */
 
-package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remoteresolver;
 
 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.
+ * A {@link Criterion} representing request message details to Resolve Entity API.
  */
-public class TrustMarkStatusRequestCriterion implements Criterion {
+public class RemoteResolveEntityCacheIdentifierCriterion implements Criterion {
 
-    /** The request message. */
-    @Nonnull private final TrustMarkStatusRequest request;
+    /** The trust mark identifier. */
+    @Nonnull private final RemoteResolveEntityCacheContainerIdentifier identifier;
 
     /**
      * Constructor.
      *
-     * @param requestMessage request message, must not be null
+     * @param id identifier, must not be null
      */
-    public TrustMarkStatusRequestCriterion(@Nonnull final TrustMarkStatusRequest requestMessage) {
-        request = Constraint.isNotNull(requestMessage, "Request cannot be null");
+    public RemoteResolveEntityCacheIdentifierCriterion(@Nonnull final RemoteResolveEntityCacheContainerIdentifier id) {
+        identifier = Constraint.isNotNull(id, "Identifier cannot be null");
     }
 
     /**
-     * Get the request message.
+     * Get the trust mark identifier.
      * 
-     * @return the request message
+     * @return the identifier
      */
-    @Nonnull public TrustMarkStatusRequest getRequest() {
-        return request;
+    @Nonnull public RemoteResolveEntityCacheContainerIdentifier getIdentifier() {
+        return identifier;
     }
 
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "TrustMarkStatusRequestCriterion [request=" + request + "]";
+        return "RemoteEntityCacheIdentifierCriterion [identifier=" + identifier + "]";
     }
 
     /** {@inheritDoc} */
     @Override
     public int hashCode() {
-        return Objects.hash(request);
+        return Objects.hash(identifier);
     }
 
     /** {@inheritDoc} */
@@ -72,9 +71,8 @@ public class TrustMarkStatusRequestCriterion implements Criterion {
         if (getClass() != obj.getClass()) {
             return false;
         }
-        final TrustMarkStatusRequestCriterion other = (TrustMarkStatusRequestCriterion) obj;
-        //TODO: proper equals-check
-        return request.equals(other.request);
+        final RemoteResolveEntityCacheIdentifierCriterion other = (RemoteResolveEntityCacheIdentifierCriterion) obj;
+        return identifier.equals(other.identifier);
     }
 
 }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remoteresolver/RemoteResolveEntityResponseContainer.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remoteresolver/RemoteResolveEntityResponseContainer.java
new file mode 100644
index 0000000..6f88635
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/remoteresolver/RemoteResolveEntityResponseContainer.java
@@ -0,0 +1,69 @@
+/*
+ * 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.cache.remoteresolver;
+
+import java.io.Serializable;
+import java.time.Instant;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResolveEntityResponse;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.BaseExpirableEntityStatementContainer;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * A container class for metadata caches carrying ID and statement details related to Resolve Entity.
+ */
+public class RemoteResolveEntityResponseContainer extends BaseExpirableEntityStatementContainer
+    implements Serializable {
+
+    /** Serial version UID. */
+    private static final long serialVersionUID = 756269564456865370L;
+
+    /** Requested entity ID. */
+    @Nonnull private final RemoteResolveEntityCacheContainerIdentifier identifier;
+
+    /**
+     * Constructor.
+     *
+     * @param id identifier, must not be null
+     * @param resolveEntity resolve entity response parsed from the response
+     * @param validExpirationInstant expiration instant for valid statement, must not be null
+     * @param invalidExpirationInstant expiration instant for invalid statement, must not be null
+     */
+    public RemoteResolveEntityResponseContainer(@Nonnull final RemoteResolveEntityCacheContainerIdentifier id,
+            @Nullable final ResolveEntityResponse resolveEntity, @Nonnull final Instant validExpirationInstant,
+            @Nonnull final Instant invalidExpirationInstant) {
+        super(validExpirationInstant, resolveEntity, invalidExpirationInstant);
+        identifier = Constraint.isNotNull(id, "Identifier cannot be null");
+    }
+
+    /**
+     * Get entity ID.
+     * 
+     * @return entity ID
+     */
+    @Nonnull @NotEmpty public RemoteResolveEntityCacheContainerIdentifier getIdentifier() {
+        return identifier;
+    }
+
+    /** {@inheritDoc} */
+    @Nonnull @NotEmpty public String getEntityId() {
+        return identifier.getSubject();
+    }
+
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/DefaultTrustMarkFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/DefaultTrustMarkFetchingStrategy.java
new file mode 100644
index 0000000..eae898c
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/DefaultTrustMarkFetchingStrategy.java
@@ -0,0 +1,130 @@
+/*
+ * 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.cache.tm;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+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.HttpGet;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+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.apache.hc.core5.net.URIBuilder;
+import org.slf4j.Logger;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.TrustMark;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.AbstractFederationEndpointResponseFetchingStrategy;
+import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
+import net.shibboleth.shared.logic.ConstraintViolationException;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
+
+/**
+ * Default strategy for fetching trust mark via Trust Mark API for the request specified in the criteria set. The
+ * response is stored inside a {@link RemoteTrustMarkContainer}.
+ */
+ at ThreadSafeAfterInit
+public class DefaultTrustMarkFetchingStrategy
+    extends AbstractFederationEndpointResponseFetchingStrategy<TrustMarkCacheIdentifier, RemoteTrustMarkContainer> {
+
+    /** The JWT type header. */
+    @Nonnull
+    public static final JOSEObjectType JWT_TYPE_HEADER = new JOSEObjectType("trust-mark+jwt");
+
+    /** The HTTP response content type. */
+    @Nonnull public static final String HTTP_RESPONSE_CONTENT_TYPE = "application/" + JWT_TYPE_HEADER.toString();
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(DefaultTrustMarkFetchingStrategy.class);
+
+    /**
+     * Constructor.
+     */
+    public DefaultTrustMarkFetchingStrategy() {
+        setCriteriaToRequestDataStrategy(criteria -> {
+            final TrustMarkIdentifierCriterion identifierCriterion = criteria.get(TrustMarkIdentifierCriterion.class);
+            if (identifierCriterion == null) {
+                log.debug("No identifier criterion given, returning null");
+                return null;
+            }
+            return identifierCriterion.getIdentifier();
+        });
+    }
+
+    /** {@inheritDoc} */
+    @Nullable protected ClassicHttpRequest initializeHttpRequest(@Nonnull final CriteriaSet criteria,
+            @Nonnull TrustMarkCacheIdentifier request) {
+        final HttpGet httpRequest = new HttpGet(request.getEndpoint());
+        final List<NameValuePair> nvps = new ArrayList<>();
+        nvps.add(new BasicNameValuePair("trust_mark_type", request.getTrustMarkType()));
+        nvps.add(new BasicNameValuePair("sub", request.getSubject()));
+        try {
+            final URI uri = new URIBuilder(httpRequest.getUri()).addParameters(nvps).build();
+            httpRequest.setUri(uri);
+        } catch (final URISyntaxException e) {
+            log.error("Could not create URI with the given parameters {}", request, e);
+        }
+        return httpRequest;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable protected RemoteTrustMarkContainer parseHttpResponse(@Nonnull final CriteriaSet criteria,
+            @Nonnull final TrustMarkCacheIdentifier request, @Nullable final ClassicHttpResponse response,
+            @Nonnull final Instant validExpiration, @Nonnull final Instant invalidExpiration)
+                    throws ProtocolException, IOException {
+        if (response != null) {
+            if (!HTTP_RESPONSE_CONTENT_TYPE.equals(response.getEntity().getContentType())) {
+                log.warn("Unexpected content type: {}", response.getEntity().getContentType());
+                return new RemoteTrustMarkContainer(request, null, validExpiration, invalidExpiration);
+            }
+
+            try {
+                final SignedJWT jwt = SignedJWT.parse(EntityUtils.toString(response.getEntity()));
+                if (!JWT_TYPE_HEADER.equals(jwt.getHeader().getType())) {
+                    log.warn("Unexpected JWT type header {}", jwt.getHeader().getType());
+                    return new RemoteTrustMarkContainer(request, null, validExpiration, invalidExpiration);
+                }
+                assert objectMapper != null;
+                final TrustMark trustMark = TrustMark.parse(jwt, objectMapper);
+                return new RemoteTrustMarkContainer(
+                        request, trustMark, validExpiration, invalidExpiration);
+            } catch (final JsonProcessingException e) {
+                log.warn("Could not deserialize entity statement payload from the response", e);
+            } catch (final ConstraintViolationException e) {
+                log.warn("Parsed entity configuration claims did not pass syntax validation", e);
+            } catch (java.text.ParseException e) {
+                log.warn("Could not parse JWT from the response", e);
+            }
+        } else {
+            log.debug("Unable to fetch trust mark: {} (null response)", request.getTrustMarkType());
+        }
+
+        return new RemoteTrustMarkContainer(request, null, validExpiration, invalidExpiration);
+    }
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/DefaultTrustMarkStatusFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/DefaultTrustMarkStatusFetchingStrategy.java
new file mode 100644
index 0000000..95d0450
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/DefaultTrustMarkStatusFetchingStrategy.java
@@ -0,0 +1,129 @@
+/*
+ * 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.cache.tm;
+
+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.fasterxml.jackson.core.JsonProcessingException;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.TrustMarkStatus;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.AbstractFederationEndpointResponseFetchingStrategy;
+import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
+import net.shibboleth.shared.logic.ConstraintViolationException;
+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 RemoteTrustMarkStatusContainer}.
+ */
+ at ThreadSafeAfterInit
+public class DefaultTrustMarkStatusFetchingStrategy
+    extends AbstractFederationEndpointResponseFetchingStrategy
+        <TrustMarkStatusCacheIdentifier, RemoteTrustMarkStatusContainer> {
+
+    /** The JWT type header. */
+    @Nonnull
+    public static final JOSEObjectType JWT_TYPE_HEADER = new JOSEObjectType("trust-mark-status-response+jwt");
+
+    /** The HTTP response content type. */
+    @Nonnull public static final String HTTP_RESPONSE_CONTENT_TYPE = "application/" + JWT_TYPE_HEADER.toString();
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(DefaultTrustMarkStatusFetchingStrategy.class);
+
+    /**
+     * Constructor.
+     */
+    public DefaultTrustMarkStatusFetchingStrategy() {
+        setCriteriaToRequestDataStrategy(criteria -> {
+            final TrustMarkStatusIdentifierCriterion identifierCriterion =
+                    criteria.get(TrustMarkStatusIdentifierCriterion.class);
+            if (identifierCriterion == null) {
+                log.debug("No identifier criterion given, returning null");
+                return null;
+            }
+            return identifierCriterion.getIdentifier();
+        });
+    }
+
+    /** {@inheritDoc} */
+    @Nullable protected ClassicHttpRequest initializeHttpRequest(@Nonnull final CriteriaSet criteria,
+            @Nonnull TrustMarkStatusCacheIdentifier identifier) {
+        final HttpPost httpRequest = new HttpPost(identifier.getEndpoint());
+        final List<NameValuePair> nvps = new ArrayList<>();
+        nvps.add(new BasicNameValuePair("trust_mark", identifier.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 RemoteTrustMarkStatusContainer parseHttpResponse(@Nonnull final CriteriaSet criteria,
+            @Nonnull final TrustMarkStatusCacheIdentifier identifier, @Nullable final ClassicHttpResponse response,
+            @Nonnull final Instant validExpiration, @Nonnull final Instant invalidExpiration)
+                    throws ProtocolException, IOException {
+        if (response != null) {
+            if (!HTTP_RESPONSE_CONTENT_TYPE.equals(response.getEntity().getContentType())) {
+                log.warn("Unexpected content type: {}", response.getEntity().getContentType());
+                return new RemoteTrustMarkStatusContainer(identifier, null, validExpiration, invalidExpiration);
+            }
+
+            try {
+                final SignedJWT jwt = SignedJWT.parse(EntityUtils.toString(response.getEntity()));
+                if (!JWT_TYPE_HEADER.equals(jwt.getHeader().getType())) {
+                    log.warn("Unexpected JWT type header {}", jwt.getHeader().getType());
+                    return new RemoteTrustMarkStatusContainer(identifier, null, validExpiration, invalidExpiration);
+                }
+                assert objectMapper != null;
+                final TrustMarkStatus trustMarkStatus = TrustMarkStatus.parse(jwt, objectMapper);
+                return new RemoteTrustMarkStatusContainer(
+                        identifier, trustMarkStatus, validExpiration, invalidExpiration);
+            } catch (final JsonProcessingException e) {
+                log.warn("Could not deserialize trust mark status payload from the response", e);
+            } catch (final ConstraintViolationException e) {
+                log.warn("Parsed trust mark status claims did not pass syntax validation", e);
+            } catch (java.text.ParseException e) {
+                log.warn("Could not parse JWT from the response", e);
+            }
+        } else {
+            log.debug("Unable to fetch trust mark status: {} (null response)", identifier.getEndpoint());
+        }
+
+        return new RemoteTrustMarkStatusContainer(identifier, null, validExpiration, invalidExpiration);
+    }
+}
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/cache/tm/DefaultTrustMarkValidationCriteriaSetLookupFunction.java
similarity index 55%
rename from idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy.java
rename to idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/DefaultTrustMarkValidationCriteriaSetLookupFunction.java
index 6dddce0..5ca22ca 100644
--- 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/cache/tm/DefaultTrustMarkValidationCriteriaSetLookupFunction.java
@@ -12,45 +12,44 @@
  * limitations under the License.
  */
 
-package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm;
 
-import java.text.ParseException;
 import java.util.List;
-import java.util.function.BiFunction;
+import java.util.function.Function;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.opensaml.security.trust.TrustEngine;
 import org.slf4j.Logger;
 
-import com.nimbusds.jwt.SignedJWT;
-
-import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkStatusResponse;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubjectEntityIDCriterion;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.BaseExpirableEntityStatementContainer;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.IssuerEntityStatementCriterion;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.RemoteTrustChainsContainer;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.SubjectEntityStatementCriterion;
 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.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 signature validating filter for Trust Mark Status response. The signature validation is performed via
- * configurable {@link TrustEngine}.
+ * Default criteria set lookup strategy for {@link BaseExpirableEntityStatementContainer} that fetches the issuer
+ * entity statement via trust chain cache.
  */
 @ThreadSafeAfterInit
-public class DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy
-    extends AbstractTrustEngineSignatureValidationComponent
-    implements BiFunction<TrustMarkStatusResponseContainer, MetadataFilterContext, TrustMarkStatusResponseContainer> {
+public class DefaultTrustMarkValidationCriteriaSetLookupFunction
+    extends AbstractIdentifiableInitializableComponent
+    implements Function<BaseExpirableEntityStatementContainer, CriteriaSet> {
 
     /** Class logger. */
-    @Nonnull private Logger log =
-            LoggerFactory.getLogger(DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy.class);
+    @Nonnull
+    private Logger log = LoggerFactory.getLogger(DefaultTrustMarkValidationCriteriaSetLookupFunction.class);
 
     /** Cache used to fetch the issuer entity configuration from. */
     @NonnullAfterInit private MetadataCache<RemoteTrustChainsContainer> trustChainCache;
@@ -65,6 +64,7 @@ public class DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy
         trustChainCache = Constraint.isNotNull(cache, "Trust Chain cache cannot be null");
     }
 
+
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -72,59 +72,52 @@ public class DefaultTrustMarkStatusResponseSignatureValidationFilterStrategy
         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) {
+    public CriteriaSet apply(@Nullable final BaseExpirableEntityStatementContainer metadataContainer) {
+        if (metadataContainer == null || metadataContainer.getEntityStatement() == null) {
+            log.debug("Entity statement is not found from the container, returning 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;
+        final EntityStatement statement = metadataContainer.getEntityStatement();
+        assert statement != null;
+        final SubjectEntityStatementCriterion subjectCriterion = new SubjectEntityStatementCriterion(statement);
+        final IssuerEntityStatementCriterion issuerCriterion = getIssuerCriterion(statement);
+        if (issuerCriterion == null) {
+            log.debug("Issuer statement could not be fetched, returning null");
+            return null;
         }
-        return null;
+        return new CriteriaSet(subjectCriterion, issuerCriterion);
     }
 
     /**
-     * Fetch the issuer entity configuration from the trust chain metadata cache.
+     * Fetch the issuer entity configuration from the metadata cache and initialize the criterion.
      * 
-     * @param issuer the issuer entity ID
+     * @param statement the entity statement whose issuer is fetched
      * @return the issuer entity configuration, or null if could not be fetched
      */
-    @Nullable protected EntityStatement fetchIssuerStatement(@Nonnull final String issuer) {
+    @Nullable protected IssuerEntityStatementCriterion getIssuerCriterion(
+            @Nonnull final EntityStatement statement) {
+        final String issuer = statement.getIssuer();
         final CriteriaSet criteria = new CriteriaSet(new SubjectEntityIDCriterion(issuer));
         try {
             final List<RemoteTrustChainsContainer> result = trustChainCache.get(criteria);
             if (!result.isEmpty()) {
                 final List<List<EntityStatement>> chains = result.get(0).getTrustChains();
-                return chains.isEmpty() ? null : chains.get(0).get(0);
+                if (!chains.isEmpty()) {
+                    final EntityStatement issuerStatement = chains.get(0).get(0);
+                    assert issuerStatement != null;
+                    return new IssuerEntityStatementCriterion(issuerStatement);
+                }
             }
         } 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/cache/tm/RemoteTrustMarkContainer.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/RemoteTrustMarkContainer.java
new file mode 100644
index 0000000..87036da
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/RemoteTrustMarkContainer.java
@@ -0,0 +1,68 @@
+/*
+ * 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.cache.tm;
+
+import java.io.Serializable;
+import java.time.Instant;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.TrustMark;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.BaseExpirableEntityStatementContainer;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * A container class for metadata caches carrying ID and statement details related to Trust Mark.
+ */
+public class RemoteTrustMarkContainer extends BaseExpirableEntityStatementContainer implements Serializable {
+
+    /** Serial version UID. */
+    private static final long serialVersionUID = 756269369356865370L;
+
+    /** Requested entity ID. */
+    @Nonnull private final TrustMarkCacheIdentifier identifier;
+
+    /**
+     * Constructor.
+     *
+     * @param id identifier, must not be null
+     * @param trustMark trust mark parsed from the response
+     * @param validExpirationInstant expiration instant for valid statement, must not be null
+     * @param invalidExpirationInstant expiration instant for invalid statement, must not be null
+     */
+    public RemoteTrustMarkContainer(@Nonnull final TrustMarkCacheIdentifier id,
+            @Nullable final TrustMark trustMark, @Nonnull final Instant validExpirationInstant,
+            @Nonnull final Instant invalidExpirationInstant) {
+        super(validExpirationInstant, trustMark, invalidExpirationInstant);
+        identifier = Constraint.isNotNull(id, "Identifier cannot be null");
+    }
+
+    /**
+     * Get entity ID.
+     * 
+     * @return entity ID
+     */
+    @Nonnull @NotEmpty public TrustMarkCacheIdentifier getIdentifier() {
+        return identifier;
+    }
+
+    /** {@inheritDoc} */
+    @Nonnull @NotEmpty public String getEntityId() {
+        return identifier.getSubject();
+    }
+
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/RemoteTrustMarkStatusContainer.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/RemoteTrustMarkStatusContainer.java
new file mode 100644
index 0000000..a2b5234
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/RemoteTrustMarkStatusContainer.java
@@ -0,0 +1,68 @@
+/*
+ * 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.cache.tm;
+
+import java.io.Serializable;
+import java.time.Instant;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.TrustMarkStatus;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.BaseExpirableEntityStatementContainer;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * A container class for metadata caches carrying ID and statement details related to Trust Mark status.
+ */
+public class RemoteTrustMarkStatusContainer extends BaseExpirableEntityStatementContainer implements Serializable {
+
+    /** Serial version UID. */
+    private static final long serialVersionUID = 756269369356884270L;
+
+    /** Requested entity ID. */
+    @Nonnull private final TrustMarkStatusCacheIdentifier identifier;
+
+    /**
+     * Constructor.
+     *
+     * @param id identifier, must not be null
+     * @param trustMarkStatus trust mark status parsed from the response
+     * @param validExpirationInstant expiration instant for valid statement, must not be null
+     * @param invalidExpirationInstant expiration instant for invalid statement, must not be null
+     */
+    public RemoteTrustMarkStatusContainer(@Nonnull final TrustMarkStatusCacheIdentifier id,
+            @Nullable final TrustMarkStatus trustMarkStatus, @Nonnull final Instant validExpirationInstant,
+            @Nonnull final Instant invalidExpirationInstant) {
+        super(validExpirationInstant, trustMarkStatus, invalidExpirationInstant);
+        identifier = Constraint.isNotNull(id, "Identifier cannot be null");
+    }
+
+    /**
+     * Get entity ID.
+     * 
+     * @return entity ID
+     */
+    @Nonnull @NotEmpty public TrustMarkStatusCacheIdentifier getIdentifier() {
+        return identifier;
+    }
+
+    /** {@inheritDoc} */
+    @Nonnull @NotEmpty public String getEntityId() {
+        return identifier.getEndpoint(); //TODO: revisit
+    }
+
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkRequest.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkCacheIdentifier.java
similarity index 66%
rename from idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkRequest.java
rename to idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkCacheIdentifier.java
index 2a080ab..67efa09 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/messaging/impl/TrustMarkRequest.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkCacheIdentifier.java
@@ -12,33 +12,35 @@
  * limitations under the License.
  */
 
-package net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl;
+package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm;
 
-import java.net.URI;
+import java.io.Serializable;
+import java.util.Objects;
 
 import javax.annotation.Nonnull;
 
 import com.google.common.base.MoreObjects;
-import com.nimbusds.oauth2.sdk.Request;
-import com.nimbusds.oauth2.sdk.http.HTTPRequest;
 
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.logic.Constraint;
 
 /**
- * Request message to the OpenID federation Trust Mark endpoint.
+ * Default identifier for trust mark within {@link RemoteTrustMarkContainer}.
  */
-public class TrustMarkRequest implements Request {
+public class TrustMarkCacheIdentifier implements Serializable {
+
+    /** Serial version UID. */
+    private static final long serialVersionUID = -4143516153785776493L;
 
     /** The endpoint URI of the request. */
-    @Nonnull private final URI endpointUri;
+    @Nonnull @NotEmpty private final String endpoint;
 
     /** The identifier for the type of the Trust Mark. */
     @Nonnull @NotEmpty private final String trustMarkType;
 
     /** The entity ID of the Entity to which the Trust Mark is issued. */
     @Nonnull @NotEmpty private final String subject;
-    
+
     /**
      * Constructor.
      *
@@ -46,23 +48,20 @@ public class TrustMarkRequest implements Request {
      * @param type trust _mark type
      * @param sub subject entity ID
      */
-    public TrustMarkRequest(@Nonnull final URI uri, @Nonnull final String type, @Nonnull final String sub) {
-        endpointUri = Constraint.isNotNull(uri, "Endpoint URI cannot be null");
+    public TrustMarkCacheIdentifier(@Nonnull @NotEmpty final String uri, @Nonnull @NotEmpty final String type,
+            @Nonnull @NotEmpty final String sub) {
+        endpoint = Constraint.isNotEmpty(uri, "Endpoint URI cannot be null");
         trustMarkType = Constraint.isNotEmpty(type, "Trust Mark type cannot be null or empty");
         subject = Constraint.isNotEmpty(sub, "Subject cannot be null or empty");
     }
 
-    /** {@inheritDoc} */
-    @Override @Nonnull
-    public URI getEndpointURI() {
-        return endpointUri;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public HTTPRequest toHTTPRequest() {
-        //TODO
-        return null;
+    /**
+     * Get the endpoint for the request.
+     * 
+     * @return endpoint
+     */
+    @Nonnull @NotEmpty public String getEndpoint() {
+        return endpoint;
     }
 
     /**
@@ -89,25 +88,33 @@ public class TrustMarkRequest implements Request {
         return MoreObjects.toStringHelper(this)
                 .add("subject", getSubject())
                 .add("trustMarkType", getTrustMarkType())
-                .add("endpointURI", getEndpointURI())
+                .add("endpoint", getEndpoint())
                 .toString();
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return Objects.hash(endpoint, subject, trustMarkType);
+    }
+
     /** {@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 TrustMarkRequest other = (TrustMarkRequest) obj;
-        return endpointUri.equals(other.endpointUri) && subject.equals(other.subject) &&
-                trustMarkType.equals(other.trustMarkType);
+        final TrustMarkCacheIdentifier other = (TrustMarkCacheIdentifier) obj;
+        return endpoint.equals(other.endpoint) && subject.equals(other.subject)
+                && trustMarkType.equals(other.trustMarkType);
+
     }
 
 }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkRequestCriterion.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkIdentifierCriterion.java
similarity index 56%
rename from idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkRequestCriterion.java
rename to idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkIdentifierCriterion.java
index 2629074..512a9f0 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkRequestCriterion.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkIdentifierCriterion.java
@@ -12,52 +12,51 @@
  * limitations under the License.
  */
 
-package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm;
 
 import java.util.Objects;
 
 import javax.annotation.Nonnull;
 
-import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkRequest;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.resolver.Criterion;
 
 /**
- * A {@link Criterion} representing request message to a Trust Mark API.
+ * A {@link Criterion} representing request message details to a Trust Mark API.
  */
-public class TrustMarkRequestCriterion implements Criterion {
+public class TrustMarkIdentifierCriterion implements Criterion {
 
-    /** The request message. */
-    @Nonnull private final TrustMarkRequest request;
+    /** The trust mark identifier. */
+    @Nonnull private final TrustMarkCacheIdentifier identifier;
 
     /**
      * Constructor.
      *
-     * @param requestMessage request message, must not be null
+     * @param id identifier, must not be null
      */
-    public TrustMarkRequestCriterion(@Nonnull final TrustMarkRequest requestMessage) {
-        request = Constraint.isNotNull(requestMessage, "Request cannot be null");
+    public TrustMarkIdentifierCriterion(@Nonnull final TrustMarkCacheIdentifier id) {
+        identifier = Constraint.isNotNull(id, "Identifier cannot be null");
     }
 
     /**
-     * Get the request message.
+     * Get the trust mark identifier.
      * 
-     * @return the request message
+     * @return the identifier
      */
-    @Nonnull public TrustMarkRequest getRequest() {
-        return request;
+    @Nonnull public TrustMarkCacheIdentifier getIdentifier() {
+        return identifier;
     }
 
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "TrustMarkRequestCriterion [request=" + request + "]";
+        return "TrustMarkIdentifierCriterion [identifier=" + identifier + "]";
     }
 
     /** {@inheritDoc} */
     @Override
     public int hashCode() {
-        return Objects.hash(request);
+        return Objects.hash(identifier);
     }
 
     /** {@inheritDoc} */
@@ -72,8 +71,8 @@ public class TrustMarkRequestCriterion implements Criterion {
         if (getClass() != obj.getClass()) {
             return false;
         }
-        final TrustMarkRequestCriterion other = (TrustMarkRequestCriterion) obj;
-        return request.equals(other.request);
+        final TrustMarkIdentifierCriterion other = (TrustMarkIdentifierCriterion) obj;
+        return identifier.equals(other.identifier);
     }
 
 }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkStatusCacheIdentifier.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkStatusCacheIdentifier.java
new file mode 100644
index 0000000..3b56153
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkStatusCacheIdentifier.java
@@ -0,0 +1,103 @@
+/*
+ * 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.cache.tm;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.base.MoreObjects;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * Request message to the OpenID federation Trust Mark Status endpoint.
+ */
+public class TrustMarkStatusCacheIdentifier implements Serializable {
+
+    /** Serial version UID. */
+    private static final long serialVersionUID = -4143643153785776493L;
+
+    /** The endpoint URI of the request. */
+    @Nonnull private final String endpoint;
+
+    /** The trust mark for the request. */
+    @Nonnull private final SignedJWT trustMark;
+
+    /**
+     * Constructor.
+     *
+     * @param uri endpoint URI
+     * @param jwt trust mark
+     */
+    public TrustMarkStatusCacheIdentifier(@Nonnull @NotEmpty final String uri, @Nonnull final SignedJWT jwt) {
+        endpoint = Constraint.isNotEmpty(uri, "Endpoint URI cannot be null");
+        trustMark = Constraint.isNotNull(jwt, "Trust Mark JWT cannot be null");
+    }
+
+    /**
+     * Get the endpoint URI of the request.
+     * 
+     * @return endpoint
+     */
+    @Nonnull @NotEmpty public String getEndpoint() {
+        return endpoint;
+    }
+
+    /**
+     * Get the trust mark (serialized JWT) for the request.
+     * 
+     * @return trust mark
+     */
+    @Nonnull @NotEmpty public SignedJWT getTrustMark() {
+        return trustMark;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("trustMark", getTrustMark().serialize())
+                .add("endpoint", getEndpoint())
+                .toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return Objects.hash(endpoint, trustMark.serialize());
+    }
+
+    /** {@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 TrustMarkStatusCacheIdentifier other = (TrustMarkStatusCacheIdentifier) obj;
+        return endpoint.equals(other.endpoint) && trustMark.serialize().equals(other.trustMark.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/cache/tm/TrustMarkStatusIdentifierCriterion.java
similarity index 54%
rename from idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/TrustMarkStatusRequestCriterion.java
rename to idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/cache/tm/TrustMarkStatusIdentifierCriterion.java
index f33a060..4a2f9f2 100644
--- 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/cache/tm/TrustMarkStatusIdentifierCriterion.java
@@ -12,52 +12,51 @@
  * limitations under the License.
  */
 
-package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm;
 
 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.
+ * A {@link Criterion} representing request message details to a Trust Mark Status API.
  */
-public class TrustMarkStatusRequestCriterion implements Criterion {
+public class TrustMarkStatusIdentifierCriterion implements Criterion {
 
-    /** The request message. */
-    @Nonnull private final TrustMarkStatusRequest request;
+    /** The trust mark status identifier. */
+    @Nonnull private final TrustMarkStatusCacheIdentifier identifier;
 
     /**
      * Constructor.
      *
-     * @param requestMessage request message, must not be null
+     * @param id identifier, must not be null
      */
-    public TrustMarkStatusRequestCriterion(@Nonnull final TrustMarkStatusRequest requestMessage) {
-        request = Constraint.isNotNull(requestMessage, "Request cannot be null");
+    public TrustMarkStatusIdentifierCriterion(@Nonnull final TrustMarkStatusCacheIdentifier id) {
+        identifier = Constraint.isNotNull(id, "Identifier cannot be null");
     }
 
     /**
-     * Get the request message.
+     * Get the trust mark status identifier.
      * 
-     * @return the request message
+     * @return the identifier
      */
-    @Nonnull public TrustMarkStatusRequest getRequest() {
-        return request;
+    @Nonnull public TrustMarkStatusCacheIdentifier getIdentifier() {
+        return identifier;
     }
 
     /** {@inheritDoc} */
     @Override
     public String toString() {
-        return "TrustMarkStatusRequestCriterion [request=" + request + "]";
+        return "TrustMarkStatusIdentifierCriterion [identifier=" + identifier + "]";
     }
 
     /** {@inheritDoc} */
     @Override
     public int hashCode() {
-        return Objects.hash(request);
+        return Objects.hash(identifier);
     }
 
     /** {@inheritDoc} */
@@ -72,9 +71,8 @@ public class TrustMarkStatusRequestCriterion implements Criterion {
         if (getClass() != obj.getClass()) {
             return false;
         }
-        final TrustMarkStatusRequestCriterion other = (TrustMarkStatusRequestCriterion) obj;
-        //TODO: proper equals-check
-        return request.equals(other.request);
+        final TrustMarkStatusIdentifierCriterion other = (TrustMarkStatusIdentifierCriterion) obj;
+        return identifier.equals(other.identifier);
     }
 
 }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ss/DefaultSubordinateStatementFetchingStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ss/DefaultSubordinateStatementFetchingStrategy.java
index 76af4b5..f726bfb 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ss/DefaultSubordinateStatementFetchingStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ss/DefaultSubordinateStatementFetchingStrategy.java
@@ -49,6 +49,7 @@ import net.shibboleth.oidc.metadata.cache.MetadataCache;
 import net.shibboleth.oidc.metadata.cache.MetadataCacheException;
 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.logic.ConstraintViolationException;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -73,6 +74,7 @@ public class DefaultSubordinateStatementFetchingStrategy
     /** Class logger. */
     @Nonnull private Logger log = LoggerFactory.getLogger(DefaultSubordinateStatementFetchingStrategy.class);
 
+    /** The entity configuration cache used for fetching issuer statement. */
     @NonnullAfterInit private MetadataCache<RemoteEntityConfigurationContainer> entityConfigurationCache;
 
     /**
@@ -94,11 +96,25 @@ public class DefaultSubordinateStatementFetchingStrategy
         });
     }
 
+    /**
+     * Set the entity configuration cache used for fetching issuer statement.
+     * 
+     * @param cache entity configuration cache
+     */
     public void setEntityConfigurationCache(@Nonnull final MetadataCache<RemoteEntityConfigurationContainer> cache) {
         checkSetterPreconditions();
         entityConfigurationCache = Constraint.isNotNull(cache, "Entity configuration cache cannot be null");
     }
 
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        if (entityConfigurationCache == null) {
+            throw new ComponentInitializationException("Entity configuration cache cannot be null");
+        }
+    }
+
     /** {@inheritDoc} */
     @Nullable protected ClassicHttpRequest initializeHttpRequest(@Nonnull final CriteriaSet criteria,
             @Nonnull final SubordinateStatementCacheIdentifier id) {
@@ -106,8 +122,7 @@ public class DefaultSubordinateStatementFetchingStrategy
         final List<RemoteEntityConfigurationContainer> issuerStatements;
         try {
             issuerStatements =
-                    entityConfigurationCache.get(new CriteriaSet(
-                            new SubjectEntityIDCriterion(issuerEntityId)));
+                    entityConfigurationCache.get(new CriteriaSet(new SubjectEntityIDCriterion(issuerEntityId)));
         } catch (final MetadataCacheException e) {
             log.error("Could not resolve entity configuration for issuer {}", issuerEntityId, e);
             return null;
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ss/DefaultSubordinateStatementSignatureValidationCondition.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ss/DefaultSubordinateStatementSignatureValidationCondition.java
deleted file mode 100644
index 7ba3b68..0000000
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/ss/DefaultSubordinateStatementSignatureValidationCondition.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.ss;
-
-import java.util.List;
-import java.util.function.BiPredicate;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.security.trust.TrustEngine;
-import org.slf4j.Logger;
-
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.AbstractTrustEngineSignatureValidationComponent;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubjectEntityIDCriterion;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.IssuerEntityStatementCriterion;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.RemoteEntityConfigurationContainer;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.RemoteSubordinateStatementContainer;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.SubjectEntityStatementCriterion;
-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.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.shared.resolver.CriteriaSet;
-
-/**
- * Default signature validating filter for entity statement. The signature validation is performed via configurable
- * {@link TrustEngine}.
- */
- at ThreadSafeAfterInit
-public class DefaultSubordinateStatementSignatureValidationCondition
-    extends AbstractTrustEngineSignatureValidationComponent
-    implements BiPredicate<RemoteSubordinateStatementContainer, MetadataFilterContext> {
-
-    /** Class logger. */
-    @Nonnull private Logger log =
-            LoggerFactory.getLogger(DefaultSubordinateStatementSignatureValidationCondition.class);
-
-    @NonnullAfterInit private MetadataCache<RemoteEntityConfigurationContainer> entityConfigurationCache;
-
-    public void setEntityConfigurationCache(@Nonnull final MetadataCache<RemoteEntityConfigurationContainer> cache) {
-        checkSetterPreconditions();
-        entityConfigurationCache = Constraint.isNotNull(cache, "Entity configuration cache cannot be null");
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean test(@Nullable final RemoteSubordinateStatementContainer responseContainer,
-            @Nullable final MetadataFilterContext filterContext) {
-        checkComponentActive();
-        if (responseContainer == null) {
-            return false;
-        }
-
-        final EntityStatement statement = responseContainer.getEntityStatement();
-        if (statement != null ) {
-            final String entityId = responseContainer.getIdentifier().getSubject();
-            final String issuer = responseContainer.getIdentifier().getIssuer();
-            assert issuer != null;
-            log.trace("Validating subordinate statement for {}, issued by {}", entityId, issuer);
-            final EntityStatement issuerStatement = fetchIssuerStatement(issuer);
-            if (issuerStatement == null) {
-                log.debug("Could not fetch issuer statement");
-                return false;
-            }
-            final CriteriaSet criteria = new CriteriaSet();
-            criteria.add(new IssuerEntityStatementCriterion(issuerStatement));
-            criteria.add(new SubjectEntityStatementCriterion(statement));
-
-            log.trace("Starting signature validation of entity configuration for {}", entityId);
-            if (validateJwt(statement.getJwt(), criteria, entityId)) {
-                return true;
-            }
-            return false;
-        } else {
-            log.debug("Ignoring signature check for the error response");
-        }
-        return true;
-    }
-
-    /**
-     * Fetch the issuer entity configuration from the 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<RemoteEntityConfigurationContainer> result = entityConfigurationCache.get(criteria);
-            if (!result.isEmpty()) {
-                return result.get(0).getEntityStatement();
-            }
-        } catch (final MetadataCacheException e) {
-            log.debug("Error while fetching issuer entity configuration 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/profile/impl/CallResolveEntityApi.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/CallResolveEntityApi.java
index a4539c8..a21ba8e 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/CallResolveEntityApi.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/CallResolveEntityApi.java
@@ -45,16 +45,16 @@ import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.oauth2.sdk.id.ClientID;
 
 import net.shibboleth.idp.authn.AuthnEventIds;
-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.idp.plugin.oidc.op.oidfed.metadata.EntityStatement;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatementHelper;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResolveEntityRequestCriterion;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResolveEntityResponseContainer;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResolveEntityResponse;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResolveEntityResponsePayload;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResponseContainerExpirationCriterion;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.SubjectEntityIDCriterion;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.RemoteEntityConfigurationContainer;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.SubjectEntityStatementCriterion;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remoteresolver.RemoteResolveEntityCacheContainerIdentifier;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remoteresolver.RemoteResolveEntityCacheIdentifierCriterion;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remoteresolver.RemoteResolveEntityResponseContainer;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.context.RelyingPartyTrustChainContext;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate.DefaultPreSelectedTrustChainIDsLookupStrategy;
@@ -97,7 +97,7 @@ public class CallResolveEntityApi extends AbstractProfileAction {
     @NonnullAfterInit private MetadataCache<RemoteEntityConfigurationContainer> entityConfigurationCache;
 
     /** Cache containing responses from resolve entity APIs. */
-    @NonnullAfterInit private MetadataCache<ResolveEntityResponseContainer> resolveEntityTrustChainMetadataCache;
+    @NonnullAfterInit private MetadataCache<RemoteResolveEntityResponseContainer> resolveEntityTrustChainMetadataCache;
 
     /** Strategy used to obtain the client id value of the request. */
     @NonnullAfterInit private Function<MessageContext, ClientID> clientIDLookupStrategy;
@@ -173,7 +173,7 @@ public class CallResolveEntityApi extends AbstractProfileAction {
     }
 
     public void setResolveEntityTrustChainMetadataCache(
-            @Nonnull final MetadataCache<ResolveEntityResponseContainer> cache) {
+            @Nonnull final MetadataCache<RemoteResolveEntityResponseContainer> cache) {
         checkSetterPreconditions();
         resolveEntityTrustChainMetadataCache =
                 Constraint.isNotNull(cache, "ResolveEntityTrustChainMetadataCache cannot be null");
@@ -398,12 +398,13 @@ public class CallResolveEntityApi extends AbstractProfileAction {
                 log.warn("{} Could not fetch federation resolve endpoint for {}", getLogPrefix(), trustedEntity);
                 continue;
             }
-            final ResolveEntityRequest entityRequest = new ResolveEntityRequest(
-                    uri, clientId, List.copyOf(trustedEntity.getTrustAnchors()), List.of("openid_relying_party"));
+            final RemoteResolveEntityCacheContainerIdentifier entityRequest = new RemoteResolveEntityCacheContainerIdentifier(
+                    uri.toString(), clientId, List.copyOf(trustedEntity.getTrustAnchors()),
+                    List.of("openid_relying_party"));
             final CriteriaSet criteriaSet = new CriteriaSet();
             baseCriteriaSet.forEach(c -> criteriaSet.add(c));
-            criteriaSet.add(new ResolveEntityRequestCriterion(entityRequest));
-            final List<ResolveEntityResponseContainer> cacheResult;
+            criteriaSet.add(new RemoteResolveEntityCacheIdentifierCriterion(entityRequest));
+            final List<RemoteResolveEntityResponseContainer> cacheResult;
             try {
                 cacheResult = resolveEntityTrustChainMetadataCache.get(criteriaSet);
             } catch (final MetadataCacheException e) {
@@ -414,20 +415,12 @@ public class CallResolveEntityApi extends AbstractProfileAction {
                 log.debug("{} No data resolved for {} from {}", getLogPrefix(), clientId, trustedEntity);
                 continue;
             }
-            if (cacheResult.get(0).getResponse() instanceof ResolveEntityResponse successResponse) {
-                final List<String> rawTrustChain;
-                final Map<String, Object> rawMetadata;
-                final List<Object> rawTrustMarks;
-                try {
-                    rawTrustChain = successResponse.getJWT().getJWTClaimsSet().getStringListClaim("trust_chain");
-                    rawMetadata = successResponse.getJWT().getJWTClaimsSet().getJSONObjectClaim("metadata");
-                    rawTrustMarks = successResponse.getJWT().getJWTClaimsSet().getListClaim("trust_marks");
-                } catch (final ParseException e) {
-                    log.error("{} Could not parse resolve entity response contents from {}", getLogPrefix(),
-                            trustedEntity, e);
-                    continue;
-                }
-                if (rawTrustChain == null || rawTrustChain.isEmpty() || rawMetadata == null || rawMetadata.isEmpty()) {
+            if (cacheResult.get(0).getEntityStatement() instanceof ResolveEntityResponse successResponse
+                    && successResponse.getParsedPayload() instanceof ResolveEntityResponsePayload payload) {
+                final List<String> rawTrustChain = payload.getTrustChain();
+                final Map<String, Map<String, Object>> metadata = payload.getMetadata();
+                final List<Map<String,String>> rawTrustMarks = payload.getTrustMarks();
+                if (rawTrustChain == null || rawTrustChain.isEmpty() || metadata == null || metadata.isEmpty()) {
                     log.warn("{} Could not parse mandatory parameters from the response from {}", getLogPrefix(),
                             trustedEntity);
                     continue;
@@ -452,13 +445,6 @@ public class CallResolveEntityApi extends AbstractProfileAction {
                             getLogPrefix());
                     continue;
                 }
-                final Map<String, Map<String, Object>> metadata = rawMetadata.entrySet().stream()
-                        .filter(entry -> entry.getKey() instanceof String && entry.getValue() instanceof Map<?,?>)
-                        .collect(Collectors.toMap(entry -> (String) entry.getKey(),
-                                entry -> ((Map<?,?>)entry.getValue()).entrySet().stream()
-                                .filter(e -> e.getKey() instanceof String)
-                                .collect(Collectors.toMap(e -> (String) e.getKey(), e -> e.getValue()))));
-
                 final List<Pair<List<EntityStatement>, Map<String,Map<String,Object>>>> policyCompliantChains =
                         new ArrayList<>();
                 policyCompliantChains.add(new Pair<>(chain, metadata));
@@ -510,7 +496,7 @@ public class CallResolveEntityApi extends AbstractProfileAction {
                 return;
             } else {
                 log.debug("{} The response from {} was not a success response: {}", getLogPrefix(), trustedEntity,
-                        cacheResult.get(0).getResponse());
+                        cacheResult.get(0).getEntityStatement());
                 continue;
             }
         }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/DefaultTrustMarkFromMetadataCacheFetchingFunction.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/DefaultTrustMarkFromMetadataCacheFetchingFunction.java
index 47ca881..4882312 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/DefaultTrustMarkFromMetadataCacheFetchingFunction.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/DefaultTrustMarkFromMetadataCacheFetchingFunction.java
@@ -29,13 +29,13 @@ import org.slf4j.Logger;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
-import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkRequest;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkResponse;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.EntityStatementHelper;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ResponseContainerExpirationCriterion;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.TrustMarkRequestCriterion;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.TrustMarkResponseContainer;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.TrustMark;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.RemoteEntityConfigurationContainer;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.RemoteTrustMarkContainer;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.TrustMarkCacheIdentifier;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.TrustMarkIdentifierCriterion;
 import net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteEntity;
 import net.shibboleth.oidc.metadata.cache.MetadataCache;
 import net.shibboleth.oidc.metadata.cache.MetadataCacheException;
@@ -61,7 +61,7 @@ public class DefaultTrustMarkFromMetadataCacheFetchingFunction extends AbstractI
     @NonnullAfterInit private MetadataCache<RemoteEntityConfigurationContainer> entityConfigurationCache;
 
     /** Cache containing responses from Trust Mark APIs. */
-    @NonnullAfterInit private MetadataCache<TrustMarkResponseContainer> trustMarkCache;
+    @NonnullAfterInit private MetadataCache<RemoteTrustMarkContainer> trustMarkCache;
 
     /** JSON object mapper used for decoding JSON into Map. */
     @NonnullAfterInit private ObjectMapper objectMapper;
@@ -100,7 +100,7 @@ public class DefaultTrustMarkFromMetadataCacheFetchingFunction extends AbstractI
      * 
      * @param cache cache containing responses from Trust Mark APIs
      */
-    public void setTrustMarkCache(@Nonnull final MetadataCache<TrustMarkResponseContainer> cache) {
+    public void setTrustMarkCache(@Nonnull final MetadataCache<RemoteTrustMarkContainer> cache) {
         checkSetterPreconditions();
         trustMarkCache = Constraint.isNotNull(cache, "Trust Mark cache cannot be null");
     }
@@ -174,15 +174,16 @@ public class DefaultTrustMarkFromMetadataCacheFetchingFunction extends AbstractI
         checkComponentActive();
         final String entityId = trustedEntity.getEntityId();
         final URI uri = EntityStatementHelper.fetchEndpointUriFromFederationEntity(entityConfigurationCache,
-                entityId, "trust_mark_endpoint", Instant.now().plusSeconds(300)); //TODO
+                entityId, "trust_mark_endpoint");
         if (uri == null) {
             log.warn("Could not fetch trust mark endpoint for {}", entityId);
             return null;
         }
-        final TrustMarkRequest trustMarkRequest = new TrustMarkRequest(uri, trustMarkType, subject);
-        final CriteriaSet criteriaSet = new CriteriaSet(new TrustMarkRequestCriterion(trustMarkRequest));
+        final TrustMarkCacheIdentifier trustMarkIdentifier =
+                new TrustMarkCacheIdentifier(uri.toString(), trustMarkType, subject);
+        final CriteriaSet criteriaSet = new CriteriaSet(new TrustMarkIdentifierCriterion(trustMarkIdentifier));
         criteriaSet.add(new ResponseContainerExpirationCriterion(Instant.now().plus(cachedLifetime)));
-        final List<TrustMarkResponseContainer> cacheResult;
+        final List<RemoteTrustMarkContainer> cacheResult;
         try {
             cacheResult = trustMarkCache.get(criteriaSet);
         } catch (final MetadataCacheException e) {
@@ -193,11 +194,11 @@ public class DefaultTrustMarkFromMetadataCacheFetchingFunction extends AbstractI
             log.debug("No data resolved for {} from {}", trustMarkType, trustedEntity);
             return null;
         }
-        if (cacheResult.get(0).getResponse() instanceof TrustMarkResponse successResponse) {
-            return Map.of("trust_mark_type", trustMarkType, "trust_mark", successResponse.getJWT().serialize());
+        if (cacheResult.get(0).getEntityStatement() instanceof TrustMark trustMark) {
+            return Map.of("trust_mark_type", trustMarkType, "trust_mark", trustMark.getJwt().serialize());
         } else {
             log.debug("The response from {} was not a success response: {}", trustedEntity,
-                    cacheResult.get(0).getResponse());
+                    cacheResult.get(0).getEntityStatement());
         }
         return null;
     }
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 2d5aad1..ac97b8c 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
@@ -126,7 +126,7 @@
                                 <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ec.DefaultEntityConfigurationCriteriaSetLookupFunction"/>
                             </property>
                         </bean>
-                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ec.DefaultEntityConfigurationContentValidationCondition"
+                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
                             p:claimsValidator-ref="%{idp.oidfed.entityConfiguration.claimsValidator:shibboleth.oidfed.DefaultEntityConfigurationClaimsValidator}"/>
                     </util:list>
                 </property>
@@ -210,10 +210,14 @@
             <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementMetadataFilterStrategy">
                 <property name="validationConditions">
                     <util:list value-type="java.util.function.BiPredicate">
-                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ss.DefaultSubordinateStatementSignatureValidationCondition"
-                            p:trustEngine-ref="shibboleth.oidfed.DefaultSubordinateStatementTrustEngine"
-                            p:entityConfigurationCache-ref="shibboleth.oidfed.EntityConfigurationMetadataCache"/>
-                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.ec.DefaultEntityConfigurationContentValidationCondition"
+                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementSignatureValidationCondition"
+                            p:trustEngine-ref="shibboleth.oidfed.DefaultSubordinateStatementTrustEngine">
+                            <property name="criteriaSetLookupStrategy">
+                                <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementValidationCriteriaSetLookupFunction"
+                                    p:entityConfigurationCache-ref="shibboleth.oidfed.EntityConfigurationMetadataCache"/>
+                            </property>
+                        </bean>
+                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
                             p:claimsValidator-ref="%{idp.oidfed.subordinateStatement.claimsValidator:shibboleth.oidfed.DefaultSubordinateStatementClaimsValidator}"/>
                     </util:list>
                 </property>
@@ -341,37 +345,74 @@
 
     <bean id="shibboleth.oidfed.ResolveEntityTrustChainMetadataCacheBuilderSpec"
         class="net.shibboleth.oidc.metadata.cache.impl.DynamicMetadataCacheBuilderSpec"
-        p:minCacheDuration="%{idp.oidfed.entityConfiguration.maxRefreshDelay:PT1S}"
-        p:maxCacheDuration="%{idp.oidfed.entityConfiguration.maxRefreshDelay:PT30S}">
+        p:minCacheDuration="%{idp.oidfed.cache.resolveEntity.minRefreshDelay:PT1M}"
+        p:maxCacheDuration="%{idp.oidfed.cache.resolveEntity.maxRefreshDelay:PT30M}"
+        p:metadataExpirationTimeStrategy-ref="DefaultResponseContainerExpirationTimeStrategy">
         <property name="criteriaToIdentifierStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultResolveEntityRequestCriteriaToIdentifierStrategy" />
+            <bean parent="shibboleth.Functions.Expression" c:expression="#input?.get(T(net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remoteresolver.RemoteResolveEntityCacheIdentifierCriterion))?.getIdentifier()"/>
         </property>
         <property name="identifierExtractionStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultResolveEntityResponseIdentifierExtractionStrategy" />
-        </property>
-        <property name="metadataExpirationTimeStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultNimbusResponseContainerExpirationTimeStrategy"/>
+            <bean parent="shibboleth.Functions.Expression" c:expression="#input?.getIdentifier()"/>
         </property>
         <property name="metadataFilterStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultResolveEntityResponseSignatureValidationFilterStrategy"
-                p:entityConfigurationCache-ref="shibboleth.oidfed.EntityConfigurationMetadataCache">
-                <property name="trustEngine">
-                    <bean class="net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine">
-                        <constructor-arg index="0">
-                            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.security.credential.DefaultEntityConfigurationCredentialResolver" />
-                        </constructor-arg>
-                        <constructor-arg index="1">
-                            <bean class="net.shibboleth.oidc.security.credential.impl.BasicJOSEObjectCredentialResolver" />
-                        </constructor-arg>
-                    </bean>
+            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementMetadataFilterStrategy">
+                <property name="validationConditions">
+                    <util:list value-type="java.util.function.BiPredicate">
+                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementSignatureValidationCondition"
+                            p:trustEngine-ref="shibboleth.oidfed.DefaultSubordinateStatementTrustEngine">
+                            <property name="criteriaSetLookupStrategy">
+                                <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementValidationCriteriaSetLookupFunction"
+                                    p:entityConfigurationCache-ref="shibboleth.oidfed.EntityConfigurationMetadataCache"/>
+                            </property>
+                        </bean>
+                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
+                            p:claimsValidator-ref="%{idp.oidfed.remoteResolver.claimsValidator:shibboleth.oidfed.DefaultResolveEntityResponseClaimsValidator}"/>
+                    </util:list>
                 </property>
             </bean>
         </property>
         <property name="fetchStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultResolveEntityTrustChainFetchingStrategy"
+            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.remoteresolver.DefaultResolveEntityTrustChainFetchingStrategy"
                 p:httpClient="#{getObject('shibboleth.oidfed.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
                 p:httpClientSecurityParameters="#{getObject('shibboleth.oidfed.NonBrowser.HttpClientSecurityParameters')}"
-                p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper"/>
+                p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper">
+                <property name="criteriaToValidContainerLifetimeStrategy">
+                    <bean parent="shibboleth.Functions.Constant">
+                        <constructor-arg>
+                            <bean class="java.time.Duration" factory-method="parse" c:_0="%{idp.oidfed.cache.resolveEntity.validContainerLifetime:PT5M}" />
+                        </constructor-arg>
+                    </bean>
+                </property>
+                <property name="criteriaToInvalidContainerLifetimeStrategy">
+                    <bean parent="shibboleth.Functions.Constant">
+                        <constructor-arg>
+                            <bean class="java.time.Duration" factory-method="parse" c:_0="%{idp.oidfed.cache.resolveEntity.invalidContainerLifetime:PT1M}" />
+                        </constructor-arg>
+                    </bean>
+                </property>
+            </bean>
+        </property>
+    </bean>
+
+    <bean id="shibboleth.oidfed.DefaultResolveEntityResponseClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator">
+        <property name="claimValidators">
+            <util:list value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator"
+                    p:clockSkew="%{idp.policy.clockSkew:PT1M}"
+                    p:messageLifetime="%{idp.policy.messageLifetime:PT1M}"
+                    p:requiredRule="true" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="iss" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="sub" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
+                    p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="metadata" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="trust_chain" />
+            </util:list>
         </property>
     </bean>
 
@@ -430,18 +471,65 @@
             <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()"/>
+            <bean parent="shibboleth.Functions.Expression" c:expression="#input?.get(T(net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.TrustMarkStatusIdentifierCriterion))?.getIdentifier()"/>
         </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"/>
+            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementMetadataFilterStrategy">
+                <property name="validationConditions">
+                    <util:list value-type="java.util.function.BiPredicate">
+                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementSignatureValidationCondition"
+                            p:trustEngine-ref="shibboleth.oidfed.DefaultSubordinateStatementTrustEngine">
+                            <property name="criteriaSetLookupStrategy">
+                                <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.DefaultTrustMarkValidationCriteriaSetLookupFunction"
+                                    p:trustChainCache-ref="shibboleth.oidfed.TrustChainMetadataCache"/>
+                            </property>
+                        </bean>
+                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
+                            p:claimsValidator-ref="%{idp.oidfed.trustMarkStatus.claimsValidator:shibboleth.oidfed.DefaultTrustMarkStatusClaimsValidator}"/>
+                    </util:list>
+                </property>
+            </bean>
         </property>
         <property name="fetchStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultTrustMarkStatusFetchingStrategy"
+            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.DefaultTrustMarkStatusFetchingStrategy"
                 p:httpClient="#{getObject('shibboleth.oidfed.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
                 p:httpClientSecurityParameters="#{getObject('shibboleth.oidfed.NonBrowser.HttpClientSecurityParameters')}"
-                p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper"/>
+                p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper">
+                <property name="criteriaToValidContainerLifetimeStrategy">
+                    <bean parent="shibboleth.Functions.Constant">
+                        <constructor-arg>
+                            <bean class="java.time.Duration" factory-method="parse" c:_0="%{idp.oidfed.cache.trustMarkStatus.validContainerLifetime:PT5M}" />
+                        </constructor-arg>
+                    </bean>
+                </property>
+                <property name="criteriaToInvalidContainerLifetimeStrategy">
+                    <bean parent="shibboleth.Functions.Constant">
+                        <constructor-arg>
+                            <bean class="java.time.Duration" factory-method="parse" c:_0="%{idp.oidfed.cache.trustMarkStatus.invalidContainerLifetime:PT1M}" />
+                        </constructor-arg>
+                    </bean>
+                </property>
+            </bean>
+        </property>
+    </bean>
+
+    <bean id="shibboleth.oidfed.DefaultTrustMarkStatusClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator">
+        <property name="claimValidators">
+            <util:list value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator"
+                    p:clockSkew="%{idp.policy.clockSkew:PT1M}"
+                    p:messageLifetime="%{idp.policy.messageLifetime:PT1M}"
+                    p:requiredRule="true" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="iss" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
+                    p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="trust_mark" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="status" />
+            </util:list>
         </property>
     </bean>
 
@@ -455,26 +543,71 @@
     <bean id="shibboleth.oidfed.TrustMarkMetadataCacheBuilderSpec"
         class="net.shibboleth.oidc.metadata.cache.impl.DynamicMetadataCacheBuilderSpec"
         p:minCacheDuration="%{idp.oidfed.cache.trustMark.minRefreshDelay:PT1H}"
-        p:maxCacheDuration="%{idp.oidfed.cache.trustMark.maxRefreshDelay:PT24H}">
+        p:maxCacheDuration="%{idp.oidfed.cache.trustMark.maxRefreshDelay:PT24H}"
+        p:metadataExpirationTimeStrategy-ref="DefaultResponseContainerExpirationTimeStrategy">
         <property name="identifierExtractionStrategy">
-            <bean parent="shibboleth.Functions.Expression" c:expression="#input?.getRequestMessage().toString()"/>
+            <bean parent="shibboleth.Functions.Expression" c:expression="#input?.getIdentifier()"/>
         </property>
         <property name="criteriaToIdentifierStrategy">
-            <bean parent="shibboleth.Functions.Expression" c:expression="#input?.get(T(net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.TrustMarkRequestCriterion))?.getRequest().toString()"/>
+            <bean parent="shibboleth.Functions.Expression" c:expression="#input?.get(T(net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.TrustMarkIdentifierCriterion))?.getIdentifier()"/>
         </property>
         <property name="metadataFilterStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultTrustMarkResponseSignatureValidationFilterStrategy"
-                p:trustChainCache-ref="shibboleth.oidfed.TrustChainMetadataCache"
-                p:trustEngine-ref="shibboleth.oidfed.DefaultEntityConfigurationTrustEngine"/>
+            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementMetadataFilterStrategy">
+                <property name="validationConditions">
+                    <util:list value-type="java.util.function.BiPredicate">
+                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementSignatureValidationCondition"
+                            p:trustEngine-ref="shibboleth.oidfed.DefaultSubordinateStatementTrustEngine">
+                            <property name="criteriaSetLookupStrategy">
+                                <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.DefaultTrustMarkValidationCriteriaSetLookupFunction"
+                                    p:trustChainCache-ref="shibboleth.oidfed.TrustChainMetadataCache"/>
+                            </property>
+                        </bean>
+                        <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.DefaultEntityStatementContentValidationCondition"
+                            p:claimsValidator-ref="%{idp.oidfed.trustMark.claimsValidator:shibboleth.oidfed.DefaultTrustMarkClaimsValidator}"/>
+                    </util:list>
+                </property>
+            </bean>
         </property>
         <property name="fetchStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultTrustMarkFetchingStrategy"
+            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.DefaultTrustMarkFetchingStrategy"
                 p:httpClient="#{getObject('shibboleth.oidfed.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
                 p:httpClientSecurityParameters="#{getObject('shibboleth.oidfed.NonBrowser.HttpClientSecurityParameters')}"
-                p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper"/>
+                p:objectMapper-ref="shibboleth.oidfed.JWTPayloadJSONObjectMapper">
+                <property name="criteriaToValidContainerLifetimeStrategy">
+                    <bean parent="shibboleth.Functions.Constant">
+                        <constructor-arg>
+                            <bean class="java.time.Duration" factory-method="parse" c:_0="%{idp.oidfed.cache.trustMark.validContainerLifetime:PT5M}" />
+                        </constructor-arg>
+                    </bean>
+                </property>
+                <property name="criteriaToInvalidContainerLifetimeStrategy">
+                    <bean parent="shibboleth.Functions.Constant">
+                        <constructor-arg>
+                            <bean class="java.time.Duration" factory-method="parse" c:_0="%{idp.oidfed.cache.trustMark.invalidContainerLifetime:PT1M}" />
+                        </constructor-arg>
+                    </bean>
+                </property>
+            </bean>
         </property>
-        <property name="metadataExpirationTimeStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultNimbusResponseContainerExpirationTimeStrategy"/>
+    </bean>
+
+    <bean id="shibboleth.oidfed.DefaultTrustMarkClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator">
+        <property name="claimValidators">
+            <util:list value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator"
+                    p:clockSkew="%{idp.policy.clockSkew:PT1M}"
+                    p:messageLifetime="%{idp.policy.messageLifetime:PT1M}"
+                    p:requiredRule="true" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="iss" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="sub" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
+                    p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator"
+                    p:requiredClaims="trust_mark_type" />
+            </util:list>
         </property>
     </bean>
 
@@ -605,7 +738,10 @@
         </property>
     </bean>
 
-    <bean id="DefaultTrustMarkClaimsValidationLookupStrategy" parent="shibboleth.Functions.Constant">
+    <bean id="DefaultTrustMarkClaimsValidationLookupStrategy" parent="shibboleth.Functions.Constant"
+        c:target-ref="shibboleth.oidfed.DefaultTrustMarkClaimsValidator" />
+
+    <bean id="DefaultDelegatedTrustMarkClaimsValidationLookupStrategy" parent="shibboleth.Functions.Constant">
         <constructor-arg name="target">
             <bean class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator">
                 <property name="claimValidators">
@@ -628,6 +764,7 @@
         </constructor-arg>
     </bean>
 
+
     <bean id="shibboleth.oidfed.DefaultPreSelectedTrustChainIDsLookupStrategy"
         class="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate.DefaultPreSelectedTrustChainIDsLookupStrategy">
         <property name="profileIdLookupStrategy">
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml
index 1d6f6f1..370dc07 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/metadata-lookup-ext/oidfed/metadata-lookup-ext-oidfed-beans.xml
@@ -107,7 +107,7 @@
         scope="prototype"
         p:trustChainCache-ref="#{'%{idp.oidfed.authorize.TrustChainMetadataCache:shibboleth.oidfed.TrustChainMetadataCache}'.trim()}"
         p:trustMarkClaimsValidationLookupStrategy="#{getObject('shibboleth.oidfed.TrustMarkClaimsValidationLookupStrategy') ?: getObject('DefaultTrustMarkClaimsValidationLookupStrategy')}"
-        p:delegatedTrustMarkClaimsValidationLookupStrategy="#{getObject('shibboleth.oidfed.DelegatedTrustMarkClaimsValidationLookupStrategy') ?: getObject('DefaultTrustMarkClaimsValidationLookupStrategy')}"
+        p:delegatedTrustMarkClaimsValidationLookupStrategy="#{getObject('shibboleth.oidfed.DelegatedTrustMarkClaimsValidationLookupStrategy') ?: getObject('DefaultDelegatedTrustMarkClaimsValidationLookupStrategy')}"
         p:trustEngine-ref="shibboleth.oidfed.DefaultEntityConfigurationTrustEngine"
         p:delegationTrustEngine-ref="shibboleth.oidfed.DefaultDelegatedTrustMarkTrustEngine">
         <property name="trustChainTrustMarksParsingStrategy">
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
index c9c63b1..142e58a 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
@@ -215,7 +215,7 @@
         scope="prototype"
         p:trustChainCache-ref="#{'%{idp.oidfed.register.TrustChainMetadataCache:shibboleth.oidfed.TrustChainMetadataCache}'.trim()}"
         p:trustMarkClaimsValidationLookupStrategy="#{getObject('shibboleth.oidfed.TrustMarkClaimsValidationLookupStrategy') ?: getObject('DefaultTrustMarkClaimsValidationLookupStrategy')}"
-        p:delegatedTrustMarkClaimsValidationLookupStrategy="#{getObject('shibboleth.oidfed.DelegatedTrustMarkClaimsValidationLookupStrategy') ?: getObject('DefaultTrustMarkClaimsValidationLookupStrategy')}"
+        p:delegatedTrustMarkClaimsValidationLookupStrategy="#{getObject('shibboleth.oidfed.DelegatedTrustMarkClaimsValidationLookupStrategy') ?: getObject('DefaultDelegatedTrustMarkClaimsValidationLookupStrategy')}"
         p:trustEngine-ref="shibboleth.oidfed.DefaultEntityConfigurationTrustEngine"
         p:delegationTrustEngine-ref="shibboleth.oidfed.DefaultDelegatedTrustMarkTrustEngine">
         <property name="trustChainTrustMarksParsingStrategy">
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/resolve-entity/resolve-entity-beans.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/resolve-entity/resolve-entity-beans.xml
index c5a6652..0bea4da 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/resolve-entity/resolve-entity-beans.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/resolve-entity/resolve-entity-beans.xml
@@ -128,7 +128,7 @@
         scope="prototype"
         p:trustChainCache-ref="#{'%{idp.oidfed.resolve-entity.TrustChainMetadataCache:shibboleth.oidfed.TrustChainMetadataCache}'.trim()}"
         p:trustMarkClaimsValidationLookupStrategy="#{getObject('shibboleth.oidfed.TrustMarkClaimsValidationLookupStrategy') ?: getObject('DefaultTrustMarkClaimsValidationLookupStrategy')}"
-        p:delegatedTrustMarkClaimsValidationLookupStrategy="#{getObject('shibboleth.oidfed.DelegatedTrustMarkClaimsValidationLookupStrategy') ?: getObject('DefaultTrustMarkClaimsValidationLookupStrategy')}"
+        p:delegatedTrustMarkClaimsValidationLookupStrategy="#{getObject('shibboleth.oidfed.DelegatedTrustMarkClaimsValidationLookupStrategy') ?: getObject('DefaultDelegatedTrustMarkClaimsValidationLookupStrategy')}"
         p:trustEngine-ref="shibboleth.oidfed.DefaultEntityConfigurationTrustEngine"
         p:delegationTrustEngine-ref="shibboleth.oidfed.DefaultDelegatedTrustMarkTrustEngine">
         <property name="trustChainTrustMarksParsingStrategy">
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/EntityConfigurationFlowTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/EntityConfigurationFlowTest.java
index 25729f6..867a617 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/EntityConfigurationFlowTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/EntityConfigurationFlowTest.java
@@ -42,7 +42,7 @@ import com.nimbusds.openid.connect.sdk.federation.registration.ClientRegistratio
 import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
 
 import net.shibboleth.idp.plugin.oidc.op.oidfed.TrustChainTestUtil;
-import net.shibboleth.idp.plugin.oidc.op.oidfed.messaging.impl.TrustMarkResponse;
+import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.cache.tm.DefaultTrustMarkFetchingStrategy;
 import net.shibboleth.shared.collection.CollectionSupport;
 
 /**
@@ -75,7 +75,8 @@ public class EntityConfigurationFlowTest extends AbstractFederationFlowTest {
                     + URLEncoder.encode(dynamicTrustMarkType, Charset.forName("UTF-8")) 
                     + "&sub=" + URLEncoder.encode(issuer, Charset.forName("UTF-8"));
             mapResponse(trustMarkUrl,
-                    mockResponse(200, TrustMarkResponse.HTTP_RESPONSE_CONTENT_TYPE.toString(), trustMark));
+                    mockResponse(200, DefaultTrustMarkFetchingStrategy.HTTP_RESPONSE_CONTENT_TYPE.toString(),
+                            trustMark));
         } catch (UnsupportedOperationException | IOException e) {
             Assert.fail("Could not initialize mock HTTP client", e);
         }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list