-
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 Management API for KeyPairResources
- Loading branch information
1 parent
3928c05
commit a10c644
Showing
16 changed files
with
570 additions
and
16 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
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,19 @@ | ||
plugins { | ||
`java-library` | ||
`maven-publish` | ||
id("io.swagger.core.v3.swagger-gradle-plugin") | ||
} | ||
|
||
dependencies { | ||
api(libs.edc.spi.core) | ||
api(project(":spi:identity-hub-spi")) | ||
api(project(":spi:identity-hub-store-spi")) | ||
implementation(project(":extensions:api:identityhub-management-api-configuration")) | ||
implementation(libs.edc.spi.web) | ||
implementation(libs.edc.util) | ||
implementation(libs.jakarta.rsApi) | ||
|
||
testImplementation(libs.edc.junit) | ||
testImplementation(libs.restAssured) | ||
testImplementation(testFixtures(libs.edc.core.jersey)) | ||
} |
44 changes: 44 additions & 0 deletions
44
...ipse/edc/identityhub/api/verifiablecredentials/KeyPairResourceManagementApiExtension.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,44 @@ | ||
/* | ||
* Copyright (c) 2024 Metaform Systems, Inc. | ||
* | ||
* 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: | ||
* Metaform Systems, Inc. - initial API and implementation | ||
* | ||
*/ | ||
|
||
package org.eclipse.edc.identityhub.api.verifiablecredentials; | ||
|
||
import org.eclipse.edc.identityhub.api.configuration.ManagementApiConfiguration; | ||
import org.eclipse.edc.identityhub.api.verifiablecredentials.v1.KeyPairResourceApiController; | ||
import org.eclipse.edc.identityhub.spi.KeyPairService; | ||
import org.eclipse.edc.runtime.metamodel.annotation.Extension; | ||
import org.eclipse.edc.runtime.metamodel.annotation.Inject; | ||
import org.eclipse.edc.spi.system.ServiceExtension; | ||
import org.eclipse.edc.spi.system.ServiceExtensionContext; | ||
import org.eclipse.edc.web.spi.WebService; | ||
|
||
import static org.eclipse.edc.identityhub.api.verifiablecredentials.KeyPairResourceManagementApiExtension.NAME; | ||
|
||
@Extension(NAME) | ||
public class KeyPairResourceManagementApiExtension implements ServiceExtension { | ||
public static final String NAME = "KeyPairResource Management API Extension"; | ||
|
||
@Inject | ||
private ManagementApiConfiguration apiConfiguration; | ||
@Inject | ||
private WebService webService; | ||
@Inject | ||
private KeyPairService keyPairService; | ||
|
||
@Override | ||
public void initialize(ServiceExtensionContext context) { | ||
var controller = new KeyPairResourceApiController(keyPairService); | ||
webService.registerResource(apiConfiguration.getContextAlias(), controller); | ||
} | ||
} |
117 changes: 117 additions & 0 deletions
117
...ain/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApi.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,117 @@ | ||
/* | ||
* Copyright (c) 2024 Metaform Systems, Inc. | ||
* | ||
* 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: | ||
* Metaform Systems, Inc. - initial API and implementation | ||
* | ||
*/ | ||
|
||
package org.eclipse.edc.identityhub.api.verifiablecredentials.v1; | ||
|
||
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.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.tags.Tag; | ||
import org.eclipse.edc.identityhub.spi.model.KeyPairResource; | ||
import org.eclipse.edc.identityhub.spi.model.participant.KeyDescriptor; | ||
import org.eclipse.edc.identityhub.spi.model.participant.ParticipantContext; | ||
import org.eclipse.edc.web.spi.ApiErrorDetail; | ||
|
||
import java.util.Collection; | ||
|
||
@OpenAPIDefinition(info = @Info(description = "This is the Management API for KeyPairResources", title = "KeyPairResources Management API", version = "1")) | ||
public interface KeyPairResourceApi { | ||
|
||
@Tag(name = "KeyPairResources Management API") | ||
@Operation(description = "Finds a KeyPairResource by ID.", | ||
responses = { | ||
@ApiResponse(responseCode = "200", description = "The KeyPairResource.", | ||
content = @Content(schema = @Schema(implementation = ParticipantContext.class))), | ||
@ApiResponse(responseCode = "400", description = "Request body was malformed, or the request could not be processed", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "401", description = "The request could not be completed, because either the authentication was missing or was not valid.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "404", description = "A KeyPairResource with the given ID does not exist.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")) | ||
} | ||
) | ||
KeyPairResource findById(String id); | ||
|
||
@Tag(name = "KeyPairResources Management API") | ||
@Operation(description = "Finds all KeyPairResources for a particular ParticipantContext.", | ||
parameters = @Parameter(name = "participantId", description = "ID of the participant context for which to list the keys. May need elevated rights."), | ||
responses = { | ||
@ApiResponse(responseCode = "200", description = "The KeyPairResource.", | ||
content = @Content(schema = @Schema(implementation = ParticipantContext.class))), | ||
@ApiResponse(responseCode = "400", description = "Request body was malformed, or the request could not be processed", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "401", description = "The request could not be completed, because either the authentication was missing or was not valid.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "404", description = "A KeyPairResource with the given ID does not exist.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")) | ||
} | ||
) | ||
Collection<KeyPairResource> findForParticipant(String participantId); | ||
|
||
@Tag(name = "KeyPairResources Management API") | ||
@Operation(description = "Adds a new key pair to a ParticipantContext. Note that the key pair is either generated, or the private key is expected to be found in the vault.", | ||
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = KeyDescriptor.class), mediaType = "application/json")), | ||
parameters = @Parameter(name = "makeDefault", description = "Make the new key pair the default key pair"), | ||
responses = { | ||
@ApiResponse(responseCode = "200", description = "The KeyPairResource was successfully created and linked to the participant.", | ||
content = @Content(schema = @Schema(implementation = ParticipantContext.class))), | ||
@ApiResponse(responseCode = "400", description = "Request body was malformed, or the request could not be processed", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "401", description = "The request could not be completed, because either the authentication was missing or was not valid.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "404", description = "A KeyPairResource with the given ID does not exist.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")) | ||
} | ||
) | ||
void addKeyPair(String participantId, KeyDescriptor keyDescriptor, boolean makeDefault); | ||
|
||
@Tag(name = "KeyPairResources Management API") | ||
@Operation(description = "Rotates (=retires) a particular key pair, identified by their ID and create a new successor key.", | ||
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = KeyDescriptor.class), mediaType = "application/json")), | ||
parameters = @Parameter(name = "duration", description = "Indicates for how long the public key of the rotated/retired key pair should still be available "), | ||
responses = { | ||
@ApiResponse(responseCode = "200", description = "The KeyPairResource was successfully rotated and linked to the participant.", | ||
content = @Content(schema = @Schema(implementation = ParticipantContext.class))), | ||
@ApiResponse(responseCode = "400", description = "Request body was malformed, or the request could not be processed", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "401", description = "The request could not be completed, because either the authentication was missing or was not valid.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "404", description = "A KeyPairResource with the given ID does not exist.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")) | ||
} | ||
) | ||
void rotateKeyPair(String id, KeyDescriptor newKey, long duration); | ||
|
||
@Tag(name = "KeyPairResources Management API") | ||
@Operation(description = "Revokes (=removes) a particular key pair, identified by their ID and create a new successor key.", | ||
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = KeyDescriptor.class), mediaType = "application/json")), | ||
responses = { | ||
@ApiResponse(responseCode = "200", description = "The KeyPairResource was successfully rotated and linked to the participant.", | ||
content = @Content(schema = @Schema(implementation = ParticipantContext.class))), | ||
@ApiResponse(responseCode = "400", description = "Request body was malformed, or the request could not be processed", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "401", description = "The request could not be completed, because either the authentication was missing or was not valid.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "404", description = "A KeyPairResource with the given ID does not exist.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")) | ||
} | ||
) | ||
void revokeKey(String id, KeyDescriptor newKey); | ||
} |
95 changes: 95 additions & 0 deletions
95
...rg/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApiController.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,95 @@ | ||
/* | ||
* Copyright (c) 2024 Metaform Systems, Inc. | ||
* | ||
* 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: | ||
* Metaform Systems, Inc. - initial API and implementation | ||
* | ||
*/ | ||
|
||
package org.eclipse.edc.identityhub.api.verifiablecredentials.v1; | ||
|
||
import jakarta.ws.rs.Consumes; | ||
import jakarta.ws.rs.GET; | ||
import jakarta.ws.rs.POST; | ||
import jakarta.ws.rs.PUT; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.PathParam; | ||
import jakarta.ws.rs.Produces; | ||
import jakarta.ws.rs.QueryParam; | ||
import org.eclipse.edc.identityhub.spi.KeyPairService; | ||
import org.eclipse.edc.identityhub.spi.model.KeyPairResource; | ||
import org.eclipse.edc.identityhub.spi.model.participant.KeyDescriptor; | ||
import org.eclipse.edc.spi.EdcException; | ||
import org.eclipse.edc.spi.query.Criterion; | ||
import org.eclipse.edc.spi.query.QuerySpec; | ||
import org.eclipse.edc.web.spi.exception.ObjectNotFoundException; | ||
|
||
import java.util.Collection; | ||
|
||
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; | ||
import static org.eclipse.edc.web.spi.exception.ServiceResultHandler.exceptionMapper; | ||
|
||
@Consumes(APPLICATION_JSON) | ||
@Produces(APPLICATION_JSON) | ||
@Path("/v1/keypairs") | ||
public class KeyPairResourceApiController implements KeyPairResourceApi { | ||
|
||
|
||
private final KeyPairService keyPairService; | ||
|
||
public KeyPairResourceApiController(KeyPairService keyPairService) { | ||
|
||
this.keyPairService = keyPairService; | ||
} | ||
|
||
@GET | ||
@Path("/{keyPairId}") | ||
@Override | ||
public KeyPairResource findById(@PathParam("keyPairId") String id) { | ||
var query = QuerySpec.Builder.newInstance().filter(new Criterion("id", "=", id)).build(); | ||
var result = keyPairService.query(query).orElseThrow(exceptionMapper(KeyPairResource.class, id)); | ||
if (result.isEmpty()) { | ||
throw new ObjectNotFoundException(KeyPairResource.class, id); | ||
} | ||
if (result.size() > 1) { | ||
throw new EdcException("Expected only 1 result, but got %s".formatted(result.size())); | ||
} | ||
return result.iterator().next(); | ||
} | ||
|
||
@GET | ||
@Override | ||
public Collection<KeyPairResource> findForParticipant(@QueryParam("participantId") String participantId) { | ||
var query = QuerySpec.Builder.newInstance().filter(new Criterion("participantId", "=", participantId)).build(); | ||
return keyPairService.query(query).orElseThrow(exceptionMapper(KeyPairResource.class, participantId)); | ||
} | ||
|
||
@PUT | ||
@Override | ||
public void addKeyPair(@QueryParam("participantId") String participantId, KeyDescriptor keyDescriptor, @QueryParam("makeDefault") boolean makeDefault) { | ||
keyPairService.addKeyPair(participantId, keyDescriptor, makeDefault) | ||
.orElseThrow(exceptionMapper(KeyPairResource.class)); | ||
} | ||
|
||
@POST | ||
@Path("/{keyPairId}/rotate") | ||
@Override | ||
public void rotateKeyPair(@PathParam("keyPairId") String id, KeyDescriptor newKey, @QueryParam("duration") long duration) { | ||
keyPairService.rotateKeyPair(id, newKey, duration) | ||
.orElseThrow(exceptionMapper(KeyPairResource.class, id)); | ||
} | ||
|
||
@POST | ||
@Path("/{keyPairId}/revoke") | ||
@Override | ||
public void revokeKey(@PathParam("keyPairId") String id, KeyDescriptor newKey) { | ||
keyPairService.revokeKey(id, newKey) | ||
.orElseThrow(exceptionMapper(KeyPairResource.class, id)); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
...mgmt-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension
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,15 @@ | ||
# | ||
# Copyright (c) 2024 Metaform Systems, Inc. | ||
# | ||
# 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: | ||
# Metaform Systems, Inc. - initial API and implementation | ||
# | ||
# | ||
|
||
org.eclipse.edc.identityhub.api.verifiablecredentials.KeyPairResourceManagementApiExtension |
Oops, something went wrong.