From 05e2398dbdef49f207db554421cecb48c37799dd Mon Sep 17 00:00:00 2001 From: Paul Latzelsperger <43503240+paullatzelsperger@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:26:19 +0100 Subject: [PATCH] feat: add Issuer Service skeleton (#524) * feat: add Credential Request API + issuer service skeleton * added issuer-service launcher * added issuer APIs (skeletons) * removed yaml folder * license headers * update api version files * fix API version file --- .github/workflows/verify.yaml | 27 +++++- .../ParticipantContextExtension.java | 3 - .../issuerservice-base-bom/build.gradle.kts | 40 ++++++++ dist/bom/issuerservice-bom/build.gradle.kts | 27 ++++++ .../build.gradle.kts | 39 ++++++++ .../eclipse/edc/test/bom/BomSmokeTests.java | 24 +++++ .../main/resources/identity-api-version.json | 2 +- .../protocols/dcp/issuer-api/build.gradle.kts | 45 +++++++++ .../dcp/issuer/IssuerApiExtension.java | 95 ++++++++++++++++++ .../dcp/issuer/api/v1alpha/ApiSchema.java | 36 +++++++ .../credentialrequest/CredentialRequest.java | 22 +++++ .../CredentialRequestApi.java | 59 +++++++++++ .../CredentialRequestApiController.java | 36 +++++++ .../CredentialRequestMessage.java | 86 ++++++++++++++++ .../CredentialRequestStatus.java | 97 +++++++++++++++++++ .../CredentialRequestStatusApi.java | 62 ++++++++++++ .../CredentialRequestStatusApiController.java | 47 +++++++++ .../issuermetadata/IssuerMetadata.java | 19 ++++ .../issuermetadata/IssuerMetadataApi.java | 43 ++++++++ .../IssuerMetadataApiController.java | 36 +++++++ ...rg.eclipse.edc.spi.system.ServiceExtension | 15 +++ .../main/resources/issuer-api-version.json | 8 ++ .../resources/presentation-api-version.json | 2 +- launcher/identityhub/Dockerfile | 1 - launcher/issuer-service/Dockerfile | 25 +++++ launcher/issuer-service/build.gradle.kts | 38 ++++++++ resources/openapi/issuer-api.version | 1 + resources/openapi/presentation-api.version | 2 +- settings.gradle.kts | 11 ++- .../spi/webcontext/IdentityHubApiContext.java | 1 + 30 files changed, 939 insertions(+), 10 deletions(-) create mode 100644 dist/bom/issuerservice-base-bom/build.gradle.kts create mode 100644 dist/bom/issuerservice-bom/build.gradle.kts create mode 100644 dist/bom/issuerservice-feature-sql-bom/build.gradle.kts create mode 100644 extensions/protocols/dcp/issuer-api/build.gradle.kts create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/IssuerApiExtension.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/ApiSchema.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequest.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApi.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiController.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestMessage.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatus.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatusApi.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatusApiController.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadata.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadataApi.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadataApiController.java create mode 100644 extensions/protocols/dcp/issuer-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension create mode 100644 extensions/protocols/dcp/issuer-api/src/main/resources/issuer-api-version.json create mode 100644 launcher/issuer-service/Dockerfile create mode 100644 launcher/issuer-service/build.gradle.kts create mode 100644 resources/openapi/issuer-api.version diff --git a/.github/workflows/verify.yaml b/.github/workflows/verify.yaml index 5c38c6703..3d5dfc783 100644 --- a/.github/workflows/verify.yaml +++ b/.github/workflows/verify.yaml @@ -35,7 +35,7 @@ jobs: - name: Run Javadoc run: ./gradlew javadoc - Verify-Launcher: + Verify-Identityhub-Launcher: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -63,6 +63,31 @@ jobs: container-name: identity-hub timeout: 60 + Verify-Issuer-Service-Launcher: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: eclipse-edc/.github/.github/actions/setup-build@main + + - name: 'Build launcher' + run: ./gradlew :launcher:issuer-service:shadowJar + + - name: 'Build Docker image' + run: docker build -t issuer-service ./launcher/issuer-service + + - name: 'Start Identity Hub' + run: | + docker run -d --rm --name issuer-service \ + -e "EDC_STS_ACCOUNT_API_URL=https://sts.com" \ + -e "EDC_STS_ACCOUNTS_API_AUTH_HEADER_VALUE=auth-header" \ + issuer-service:latest + + - name: 'Wait for Issuer-Service to be healthy' + uses: raschmitt/wait-for-healthy-container@v1 + with: + container-name: issuer-service + timeout: 60 + Test: permissions: checks: write diff --git a/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextExtension.java b/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextExtension.java index e8bb12f05..c67410171 100644 --- a/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextExtension.java +++ b/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextExtension.java @@ -15,7 +15,6 @@ package org.eclipse.edc.identityhub.participantcontext; import org.eclipse.edc.identityhub.spi.did.store.DidResourceStore; -import org.eclipse.edc.identityhub.spi.keypair.KeyPairService; import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; import org.eclipse.edc.identityhub.spi.participantcontext.StsAccountProvisioner; import org.eclipse.edc.identityhub.spi.participantcontext.events.ParticipantContextObservable; @@ -43,8 +42,6 @@ public class ParticipantContextExtension implements ServiceExtension { @Inject private TransactionContext transactionContext; @Inject - private KeyPairService keyPairService; - @Inject private Clock clock; @Inject private EventRouter eventRouter; diff --git a/dist/bom/issuerservice-base-bom/build.gradle.kts b/dist/bom/issuerservice-base-bom/build.gradle.kts new file mode 100644 index 000000000..b5e4364ec --- /dev/null +++ b/dist/bom/issuerservice-base-bom/build.gradle.kts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +plugins { + `java-library` +} + +dependencies { + runtimeOnly(project(":core:identity-hub-did")) + runtimeOnly(project(":core:identity-hub-core")) + runtimeOnly(project(":core:identity-hub-participants")) + runtimeOnly(project(":core:identity-hub-keypairs")) + runtimeOnly(project(":extensions:did:local-did-publisher")) + // API modules + runtimeOnly(project(":extensions:protocols:dcp:issuer-api")) + + runtimeOnly(project(":extensions:sts:sts-account-provisioner")) + runtimeOnly(libs.edc.identity.did.core) + runtimeOnly(libs.edc.core.token) + runtimeOnly(libs.edc.api.version) + runtimeOnly(libs.edc.transaction.local) // needed by the PresentationCreatorRegistry + + runtimeOnly(libs.edc.identity.did.web) + runtimeOnly(libs.bundles.connector) +} + +edcBuild { + +} \ No newline at end of file diff --git a/dist/bom/issuerservice-bom/build.gradle.kts b/dist/bom/issuerservice-bom/build.gradle.kts new file mode 100644 index 000000000..6aa3d6de1 --- /dev/null +++ b/dist/bom/issuerservice-bom/build.gradle.kts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + + +plugins { + `java-library` +} + +dependencies { + runtimeOnly(project(":dist:bom:issuerservice-base-bom")) + runtimeOnly(project(":extensions:sts:sts-account-service-remote")) +} + +edcBuild { + +} \ No newline at end of file diff --git a/dist/bom/issuerservice-feature-sql-bom/build.gradle.kts b/dist/bom/issuerservice-feature-sql-bom/build.gradle.kts new file mode 100644 index 000000000..fb04471d5 --- /dev/null +++ b/dist/bom/issuerservice-feature-sql-bom/build.gradle.kts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + + +plugins { + `java-library` +} + +dependencies { + // sql modules + api(project(":extensions:store:sql:identity-hub-credentials-store-sql")) + api(project(":extensions:store:sql:identity-hub-did-store-sql")) + api(project(":extensions:store:sql:identity-hub-keypair-store-sql")) + api(project(":extensions:store:sql:identity-hub-participantcontext-store-sql")) + + api(libs.edc.sql.core) + api(libs.edc.transaction.local) + api(libs.edc.sql.pool) + api(libs.edc.sql.bootstrapper) + api(libs.edc.sql.jtivdalidation) + + // third-party deps + api(libs.postgres) +} + +edcBuild { + +} \ No newline at end of file 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 611d6f7a9..eba84d2a2 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 @@ -109,4 +109,28 @@ class IdentityHubWithSts extends SmokeTest { ":dist:bom:identityhub-with-sts-bom" )); } + + @Nested + @EndToEndTest + class IssuerService extends SmokeTest { + @RegisterExtension + protected RuntimeExtension runtime = + new RuntimePerMethodExtension(new EmbeddedRuntime("issuer-service-bom", + new HashMap<>() { + { + put("web.http.port", DEFAULT_PORT); + put("web.http.path", DEFAULT_PATH); + put("web.http.version.port", valueOf(getFreePort())); + put("web.http.version.path", "/api/version"); + put("web.http.did.port", valueOf(getFreePort())); + put("web.http.did.path", "/api/did"); + put("web.http.issuer-api.port", valueOf(getFreePort())); + put("web.http.issuer-api.path", "/api/issuer"); + put("edc.sts.account.api.url", "https://sts.com/accounts"); + put("edc.sts.accounts.api.auth.header.value", "password"); + } + }, + ":dist:bom:issuerservice-bom" + )); + } } diff --git a/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json b/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json index d4a4bbc69..0480297d6 100644 --- a/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json +++ b/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json @@ -2,7 +2,7 @@ { "version": "1.0.0-alpha", "urlPath": "/v1alpha", - "lastUpdated": "2025-01-16T12:00:00Z", + "lastUpdated": "2025-01-17T12:00:00Z", "maturity": null } ] diff --git a/extensions/protocols/dcp/issuer-api/build.gradle.kts b/extensions/protocols/dcp/issuer-api/build.gradle.kts new file mode 100644 index 000000000..6b1e0ce16 --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/build.gradle.kts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + + +plugins { + `java-library` + `maven-publish` + id("io.swagger.core.v3.swagger-gradle-plugin") +} + +dependencies { + api(project(":spi:identity-hub-spi")) + api(project(":spi:verifiable-credential-spi")) + api(libs.edc.spi.jsonld) + api(libs.edc.spi.jwt) + api(libs.edc.spi.core) + implementation(libs.edc.spi.web) + implementation(libs.edc.spi.dcp) + implementation(libs.edc.lib.jerseyproviders) + implementation(libs.edc.lib.transform) + implementation(libs.edc.dcp.transform) + implementation(libs.jakarta.rsApi) + testImplementation(libs.edc.junit) + testImplementation(libs.edc.jsonld) + testImplementation(testFixtures(libs.edc.core.jersey)) + testImplementation(testFixtures(project(":spi:verifiable-credential-spi"))) + testImplementation(libs.nimbus.jwt) +} + +edcBuild { + swagger { + apiGroup.set("issuer-api") + } +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/IssuerApiExtension.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/IssuerApiExtension.java new file mode 100644 index 000000000..d13fbf948 --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/IssuerApiExtension.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.credentialrequest.CredentialRequestApiController; +import org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.credentialrequeststatus.CredentialRequestStatusApiController; +import org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.issuermetadata.IssuerMetadataApiController; +import org.eclipse.edc.runtime.metamodel.annotation.Configuration; +import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.runtime.metamodel.annotation.Setting; +import org.eclipse.edc.runtime.metamodel.annotation.Settings; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.apiversion.ApiVersionService; +import org.eclipse.edc.spi.system.apiversion.VersionRecord; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.web.spi.WebService; +import org.eclipse.edc.web.spi.configuration.PortMapping; +import org.eclipse.edc.web.spi.configuration.PortMappingRegistry; + +import java.io.IOException; +import java.util.stream.Stream; + +import static org.eclipse.edc.identityhub.protocols.dcp.issuer.IssuerApiExtension.NAME; +import static org.eclipse.edc.identityhub.spi.webcontext.IdentityHubApiContext.ISSUER_API; + +@Extension(value = NAME) +public class IssuerApiExtension implements ServiceExtension { + public static final String NAME = "Issuer API extension"; + + private static final String API_VERSION_JSON_FILE = "issuer-api-version.json"; + + @Inject + private TypeManager typeManager; + @Inject + private ApiVersionService apiVersionService; + @Inject + private WebService webService; + @Inject + private PortMappingRegistry portMappingRegistry; + + @Configuration + private CredentialRequestApiConfiguration apiConfiguration; + + @Override + public void initialize(ServiceExtensionContext context) { + + portMappingRegistry.register(new PortMapping(ISSUER_API, apiConfiguration.port(), apiConfiguration.path())); + + webService.registerResource(ISSUER_API, new CredentialRequestApiController()); + webService.registerResource(ISSUER_API, new CredentialRequestStatusApiController()); + webService.registerResource(ISSUER_API, new IssuerMetadataApiController()); + + registerVersionInfo(getClass().getClassLoader()); + } + + private void registerVersionInfo(ClassLoader resourceClassLoader) { + try (var versionContent = resourceClassLoader.getResourceAsStream(API_VERSION_JSON_FILE)) { + if (versionContent == null) { + throw new EdcException("Version file '%s' not found or not readable.".formatted(API_VERSION_JSON_FILE)); + } + Stream.of(typeManager.getMapper() + .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + .readValue(versionContent, VersionRecord[].class)) + .forEach(vr -> apiVersionService.addRecord("issuer-api", vr)); + } catch (IOException e) { + throw new EdcException(e); + } + } + + @Settings + record CredentialRequestApiConfiguration( + @Setting(key = "web.http." + ISSUER_API + ".port", description = "Port for " + ISSUER_API + " api context", defaultValue = 13132 + "") + int port, + @Setting(key = "web.http." + ISSUER_API + ".path", description = "Path for " + ISSUER_API + " api context", defaultValue = "/api/issuer") + String path + ) { + + } +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/ApiSchema.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/ApiSchema.java new file mode 100644 index 000000000..d9d223fcf --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/ApiSchema.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha; + +import io.swagger.v3.oas.annotations.media.Schema; + +public interface ApiSchema { + @Schema(name = "ApiErrorDetail", example = ApiErrorDetailSchema.API_ERROR_EXAMPLE) + record ApiErrorDetailSchema( + String message, + String type, + String path, + String invalidValue + ) { + public static final String API_ERROR_EXAMPLE = """ + { + "message": "error message", + "type": "ErrorType", + "path": "object.error.path", + "invalidValue": "this value is not valid" + } + """; + } +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequest.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequest.java new file mode 100644 index 000000000..e301ebbd3 --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequest.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.credentialrequest; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public record CredentialRequest(@JsonProperty("credentialType") String credentialType, + @JsonProperty("format") String format, + @JsonProperty("payload") Object payload) { +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApi.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApi.java new file mode 100644 index 000000000..8629f397d --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApi.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.credentialrequest; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.ws.rs.core.Response; +import org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.ApiSchema; + +@OpenAPIDefinition( + info = @Info(description = "This represents the Credential Request API as per DCP specification. It serves endpoints to request the issuance of Verifiable Credentials from an issuer.", title = "Credential Request API", + version = "v1alpha")) +@SecurityScheme(name = "Authentication", + description = "Self-Issued ID token containing an access_token", + type = SecuritySchemeType.HTTP, + scheme = "bearer", + bearerFormat = "JWT") +public interface CredentialRequestApi { + + @Tag(name = "Credential Request API") + @Operation(description = "Requests the issuance of one or several verifiable credentials from an issuer", + operationId = "requestCredentials", + requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = CredentialRequestMessage.class))), + responses = { + @ApiResponse(responseCode = "201", description = "The request was successfully received and is being processed.", headers = {@Header(name = "Location", + description = "contains the relative URL where the status of the request can be queried (Credential Request Status API)")}), + @ApiResponse(responseCode = "400", description = "Request body was malformed, e.g. required parameter or properties were missing", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)))), + @ApiResponse(responseCode = "401", description = "No Authorization header was provided.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)))), + @ApiResponse(responseCode = "403", description = "The given authentication token could not be validated or the client is not authorized to call this endpoint.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)))) + + } + ) + Response requestCredential(CredentialRequestMessage message); +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiController.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiController.java new file mode 100644 index 000000000..20a4e2f25 --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestApiController.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.credentialrequest; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Response; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Consumes(APPLICATION_JSON) +@Produces(APPLICATION_JSON) +@Path("/v1alpha/credentials") +public class CredentialRequestApiController implements CredentialRequestApi { + + @POST + @Path("/") + @Override + public Response requestCredential(CredentialRequestMessage message) { + return Response.noContent().build(); + } +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestMessage.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestMessage.java new file mode 100644 index 000000000..e8bb3f3ef --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequest/CredentialRequestMessage.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.credentialrequest; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +import java.util.List; + +/** + * Represents a request made by a credential holder to a credential issuer to request the issuance of one or several + * Verifiable Credentials + */ +@JsonDeserialize(builder = CredentialRequestMessage.Builder.class) +public class CredentialRequestMessage { + private List credentials = List.of(); + private List contexts = List.of("https://w3id.org/dspace-dcp/v1.0/dcp.jsonld"); + private String type = "CredentialRequestMessage"; + + public String getType() { + return type; + } + + public List getContexts() { + return contexts; + } + + public List getCredentials() { + return credentials; + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + + private final CredentialRequestMessage instance; + + private Builder() { + instance = new CredentialRequestMessage(); + } + + @JsonCreator + public static Builder newInstance() { + return new Builder(); + } + + public Builder contexts(List contexts) { + this.instance.contexts = contexts; + return this; + } + + public Builder type(String type) { + this.instance.type = type; + return this; + } + + public Builder credentials(List credentials) { + this.instance.credentials = credentials; + return this; + } + + public Builder credential(CredentialRequest credential) { + this.instance.credentials.add(credential); + return this; + } + + public CredentialRequestMessage build() { + if (instance.contexts == null || instance.contexts.isEmpty()) { + throw new IllegalArgumentException("@context object cannot be null or empty"); + } + return instance; + } + } +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatus.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatus.java new file mode 100644 index 000000000..0eecd43bb --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatus.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.credentialrequeststatus; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@JsonDeserialize(builder = CredentialRequestStatus.Builder.class) +public class CredentialRequestStatus { + private List messages = new ArrayList<>(); + private String requestStatus; //todo: change this to an enum later + private Instant timestamp; + private String requestId; + + private CredentialRequestStatus() { + } + + public List getMessages() { + return messages; + } + + public String getRequestStatus() { + return requestStatus; + } + + public Instant getTimestamp() { + return timestamp; + } + + public String getRequestId() { + return requestId; + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private final CredentialRequestStatus credentialRequestStatus; + + private Builder() { + credentialRequestStatus = new CredentialRequestStatus(); + } + + @JsonCreator + public static Builder newInstance() { + return new Builder(); + } + + public Builder requestStatus(String requestStatus) { + this.credentialRequestStatus.requestStatus = requestStatus; + return this; + } + + public Builder timestamp(Instant timestamp) { + this.credentialRequestStatus.timestamp = timestamp; + return this; + } + + public Builder requestId(String requestId) { + this.credentialRequestStatus.requestId = requestId; + return this; + } + + public Builder messages(List messages) { + this.credentialRequestStatus.messages = messages; + return this; + } + + public Builder message(String message) { + this.credentialRequestStatus.messages.add(message); + return this; + } + + public CredentialRequestStatus build() { + Objects.requireNonNull(credentialRequestStatus.requestId, "requestId"); + Objects.requireNonNull(credentialRequestStatus.timestamp, "timestamp"); + Objects.requireNonNull(credentialRequestStatus.requestStatus, "requestStatus"); + return credentialRequestStatus; + } + } +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatusApi.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatusApi.java new file mode 100644 index 000000000..87efc6e73 --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatusApi.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.credentialrequeststatus; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.ws.rs.core.Response; +import org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.ApiSchema; + +@OpenAPIDefinition( + info = @Info(description = "This represents the Credential Request Status API as per DCP specification. " + + "It serves endpoints to query the status of a credential issuance request from an issuer.", + title = "Credential Request Status API", + version = "v1alpha")) +@SecurityScheme(name = "Authentication", + description = "Self-Issued ID token containing an access_token", + type = SecuritySchemeType.HTTP, + scheme = "bearer", + bearerFormat = "JWT") +public interface CredentialRequestStatusApi { + + @Tag(name = "Credential Request Status API") + @Operation(description = "Requests status information about an issuance request from an issuer", + operationId = "getCredentialRequestStatus", + parameters = {@Parameter(name = "credentialRequestId", description = "ID of the Credential Request that was sent previously", required = true, in = ParameterIn.PATH)}, + responses = { + @ApiResponse(responseCode = "200", description = "Gets the status of a credentials request.", + content = @Content(schema = @Schema(implementation = CredentialRequestStatus.class))), + @ApiResponse(responseCode = "400", description = "Request was malformed, e.g. required parameter or properties were missing", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)))), + @ApiResponse(responseCode = "401", description = "No Authorization header was provided.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)))), + @ApiResponse(responseCode = "403", description = "The given authentication token could not be validated or the client is not authorized to call this endpoint.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)))), + @ApiResponse(responseCode = "404", description = "No credential request was found for the given ID.", + content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)))) + } + ) + Response requestCredential(String credentialRequestId); +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatusApiController.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatusApiController.java new file mode 100644 index 000000000..b8ed8ce80 --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/credentialrequeststatus/CredentialRequestStatusApiController.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.credentialrequeststatus; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Response; + +import java.time.Instant; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Consumes(APPLICATION_JSON) +@Produces(APPLICATION_JSON) +@Path("/v1alpha/requests") +public class CredentialRequestStatusApiController implements CredentialRequestStatusApi { + + @GET + @Path("/{credentialRequestId}") + @Override + public Response requestCredential(@PathParam("credentialRequestId") String credentialRequestId) { + if (credentialRequestId == null || credentialRequestId.isEmpty()) { + return Response.status(400).build(); + } + return Response.ok(CredentialRequestStatus.Builder.newInstance() + .message("dummy-message") + .requestId("dummy-request-id") + .requestStatus("RECEIVED") + .timestamp(Instant.now()).build()) + .build(); + } +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadata.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadata.java new file mode 100644 index 000000000..a7b696dcf --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadata.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.issuermetadata; + +public class IssuerMetadata { + // todo: implement +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadataApi.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadataApi.java new file mode 100644 index 000000000..d89a92e5f --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadataApi.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.issuermetadata; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.ws.rs.core.Response; + +@OpenAPIDefinition( + info = @Info(description = "This API provides information about the capabilities of this issuer. " + + "Specifically, it provides information about supported credentials, profiles and binding methods." + + "This API is publicly available without Authentication.", + title = "Issuer Metadata API", + version = "v1alpha")) +public interface IssuerMetadataApi { + + @Tag(name = "Issuer Metadata API") + @Operation(description = "Requests information about the capabilities of this issuer.", + operationId = "getIssuerMetadata", + responses = { + @ApiResponse(responseCode = "200", description = "Gets the issuer metadata.", + content = @Content(schema = @Schema(implementation = IssuerMetadata.class))) + } + ) + Response getIssuerMetadata(); +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadataApiController.java b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadataApiController.java new file mode 100644 index 000000000..a7b2732bc --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/java/org/eclipse/edc/identityhub/protocols/dcp/issuer/api/v1alpha/issuermetadata/IssuerMetadataApiController.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.protocols.dcp.issuer.api.v1alpha.issuermetadata; + +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Response; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +@Consumes(APPLICATION_JSON) +@Produces(APPLICATION_JSON) +@Path("/v1alpha/.well-known/vci") +public class IssuerMetadataApiController implements IssuerMetadataApi { + + @GET + @Path("/") + @Override + public Response getIssuerMetadata() { + return Response.ok(new IssuerMetadata()).build(); + } +} diff --git a/extensions/protocols/dcp/issuer-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/protocols/dcp/issuer-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..a19d9ea3f --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,15 @@ +# +# Copyright (c) 2025 Cofinity-X +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# +# Contributors: +# Cofinity-X - initial API and implementation +# +# + +org.eclipse.edc.identityhub.protocols.dcp.issuer.IssuerApiExtension \ No newline at end of file diff --git a/extensions/protocols/dcp/issuer-api/src/main/resources/issuer-api-version.json b/extensions/protocols/dcp/issuer-api/src/main/resources/issuer-api-version.json new file mode 100644 index 000000000..d292a3b51 --- /dev/null +++ b/extensions/protocols/dcp/issuer-api/src/main/resources/issuer-api-version.json @@ -0,0 +1,8 @@ +[ + { + "version": "1.0.0", + "urlPath": "/v1alpha", + "lastUpdated": "2025-01-17T12:00:00Z", + "maturity": null + } +] \ No newline at end of file diff --git a/extensions/protocols/dcp/presentation-api/src/main/resources/presentation-api-version.json b/extensions/protocols/dcp/presentation-api/src/main/resources/presentation-api-version.json index 097430628..56e8cb56c 100644 --- a/extensions/protocols/dcp/presentation-api/src/main/resources/presentation-api-version.json +++ b/extensions/protocols/dcp/presentation-api/src/main/resources/presentation-api-version.json @@ -2,7 +2,7 @@ { "version": "1.0.0", "urlPath": "/v1", - "lastUpdated": "2025-01-16T12:00:00Z", + "lastUpdated": "2025-01-17T12:00:00Z", "maturity": "stable" } ] \ No newline at end of file diff --git a/launcher/identityhub/Dockerfile b/launcher/identityhub/Dockerfile index 60fd63c48..dd6995e4f 100644 --- a/launcher/identityhub/Dockerfile +++ b/launcher/identityhub/Dockerfile @@ -22,5 +22,4 @@ HEALTHCHECK --interval=5s --timeout=5s --retries=10 CMD curl --fail http://local # Use "exec" for graceful termination (SIGINT) to reach JVM. # ARG can not be used in ENTRYPOINT so storing value in an ENV variable ENV ENV_JVM_ARGS=$JVM_ARGS -ENV ENV_APPINSIGHTS_AGENT_VERSION=$APPINSIGHTS_AGENT_VERSION ENTRYPOINT [ "sh", "-c", "exec java $ENV_JVM_ARGS -jar identity-hub.jar"] \ No newline at end of file diff --git a/launcher/issuer-service/Dockerfile b/launcher/issuer-service/Dockerfile new file mode 100644 index 000000000..eb1995bdd --- /dev/null +++ b/launcher/issuer-service/Dockerfile @@ -0,0 +1,25 @@ +# -buster is required to have apt available +FROM openjdk:17-slim-buster + +# Optional JVM arguments, such as memory settings +ARG JVM_ARGS="" + +RUN apt update \ + && apt install -y curl \ + && rm -rf /var/cache/apt/archives /var/lib/apt/lists + +WORKDIR /app + +COPY ./build/libs/issuer-service.jar /app + +EXPOSE 8188 + +ENV WEB_HTTP_PORT="8181" +ENV WEB_HTTP_PATH="/api" + +HEALTHCHECK --interval=5s --timeout=5s --retries=10 CMD curl --fail http://localhost:8181/api/check/health + +# Use "exec" for graceful termination (SIGINT) to reach JVM. +# ARG can not be used in ENTRYPOINT so storing value in an ENV variable +ENV ENV_JVM_ARGS=$JVM_ARGS +ENTRYPOINT [ "sh", "-c", "exec java $ENV_JVM_ARGS -jar issuer-service.jar"] \ No newline at end of file diff --git a/launcher/issuer-service/build.gradle.kts b/launcher/issuer-service/build.gradle.kts new file mode 100644 index 000000000..61a9023be --- /dev/null +++ b/launcher/issuer-service/build.gradle.kts @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + + +plugins { + `java-library` + id("application") + alias(libs.plugins.shadow) +} + +dependencies { + runtimeOnly(project(":dist:bom:issuerservice-bom")) +} + +application { + mainClass.set("org.eclipse.edc.boot.system.runtime.BaseRuntime") +} + +tasks.withType { + exclude("**/pom.properties", "**/pom.xm") + mergeServiceFiles() + archiveFileName.set("issuer-service.jar") +} + +edcBuild { + publish.set(false) +} diff --git a/resources/openapi/issuer-api.version b/resources/openapi/issuer-api.version new file mode 100644 index 000000000..d1fae9b90 --- /dev/null +++ b/resources/openapi/issuer-api.version @@ -0,0 +1 @@ +extensions/protocols/dcp/issuer-api/src/main/resources/issuer-api-version.json \ No newline at end of file diff --git a/resources/openapi/presentation-api.version b/resources/openapi/presentation-api.version index 0d7896eb5..6450a7022 100644 --- a/resources/openapi/presentation-api.version +++ b/resources/openapi/presentation-api.version @@ -1 +1 @@ -core/presentation-api/src/main/resources/presentation-api-version.json \ No newline at end of file +extensions/protocols/dcp/presentation-api/src/main/resources/presentation-api-version.json \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 6bbe78816..d7a429a8f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -42,7 +42,6 @@ include(":core:lib:keypair-lib") include(":core:lib:accesstoken-lib") // extension modules -include(":extensions:protocols:dcp:presentation-api") include(":extensions:store:sql:identity-hub-did-store-sql") include(":extensions:store:sql:identity-hub-credentials-store-sql") include(":extensions:store:sql:identity-hub-participantcontext-store-sql") @@ -53,6 +52,10 @@ include(":extensions:sts:sts-account-provisioner") include(":extensions:sts:sts-account-service-local") include(":extensions:sts:sts-account-service-remote") +// DCP protocol modules +include(":extensions:protocols:dcp:presentation-api") +include(":extensions:protocols:dcp:issuer-api") + // Identity APIs include(":extensions:api:identity-api:validators") include(":extensions:api:identity-api:api-configuration") @@ -69,6 +72,7 @@ include(":extensions:api:identity-api:validators:verifiable-credential-validator // other modules include(":launcher:identityhub") +include(":launcher:issuer-service") include(":version-catalog") // test modules @@ -84,4 +88,7 @@ include(":dist:bom:identityhub-base-bom") include(":dist:bom:identityhub-bom") include(":dist:bom:identityhub-with-sts-bom") include(":dist:bom:identityhub-feature-sql-bom") -include(":dist:bom:identityhub-feature-sql-sts-bom") \ No newline at end of file +include(":dist:bom:identityhub-feature-sql-sts-bom") +include(":dist:bom:issuerservice-base-bom") +include(":dist:bom:issuerservice-bom") +include(":dist:bom:issuerservice-feature-sql-bom") \ No newline at end of file diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/webcontext/IdentityHubApiContext.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/webcontext/IdentityHubApiContext.java index 14af86fb8..0a3b054fb 100644 --- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/webcontext/IdentityHubApiContext.java +++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/webcontext/IdentityHubApiContext.java @@ -18,6 +18,7 @@ public interface IdentityHubApiContext { String IDENTITY = "identity"; String IH_DID = "did"; String PRESENTATION = "presentation"; + String ISSUER_API = "issuer-api"; @Deprecated(since = "0.9.0") String RESOLUTION = "resolution"; }