-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add Credential Request API + issuer service skeleton
- Loading branch information
1 parent
bca2455
commit f73a831
Showing
34 changed files
with
3,246 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) | ||
* | ||
* 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: | ||
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - 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:credential-request-api")) | ||
runtimeOnly(project(":extensions:protocols:dcp:credential-request-status-api")) | ||
runtimeOnly(project(":extensions:protocols:dcp:issuer-metadata-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 { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) | ||
* | ||
* 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: | ||
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation | ||
* | ||
*/ | ||
|
||
plugins { | ||
`java-library` | ||
} | ||
|
||
dependencies { | ||
runtimeOnly(project(":dist:bom:issuerservice-base-bom")) | ||
runtimeOnly(project(":extensions:sts:sts-account-service-remote")) | ||
} | ||
|
||
edcBuild { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Copyright (c) 2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) | ||
* | ||
* 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: | ||
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - 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 { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
extensions/protocols/dcp/credential-request-api/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) | ||
* | ||
* 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: | ||
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - 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("credential-request-api") | ||
} | ||
} |
92 changes: 92 additions & 0 deletions
92
...n/java/org/eclipse/edc/protocols/dcp/credentialrequest/CredentialRequestApiExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* 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.protocols.dcp.credentialrequest; | ||
|
||
import com.fasterxml.jackson.databind.DeserializationFeature; | ||
import org.eclipse.edc.protocols.dcp.credentialrequest.v1alpha.api.CredentialRequestApiController; | ||
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.spi.webcontext.IdentityHubApiContext.CREDENTIAL_REQUEST; | ||
import static org.eclipse.edc.protocols.dcp.credentialrequest.CredentialRequestApiExtension.NAME; | ||
|
||
@Extension(value = NAME) | ||
public class CredentialRequestApiExtension implements ServiceExtension { | ||
public static final String NAME = "CredentialRequestApiExtension"; | ||
|
||
private static final String API_VERSION_JSON_FILE = "credential-request-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(CREDENTIAL_REQUEST, apiConfiguration.port(), apiConfiguration.path())); | ||
|
||
var controller = new CredentialRequestApiController(); | ||
webService.registerResource(CREDENTIAL_REQUEST, controller); | ||
|
||
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("credential-request", vr)); | ||
} catch (IOException e) { | ||
throw new EdcException(e); | ||
} | ||
} | ||
|
||
@Settings | ||
record CredentialRequestApiConfiguration( | ||
@Setting(key = "web.http." + CREDENTIAL_REQUEST + ".port", description = "Port for " + CREDENTIAL_REQUEST + " api context", defaultValue = 13132 + "") | ||
int port, | ||
@Setting(key = "web.http." + CREDENTIAL_REQUEST + ".path", description = "Path for " + CREDENTIAL_REQUEST + " api context", defaultValue = "/api/issuance") | ||
String path | ||
) { | ||
|
||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
.../src/main/java/org/eclipse/edc/protocols/dcp/credentialrequest/v1alpha/api/ApiSchema.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.protocols.dcp.credentialrequest.v1alpha.api; | ||
|
||
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" | ||
} | ||
"""; | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
...ava/org/eclipse/edc/protocols/dcp/credentialrequest/v1alpha/api/CredentialRequestApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.protocols.dcp.credentialrequest.v1alpha.api; | ||
|
||
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.protocols.dcp.credentialrequest.v1alpha.model.CredentialRequestMessage; | ||
|
||
@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); | ||
} |
Oops, something went wrong.