From 87e0583b3c490b6e4dd5f7e2417ba0b0a126b2ea Mon Sep 17 00:00:00 2001 From: Enrico Risa Date: Tue, 18 Feb 2025 11:47:29 +0100 Subject: [PATCH] feat: Add support for participant context in IssuanceProcess --- .../CredentialDefinitionServiceImpl.java | 3 + .../IssuanceProcessServiceImplTest.java | 1 + .../build.gradle.kts | 3 + .../tests/dcp/DcpIssuanceApiEndToEndTest.java | 30 +++++--- .../IssuerServiceEndToEndExtension.java | 4 +- .../IssuerServiceEndToEndTestContext.java | 38 ++++++++++ .../IssuerServiceRuntimeConfiguration.java | 8 +-- .../eclipse/edc/test/bom/BomSmokeTests.java | 2 - .../BaseSqlDialectStatements.java | 1 + .../IssuanceProcessStoreStatements.java | 3 + .../SqlIssuanceProcessStore.java | 2 + .../postgres/IssuanceProcessMapping.java | 2 + .../resources/issuance-process-schema.sql | 1 + .../BaseSqlDialectStatements.java | 4 +- .../CredentialDefinitionStoreStatements.java | 2 +- .../SqlCredentialDefinitionStore.java | 2 +- ...SqlCredentialDefinitionStoreExtension.java | 6 +- .../postgres/CredentialDefinitionMapping.java | 8 +-- .../postgres/PostgresDialectStatements.java | 4 +- ...rg.eclipse.edc.spi.system.ServiceExtension | 2 +- .../SqlCredentialDefinitionStoreTest.java | 4 +- .../dcp/issuer/IssuerApiExtension.java | 6 +- .../CredentialRequestApi.java | 2 +- .../CredentialRequestApiController.java | 20 ++++-- .../main/resources/issuer-api-version.json | 2 +- .../CredentialRequestApiControllerTest.java | 69 ++++++++++++++----- .../issuer/DcpHolderTokenVerifierImpl.java | 32 ++++++--- .../dcp/issuer/DcpIssuerCoreExtension.java | 19 +---- .../dcp/issuer/DcpIssuerServiceImpl.java | 7 +- .../DcpHolderTokenVerifierImplTest.java | 30 +++++--- .../dcp/issuer/DcpIssuerServiceImplTest.java | 3 +- .../dcp/issuer/spi/DcpIssuerService.java | 2 +- .../dcp/spi/DcpHolderTokenVerifier.java | 3 +- .../spi/issuance/model/IssuanceProcess.java | 14 +++- .../store/IssuanceProcessStoreTestBase.java | 20 ++++++ 35 files changed, 256 insertions(+), 103 deletions(-) rename extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/{attestationdefinition => credentialdefinition}/BaseSqlDialectStatements.java (94%) rename extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/{attestationdefinition => credentialdefinition}/CredentialDefinitionStoreStatements.java (96%) rename extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/{attestationdefinition => credentialdefinition}/SqlCredentialDefinitionStore.java (99%) rename extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/{attestationdefinition => credentialdefinition}/SqlCredentialDefinitionStoreExtension.java (89%) rename extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/{attestationdefinition => credentialdefinition}/schema/postgres/CredentialDefinitionMapping.java (83%) rename extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/{attestationdefinition => credentialdefinition}/schema/postgres/PostgresDialectStatements.java (91%) rename extensions/store/sql/issuerservice-credential-definition-store-sql/src/test/java/org/eclipse/edc/issuerservice/store/sql/{attestationdefinition => credentialdefinition}/SqlCredentialDefinitionStoreTest.java (96%) diff --git a/core/issuerservice/issuerservice-issuance/src/main/java/org/eclipse/edc/issuerservice/issuance/credentialdefinition/CredentialDefinitionServiceImpl.java b/core/issuerservice/issuerservice-issuance/src/main/java/org/eclipse/edc/issuerservice/issuance/credentialdefinition/CredentialDefinitionServiceImpl.java index eef967ed6..9b3912d61 100644 --- a/core/issuerservice/issuerservice-issuance/src/main/java/org/eclipse/edc/issuerservice/issuance/credentialdefinition/CredentialDefinitionServiceImpl.java +++ b/core/issuerservice/issuerservice-issuance/src/main/java/org/eclipse/edc/issuerservice/issuance/credentialdefinition/CredentialDefinitionServiceImpl.java @@ -88,6 +88,9 @@ private ServiceResult internalUpdate(CredentialDefinition credentialDefini } private ServiceResult validateAttestations(CredentialDefinition credentialDefinition) { + if (credentialDefinition.getAttestations().isEmpty()) { + return ServiceResult.success(); + } var query = QuerySpec.Builder.newInstance() .filter(Criterion.criterion("id", "in", credentialDefinition.getAttestations())) .build(); diff --git a/core/issuerservice/issuerservice-issuance/src/test/java/org/eclipse/edc/issuerservice/issuance/process/IssuanceProcessServiceImplTest.java b/core/issuerservice/issuerservice-issuance/src/test/java/org/eclipse/edc/issuerservice/issuance/process/IssuanceProcessServiceImplTest.java index 633c84b8b..48c1bb29a 100644 --- a/core/issuerservice/issuerservice-issuance/src/test/java/org/eclipse/edc/issuerservice/issuance/process/IssuanceProcessServiceImplTest.java +++ b/core/issuerservice/issuerservice-issuance/src/test/java/org/eclipse/edc/issuerservice/issuance/process/IssuanceProcessServiceImplTest.java @@ -75,6 +75,7 @@ private IssuanceProcess createIssuanceProcess() { .id("id") .state(IssuanceProcessStates.APPROVED.code()) .participantId("participantId") + .issuerContextId("issuerContextId") .build(); } } diff --git a/dist/bom/issuerservice-feature-sql-bom/build.gradle.kts b/dist/bom/issuerservice-feature-sql-bom/build.gradle.kts index 7b710d935..7bf6a9f20 100644 --- a/dist/bom/issuerservice-feature-sql-bom/build.gradle.kts +++ b/dist/bom/issuerservice-feature-sql-bom/build.gradle.kts @@ -20,6 +20,9 @@ plugins { dependencies { // sql modules api(project(":extensions:store:sql:issuerservice-participant-store-sql")) + api(project(":extensions:store:sql:issuerservice-attestation-definition-store-sql")) + api(project(":extensions:store:sql:issuerservice-credential-definition-store-sql")) + api(project(":extensions:store:sql:issuance-process-store-sql")) api(libs.edc.sql.core) api(libs.edc.transaction.local) diff --git a/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/dcp/DcpIssuanceApiEndToEndTest.java b/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/dcp/DcpIssuanceApiEndToEndTest.java index 5b018c28e..202b4b88f 100644 --- a/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/dcp/DcpIssuanceApiEndToEndTest.java +++ b/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/dcp/DcpIssuanceApiEndToEndTest.java @@ -38,6 +38,7 @@ import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.validator.spi.ValidationResult; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; @@ -45,6 +46,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import java.util.Base64; import java.util.Map; import static io.restassured.http.ContentType.JSON; @@ -69,6 +71,10 @@ abstract static class Tests { public static final String DID_WEB_PARTICIPANT_KEY_1 = "did:web:participant#key1"; public static final ECKey PARTICIPANT_KEY = generateEcKey(DID_WEB_PARTICIPANT_KEY_1); protected static final AttestationSourceFactory ATTESTATION_SOURCE_FACTORY = mock(); + + protected static final String ISSUER_ID = "issuer"; + private static final String ISSUER_ID_ENCODED = Base64.getUrlEncoder().encodeToString(ISSUER_ID.getBytes()); + private static final String VALID_CREDENTIAL_REQUEST_MESSAGE = """ { "@context": [ @@ -98,6 +104,11 @@ static void beforeAll(IssuerServiceEndToEndTestContext context) { var validationRegistry = context.getRuntime().getService(AttestationDefinitionValidatorRegistry.class); pipelineFactory.registerFactory("Attestation", ATTESTATION_SOURCE_FACTORY); validationRegistry.registerValidator("Attestation", def -> ValidationResult.success()); + context.createParticipant(ISSUER_ID); + } + + private static @NotNull String issuanceUrl() { + return "/v1alpha/participants/%s/credentials".formatted(ISSUER_ID_ENCODED); } @AfterEach @@ -150,14 +161,14 @@ void requestCredential(IssuerServiceEndToEndTestContext context, ParticipantServ .contentType(JSON) .header(AUTHORIZATION, token) .body(VALID_CREDENTIAL_REQUEST_MESSAGE) - .post("/v1alpha/credentials") + .post(issuanceUrl()) .then() .log().ifValidationFails() .statusCode(201) .extract() .header("Location"); - assertThat(location).contains("/v1alpha/requests/"); + assertThat(location).contains("/v1alpha/participants/%s/requests".formatted(ISSUER_ID_ENCODED)); var processId = location.substring(location.lastIndexOf('/') + 1); var issuanceProcess = issuanceProcessStore.findById(processId); @@ -167,6 +178,7 @@ void requestCredential(IssuerServiceEndToEndTestContext context, ParticipantServ assertThat(process.getParticipantId()).isEqualTo(PARTICIPANT_DID); assertThat(process.getCredentialDefinitions()).containsExactly("credential-id"); assertThat(process.getClaims()).containsAllEntriesOf(claims); + assertThat(process.getIssuerContextId()).isEqualTo(ISSUER_ID); }); } @@ -179,7 +191,7 @@ void requestCredential_validationError_shouldReturn400(IssuerServiceEndToEndTest .contentType(JSON) .header(AUTHORIZATION, token) .body(FAULTY_CREDENTIAL_REQUEST_MESSAGE) - .post("/v1alpha/credentials") + .post(issuanceUrl()) .then() .log().ifValidationFails() .statusCode(400); @@ -191,7 +203,7 @@ void requestCredential_tokenNotPresent_shouldReturn401(IssuerServiceEndToEndTest context.getDcpIssuanceEndpoint().baseRequest() .contentType(JSON) .body(VALID_CREDENTIAL_REQUEST_MESSAGE) - .post("/v1alpha/credentials") + .post(issuanceUrl()) .then() .log().ifValidationFails() .statusCode(401); @@ -206,7 +218,7 @@ void requestCredential_participantNotFound_shouldReturn401(IssuerServiceEndToEnd .contentType(JSON) .header(AUTHORIZATION, token) .body(VALID_CREDENTIAL_REQUEST_MESSAGE) - .post("/v1alpha/credentials") + .post(issuanceUrl()) .then() .log().ifValidationFails() .statusCode(401); @@ -228,7 +240,7 @@ void requestCredential_tokenVerificationFails_shouldReturn401(IssuerServiceEndTo .contentType(JSON) .header(AUTHORIZATION, token) .body(VALID_CREDENTIAL_REQUEST_MESSAGE) - .post("/v1alpha/credentials") + .post(issuanceUrl()) .then() .log().ifValidationFails() .statusCode(401); @@ -248,7 +260,7 @@ void requestCredential_wrongTokenAudience_shouldReturn401(IssuerServiceEndToEndT .contentType(JSON) .header(AUTHORIZATION, token) .body(VALID_CREDENTIAL_REQUEST_MESSAGE) - .post("/v1alpha/credentials") + .post(issuanceUrl()) .then() .log().ifValidationFails() .statusCode(401); @@ -268,7 +280,7 @@ void requestCredential_definitionNotFound_shouldReturn400(IssuerServiceEndToEndT .contentType(JSON) .header(AUTHORIZATION, token) .body(VALID_CREDENTIAL_REQUEST_MESSAGE) - .post("/v1alpha/credentials") + .post(issuanceUrl()) .then() .log().ifValidationFails() .statusCode(400); @@ -314,7 +326,7 @@ void requestCredential_attestationsNotFulfilled_shouldReturn403(IssuerServiceEnd .contentType(JSON) .header(AUTHORIZATION, token) .body(VALID_CREDENTIAL_REQUEST_MESSAGE) - .post("/v1alpha/credentials") + .post(issuanceUrl()) .then() .log().ifValidationFails() .statusCode(403); diff --git a/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceEndToEndExtension.java b/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceEndToEndExtension.java index fb433d8b9..02643e4ae 100644 --- a/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceEndToEndExtension.java +++ b/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceEndToEndExtension.java @@ -76,7 +76,7 @@ public static IssuerServiceEndToEndTestContext context() { var runtime = new EmbeddedRuntime( "issuerservice", configuration.config(), - ":dist:bom:issuerservice-bom" + ":dist:bom:issuerservice-with-sts-bom" ); return new IssuerServiceEndToEndTestContext(runtime, configuration); @@ -112,7 +112,7 @@ public static IssuerServiceEndToEndTestContext context(String dbName, Integer po var runtime = new EmbeddedRuntime( "issuerservice-pg", cfg, - ":dist:bom:issuerservice-bom", + ":dist:bom:issuerservice-with-sts-bom", ":dist:bom:issuerservice-feature-sql-bom" ); diff --git a/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceEndToEndTestContext.java b/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceEndToEndTestContext.java index abac072bf..5b680736c 100644 --- a/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceEndToEndTestContext.java +++ b/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceEndToEndTestContext.java @@ -14,7 +14,15 @@ package org.eclipse.edc.identityhub.tests.fixtures; +import org.eclipse.edc.iam.did.spi.document.Service; +import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; +import org.eclipse.edc.identityhub.spi.participantcontext.model.KeyDescriptor; +import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantManifest; import org.eclipse.edc.junit.extensions.EmbeddedRuntime; +import org.eclipse.edc.spi.EdcException; + +import java.util.List; +import java.util.Map; /** * IssuerService end to end context used in tests extended with {@link IssuerServiceEndToEndExtension} @@ -42,4 +50,34 @@ public IssuerServiceRuntimeConfiguration.Endpoint getAdminEndpoint() { public IssuerServiceRuntimeConfiguration.Endpoint getDcpIssuanceEndpoint() { return configuration.getIssuerApiEndpoint(); } + + public String createParticipant(String participantContextId) { + return createParticipant(participantContextId, List.of()); + } + + public String createParticipant(String participantContextId, List roles, boolean isActive) { + var manifest = ParticipantManifest.Builder.newInstance() + .participantId(participantContextId) + .active(isActive) + .roles(roles) + .serviceEndpoint(new Service("test-service-id", "test-type", "http://foo.bar.com")) + .did("did:web:" + participantContextId) + .key(KeyDescriptor.Builder.newInstance() + .privateKeyAlias(participantContextId + "-alias") + .resourceId(participantContextId + "-resource") + .keyId(participantContextId + "-key") + .keyGeneratorParams(Map.of("algorithm", "EC", "curve", "secp256r1")) + .build()) + .build(); + var srv = runtime.getService(ParticipantContextService.class); + return srv.createParticipantContext(manifest) + .orElseThrow(f -> new EdcException(f.getFailureDetail())) + .apiKey(); + } + + + public String createParticipant(String participantContextId, List roles) { + return createParticipant(participantContextId, roles, true); + } + } diff --git a/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceRuntimeConfiguration.java b/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceRuntimeConfiguration.java index 98beaa1f9..45d5d9d63 100644 --- a/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceRuntimeConfiguration.java +++ b/e2e-tests/admin-api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IssuerServiceRuntimeConfiguration.java @@ -57,16 +57,14 @@ public Map config() { put("web.http.version.path", "/.well-known/api"); put("web.http.did.port", String.valueOf(getFreePort())); put("web.http.did.path", "/"); - put("edc.ih.iam.id", "did:web:issuer"); put("edc.sql.schema.autocreate", "true"); put("edc.sts.account.api.url", "http://sts.com/accounts"); put("edc.sts.accounts.api.auth.header.value", "password"); put("edc.iam.accesstoken.jti.validation", String.valueOf(false)); put("edc.issuer.statuslist.signing.key.alias", "signing-key"); - // config for the remote STS - put("edc.iam.sts.oauth.token.url", "https://sts.com/oauth/token"); - put("edc.iam.sts.oauth.client.secret.alias", "secret"); - put("edc.iam.sts.oauth.client.id", "clientId"); + // config for the embedded STS + put("edc.iam.sts.publickey.id", "test-public-key"); + put("edc.iam.sts.privatekey.alias", "issuer-alias"); } }; } diff --git a/e2e-tests/bom-tests/src/test/java/org/eclipse/edc/test/bom/BomSmokeTests.java b/e2e-tests/bom-tests/src/test/java/org/eclipse/edc/test/bom/BomSmokeTests.java index f10077dab..2a2942388 100644 --- a/e2e-tests/bom-tests/src/test/java/org/eclipse/edc/test/bom/BomSmokeTests.java +++ b/e2e-tests/bom-tests/src/test/java/org/eclipse/edc/test/bom/BomSmokeTests.java @@ -141,7 +141,6 @@ class IssuerService extends SmokeTest { put("edc.sts.account.api.url", "https://sts.com/accounts"); put("edc.sts.accounts.api.auth.header.value", "password"); put("edc.issuer.statuslist.signing.key.alias", "signing-key"); - put("edc.ih.iam.id", "did:web:issuer"); // config for the remote STS put("edc.iam.sts.oauth.token.url", "https://sts.com/oauth/token"); put("edc.iam.sts.oauth.client.secret.alias", "secret"); @@ -170,7 +169,6 @@ class IssuerServiceWithSts extends SmokeTest { put("edc.sts.account.api.url", "https://sts.com/accounts"); put("edc.sts.accounts.api.auth.header.value", "password"); put("edc.issuer.statuslist.signing.key.alias", "signing-key"); - put("edc.ih.iam.id", "did:web:issuer"); // interaction with embedded STS put("edc.iam.sts.publickey.id", "test-public-key"); put("edc.iam.sts.privatekey.alias", "test-private-key"); diff --git a/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/BaseSqlDialectStatements.java b/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/BaseSqlDialectStatements.java index 30c06e3c2..7ad897baa 100644 --- a/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/BaseSqlDialectStatements.java +++ b/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/BaseSqlDialectStatements.java @@ -42,6 +42,7 @@ public String getInsertTemplate() { .jsonColumn(getTraceContextColumn()) .column(getErrorDetailColumn()) .column(getParticipantIdColumn()) + .column(getIssuerContextIdColumn()) .jsonColumn(getClaimsColumn()) .jsonColumn(getCredentialDefinitionsColumn()) .insertInto(getIssuanceProcessTable()); diff --git a/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/IssuanceProcessStoreStatements.java b/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/IssuanceProcessStoreStatements.java index 7859a5b08..caeb9e49d 100644 --- a/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/IssuanceProcessStoreStatements.java +++ b/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/IssuanceProcessStoreStatements.java @@ -47,6 +47,9 @@ default String getParticipantIdColumn() { return "participant_id"; } + default String getIssuerContextIdColumn() { + return "issuer_context_id"; + } String getInsertTemplate(); diff --git a/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/SqlIssuanceProcessStore.java b/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/SqlIssuanceProcessStore.java index 3b8c5fb2b..56e9b52c5 100644 --- a/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/SqlIssuanceProcessStore.java +++ b/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/SqlIssuanceProcessStore.java @@ -159,6 +159,7 @@ private void insert(Connection conn, IssuanceProcess process) { toJson(process.getTraceContext()), process.getErrorDetail(), process.getParticipantId(), + process.getIssuerContextId(), toJson(process.getClaims()), toJson(process.getCredentialDefinitions()) ); @@ -198,6 +199,7 @@ private IssuanceProcess mapResultSet(ResultSet resultSet) throws Exception { .traceContext(fromJson(resultSet.getString(statements.getTraceContextColumn()), getTypeRef())) .errorDetail(resultSet.getString(statements.getErrorDetailColumn())) .participantId(resultSet.getString(statements.getParticipantIdColumn())) + .issuerContextId(resultSet.getString(statements.getIssuerContextIdColumn())) .claims(fromJson(resultSet.getString(statements.getClaimsColumn()), getTypeRef())) .credentialDefinitions(fromJson(resultSet.getString(statements.getCredentialDefinitionsColumn()), ATTESTATIONS_LIST_REF)) .build(); diff --git a/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/schema/postgres/IssuanceProcessMapping.java b/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/schema/postgres/IssuanceProcessMapping.java index 34fd87084..8f40436fd 100644 --- a/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/schema/postgres/IssuanceProcessMapping.java +++ b/extensions/store/sql/issuance-process-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/issuanceprocess/schema/postgres/IssuanceProcessMapping.java @@ -27,6 +27,7 @@ public class IssuanceProcessMapping extends StatefulEntityMapping { public static final String FIELD_ID = "id"; public static final String FIELD_PARTICIPANT_ID = "participantId"; + public static final String FIELD_ISSUER_CONTEXT_ID = "issuerContextId"; public static final String FIELD_CLAIMS = "claims"; public static final String FIELD_CREDENTIAL_DEFINITIONS = "credentialDefinitions"; @@ -34,6 +35,7 @@ public IssuanceProcessMapping(IssuanceProcessStoreStatements statements) { super(statements); add(FIELD_ID, statements.getIdColumn()); add(FIELD_PARTICIPANT_ID, statements.getParticipantIdColumn()); + add(FIELD_ISSUER_CONTEXT_ID, statements.getIssuerContextIdColumn()); add(FIELD_CLAIMS, new JsonFieldTranslator(FIELD_CLAIMS)); add(FIELD_CREDENTIAL_DEFINITIONS, new JsonArrayTranslator(statements.getCredentialDefinitionsColumn())); } diff --git a/extensions/store/sql/issuance-process-store-sql/src/main/resources/issuance-process-schema.sql b/extensions/store/sql/issuance-process-store-sql/src/main/resources/issuance-process-schema.sql index fd00a3510..bfa2615a2 100644 --- a/extensions/store/sql/issuance-process-store-sql/src/main/resources/issuance-process-schema.sql +++ b/extensions/store/sql/issuance-process-store-sql/src/main/resources/issuance-process-schema.sql @@ -39,6 +39,7 @@ CREATE TABLE IF NOT EXISTS edc_issuance_process pending BOOLEAN DEFAULT FALSE, lease_id VARCHAR CONSTRAINT issuance_process_lease_lease_id_fk REFERENCES edc_lease ON DELETE SET NULL, participant_id VARCHAR NOT NULL, + issuer_context_id VARCHAR NOT NULL, claims JSON NOT NULL, credential_definitions JSONB NOT NULL ); diff --git a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/BaseSqlDialectStatements.java b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/BaseSqlDialectStatements.java similarity index 94% rename from extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/BaseSqlDialectStatements.java rename to extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/BaseSqlDialectStatements.java index c9808ba85..9241ac5f9 100644 --- a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/BaseSqlDialectStatements.java +++ b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/BaseSqlDialectStatements.java @@ -12,9 +12,9 @@ * */ -package org.eclipse.edc.issuerservice.store.sql.attestationdefinition; +package org.eclipse.edc.issuerservice.store.sql.credentialdefinition; -import org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres.CredentialDefinitionMapping; +import org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres.CredentialDefinitionMapping; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.sql.translation.PostgresqlOperatorTranslator; import org.eclipse.edc.sql.translation.SqlQueryStatement; diff --git a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/CredentialDefinitionStoreStatements.java b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/CredentialDefinitionStoreStatements.java similarity index 96% rename from extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/CredentialDefinitionStoreStatements.java rename to extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/CredentialDefinitionStoreStatements.java index dbc5328dd..74ae4110e 100644 --- a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/CredentialDefinitionStoreStatements.java +++ b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/CredentialDefinitionStoreStatements.java @@ -12,7 +12,7 @@ * */ -package org.eclipse.edc.issuerservice.store.sql.attestationdefinition; +package org.eclipse.edc.issuerservice.store.sql.credentialdefinition; import org.eclipse.edc.issuerservice.spi.issuance.model.CredentialDefinition; import org.eclipse.edc.spi.query.QuerySpec; diff --git a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/SqlCredentialDefinitionStore.java b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/SqlCredentialDefinitionStore.java similarity index 99% rename from extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/SqlCredentialDefinitionStore.java rename to extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/SqlCredentialDefinitionStore.java index bc783feaa..c3797abaa 100644 --- a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/SqlCredentialDefinitionStore.java +++ b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/SqlCredentialDefinitionStore.java @@ -12,7 +12,7 @@ * */ -package org.eclipse.edc.issuerservice.store.sql.attestationdefinition; +package org.eclipse.edc.issuerservice.store.sql.credentialdefinition; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/SqlCredentialDefinitionStoreExtension.java b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/SqlCredentialDefinitionStoreExtension.java similarity index 89% rename from extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/SqlCredentialDefinitionStoreExtension.java rename to extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/SqlCredentialDefinitionStoreExtension.java index 2c05d39e5..f4143b564 100644 --- a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/SqlCredentialDefinitionStoreExtension.java +++ b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/SqlCredentialDefinitionStoreExtension.java @@ -12,10 +12,10 @@ * */ -package org.eclipse.edc.issuerservice.store.sql.attestationdefinition; +package org.eclipse.edc.issuerservice.store.sql.credentialdefinition; import org.eclipse.edc.issuerservice.spi.issuance.credentialdefinition.store.CredentialDefinitionStore; -import org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres.PostgresDialectStatements; +import org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres.PostgresDialectStatements; import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Provider; @@ -30,7 +30,7 @@ import java.time.Clock; -import static org.eclipse.edc.issuerservice.store.sql.attestationdefinition.SqlCredentialDefinitionStoreExtension.NAME; +import static org.eclipse.edc.issuerservice.store.sql.credentialdefinition.SqlCredentialDefinitionStoreExtension.NAME; @Extension(value = NAME) public class SqlCredentialDefinitionStoreExtension implements ServiceExtension { diff --git a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/schema/postgres/CredentialDefinitionMapping.java b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/schema/postgres/CredentialDefinitionMapping.java similarity index 83% rename from extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/schema/postgres/CredentialDefinitionMapping.java rename to extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/schema/postgres/CredentialDefinitionMapping.java index b42bcb5d5..2c1709e37 100644 --- a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/schema/postgres/CredentialDefinitionMapping.java +++ b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/schema/postgres/CredentialDefinitionMapping.java @@ -12,15 +12,15 @@ * */ -package org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres; +package org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres; -import org.eclipse.edc.issuerservice.store.sql.attestationdefinition.CredentialDefinitionStoreStatements; +import org.eclipse.edc.issuerservice.store.sql.credentialdefinition.CredentialDefinitionStoreStatements; import org.eclipse.edc.sql.translation.JsonArrayTranslator; import org.eclipse.edc.sql.translation.JsonFieldTranslator; import org.eclipse.edc.sql.translation.TranslationMapping; -import static org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres.PostgresDialectStatements.MAPPING_ALIAS; -import static org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres.PostgresDialectStatements.RULES_ALIAS; +import static org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres.PostgresDialectStatements.MAPPING_ALIAS; +import static org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres.PostgresDialectStatements.RULES_ALIAS; /** diff --git a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/schema/postgres/PostgresDialectStatements.java b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/schema/postgres/PostgresDialectStatements.java similarity index 91% rename from extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/schema/postgres/PostgresDialectStatements.java rename to extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/schema/postgres/PostgresDialectStatements.java index 5747c2db8..a965f608e 100644 --- a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/schema/postgres/PostgresDialectStatements.java +++ b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/schema/postgres/PostgresDialectStatements.java @@ -12,9 +12,9 @@ * */ -package org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres; +package org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres; -import org.eclipse.edc.issuerservice.store.sql.attestationdefinition.BaseSqlDialectStatements; +import org.eclipse.edc.issuerservice.store.sql.credentialdefinition.BaseSqlDialectStatements; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.sql.dialect.PostgresDialect; import org.eclipse.edc.sql.translation.PostgresqlOperatorTranslator; diff --git a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension index 19208e013..bfa649b4e 100644 --- a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension +++ b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -12,4 +12,4 @@ # # -org.eclipse.edc.issuerservice.store.sql.attestationdefinition.SqlCredentialDefinitionStoreExtension \ No newline at end of file +org.eclipse.edc.issuerservice.store.sql.credentialdefinition.SqlCredentialDefinitionStoreExtension \ No newline at end of file diff --git a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/test/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/SqlCredentialDefinitionStoreTest.java b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/test/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/SqlCredentialDefinitionStoreTest.java similarity index 96% rename from extensions/store/sql/issuerservice-credential-definition-store-sql/src/test/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/SqlCredentialDefinitionStoreTest.java rename to extensions/store/sql/issuerservice-credential-definition-store-sql/src/test/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/SqlCredentialDefinitionStoreTest.java index f894bbee8..3862f6d73 100644 --- a/extensions/store/sql/issuerservice-credential-definition-store-sql/src/test/java/org/eclipse/edc/issuerservice/store/sql/attestationdefinition/SqlCredentialDefinitionStoreTest.java +++ b/extensions/store/sql/issuerservice-credential-definition-store-sql/src/test/java/org/eclipse/edc/issuerservice/store/sql/credentialdefinition/SqlCredentialDefinitionStoreTest.java @@ -12,13 +12,13 @@ * */ -package org.eclipse.edc.issuerservice.store.sql.attestationdefinition; +package org.eclipse.edc.issuerservice.store.sql.credentialdefinition; import org.assertj.core.api.Assertions; import org.eclipse.edc.issuerservice.spi.issuance.credentialdefinition.store.CredentialDefinitionStore; import org.eclipse.edc.issuerservice.spi.issuance.credentialdefinition.store.CredentialDefinitionStoreTestBase; import org.eclipse.edc.issuerservice.spi.issuance.model.CredentialRuleDefinition; -import org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres.PostgresDialectStatements; +import org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres.PostgresDialectStatements; import org.eclipse.edc.json.JacksonTypeManager; import org.eclipse.edc.junit.annotations.PostgresqlIntegrationTest; import org.eclipse.edc.junit.testfixtures.TestUtils; diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/IssuerApiExtension.java b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/IssuerApiExtension.java index 0f5899177..15e4daa92 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/IssuerApiExtension.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/IssuerApiExtension.java @@ -25,6 +25,7 @@ import org.eclipse.edc.identityhub.protocols.dcp.transform.from.JsonObjectFromCredentialRequestStatusTransformer; import org.eclipse.edc.identityhub.protocols.dcp.transform.from.JsonObjectFromIssuerMetadataTransformer; import org.eclipse.edc.identityhub.protocols.dcp.transform.to.JsonObjectToCredentialRequestMessageTransformer; +import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.jsonld.spi.JsonLdNamespace; import org.eclipse.edc.runtime.metamodel.annotation.Configuration; @@ -90,6 +91,9 @@ public class IssuerApiExtension implements ServiceExtension { @Inject private JsonObjectValidatorRegistry validatorRegistry; + @Inject + private ParticipantContextService participantContextService; + @Override public void initialize(ServiceExtensionContext context) { @@ -99,7 +103,7 @@ public void initialize(ServiceExtensionContext context) { registerTransformers(dcpRegistry, DSPACE_DCP_NAMESPACE_V_1_0); registerValidators(DSPACE_DCP_NAMESPACE_V_1_0); - webService.registerResource(ISSUANCE_API, new CredentialRequestApiController(dcpIssuerService, dcpHolderTokenVerifier, validatorRegistry, dcpRegistry, DSPACE_DCP_NAMESPACE_V_1_0)); + webService.registerResource(ISSUANCE_API, new CredentialRequestApiController(participantContextService, dcpIssuerService, dcpHolderTokenVerifier, validatorRegistry, dcpRegistry, DSPACE_DCP_NAMESPACE_V_1_0)); webService.registerResource(ISSUANCE_API, new CredentialRequestStatusApiController(dcpRegistry)); webService.registerResource(ISSUANCE_API, new IssuerMetadataApiController(dcpRegistry)); diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApi.java b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApi.java index c03bf0f4f..213bdf4bb 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApi.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApi.java @@ -56,5 +56,5 @@ public interface CredentialRequestApi { } ) - Response requestCredential(JsonObject message, String token); + Response requestCredential(String participantContextId, JsonObject message, String token); } diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiController.java b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiController.java index ea306f14d..642ebee13 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiController.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiController.java @@ -19,11 +19,13 @@ import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Response; import org.eclipse.edc.identityhub.protocols.dcp.issuer.spi.DcpIssuerService; import org.eclipse.edc.identityhub.protocols.dcp.spi.DcpHolderTokenVerifier; import org.eclipse.edc.identityhub.protocols.dcp.spi.model.CredentialRequestMessage; +import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; import org.eclipse.edc.jsonld.spi.JsonLdNamespace; import org.eclipse.edc.spi.iam.TokenRepresentation; import org.eclipse.edc.transform.spi.TypeTransformerRegistry; @@ -37,24 +39,27 @@ import static jakarta.ws.rs.core.HttpHeaders.AUTHORIZATION; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.eclipse.edc.identityhub.protocols.dcp.spi.model.CredentialRequestMessage.CREDENTIAL_REQUEST_MESSAGE_TERM; +import static org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextId.onEncoded; import static org.eclipse.edc.web.spi.exception.ServiceResultHandler.exceptionMapper; @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) -@Path("/v1alpha/credentials") +@Path("/v1alpha/participants/{participantContextId}/credentials") public class CredentialRequestApiController implements CredentialRequestApi { + private final ParticipantContextService participantContextService; private final DcpIssuerService dcpIssuerService; private final DcpHolderTokenVerifier tokenValidator; private final JsonObjectValidatorRegistry validatorRegistry; private final TypeTransformerRegistry dcpTransformerRegistry; private final JsonLdNamespace namespace; - public CredentialRequestApiController(DcpIssuerService dcpIssuerService, + public CredentialRequestApiController(ParticipantContextService participantContextService, DcpIssuerService dcpIssuerService, DcpHolderTokenVerifier tokenValidator, JsonObjectValidatorRegistry validatorRegistry, TypeTransformerRegistry dcpTransformerRegistry, JsonLdNamespace namespace) { + this.participantContextService = participantContextService; this.dcpIssuerService = dcpIssuerService; this.tokenValidator = tokenValidator; this.validatorRegistry = validatorRegistry; @@ -66,23 +71,26 @@ public CredentialRequestApiController(DcpIssuerService dcpIssuerService, @POST @Path("/") @Override - public Response requestCredential(JsonObject message, @HeaderParam(AUTHORIZATION) String token) { + public Response requestCredential(@PathParam("participantContextId") String participantContextId, JsonObject message, @HeaderParam(AUTHORIZATION) String token) { if (token == null) { throw new AuthenticationFailedException("Authorization header missing"); } token = token.replace("Bearer", "").trim(); + var decodedParticipantContextId = onEncoded(participantContextId).orElseThrow(InvalidRequestException::new); validatorRegistry.validate(namespace.toIri(CREDENTIAL_REQUEST_MESSAGE_TERM), message).orElseThrow(ValidationFailureException::new); var credentialMessage = dcpTransformerRegistry.transform(message, CredentialRequestMessage.class).orElseThrow(InvalidRequestException::new); var tokenRepresentation = TokenRepresentation.Builder.newInstance().token(token).build(); + var participantContext = participantContextService.getParticipantContext(decodedParticipantContextId) + .orElseThrow((f) -> new AuthenticationFailedException("Invalid issuer")); - var participant = tokenValidator.verify(tokenRepresentation) + var participant = tokenValidator.verify(participantContext, tokenRepresentation) .orElseThrow((f) -> new AuthenticationFailedException("ID token verification failed: %s".formatted(f.getFailureDetail()))); - return dcpIssuerService.initiateCredentialsIssuance(credentialMessage, participant) - .map(response -> Response.created(URI.create("/v1alpha/requests/" + response.requestId())).build()) + return dcpIssuerService.initiateCredentialsIssuance(participantContext.getParticipantContextId(), credentialMessage, participant) + .map(response -> Response.created(URI.create("/v1alpha/participants/%s/requests/%s".formatted(participantContextId, response.requestId()))).build()) .orElseThrow(exceptionMapper(CredentialRequestMessage.class, null)); } diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/resources/issuer-api-version.json b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/resources/issuer-api-version.json index 761c8d2a6..1d31083e1 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/resources/issuer-api-version.json +++ b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/main/resources/issuer-api-version.json @@ -2,7 +2,7 @@ { "version": "1.0.0", "urlPath": "/v1alpha", - "lastUpdated": "2025-02-11T08:00:00Z", + "lastUpdated": "2025-02-18T08:00:00Z", "maturity": null } ] \ No newline at end of file diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiControllerTest.java b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiControllerTest.java index d3ab7b0cb..83da891bf 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-api/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiControllerTest.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-api/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiControllerTest.java @@ -21,6 +21,8 @@ import org.eclipse.edc.identityhub.protocols.dcp.spi.model.CredentialRequest; import org.eclipse.edc.identityhub.protocols.dcp.spi.model.CredentialRequestMessage; import org.eclipse.edc.identityhub.protocols.dcp.spi.model.DcpRequestContext; +import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; +import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.issuerservice.spi.participant.model.Participant; import org.eclipse.edc.jsonld.spi.JsonLdNamespace; import org.eclipse.edc.junit.annotations.ApiTest; @@ -37,6 +39,7 @@ import java.sql.Date; import java.time.Instant; +import java.util.Base64; import java.util.Map; import java.util.UUID; @@ -68,10 +71,13 @@ class CredentialRequestApiControllerTest extends RestControllerTestBase { private final DcpIssuerService dcpIssuerService = mock(); private final DcpHolderTokenVerifier dcpIssuerTokenVerifier = mock(); private final JsonLdNamespace namespace = DSPACE_DCP_NAMESPACE_V_1_0; + private final ParticipantContextService participantContextService = mock(); + private final String participantContextId = "participantContextId"; + private final String participantContextIdEncoded = Base64.getEncoder().encodeToString(participantContextId.getBytes()); @Test void requestCredential_tokenNotPresent_shouldReturn401() { - assertThatThrownBy(() -> controller().requestCredential(createObjectBuilder().build(), null)) + assertThatThrownBy(() -> controller().requestCredential(participantContextId, createObjectBuilder().build(), null)) .isInstanceOf(AuthenticationFailedException.class) .hasMessage("Authorization header missing"); @@ -83,7 +89,7 @@ void requestCredential_tokenNotPresent_shouldReturn401() { void requestCredential_validationError_shouldReturn400() { when(validatorRegistryMock.validate(eq(namespace.toIri(CREDENTIAL_REQUEST_MESSAGE_TERM)), any())).thenReturn(failure(violation("foo", "bar"))); - assertThatThrownBy(() -> controller().requestCredential(createObjectBuilder().build(), generateJwt())) + assertThatThrownBy(() -> controller().requestCredential(participantContextIdEncoded, createObjectBuilder().build(), generateJwt())) .isInstanceOf(ValidationFailureException.class) .hasMessage("foo"); verifyNoInteractions(dcpIssuerService, dcpIssuerTokenVerifier, typeTransformerRegistry); @@ -94,8 +100,8 @@ void requestCredential_validationError_shouldReturn400() { void requestCredential_transformationError_shouldReturn400() { when(validatorRegistryMock.validate(eq(namespace.toIri(CREDENTIAL_REQUEST_MESSAGE_TERM)), any())).thenReturn(success()); when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(CredentialRequestMessage.class))).thenReturn(Result.failure("cannot transform")); - - assertThatThrownBy(() -> controller().requestCredential(createObjectBuilder().build(), generateJwt())) + when(participantContextService.getParticipantContext(eq(participantContextId))).thenReturn(ServiceResult.success(createParticipantContext())); + assertThatThrownBy(() -> controller().requestCredential(participantContextIdEncoded, createObjectBuilder().build(), generateJwt())) .isInstanceOf(InvalidRequestException.class) .hasMessage("cannot transform"); @@ -107,15 +113,30 @@ void requestCredential_tokenVerificationFails_shouldReturn401() { when(validatorRegistryMock.validate(eq(namespace.toIri(CREDENTIAL_REQUEST_MESSAGE_TERM)), any())).thenReturn(success()); var requestMessage = createCredentialRequestMessage(); when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(CredentialRequestMessage.class))).thenReturn(Result.success(requestMessage)); - when(dcpIssuerTokenVerifier.verify(any())).thenReturn(ServiceResult.unauthorized("unauthorized")); + when(dcpIssuerTokenVerifier.verify(any(), any())).thenReturn(ServiceResult.unauthorized("unauthorized")); + when(participantContextService.getParticipantContext(eq(participantContextId))).thenReturn(ServiceResult.success(createParticipantContext())); - assertThatThrownBy(() -> controller().requestCredential(createObjectBuilder().build(), generateJwt())) + assertThatThrownBy(() -> controller().requestCredential(participantContextIdEncoded, createObjectBuilder().build(), generateJwt())) .isExactlyInstanceOf(AuthenticationFailedException.class) .hasMessageContaining("unauthorized"); verifyNoInteractions(dcpIssuerService); } + @Test + void requestCredential_participantNotFound_shouldReturn401() { + when(validatorRegistryMock.validate(eq(namespace.toIri(CREDENTIAL_REQUEST_MESSAGE_TERM)), any())).thenReturn(success()); + var requestMessage = createCredentialRequestMessage(); + when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(CredentialRequestMessage.class))).thenReturn(Result.success(requestMessage)); + when(participantContextService.getParticipantContext(eq(participantContextId))).thenReturn(ServiceResult.notFound("not found")); + + assertThatThrownBy(() -> controller().requestCredential(participantContextIdEncoded, createObjectBuilder().build(), generateJwt())) + .isExactlyInstanceOf(AuthenticationFailedException.class) + .hasMessageContaining("Invalid issuer"); + + verifyNoInteractions(dcpIssuerService); + } + @Test void requestCredential_initiateCredentialIssuanceFails_shouldReturn_401() { when(validatorRegistryMock.validate(eq(namespace.toIri(CREDENTIAL_REQUEST_MESSAGE_TERM)), any())).thenReturn(success()); @@ -125,19 +146,22 @@ void requestCredential_initiateCredentialIssuanceFails_shouldReturn_401() { var ctx = new DcpRequestContext(participant, Map.of()); var token = generateJwt(); - when(dcpIssuerTokenVerifier.verify(any())).thenReturn(ServiceResult.success(ctx)); - when(dcpIssuerService.initiateCredentialsIssuance(any(), any())).thenReturn(ServiceResult.unauthorized("cannot initiate unauthorized")); + when(dcpIssuerTokenVerifier.verify(any(), any())).thenReturn(ServiceResult.success(ctx)); + when(dcpIssuerService.initiateCredentialsIssuance(eq(participantContextId), any(), any())).thenReturn(ServiceResult.unauthorized("cannot initiate unauthorized")); + when(participantContextService.getParticipantContext(eq(participantContextId))).thenReturn(ServiceResult.success(createParticipantContext())); - assertThatThrownBy(() -> controller().requestCredential(createObjectBuilder().build(), token)) + assertThatThrownBy(() -> controller().requestCredential(participantContextIdEncoded, createObjectBuilder().build(), token)) .isExactlyInstanceOf(NotAuthorizedException.class) .hasMessage("cannot initiate unauthorized"); - verify(dcpIssuerTokenVerifier).verify(argThat(tr -> tr.getToken().equals(token))); - verify(dcpIssuerService).initiateCredentialsIssuance(requestMessage, ctx); + verify(dcpIssuerTokenVerifier).verify(any(), argThat(tr -> tr.getToken().equals(token))); + verify(dcpIssuerService).initiateCredentialsIssuance(participantContextId, requestMessage, ctx); } @Test void requestCredential() { + + when(validatorRegistryMock.validate(eq(namespace.toIri(CREDENTIAL_REQUEST_MESSAGE_TERM)), any())).thenReturn(success()); var requestMessage = createCredentialRequestMessage(); when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(CredentialRequestMessage.class))).thenReturn(Result.success(requestMessage)); @@ -146,22 +170,23 @@ void requestCredential() { var token = generateJwt(); var responseMessage = new CredentialRequestMessage.Response(UUID.randomUUID().toString()); - when(dcpIssuerTokenVerifier.verify(any())).thenReturn(ServiceResult.success(ctx)); - when(dcpIssuerService.initiateCredentialsIssuance(any(), any())).thenReturn(ServiceResult.success(responseMessage)); + when(dcpIssuerTokenVerifier.verify(any(), any())).thenReturn(ServiceResult.success(ctx)); + when(dcpIssuerService.initiateCredentialsIssuance(eq(participantContextId), any(), any())).thenReturn(ServiceResult.success(responseMessage)); + when(participantContextService.getParticipantContext(eq(participantContextId))).thenReturn(ServiceResult.success(createParticipantContext())); - var response = controller().requestCredential(createObjectBuilder().build(), token); + var response = controller().requestCredential(participantContextIdEncoded, createObjectBuilder().build(), token); assertThat(response).isNotNull(); assertThat(response.getStatus()).isEqualTo(201); - assertThat(response.getHeaderString("Location")).contains("/v1alpha/requests/%s".formatted(responseMessage.requestId())); + assertThat(response.getHeaderString("Location")).contains("/v1alpha/participants/%s/requests/%s".formatted(participantContextIdEncoded, responseMessage.requestId())); - verify(dcpIssuerTokenVerifier).verify(argThat(tr -> tr.getToken().equals(token))); - verify(dcpIssuerService).initiateCredentialsIssuance(requestMessage, ctx); + verify(dcpIssuerTokenVerifier).verify(any(), argThat(tr -> tr.getToken().equals(token))); + verify(dcpIssuerService).initiateCredentialsIssuance(participantContextId, requestMessage, ctx); } @Override protected CredentialRequestApiController controller() { - return new CredentialRequestApiController(dcpIssuerService, dcpIssuerTokenVerifier, validatorRegistryMock, typeTransformerRegistry, namespace); + return new CredentialRequestApiController(participantContextService, dcpIssuerService, dcpIssuerTokenVerifier, validatorRegistryMock, typeTransformerRegistry, namespace); } @@ -175,6 +200,14 @@ private CredentialRequestMessage.Builder createCredentialRequestMessageBuilder() return CredentialRequestMessage.Builder.newInstance(); } + private ParticipantContext createParticipantContext() { + return ParticipantContext.Builder.newInstance() + .participantContextId(participantContextId) + .did("did") + .apiTokenAlias("apiTokenAlias") + .build(); + } + private String generateJwt() { var ecKey = generateEcKey(null); var jwt = buildSignedJwt(new JWTClaimsSet.Builder().audience("test-audience") diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpHolderTokenVerifierImpl.java b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpHolderTokenVerifierImpl.java index f944bbb85..a4cdce81d 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpHolderTokenVerifierImpl.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpHolderTokenVerifierImpl.java @@ -15,38 +15,49 @@ package org.eclipse.edc.identityhub.protocols.dcp.issuer; import com.nimbusds.jwt.SignedJWT; -import org.eclipse.edc.iam.identitytrust.spi.validation.TokenValidationAction; import org.eclipse.edc.identityhub.protocols.dcp.spi.DcpHolderTokenVerifier; import org.eclipse.edc.identityhub.protocols.dcp.spi.model.DcpRequestContext; +import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.issuerservice.spi.participant.model.Participant; import org.eclipse.edc.issuerservice.spi.participant.store.ParticipantStore; import org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames; +import org.eclipse.edc.keys.spi.PublicKeyResolver; import org.eclipse.edc.spi.iam.TokenRepresentation; import org.eclipse.edc.spi.query.Criterion; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.spi.result.ServiceResult; +import org.eclipse.edc.token.rules.AudienceValidationRule; +import org.eclipse.edc.token.spi.TokenValidationRulesRegistry; +import org.eclipse.edc.token.spi.TokenValidationService; import java.text.ParseException; +import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.Optional; +import static org.eclipse.edc.identityhub.protocols.dcp.issuer.DcpIssuerCoreExtension.DCP_ISSUER_SELF_ISSUED_TOKEN_CONTEXT; + public class DcpHolderTokenVerifierImpl implements DcpHolderTokenVerifier { + private final TokenValidationRulesRegistry rulesRegistry; + private final TokenValidationService tokenValidationService; + private final PublicKeyResolver publicKeyResolver; private final ParticipantStore store; - private final TokenValidationAction tokenValidation; - public DcpHolderTokenVerifierImpl(ParticipantStore store, TokenValidationAction tokenValidation) { + public DcpHolderTokenVerifierImpl(TokenValidationRulesRegistry rulesRegistry, TokenValidationService tokenValidationService, PublicKeyResolver publicKeyResolver, ParticipantStore store) { + this.rulesRegistry = rulesRegistry; + this.tokenValidationService = tokenValidationService; + this.publicKeyResolver = publicKeyResolver; this.store = store; - this.tokenValidation = tokenValidation; } @Override - public ServiceResult verify(TokenRepresentation tokenRepresentation) { + public ServiceResult verify(ParticipantContext issuerContext, TokenRepresentation tokenRepresentation) { return getTokenIssuer(tokenRepresentation.getToken()) .compose(this::getParticipant) - .compose(participant -> validateToken(tokenRepresentation, participant)); + .compose(participant -> validateToken(issuerContext, tokenRepresentation, participant)); } private ServiceResult getTokenIssuer(String token) { @@ -71,11 +82,16 @@ private ServiceResult findFirst(Collection participant .orElseGet(() -> ServiceResult.unauthorized("Participant not found")); } - private ServiceResult validateToken(TokenRepresentation token, Participant participant) { - var res = tokenValidation.apply(token); + private ServiceResult validateToken(ParticipantContext issuerContext, TokenRepresentation token, Participant participant) { + + var rules = rulesRegistry.getRules(DCP_ISSUER_SELF_ISSUED_TOKEN_CONTEXT); + var newRules = new ArrayList<>(rules); + newRules.add(new AudienceValidationRule(issuerContext.getDid())); + var res = tokenValidationService.validate(token.getToken(), publicKeyResolver, newRules); if (res.failed()) { return ServiceResult.unauthorized("Token validation failed"); } return ServiceResult.success(new DcpRequestContext(participant, Map.of())); } + } diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerCoreExtension.java b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerCoreExtension.java index 1fd2549e8..64b7d09a8 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerCoreExtension.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerCoreExtension.java @@ -15,7 +15,6 @@ package org.eclipse.edc.identityhub.protocols.dcp.issuer; import org.eclipse.edc.iam.did.spi.resolution.DidPublicKeyResolver; -import org.eclipse.edc.iam.identitytrust.spi.validation.TokenValidationAction; import org.eclipse.edc.identityhub.protocols.dcp.issuer.spi.DcpIssuerService; import org.eclipse.edc.identityhub.protocols.dcp.spi.DcpHolderTokenVerifier; import org.eclipse.edc.issuerservice.spi.issuance.attestation.AttestationPipeline; @@ -26,16 +25,13 @@ import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Provider; -import org.eclipse.edc.runtime.metamodel.annotation.Setting; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; -import org.eclipse.edc.token.rules.AudienceValidationRule; import org.eclipse.edc.token.rules.ExpirationIssuedAtValidationRule; import org.eclipse.edc.token.spi.TokenValidationRulesRegistry; import org.eclipse.edc.token.spi.TokenValidationService; import org.eclipse.edc.transaction.spi.TransactionContext; import org.eclipse.edc.verifiablecredentials.jwt.rules.IssuerEqualsSubjectRule; -import org.jetbrains.annotations.NotNull; import java.time.Clock; @@ -44,10 +40,6 @@ public class DcpIssuerCoreExtension implements ServiceExtension { public static final String DCP_ISSUER_SELF_ISSUED_TOKEN_CONTEXT = "dcp-issuer-si"; - - @Setting(description = "DID of this issuer", key = "edc.ih.iam.id") - private String issuerId; - @Inject private TokenValidationRulesRegistry rulesRegistry; @@ -82,7 +74,6 @@ public class DcpIssuerCoreExtension implements ServiceExtension { @Override public void initialize(ServiceExtensionContext context) { rulesRegistry.addRule(DCP_ISSUER_SELF_ISSUED_TOKEN_CONTEXT, new IssuerEqualsSubjectRule()); - rulesRegistry.addRule(DCP_ISSUER_SELF_ISSUED_TOKEN_CONTEXT, new AudienceValidationRule(issuerId)); rulesRegistry.addRule(DCP_ISSUER_SELF_ISSUED_TOKEN_CONTEXT, new ExpirationIssuedAtValidationRule(clock, 5, false)); } @@ -93,14 +84,6 @@ public DcpIssuerService createIssuerService() { @Provider public DcpHolderTokenVerifier createTokenVerifier() { - return new DcpHolderTokenVerifierImpl(participantStore, tokenValidationAction()); - } - - @NotNull - private TokenValidationAction tokenValidationAction() { - return (tokenRepresentation) -> { - var rules = rulesRegistry.getRules(DCP_ISSUER_SELF_ISSUED_TOKEN_CONTEXT); - return tokenValidationService.validate(tokenRepresentation, didPublicKeyResolver, rules); - }; + return new DcpHolderTokenVerifierImpl(rulesRegistry, tokenValidationService, didPublicKeyResolver, participantStore); } } diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerServiceImpl.java b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerServiceImpl.java index 448391147..3e9f22d22 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerServiceImpl.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerServiceImpl.java @@ -56,14 +56,14 @@ public DcpIssuerServiceImpl(TransactionContext transactionContext, } @Override - public ServiceResult initiateCredentialsIssuance(CredentialRequestMessage message, DcpRequestContext context) { + public ServiceResult initiateCredentialsIssuance(String issuerContextId, CredentialRequestMessage message, DcpRequestContext context) { if (message.getCredentials().isEmpty()) { return ServiceResult.badRequest("No credentials requested"); } return transactionContext.execute(() -> getCredentialsDefinitions(message) .compose(credentialDefinitions -> evaluateAttestations(context, credentialDefinitions)) .compose(this::evaluateRules) - .compose(evaluation -> createIssuanceProcess(context, evaluation)) + .compose(evaluation -> createIssuanceProcess(issuerContextId, context, evaluation)) .map(issuanceProcess -> new CredentialRequestMessage.Response(issuanceProcess.getId()))); } @@ -120,7 +120,7 @@ private ServiceResult evaluateRules(AttestationEv return ServiceResult.success(evaluationResponse); } - private ServiceResult createIssuanceProcess(DcpRequestContext context, AttestationEvaluationResponse evaluationResponse) { + private ServiceResult createIssuanceProcess(String issuerContextId, DcpRequestContext context, AttestationEvaluationResponse evaluationResponse) { var credentialDefinitionIds = evaluationResponse.credentialDefinitions().stream() .map(CredentialDefinition::getId) @@ -131,6 +131,7 @@ private ServiceResult createIssuanceProcess(DcpRequestContext c .state(IssuanceProcessStates.APPROVED.code()) .credentialDefinitions(credentialDefinitionIds) .claims(evaluationResponse.claims()) + .issuerContextId(issuerContextId) .build(); issuanceProcessStore.save(issuanceProcess); diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpHolderTokenVerifierImplTest.java b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpHolderTokenVerifierImplTest.java index 7b3ce6583..c760799b4 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpHolderTokenVerifierImplTest.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpHolderTokenVerifierImplTest.java @@ -15,14 +15,17 @@ package org.eclipse.edc.identityhub.protocols.dcp.issuer; import com.nimbusds.jose.jwk.ECKey; -import org.eclipse.edc.iam.identitytrust.spi.validation.TokenValidationAction; import org.eclipse.edc.identityhub.protocols.dcp.spi.DcpHolderTokenVerifier; +import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.issuerservice.spi.participant.model.Participant; import org.eclipse.edc.issuerservice.spi.participant.store.ParticipantStore; +import org.eclipse.edc.keys.spi.PublicKeyResolver; import org.eclipse.edc.spi.iam.ClaimToken; import org.eclipse.edc.spi.iam.TokenRepresentation; import org.eclipse.edc.spi.result.Result; import org.eclipse.edc.spi.result.StoreResult; +import org.eclipse.edc.token.spi.TokenValidationRulesRegistry; +import org.eclipse.edc.token.spi.TokenValidationService; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -33,6 +36,8 @@ import static org.eclipse.edc.identityhub.verifiablecredentials.testfixtures.VerifiableCredentialTestUtil.generateEcKey; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -44,10 +49,17 @@ public class DcpHolderTokenVerifierImplTest { public static final String DID_WEB_PARTICIPANT_KEY_1 = "did:web:participant#key1"; public static final ECKey PARTICIPANT_KEY = generateEcKey(DID_WEB_PARTICIPANT_KEY_1); - private final TokenValidationAction tokenValidationAction = mock(); + private final TokenValidationRulesRegistry rulesRegistry = mock(); + private final TokenValidationService tokenValidationService = mock(); + private final PublicKeyResolver publicKeyResolver = mock(); + private final ParticipantStore participantStore = mock(); - private final DcpHolderTokenVerifier dcpIssuerTokenVerifier = new DcpHolderTokenVerifierImpl(participantStore, tokenValidationAction); + private final DcpHolderTokenVerifier dcpIssuerTokenVerifier = new DcpHolderTokenVerifierImpl(rulesRegistry, tokenValidationService, publicKeyResolver, participantStore); + private final ParticipantContext participantContext = ParticipantContext.Builder.newInstance().participantContextId("participantId") + .did(PARTICIPANT_DID) + .apiTokenAlias("apiAlias") + .build(); @Test void verify() { @@ -55,9 +67,9 @@ void verify() { var token = TokenRepresentation.Builder.newInstance().token(generateToken()).build(); when(participantStore.query(any())).thenReturn(StoreResult.success(List.of(new Participant(PARTICIPANT_DID, PARTICIPANT_DID, PARTICIPANT_DID)))); - when(tokenValidationAction.apply(token)).thenReturn(Result.success(ClaimToken.Builder.newInstance().build())); + when(tokenValidationService.validate(anyString(), any(), anyList())).thenReturn(Result.success(ClaimToken.Builder.newInstance().build())); - var result = dcpIssuerTokenVerifier.verify(token); + var result = dcpIssuerTokenVerifier.verify(participantContext, token); assertThat(result).isSucceeded(); Mockito.verify(participantStore).query(argThat(qs -> qs.getFilterExpression().stream().anyMatch(c -> c.getOperandRight().equals(PARTICIPANT_DID)))); @@ -71,7 +83,7 @@ void verify_participantNotFound() { when(participantStore.query(any())).thenReturn(StoreResult.success(List.of())); - var result = dcpIssuerTokenVerifier.verify(token); + var result = dcpIssuerTokenVerifier.verify(participantContext, token); assertThat(result).isFailed(); @@ -83,9 +95,9 @@ void verify_tokenValidationFails() { var token = TokenRepresentation.Builder.newInstance().token(generateToken()).build(); when(participantStore.query(any())).thenReturn(StoreResult.success(List.of(new Participant(PARTICIPANT_DID, PARTICIPANT_DID, PARTICIPANT_DID)))); - when(tokenValidationAction.apply(token)).thenReturn(Result.failure("failed")); + when(tokenValidationService.validate(anyString(), any(), anyList())).thenReturn(Result.failure("failed")); - var result = dcpIssuerTokenVerifier.verify(token); + var result = dcpIssuerTokenVerifier.verify(participantContext, token); assertThat(result).isFailed(); @@ -96,7 +108,7 @@ void verify_faultyToken() { var token = TokenRepresentation.Builder.newInstance().token("faultyToken").build(); - var result = dcpIssuerTokenVerifier.verify(token); + var result = dcpIssuerTokenVerifier.verify(participantContext, token); assertThat(result).isFailed(); diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerServiceImplTest.java b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerServiceImplTest.java index 6626740cf..f6e294020 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-core/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerServiceImplTest.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-core/src/test/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/DcpIssuerServiceImplTest.java @@ -84,7 +84,7 @@ void initiateCredentialsIssuance() { when(attestationPipeline.evaluate(eq(attestations), any())).thenReturn(Result.success(claims)); when(credentialRuleDefinitionEvaluator.evaluate(eq(List.of(credentialRuleDefinition)), any())).thenReturn(Result.success()); - var result = dcpIssuerService.initiateCredentialsIssuance(message, participant); + var result = dcpIssuerService.initiateCredentialsIssuance("issuerContextId", message, participant); assertThat(result).isSucceeded(); @@ -99,5 +99,6 @@ void initiateCredentialsIssuance() { assertThat(issuanceProcess.getParticipantId()).isEqualTo("participantId"); assertThat(issuanceProcess.getState()).isEqualTo(IssuanceProcessStates.APPROVED.code()); assertThat(issuanceProcess.getClaims()).containsAllEntriesOf(claims); + assertThat(issuanceProcess.getIssuerContextId()).isEqualTo("issuerContextId"); } } diff --git a/protocols/dcp/dcp-issuer/dcp-issuer-spi/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/spi/DcpIssuerService.java b/protocols/dcp/dcp-issuer/dcp-issuer-spi/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/spi/DcpIssuerService.java index 75e74ae05..b29046c5f 100644 --- a/protocols/dcp/dcp-issuer/dcp-issuer-spi/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/spi/DcpIssuerService.java +++ b/protocols/dcp/dcp-issuer/dcp-issuer-spi/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/spi/DcpIssuerService.java @@ -30,5 +30,5 @@ public interface DcpIssuerService { * @param context the DCP request context * @return the result of the issuance initiation */ - ServiceResult initiateCredentialsIssuance(CredentialRequestMessage message, DcpRequestContext context); + ServiceResult initiateCredentialsIssuance(String issuerContextId, CredentialRequestMessage message, DcpRequestContext context); } diff --git a/protocols/dcp/dcp-spi/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/spi/DcpHolderTokenVerifier.java b/protocols/dcp/dcp-spi/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/spi/DcpHolderTokenVerifier.java index 6ca1c887e..4ffe0291a 100644 --- a/protocols/dcp/dcp-spi/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/spi/DcpHolderTokenVerifier.java +++ b/protocols/dcp/dcp-spi/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/spi/DcpHolderTokenVerifier.java @@ -15,6 +15,7 @@ package org.eclipse.edc.identityhub.protocols.dcp.spi; import org.eclipse.edc.identityhub.protocols.dcp.spi.model.DcpRequestContext; +import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.runtime.metamodel.annotation.ExtensionPoint; import org.eclipse.edc.spi.iam.TokenRepresentation; import org.eclipse.edc.spi.result.ServiceResult; @@ -26,6 +27,6 @@ @ExtensionPoint public interface DcpHolderTokenVerifier { - ServiceResult verify(TokenRepresentation tokenRepresentation); + ServiceResult verify(ParticipantContext issuerContext, TokenRepresentation tokenRepresentation); } diff --git a/spi/issuerservice/issuerservice-issuance-spi/src/main/java/org/eclipse/edc/issuerservice/spi/issuance/model/IssuanceProcess.java b/spi/issuerservice/issuerservice-issuance-spi/src/main/java/org/eclipse/edc/issuerservice/spi/issuance/model/IssuanceProcess.java index 43d227530..2a4e406ef 100644 --- a/spi/issuerservice/issuerservice-issuance-spi/src/main/java/org/eclipse/edc/issuerservice/spi/issuance/model/IssuanceProcess.java +++ b/spi/issuerservice/issuerservice-issuance-spi/src/main/java/org/eclipse/edc/issuerservice/spi/issuance/model/IssuanceProcess.java @@ -39,6 +39,7 @@ public class IssuanceProcess extends StatefulEntity { private final Map claims = new HashMap<>(); private final List credentialDefinitions = new ArrayList<>(); private String participantId; + private String issuerContextId; private IssuanceProcess() { } @@ -48,7 +49,8 @@ public IssuanceProcess copy() { var builder = Builder.newInstance() .claims(claims) .credentialDefinitions(credentialDefinitions) - .participantId(participantId); + .participantId(participantId) + .issuerContextId(issuerContextId); return copy(builder); } @@ -61,6 +63,10 @@ public String getParticipantId() { return participantId; } + public String getIssuerContextId() { + return issuerContextId; + } + public Map getClaims() { return claims; } @@ -126,6 +132,11 @@ public Builder participantId(String participantId) { return this; } + public Builder issuerContextId(String issuerContextId) { + this.entity.issuerContextId = issuerContextId; + return this; + } + @Override public IssuanceProcess build() { super.build(); @@ -134,6 +145,7 @@ public IssuanceProcess build() { throw new IllegalStateException("Issuance process state must be set"); } Objects.requireNonNull(entity.participantId, "Participant ID must be set"); + Objects.requireNonNull(entity.issuerContextId, "Issuer Context ID must be set"); return entity; } diff --git a/spi/issuerservice/issuerservice-issuance-spi/src/testFixtures/java/org/eclipse/edc/issuerservice/spi/issuance/process/store/IssuanceProcessStoreTestBase.java b/spi/issuerservice/issuerservice-issuance-spi/src/testFixtures/java/org/eclipse/edc/issuerservice/spi/issuance/process/store/IssuanceProcessStoreTestBase.java index 6d36c0f0e..b25b4edf1 100644 --- a/spi/issuerservice/issuerservice-issuance-spi/src/testFixtures/java/org/eclipse/edc/issuerservice/spi/issuance/process/store/IssuanceProcessStoreTestBase.java +++ b/spi/issuerservice/issuerservice-issuance-spi/src/testFixtures/java/org/eclipse/edc/issuerservice/spi/issuance/process/store/IssuanceProcessStoreTestBase.java @@ -79,6 +79,7 @@ private IssuanceProcess createIssuanceProcess(String id) { private IssuanceProcess.Builder createIssuanceProcessBuilder() { return IssuanceProcess.Builder.newInstance() .id(UUID.randomUUID().toString()) + .issuerContextId(UUID.randomUUID().toString()) .participantId(UUID.randomUUID().toString()) .state(APPROVED.code()); } @@ -419,6 +420,25 @@ void queryByParticipantId() { assertThat(result).hasSize(1).usingRecursiveFieldByFieldElementComparator().containsExactly(issuanceProcess); } + @Test + void queryByIssuanceContextId() { + + range(0, 10) + .mapToObj(i -> createIssuanceProcess("id" + i)) + .forEach(getStore()::save); + + var issuanceProcess = createIssuanceProcessBuilder().id("testprocess1").participantId("participant1").build(); + + getStore().save(issuanceProcess); + + var query = QuerySpec.Builder.newInstance() + .filter(List.of(new Criterion("issuerContextId", "=", issuanceProcess.getIssuerContextId()))) + .build(); + + var result = getStore().query(query).toList(); + assertThat(result).hasSize(1).usingRecursiveFieldByFieldElementComparator().containsExactly(issuanceProcess); + } + @Test void queryByCredentialDefinition() {