[java-idp-plugin-vci] 02/02: JSONSuccessResponse for the unsigned document. Vary set by the action. Warn when signed metadata has no certificate chain

Codeberg noreply at shibboleth.net
Fri Nov 6 12:16:29 UTC 2026


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

codeberg pushed a commit to branch dev/REVISSFLOW
in repository java-idp-plugin-vci.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/3c161d972512ce612fa1dc35d8ee5c098dee5c5e

commit 3c161d972512ce612fa1dc35d8ee5c098dee5c5e
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Fri Nov 6 14:15:52 2026 +0200

    JSONSuccessResponse for the unsigned document. Vary set by the action. Warn when signed metadata has no certificate chain
---
 .../CredentialIssuerMetadataSuccessResponse.java   | 78 ----------------------
 ...nedCredentialIssuerMetadataSuccessResponse.java |  1 -
 .../FormOutboundIssuerMetadataResponseMessage.java | 18 ++---
 ...mOutboundIssuerMetadataResponseMessageTest.java | 18 +++--
 4 files changed, 14 insertions(+), 101 deletions(-)

diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialIssuerMetadataSuccessResponse.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialIssuerMetadataSuccessResponse.java
deleted file mode 100644
index dbbe649..0000000
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialIssuerMetadataSuccessResponse.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2025, GÉANT
- *
- * 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 org.geant.shibboleth.plugin.openidvci.messaging.impl;
-
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.nimbusds.common.contenttype.ContentType;
-import com.nimbusds.oauth2.sdk.SuccessResponse;
-import com.nimbusds.oauth2.sdk.http.HTTPResponse;
-
-/**
- * Response carrying the Credential Issuer metadata, as in <a href=
- * "https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-issuer-metadata">
- * OpenID4VCI</a>.
- */
-public class CredentialIssuerMetadataSuccessResponse implements SuccessResponse {
-
-    /** Serialized metadata document. */
-    @Nonnull
-    private final String content;
-
-    /**
-     * Constructor.
-     *
-     * @param metadata members of the metadata document
-     *
-     * @throws JsonProcessingException if the members cannot be serialized
-     */
-    public CredentialIssuerMetadataSuccessResponse(@Nonnull final Map<String, Object> metadata)
-            throws JsonProcessingException {
-        content = new ObjectMapper().writeValueAsString(metadata);
-    }
-
-    /**
-     * Get the serialized metadata document.
-     *
-     * @return serialized metadata document
-     */
-    @Nonnull
-    public String getContent() {
-        return content;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean indicatesSuccess() {
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public HTTPResponse toHTTPResponse() {
-        final HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
-        httpResponse.setEntityContentType(ContentType.APPLICATION_JSON);
-        httpResponse.setHeader("Vary", "Accept");
-        httpResponse.setContent(content);
-        return httpResponse;
-    }
-
-}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/SignedCredentialIssuerMetadataSuccessResponse.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/SignedCredentialIssuerMetadataSuccessResponse.java
index a893e0c..4c369b7 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/SignedCredentialIssuerMetadataSuccessResponse.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/SignedCredentialIssuerMetadataSuccessResponse.java
@@ -65,7 +65,6 @@ public class SignedCredentialIssuerMetadataSuccessResponse implements SuccessRes
     public HTTPResponse toHTTPResponse() {
         final HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
         httpResponse.setEntityContentType(ContentType.APPLICATION_JWT);
-        httpResponse.setHeader("Vary", "Accept");
         httpResponse.setContent(content);
         return httpResponse;
     }
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundIssuerMetadataResponseMessage.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundIssuerMetadataResponseMessage.java
index 6c248a4..e82ae9b 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundIssuerMetadataResponseMessage.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundIssuerMetadataResponseMessage.java
@@ -24,7 +24,6 @@ import java.util.function.Function;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.geant.shibboleth.plugin.openidvci.messaging.impl.CredentialIssuerMetadataSuccessResponse;
 import org.geant.shibboleth.plugin.openidvci.messaging.impl.SignedCredentialIssuerMetadataSuccessResponse;
 import org.geant.shibboleth.plugin.openidvci.metadata.CredentialIssuerMetadata;
 import org.geant.shibboleth.plugin.openidvci.security.impl.CertificateChainJWSTokenSigner;
@@ -36,15 +35,16 @@ import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
 import org.slf4j.Logger;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
 import com.google.common.net.HttpHeaders;
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.SignedJWT;
 
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import net.minidev.json.JSONObject;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.oidc.profile.messaging.JSONSuccessResponse;
 import net.shibboleth.oidc.security.jose.SignatureException;
 import net.shibboleth.oidc.security.jose.SignatureSigningParameters;
 import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
@@ -57,7 +57,7 @@ import net.shibboleth.shared.primitive.StringSupport;
 import net.shibboleth.shared.resolver.ResolverException;
 
 /**
- * Action forming {@link CredentialIssuerMetadataSuccessResponse}, or
+ * Action forming {@link JSONSuccessResponse}, or
  * {@link SignedCredentialIssuerMetadataSuccessResponse} when the request names
  * signed metadata and signing is configured, from the document the attached
  * {@link CredentialIssuerMetadataResolver} resolves.
@@ -217,16 +217,9 @@ public class FormOutboundIssuerMetadataResponseMessage extends AbstractProfileAc
                     + "publishing the document unsigned", getLogPrefix());
         }
 
-        final CredentialIssuerMetadataSuccessResponse unsigned;
-        try {
-            unsigned = new CredentialIssuerMetadataSuccessResponse(metadata.getMembers());
-        } catch (final JsonProcessingException e) {
-            log.error("{} Could not serialize Credential Issuer metadata", getLogPrefix(), e);
-            ActionSupport.buildEvent(profileRequestContext, EventIds.IO_ERROR);
-            return;
-        }
         setHeaders(response);
-        profileRequestContext.ensureOutboundMessageContext().setMessage(unsigned);
+        profileRequestContext.ensureOutboundMessageContext()
+                .setMessage(new JSONSuccessResponse(new JSONObject(metadata.getMembers())));
 
         log.debug("{} Publishing Credential Issuer metadata of {}, members {}", getLogPrefix(),
                 metadata.getCredentialIssuer(), metadata.getMembers().keySet());
@@ -282,6 +275,7 @@ public class FormOutboundIssuerMetadataResponseMessage extends AbstractProfileAc
      * @param response response to set the headers of
      */
     private void setHeaders(@Nonnull final HttpServletResponse response) {
+        response.setHeader(HttpHeaders.VARY, HttpHeaders.ACCEPT);
         response.setHeader(HttpHeaders.CACHE_CONTROL, cacheControl);
         response.setHeader(HttpHeaders.X_CONTENT_TYPE_OPTIONS, FormOutboundMetadataDocumentResponseMessage.NOSNIFF);
         response.setHeader(HttpHeaders.CONTENT_SECURITY_POLICY,
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundIssuerMetadataResponseMessageTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundIssuerMetadataResponseMessageTest.java
index 86e3365..ca2c57a 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundIssuerMetadataResponseMessageTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundIssuerMetadataResponseMessageTest.java
@@ -29,7 +29,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.geant.shibboleth.plugin.openidvci.messaging.impl.CredentialIssuerMetadataSuccessResponse;
 import org.geant.shibboleth.plugin.openidvci.messaging.impl.SignedCredentialIssuerMetadataSuccessResponse;
 import org.geant.shibboleth.plugin.openidvci.metadata.CredentialIssuerMetadata;
 import org.geant.shibboleth.plugin.openidvci.metadata.resolver.CredentialIssuerMetadataResolver;
@@ -60,6 +59,7 @@ import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
 import net.shibboleth.idp.profile.testing.ActionTestingSupport;
 import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+import net.shibboleth.oidc.profile.messaging.JSONSuccessResponse;
 import net.shibboleth.oidc.jwa.support.SignatureConstants;
 import net.shibboleth.oidc.security.credential.BasicJWKCredential;
 import net.shibboleth.oidc.security.jose.SignatureSigningParameters;
@@ -139,6 +139,7 @@ public class FormOutboundIssuerMetadataResponseMessageTest {
     }
 
     private void assertDocumentHeaders(final String cacheControl) {
+        Assert.assertEquals(httpResponse.getHeaders("Vary"), List.of("Accept"));
         Assert.assertEquals(httpResponse.getHeaders("Cache-Control"), List.of(cacheControl));
         Assert.assertEquals(httpResponse.getHeaders("X-Content-Type-Options"),
                 List.of(FormOutboundMetadataDocumentResponseMessage.NOSNIFF));
@@ -192,10 +193,10 @@ public class FormOutboundIssuerMetadataResponseMessageTest {
         ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
 
         final Object message = profileRequestCtx.ensureOutboundMessageContext().getMessage();
-        Assert.assertTrue(message instanceof CredentialIssuerMetadataSuccessResponse);
+        Assert.assertTrue(message instanceof JSONSuccessResponse);
 
         final Map<String, Object> published = new ObjectMapper().readValue(
-                ((CredentialIssuerMetadataSuccessResponse) message).toHTTPResponse().getContent(),
+                ((JSONSuccessResponse) message).toHTTPResponse().getContent(),
                 new TypeReference<LinkedHashMap<String, Object>>() {
                 });
         Assert.assertEquals(published.keySet(), members().keySet());
@@ -240,10 +241,7 @@ public class FormOutboundIssuerMetadataResponseMessageTest {
 
         ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
 
-        final Object message = profileRequestCtx.ensureOutboundMessageContext().getMessage();
-        Assert.assertEquals(
-                ((CredentialIssuerMetadataSuccessResponse) message).toHTTPResponse().getHeaderMap().get("Vary"),
-                List.of("Accept"));
+        Assert.assertEquals(httpResponse.getHeaders("Vary"), List.of("Accept"));
     }
 
     @Test(dataProvider = "unsignedAccept")
@@ -257,7 +255,7 @@ public class FormOutboundIssuerMetadataResponseMessageTest {
                 actionOf(CredentialIssuerMetadata.parse(members())).execute(requestCtx));
 
         Assert.assertTrue(profileRequestCtx.ensureOutboundMessageContext()
-                .getMessage() instanceof CredentialIssuerMetadataSuccessResponse);
+                .getMessage() instanceof JSONSuccessResponse);
     }
 
     @DataProvider(name = "unsignedAccept")
@@ -304,7 +302,7 @@ public class FormOutboundIssuerMetadataResponseMessageTest {
                 actionOf(CredentialIssuerMetadata.parse(members())).execute(requestCtx));
 
         Assert.assertTrue(profileRequestCtx.ensureOutboundMessageContext()
-                .getMessage() instanceof CredentialIssuerMetadataSuccessResponse);
+                .getMessage() instanceof JSONSuccessResponse);
     }
 
     @Test
@@ -379,7 +377,7 @@ public class FormOutboundIssuerMetadataResponseMessageTest {
                 .ensureOutboundMessageContext().getMessage()).toHTTPResponse();
         Assert.assertEquals(response.getStatusCode(), 200);
         Assert.assertEquals(response.getEntityContentType().getType(), ContentType.APPLICATION_JWT.getType());
-        Assert.assertEquals(response.getHeaderMap().get("Vary"), List.of("Accept"));
+        Assert.assertEquals(httpResponse.getHeaders("Vary"), List.of("Accept"));
     }
 
     @Test

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


More information about the commits mailing list