From 5231809ccd57cb63b9aae712c324c1fa55af4f22 Mon Sep 17 00:00:00 2001 From: Enrico Risa Date: Fri, 31 Jan 2025 17:21:11 +0100 Subject: [PATCH 1/2] feat: add support for dcp v1.0 in default credential service client with backward compatibility option --- .../core/IdentityAndTrustExtension.java | 25 ++++++++++++++++++- .../DefaultCredentialServiceClient.java | 7 +++--- .../core/IdentityAndTrustExtensionTest.java | 5 ++++ .../DefaultCredentialServiceClientTest.java | 3 ++- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java index 1b3f945d0a..9dc47cfaaa 100644 --- a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java +++ b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java @@ -28,6 +28,7 @@ import org.eclipse.edc.iam.identitytrust.spi.SecureTokenService; import org.eclipse.edc.iam.identitytrust.spi.validation.TokenValidationAction; import org.eclipse.edc.iam.identitytrust.spi.verification.SignatureSuiteRegistry; +import org.eclipse.edc.iam.identitytrust.transform.to.JsonObjectToPresentationResponseMessageTransformer; import org.eclipse.edc.iam.verifiablecredentials.VerifiableCredentialValidationServiceImpl; import org.eclipse.edc.iam.verifiablecredentials.revocation.bitstring.BitstringStatusListRevocationService; import org.eclipse.edc.iam.verifiablecredentials.revocation.statuslist2021.StatusList2021RevocationService; @@ -37,6 +38,7 @@ import org.eclipse.edc.iam.verifiablecredentials.spi.validation.PresentationVerifier; import org.eclipse.edc.iam.verifiablecredentials.spi.validation.TrustedIssuerRegistry; import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.jsonld.spi.JsonLdNamespace; import org.eclipse.edc.jwt.validation.jti.JtiValidationStore; import org.eclipse.edc.participant.spi.ParticipantAgentService; import org.eclipse.edc.runtime.metamodel.annotation.Extension; @@ -70,6 +72,10 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import static org.eclipse.edc.iam.identitytrust.spi.DcpConstants.DCP_CONTEXT_URL; +import static org.eclipse.edc.iam.identitytrust.spi.DcpConstants.DSPACE_DCP_NAMESPACE_V_0_8; +import static org.eclipse.edc.iam.identitytrust.spi.DcpConstants.DSPACE_DCP_NAMESPACE_V_1_0; +import static org.eclipse.edc.iam.identitytrust.spi.DcpConstants.DSPACE_DCP_V_1_0_CONTEXT; import static org.eclipse.edc.iam.verifiablecredentials.spi.VcConstants.STATUSLIST_2021_URL; import static org.eclipse.edc.spi.constants.CoreConstants.JSON_LD; import static org.eclipse.edc.verifiablecredentials.jwt.JwtPresentationVerifier.JWT_VC_TOKEN_CONTEXT; @@ -79,6 +85,7 @@ public class IdentityAndTrustExtension implements ServiceExtension { public static final long DEFAULT_REVOCATION_CACHE_VALIDITY_MILLIS = 15 * 60 * 1000L; public static final String DCP_SELF_ISSUED_TOKEN_CONTEXT = "dcp-si"; + public static final String DCP_CLIENT_CONTEXT = "dcp-client"; public static final String JSON_2020_SIGNATURE_SUITE = "JsonWebSignature2020"; public static final long DEFAULT_CLEANUP_PERIOD_SECONDS = 60; @Setting(description = "Validity period of cached StatusList2021 credential entries in milliseconds.", defaultValue = DEFAULT_REVOCATION_CACHE_VALIDITY_MILLIS + "", key = "edc.iam.credential.revocation.cache.validity") @@ -87,6 +94,10 @@ public class IdentityAndTrustExtension implements ServiceExtension { private String issuerId; @Setting(description = "The period of the JTI entry reaper thread in seconds", defaultValue = DEFAULT_CLEANUP_PERIOD_SECONDS + "", key = "edc.sql.store.jti.cleanup.period") private long reaperCleanupPeriod; + + @Setting(description = "If set enable the dcp v0.8 namespace will be used", key = "edc.dcp.v08.enabled", required = false, defaultValue = "false") + private boolean enableDcpV08; + @Inject private SecureTokenService secureTokenService; @@ -201,8 +212,13 @@ public IdentityService createIdentityService(ServiceExtensionContext context) { @Provider public CredentialServiceClient getCredentialServiceClient(ServiceExtensionContext context) { if (credentialServiceClient == null) { + + var clientTypeTransformerRegistry = typeTransformerRegistry.forContext(DCP_CLIENT_CONTEXT); + clientTypeTransformerRegistry.register(new JsonObjectToPresentationResponseMessageTransformer(typeManager, JSON_LD, dcpNamespace())); + + credentialServiceClient = new DefaultCredentialServiceClient(httpClient, Json.createBuilderFactory(Map.of()), - typeManager, JSON_LD, typeTransformerRegistry, jsonLd, context.getMonitor()); + typeManager, JSON_LD, clientTypeTransformerRegistry, jsonLd, context.getMonitor(), dcpContext()); } return credentialServiceClient; } @@ -225,6 +241,13 @@ public PresentationVerifier createPresentationVerifier(ServiceExtensionContext c return presentationVerifier; } + private JsonLdNamespace dcpNamespace() { + return enableDcpV08 ? DSPACE_DCP_NAMESPACE_V_0_8 : DSPACE_DCP_NAMESPACE_V_1_0; + } + + private String dcpContext() { + return enableDcpV08 ? DCP_CONTEXT_URL : DSPACE_DCP_V_1_0_CONTEXT; + } @NotNull private TokenValidationAction tokenValidationAction() { diff --git a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultCredentialServiceClient.java b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultCredentialServiceClient.java index 317ac045ca..c720b6afa5 100644 --- a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultCredentialServiceClient.java +++ b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultCredentialServiceClient.java @@ -22,7 +22,6 @@ import okhttp3.RequestBody; import org.eclipse.edc.http.spi.EdcHttpClient; import org.eclipse.edc.iam.identitytrust.spi.CredentialServiceClient; -import org.eclipse.edc.iam.identitytrust.spi.DcpConstants; import org.eclipse.edc.iam.identitytrust.spi.model.PresentationQueryMessage; import org.eclipse.edc.iam.identitytrust.spi.model.PresentationResponseMessage; import org.eclipse.edc.iam.verifiablecredentials.spi.VcConstants; @@ -55,8 +54,9 @@ public class DefaultCredentialServiceClient implements CredentialServiceClient { private final TypeTransformerRegistry transformerRegistry; private final JsonLd jsonLd; private final Monitor monitor; + private final String dcpContextUrl; - public DefaultCredentialServiceClient(EdcHttpClient httpClient, JsonBuilderFactory jsonFactory, TypeManager typeManager, String typeContext, TypeTransformerRegistry transformerRegistry, JsonLd jsonLd, Monitor monitor) { + public DefaultCredentialServiceClient(EdcHttpClient httpClient, JsonBuilderFactory jsonFactory, TypeManager typeManager, String typeContext, TypeTransformerRegistry transformerRegistry, JsonLd jsonLd, Monitor monitor, String dcpContextUrl) { this.httpClient = httpClient; this.jsonFactory = jsonFactory; this.typeManager = typeManager; @@ -64,6 +64,7 @@ public DefaultCredentialServiceClient(EdcHttpClient httpClient, JsonBuilderFacto this.transformerRegistry = transformerRegistry; this.jsonLd = jsonLd; this.monitor = monitor; + this.dcpContextUrl = dcpContextUrl; } @Override @@ -154,7 +155,7 @@ private JsonObject createPresentationQuery(List scopes) { return jsonFactory.createObjectBuilder() .add(JsonLdKeywords.CONTEXT, jsonFactory.createArrayBuilder() .add(VcConstants.PRESENTATION_EXCHANGE_URL) - .add(DcpConstants.DCP_CONTEXT_URL)) + .add(dcpContextUrl)) .add(JsonLdKeywords.TYPE, PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_TERM) .add("scope", scopeArray.build()) .build(); diff --git a/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtensionTest.java b/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtensionTest.java index 15601ad048..90d97f8414 100644 --- a/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtensionTest.java +++ b/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtensionTest.java @@ -24,6 +24,7 @@ import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.edc.spi.system.configuration.ConfigFactory; import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.transform.spi.TypeTransformerRegistry; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -33,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; +import static org.eclipse.edc.iam.identitytrust.core.IdentityAndTrustExtension.DCP_CLIENT_CONTEXT; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -44,6 +46,7 @@ class IdentityAndTrustExtensionTest { private static final String CONNECTOR_DID_PROPERTY = "edc.iam.issuer.id"; private static final String CLEANUP_PERIOD = "edc.sql.store.jti.cleanup.period"; private final JtiValidationStore storeMock = mock(); + private final TypeTransformerRegistry transformerRegistry = mock(); @BeforeEach void setUp(ServiceExtensionContext context) { @@ -51,12 +54,14 @@ void setUp(ServiceExtensionContext context) { context.registerService(TypeManager.class, new JacksonTypeManager()); context.registerService(JtiValidationStore.class, storeMock); context.registerService(ExecutorInstrumentation.class, ExecutorInstrumentation.noop()); + context.registerService(TypeTransformerRegistry.class, transformerRegistry); var config = ConfigFactory.fromMap(Map.of( CONNECTOR_DID_PROPERTY, "did:web:test", CLEANUP_PERIOD, "1" )); when(context.getConfig()).thenReturn(config); + when(transformerRegistry.forContext(DCP_CLIENT_CONTEXT)).thenReturn(transformerRegistry); } @Test diff --git a/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultCredentialServiceClientTest.java b/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultCredentialServiceClientTest.java index 704244e223..2934a2235b 100644 --- a/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultCredentialServiceClientTest.java +++ b/extensions/common/iam/identity-trust/identity-trust-core/src/test/java/org/eclipse/edc/iam/identitytrust/core/defaults/DefaultCredentialServiceClientTest.java @@ -55,6 +55,7 @@ import java.util.Objects; import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.iam.identitytrust.spi.DcpConstants.DSPACE_DCP_V_1_0_CONTEXT; import static org.eclipse.edc.junit.testfixtures.TestUtils.getResourceFileContentAsString; import static org.eclipse.edc.spi.result.Result.success; import static org.mockito.ArgumentMatchers.any; @@ -96,7 +97,7 @@ void setup() { var jsonLdMock = mock(JsonLd.class); when(jsonLdMock.expand(any())).thenAnswer(a -> success(a.getArgument(0))); client = new DefaultCredentialServiceClient(httpClientMock, Json.createBuilderFactory(Map.of()), - typeManager, "test", transformerRegistry, jsonLdMock, mock()); + typeManager, "test", transformerRegistry, jsonLdMock, mock(), DSPACE_DCP_V_1_0_CONTEXT); when(typeManager.getMapper("test")).thenReturn(JacksonJsonLd.createObjectMapper()); } From b873a71daddc2793577c918fd95e0543f38707fb Mon Sep 17 00:00:00 2001 From: Enrico Risa Date: Mon, 3 Feb 2025 14:38:24 +0100 Subject: [PATCH 2/2] pr suggestions --- .../edc/iam/identitytrust/core/IdentityAndTrustExtension.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java index 9dc47cfaaa..ae44acd610 100644 --- a/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java +++ b/extensions/common/iam/identity-trust/identity-trust-core/src/main/java/org/eclipse/edc/iam/identitytrust/core/IdentityAndTrustExtension.java @@ -95,7 +95,7 @@ public class IdentityAndTrustExtension implements ServiceExtension { @Setting(description = "The period of the JTI entry reaper thread in seconds", defaultValue = DEFAULT_CLEANUP_PERIOD_SECONDS + "", key = "edc.sql.store.jti.cleanup.period") private long reaperCleanupPeriod; - @Setting(description = "If set enable the dcp v0.8 namespace will be used", key = "edc.dcp.v08.enabled", required = false, defaultValue = "false") + @Setting(description = "If set enable the dcp v0.8 namespace will be used", key = "edc.dcp.v08.forced", required = false, defaultValue = "false") private boolean enableDcpV08; @Inject