diff --git a/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/PresentationApiExtension.java b/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/PresentationApiExtension.java
index 1be8f5d89..5daf6877c 100644
--- a/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/PresentationApiExtension.java
+++ b/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/PresentationApiExtension.java
@@ -21,7 +21,7 @@
import org.eclipse.edc.identityhub.spi.generator.VerifiablePresentationService;
import org.eclipse.edc.identityhub.spi.resolution.CredentialQueryResolver;
import org.eclipse.edc.identityhub.spi.verification.AccessTokenVerifier;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage;
import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
@@ -68,7 +68,7 @@ public String name() {
@Override
public void initialize(ServiceExtensionContext context) {
// setup validator
- validatorRegistry.register(PresentationQuery.PRESENTATION_QUERY_TYPE_PROPERTY, new PresentationQueryValidator());
+ validatorRegistry.register(PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY, new PresentationQueryValidator());
var controller = new PresentationApiController(validatorRegistry, typeTransformer, credentialResolver, accessTokenVerifier, verifiablePresentationService, context.getMonitor());
diff --git a/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/v1/PresentationApi.java b/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/v1/PresentationApi.java
index cf2738d52..1015bdea6 100644
--- a/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/v1/PresentationApi.java
+++ b/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/v1/PresentationApi.java
@@ -28,7 +28,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.json.JsonObject;
import jakarta.ws.rs.core.Response;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponse;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponseMessage;
@OpenAPIDefinition(
info = @Info(description = "This represents the Presentation API as per IATP specification. It serves endpoints to query for specific VerifiablePresentations.", title = "Resolution API",
@@ -45,13 +45,13 @@ public interface PresentationApi {
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = ApiSchema.PresentationQuerySchema.class), mediaType = "application/ld+json")),
responses = {
@ApiResponse(responseCode = "200", description = "The query was successfully processed, the response contains the VerifiablePresentation",
- content = @Content(schema = @Schema(implementation = PresentationResponse.class), mediaType = "application/ld+json")),
+ content = @Content(schema = @Schema(implementation = PresentationResponseMessage.class), mediaType = "application/ld+json")),
@ApiResponse(responseCode = "400", description = "Request body was malformed, for example when both scope and presentationDefinition are given",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)), mediaType = "application/json")),
@ApiResponse(responseCode = "401", description = "No Authorization header was given.",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)), mediaType = "application/json")),
@ApiResponse(responseCode = "403", description = "The given authentication token could not be validated. This can happen, when the request body " +
- "calls for a broader query scope than the granted scope in the auth token",
+ "calls for a broader query scope than the granted scope in the auth token",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)), mediaType = "application/json")),
@ApiResponse(responseCode = "501", description = "When the request contained a presentationDefinition object, but the implementation does not support it.",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiSchema.ApiErrorDetailSchema.class)), mediaType = "application/json"))
diff --git a/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/v1/PresentationApiController.java b/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/v1/PresentationApiController.java
index 1a6ce92dd..acdd9c0cd 100644
--- a/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/v1/PresentationApiController.java
+++ b/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/v1/PresentationApiController.java
@@ -25,7 +25,7 @@
import org.eclipse.edc.identityhub.spi.generator.VerifiablePresentationService;
import org.eclipse.edc.identityhub.spi.resolution.CredentialQueryResolver;
import org.eclipse.edc.identityhub.spi.verification.AccessTokenVerifier;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
@@ -42,7 +42,7 @@
import static jakarta.ws.rs.core.HttpHeaders.AUTHORIZATION;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
-import static org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery.PRESENTATION_QUERY_TYPE_PROPERTY;
+import static org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY;
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@@ -74,9 +74,9 @@ public Response queryPresentation(JsonObject query, @HeaderParam(AUTHORIZATION)
if (token == null) {
throw new AuthenticationFailedException("Authorization header missing");
}
- validatorRegistry.validate(PRESENTATION_QUERY_TYPE_PROPERTY, query).orElseThrow(ValidationFailureException::new);
+ validatorRegistry.validate(PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY, query).orElseThrow(ValidationFailureException::new);
- var presentationQuery = transformerRegistry.transform(query, PresentationQuery.class).orElseThrow(InvalidRequestException::new);
+ var presentationQuery = transformerRegistry.transform(query, PresentationQueryMessage.class).orElseThrow(InvalidRequestException::new);
if (presentationQuery.getPresentationDefinition() != null) {
monitor.warning("DIF Presentation Queries are not supported yet. This will get implemented in future iterations.");
diff --git a/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/validation/PresentationQueryValidator.java b/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/validation/PresentationQueryValidator.java
index 504a0d114..eb9822e6a 100644
--- a/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/validation/PresentationQueryValidator.java
+++ b/core/identity-hub-api/src/main/java/org/eclipse/edc/identityhub/api/validation/PresentationQueryValidator.java
@@ -17,7 +17,7 @@
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage;
import org.eclipse.edc.jsonld.spi.JsonLdKeywords;
import org.eclipse.edc.validator.spi.ValidationResult;
import org.eclipse.edc.validator.spi.Validator;
@@ -27,7 +27,7 @@
import static org.eclipse.edc.validator.spi.Violation.violation;
/**
- * Validates, that a JsonObject representing a {@link PresentationQuery} contains either a {@code scope} property,
+ * Validates, that a JsonObject representing a {@link PresentationQueryMessage} contains either a {@code scope} property,
* or a {@code presentationDefinition} query.
*/
public class PresentationQueryValidator implements Validator {
@@ -36,9 +36,9 @@ public ValidationResult validate(JsonObject input) {
if (input == null) {
return failure(violation("Presentation query was null", "."));
}
- var scope = input.get(PresentationQuery.PRESENTATION_QUERY_SCOPE_PROPERTY);
+ var scope = input.get(PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_SCOPE_PROPERTY);
- var presentationDef = input.get(PresentationQuery.PRESENTATION_QUERY_DEFINITION_PROPERTY);
+ var presentationDef = input.get(PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_DEFINITION_PROPERTY);
if (isNullObject(scope) && isNullObject(presentationDef)) {
return failure(violation("Must contain either a 'scope' or a 'presentationDefinition' property.", null));
diff --git a/core/identity-hub-api/src/test/java/org/eclipse/edc/identityservice/api/v1/PresentationApiControllerTest.java b/core/identity-hub-api/src/test/java/org/eclipse/edc/identityservice/api/v1/PresentationApiControllerTest.java
index 24c8108f2..a7a272ad9 100644
--- a/core/identity-hub-api/src/test/java/org/eclipse/edc/identityservice/api/v1/PresentationApiControllerTest.java
+++ b/core/identity-hub-api/src/test/java/org/eclipse/edc/identityservice/api/v1/PresentationApiControllerTest.java
@@ -22,8 +22,8 @@
import org.eclipse.edc.identityhub.spi.resolution.QueryResult;
import org.eclipse.edc.identityhub.spi.verification.AccessTokenVerifier;
import org.eclipse.edc.identitytrust.model.credentialservice.InputDescriptorMapping;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponse;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponseMessage;
import org.eclipse.edc.identitytrust.model.credentialservice.PresentationSubmission;
import org.eclipse.edc.identitytrust.model.presentationdefinition.PresentationDefinition;
import org.eclipse.edc.junit.annotations.ApiTest;
@@ -51,7 +51,7 @@
import static org.eclipse.edc.identityhub.junit.testfixtures.VerifiableCredentialTestUtil.buildSignedJwt;
import static org.eclipse.edc.identityhub.junit.testfixtures.VerifiableCredentialTestUtil.generateEcKey;
import static org.eclipse.edc.identityhub.spi.resolution.QueryResult.success;
-import static org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery.PRESENTATION_QUERY_TYPE_PROPERTY;
+import static org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY;
import static org.eclipse.edc.validator.spi.ValidationResult.failure;
import static org.eclipse.edc.validator.spi.ValidationResult.success;
import static org.eclipse.edc.validator.spi.Violation.violation;
@@ -84,7 +84,7 @@ void query_tokenNotPresent_shouldReturn401() {
@Test
void query_validationError_shouldReturn400() {
- when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_TYPE_PROPERTY), any())).thenReturn(failure(violation("foo", "bar")));
+ when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY), any())).thenReturn(failure(violation("foo", "bar")));
assertThatThrownBy(() -> controller().queryPresentation(createObjectBuilder().build(), generateJwt()))
.isInstanceOf(ValidationFailureException.class)
@@ -93,8 +93,8 @@ void query_validationError_shouldReturn400() {
@Test
void query_transformationError_shouldReturn400() {
- when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_TYPE_PROPERTY), any())).thenReturn(success());
- when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQuery.class))).thenReturn(Result.failure("cannot transform"));
+ when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY), any())).thenReturn(success());
+ when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQueryMessage.class))).thenReturn(Result.failure("cannot transform"));
assertThatThrownBy(() -> controller().queryPresentation(createObjectBuilder().build(), generateJwt()))
.isInstanceOf(InvalidRequestException.class)
@@ -104,10 +104,10 @@ void query_transformationError_shouldReturn400() {
@Test
void query_withPresentationDefinition_shouldReturn501() {
- when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_TYPE_PROPERTY), any())).thenReturn(success());
+ when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY), any())).thenReturn(success());
var presentationQueryBuilder = createPresentationQueryBuilder()
.presentationDefinition(PresentationDefinition.Builder.newInstance().id(UUID.randomUUID().toString()).build());
- when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQuery.class))).thenReturn(Result.success(presentationQueryBuilder.build()));
+ when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQueryMessage.class))).thenReturn(Result.success(presentationQueryBuilder.build()));
var response = controller().queryPresentation(createObjectBuilder().build(), generateJwt());
assertThat(response.getStatus()).isEqualTo(503);
@@ -121,9 +121,9 @@ void query_withPresentationDefinition_shouldReturn501() {
@Test
void query_tokenVerificationFails_shouldReturn401() {
- when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_TYPE_PROPERTY), any())).thenReturn(success());
+ when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY), any())).thenReturn(success());
var presentationQueryBuilder = createPresentationQueryBuilder().build();
- when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQuery.class))).thenReturn(Result.success(presentationQueryBuilder));
+ when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQueryMessage.class))).thenReturn(Result.success(presentationQueryBuilder));
when(accessTokenVerifier.verify(anyString())).thenReturn(Result.failure("test-failure"));
assertThatThrownBy(() -> controller().queryPresentation(createObjectBuilder().build(), generateJwt()))
@@ -134,9 +134,9 @@ void query_tokenVerificationFails_shouldReturn401() {
@Test
void query_queryResolutionFails_shouldReturn403() {
- when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_TYPE_PROPERTY), any())).thenReturn(success());
+ when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY), any())).thenReturn(success());
var presentationQueryBuilder = createPresentationQueryBuilder().build();
- when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQuery.class))).thenReturn(Result.success(presentationQueryBuilder));
+ when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQueryMessage.class))).thenReturn(Result.success(presentationQueryBuilder));
when(accessTokenVerifier.verify(anyString())).thenReturn(Result.success(List.of("test-scope1")));
when(queryResolver.query(any(), eq(List.of("test-scope1")))).thenReturn(QueryResult.unauthorized("test-failure"));
@@ -148,9 +148,9 @@ void query_queryResolutionFails_shouldReturn403() {
@Test
void query_presentationGenerationFails_shouldReturn500() {
- when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_TYPE_PROPERTY), any())).thenReturn(success());
+ when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY), any())).thenReturn(success());
var presentationQueryBuilder = createPresentationQueryBuilder().build();
- when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQuery.class))).thenReturn(Result.success(presentationQueryBuilder));
+ when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQueryMessage.class))).thenReturn(Result.success(presentationQueryBuilder));
when(accessTokenVerifier.verify(anyString())).thenReturn(Result.success(List.of("test-scope1")));
when(queryResolver.query(any(), eq(List.of("test-scope1")))).thenReturn(success(Stream.empty()));
@@ -163,13 +163,15 @@ void query_presentationGenerationFails_shouldReturn500() {
@Test
void query_success() {
- when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_TYPE_PROPERTY), any())).thenReturn(success());
+ when(validatorRegistryMock.validate(eq(PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY), any())).thenReturn(success());
var presentationQueryBuilder = createPresentationQueryBuilder().build();
- when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQuery.class))).thenReturn(Result.success(presentationQueryBuilder));
+ when(typeTransformerRegistry.transform(isA(JsonObject.class), eq(PresentationQueryMessage.class))).thenReturn(Result.success(presentationQueryBuilder));
when(accessTokenVerifier.verify(anyString())).thenReturn(Result.success(List.of("test-scope1")));
when(queryResolver.query(any(), eq(List.of("test-scope1")))).thenReturn(success(Stream.empty()));
- var pres = new PresentationResponse(new Object[] {generateJwt()}, new PresentationSubmission("id", "def-id", List.of(new InputDescriptorMapping("id", "ldp_vp", "$.verifiableCredentials[0]"))));
+ var pres = PresentationResponseMessage.Builder.newinstance().presentation(List.of(generateJwt()))
+ .presentationSubmission(new PresentationSubmission("id", "def-id", List.of(new InputDescriptorMapping("id", "ldp_vp", "$.verifiableCredentials[0]"))))
+ .build();
when(generator.createPresentation(anyList(), any(), any())).thenReturn(Result.success(pres));
var response = controller().queryPresentation(createObjectBuilder().build(), generateJwt());
@@ -195,8 +197,8 @@ private String generateJwt() {
return jwt.serialize();
}
- private PresentationQuery.Builder createPresentationQueryBuilder() {
- return PresentationQuery.Builder.newinstance()
+ private PresentationQueryMessage.Builder createPresentationQueryBuilder() {
+ return PresentationQueryMessage.Builder.newinstance()
.scopes(List.of("test-scope1", "test-scope2"));
}
}
\ No newline at end of file
diff --git a/core/identity-hub-api/src/test/java/org/eclipse/edc/identityservice/api/validation/PresentationQueryValidatorTest.java b/core/identity-hub-api/src/test/java/org/eclipse/edc/identityservice/api/validation/PresentationQueryValidatorTest.java
index e5b965f86..77b0198b2 100644
--- a/core/identity-hub-api/src/test/java/org/eclipse/edc/identityservice/api/validation/PresentationQueryValidatorTest.java
+++ b/core/identity-hub-api/src/test/java/org/eclipse/edc/identityservice/api/validation/PresentationQueryValidatorTest.java
@@ -20,7 +20,7 @@
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import org.eclipse.edc.identityhub.api.validation.PresentationQueryValidator;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage;
import org.eclipse.edc.identitytrust.model.presentationdefinition.Constraints;
import org.eclipse.edc.identitytrust.model.presentationdefinition.Field;
import org.eclipse.edc.identitytrust.model.presentationdefinition.InputDescriptor;
@@ -48,7 +48,7 @@ class PresentationQueryValidatorTest {
@Test
void validate_withScope_success() {
var jo = createObjectBuilder()
- .add(PresentationQuery.PRESENTATION_QUERY_SCOPE_PROPERTY, createScopeArray())
+ .add(PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_SCOPE_PROPERTY, createScopeArray())
.build();
assertThat(validator.validate(jo)).isSucceeded();
@@ -61,7 +61,7 @@ void validate_withPresentationDefinition_success() throws JsonProcessingExceptio
.inputDescriptors(List.of(InputDescriptor.Builder.newInstance().id(UUID.randomUUID().toString()).constraints(new Constraints(List.of(Field.Builder.newInstance().build()))).build()))
.build();
var jo = createObjectBuilder()
- .add(PresentationQuery.PRESENTATION_QUERY_DEFINITION_PROPERTY, createPresentationDefArray(presDef))
+ .add(PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_DEFINITION_PROPERTY, createPresentationDefArray(presDef))
.build();
assertThat(validator.validate(jo)).isSucceeded();
@@ -81,8 +81,8 @@ void validate_withBoth_fails() throws JsonProcessingException {
.inputDescriptors(List.of(InputDescriptor.Builder.newInstance().id(UUID.randomUUID().toString()).constraints(new Constraints(List.of(Field.Builder.newInstance().build()))).build()))
.build();
var jo = createObjectBuilder()
- .add(PresentationQuery.PRESENTATION_QUERY_SCOPE_PROPERTY, createScopeArray())
- .add(PresentationQuery.PRESENTATION_QUERY_DEFINITION_PROPERTY, createPresentationDefArray(presDef))
+ .add(PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_SCOPE_PROPERTY, createScopeArray())
+ .add(PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_DEFINITION_PROPERTY, createPresentationDefArray(presDef))
.build();
assertThat(validator.validate(jo)).isFailed().detail().contains("Must contain either a 'scope' or a 'presentationDefinition', not both.");
diff --git a/core/identity-hub-credentials/src/main/java/org/eclipse/edc/identityhub/core/CredentialQueryResolverImpl.java b/core/identity-hub-credentials/src/main/java/org/eclipse/edc/identityhub/core/CredentialQueryResolverImpl.java
index 877e45281..5b07fd8a7 100644
--- a/core/identity-hub-credentials/src/main/java/org/eclipse/edc/identityhub/core/CredentialQueryResolverImpl.java
+++ b/core/identity-hub-credentials/src/main/java/org/eclipse/edc/identityhub/core/CredentialQueryResolverImpl.java
@@ -15,11 +15,11 @@
package org.eclipse.edc.identityhub.core;
import org.eclipse.edc.identityhub.spi.ScopeToCriterionTransformer;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.spi.resolution.CredentialQueryResolver;
import org.eclipse.edc.identityhub.spi.resolution.QueryResult;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
-import org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage;
import org.eclipse.edc.spi.query.Criterion;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.AbstractResult;
@@ -43,7 +43,7 @@ public CredentialQueryResolverImpl(CredentialStore credentialStore, ScopeToCrite
}
@Override
- public QueryResult query(PresentationQuery query, List issuerScopes) {
+ public QueryResult query(PresentationQueryMessage query, List issuerScopes) {
if (query.getPresentationDefinition() != null) {
throw new UnsupportedOperationException("Querying with a DIF Presentation Exchange definition is not yet supported.");
}
diff --git a/core/identity-hub-credentials/src/main/java/org/eclipse/edc/identityhub/core/VerifiablePresentationServiceImpl.java b/core/identity-hub-credentials/src/main/java/org/eclipse/edc/identityhub/core/VerifiablePresentationServiceImpl.java
index f08a1e97d..70179acb0 100644
--- a/core/identity-hub-credentials/src/main/java/org/eclipse/edc/identityhub/core/VerifiablePresentationServiceImpl.java
+++ b/core/identity-hub-credentials/src/main/java/org/eclipse/edc/identityhub/core/VerifiablePresentationServiceImpl.java
@@ -19,7 +19,7 @@
import org.eclipse.edc.identityhub.spi.generator.VerifiablePresentationService;
import org.eclipse.edc.identitytrust.model.CredentialFormat;
import org.eclipse.edc.identitytrust.model.VerifiableCredentialContainer;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponse;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponseMessage;
import org.eclipse.edc.identitytrust.model.presentationdefinition.PresentationDefinition;
import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.result.Result;
@@ -60,7 +60,7 @@ public VerifiablePresentationServiceImpl(CredentialFormat defaultFormatVp, Prese
* @return A Result object wrapping the PresentationResponse.
*/
@Override
- public Result createPresentation(List credentials, @Nullable PresentationDefinition presentationDefinition, @Nullable String audience) {
+ public Result createPresentation(List credentials, @Nullable PresentationDefinition presentationDefinition, @Nullable String audience) {
if (presentationDefinition != null) {
monitor.warning("A PresentationDefinition was submitted, but is currently ignored by the generator.");
@@ -92,7 +92,7 @@ public Result createPresentation(List implements KeyPairResourceStore {
diff --git a/core/identity-hub-credentials/src/test/java/org/eclipse/edc/identityhub/core/CredentialQueryResolverImplTest.java b/core/identity-hub-credentials/src/test/java/org/eclipse/edc/identityhub/core/CredentialQueryResolverImplTest.java
index ef6b7f0cc..ec2d4e7ab 100644
--- a/core/identity-hub-credentials/src/test/java/org/eclipse/edc/identityhub/core/CredentialQueryResolverImplTest.java
+++ b/core/identity-hub-credentials/src/test/java/org/eclipse/edc/identityhub/core/CredentialQueryResolverImplTest.java
@@ -16,15 +16,15 @@
import org.eclipse.edc.identityhub.defaults.EdcScopeToCriterionTransformer;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.spi.resolution.QueryFailure;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
-import org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource;
import org.eclipse.edc.identitytrust.model.CredentialFormat;
import org.eclipse.edc.identitytrust.model.CredentialSubject;
import org.eclipse.edc.identitytrust.model.Issuer;
import org.eclipse.edc.identitytrust.model.VerifiableCredential;
import org.eclipse.edc.identitytrust.model.VerifiableCredentialContainer;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage;
import org.eclipse.edc.identitytrust.model.presentationdefinition.PresentationDefinition;
import org.eclipse.edc.spi.result.StoreResult;
import org.jetbrains.annotations.Nullable;
@@ -110,7 +110,7 @@ void query_multipleScopeStrings() {
@Test
void query_presentationDefinition_unsupported() {
- var q = PresentationQuery.Builder.newinstance().presentationDefinition(PresentationDefinition.Builder.newInstance().id("test-pd").build()).build();
+ var q = PresentationQueryMessage.Builder.newinstance().presentationDefinition(PresentationDefinition.Builder.newInstance().id("test-pd").build()).build();
assertThatThrownBy(() -> resolver.query(q, List.of("org.eclipse.edc.vc.type:SomeCredential:read")))
.isInstanceOf(UnsupportedOperationException.class)
.hasMessage("Querying with a DIF Presentation Exchange definition is not yet supported.");
@@ -201,9 +201,9 @@ void query_storeReturnsFailure() {
assertThat(res.getFailureDetail()).isEqualTo("test-failure");
}
- private PresentationQuery createPresentationQuery(@Nullable String... scope) {
+ private PresentationQueryMessage createPresentationQuery(@Nullable String... scope) {
var scopes = new ArrayList<>(Arrays.asList(scope));
- return PresentationQuery.Builder.newinstance().scopes(scopes).build();
+ return PresentationQueryMessage.Builder.newinstance().scopes(scopes).build();
}
private VerifiableCredentialResource createCredentialResource(String... type) {
diff --git a/core/identity-hub-credentials/src/test/java/org/eclipse/edc/identityhub/core/VerifiablePresentationServiceImplTest.java b/core/identity-hub-credentials/src/test/java/org/eclipse/edc/identityhub/core/VerifiablePresentationServiceImplTest.java
index 1220bca05..0ea5c9bf1 100644
--- a/core/identity-hub-credentials/src/test/java/org/eclipse/edc/identityhub/core/VerifiablePresentationServiceImplTest.java
+++ b/core/identity-hub-credentials/src/test/java/org/eclipse/edc/identityhub/core/VerifiablePresentationServiceImplTest.java
@@ -63,7 +63,7 @@ void generate_noCredentials() {
List ldpVcs = List.of();
var result = presentationGenerator.createPresentation(ldpVcs, null, null);
- assertThat(result).isSucceeded().matches(pr -> pr.vpToken().length == 0, "VP Tokens should be empty");
+ assertThat(result).isSucceeded().matches(pr -> pr.getPresentation().isEmpty(), "VP Tokens should be empty");
}
@Test
diff --git a/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceExtension.java b/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceExtension.java
index ae833ff0d..bb4b738bf 100644
--- a/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceExtension.java
+++ b/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceExtension.java
@@ -21,6 +21,7 @@
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
import org.eclipse.edc.spi.security.Vault;
import org.eclipse.edc.spi.system.ServiceExtension;
+import org.eclipse.edc.spi.system.ServiceExtensionContext;
import static org.eclipse.edc.identityhub.keypairs.KeyPairServiceExtension.NAME;
@@ -34,7 +35,7 @@ public class KeyPairServiceExtension implements ServiceExtension {
private KeyPairResourceStore keyPairResourceStore;
@Provider
- public KeyPairService createParticipantService() {
- return new KeyPairServiceImpl(keyPairResourceStore, vault);
+ public KeyPairService createParticipantService(ServiceExtensionContext context) {
+ return new KeyPairServiceImpl(keyPairResourceStore, vault, context.getMonitor());
}
}
diff --git a/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceImpl.java b/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceImpl.java
index 99a063d60..517fbac91 100644
--- a/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceImpl.java
+++ b/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceImpl.java
@@ -16,11 +16,12 @@
import org.eclipse.edc.identityhub.security.KeyPairGenerator;
import org.eclipse.edc.identityhub.spi.KeyPairService;
+import org.eclipse.edc.identityhub.spi.model.KeyPairResource;
+import org.eclipse.edc.identityhub.spi.model.KeyPairState;
import org.eclipse.edc.identityhub.spi.model.participant.KeyDescriptor;
import org.eclipse.edc.identityhub.spi.store.KeyPairResourceStore;
-import org.eclipse.edc.identityhub.spi.store.model.KeyPairResource;
-import org.eclipse.edc.identityhub.spi.store.model.KeyPairState;
import org.eclipse.edc.security.token.jwt.CryptoConverter;
+import org.eclipse.edc.spi.monitor.Monitor;
import org.eclipse.edc.spi.query.Criterion;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.Result;
@@ -29,16 +30,18 @@
import org.jetbrains.annotations.Nullable;
import java.time.Instant;
-import java.util.Objects;
+import java.util.Collection;
import java.util.Optional;
public class KeyPairServiceImpl implements KeyPairService {
private final KeyPairResourceStore keyPairResourceStore;
private final Vault vault;
+ private final Monitor monitor;
- public KeyPairServiceImpl(KeyPairResourceStore keyPairResourceStore, Vault vault) {
+ public KeyPairServiceImpl(KeyPairResourceStore keyPairResourceStore, Vault vault, Monitor monitor) {
this.keyPairResourceStore = keyPairResourceStore;
this.vault = vault;
+ this.monitor = monitor;
}
@Override
@@ -50,6 +53,7 @@ public ServiceResult addKeyPair(String participantId, KeyDescriptor keyDes
}
var newResource = KeyPairResource.Builder.newInstance()
+ .id(keyDescriptor.getKeyId())
.keyId(keyDescriptor.getKeyId())
.state(KeyPairState.CREATED)
.isDefaultPair(makeDefault)
@@ -63,8 +67,8 @@ public ServiceResult addKeyPair(String participantId, KeyDescriptor keyDes
}
@Override
- public ServiceResult rotateKeyPair(String oldId, KeyDescriptor newKeySpec, long duration) {
- Objects.requireNonNull(newKeySpec);
+ public ServiceResult rotateKeyPair(String oldId, @Nullable KeyDescriptor newKeySpec, long duration) {
+
var oldKey = findById(oldId);
if (oldKey == null) {
return ServiceResult.notFound("A KeyPairResource with ID '%s' does not exist.".formatted(oldId));
@@ -79,7 +83,11 @@ public ServiceResult rotateKeyPair(String oldId, KeyDescriptor newKeySpec,
oldKey.rotate(duration);
keyPairResourceStore.update(oldKey);
- return addKeyPair(participantId, newKeySpec, wasDefault);
+ if (newKeySpec != null) {
+ return addKeyPair(participantId, newKeySpec, wasDefault);
+ }
+ monitor.warning("Rotating keys without a successor key may leave the participant without an active keypair.");
+ return ServiceResult.success();
}
@Override
@@ -102,9 +110,15 @@ public ServiceResult revokeKey(String id, @Nullable KeyDescriptor newKeySp
if (newKeySpec != null) {
return addKeyPair(participantId, newKeySpec, wasDefault);
}
+ monitor.warning("Revoking keys without a successor key may leave the participant without an active keypair.");
return ServiceResult.success();
}
+ @Override
+ public ServiceResult> query(QuerySpec querySpec) {
+ return ServiceResult.from(keyPairResourceStore.query(querySpec));
+ }
+
private KeyPairResource findById(String oldId) {
var q = QuerySpec.Builder.newInstance()
.filter(new Criterion("id", "=", oldId)).build();
diff --git a/core/identity-hub-keypairs/src/test/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceImplTest.java b/core/identity-hub-keypairs/src/test/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceImplTest.java
index ab981c646..18250a2f1 100644
--- a/core/identity-hub-keypairs/src/test/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceImplTest.java
+++ b/core/identity-hub-keypairs/src/test/java/org/eclipse/edc/identityhub/keypairs/KeyPairServiceImplTest.java
@@ -17,10 +17,10 @@
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator;
+import org.eclipse.edc.identityhub.spi.model.KeyPairResource;
+import org.eclipse.edc.identityhub.spi.model.KeyPairState;
import org.eclipse.edc.identityhub.spi.model.participant.KeyDescriptor;
import org.eclipse.edc.identityhub.spi.store.KeyPairResourceStore;
-import org.eclipse.edc.identityhub.spi.store.model.KeyPairResource;
-import org.eclipse.edc.identityhub.spi.store.model.KeyPairState;
import org.eclipse.edc.spi.security.Vault;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
@@ -47,7 +47,7 @@ class KeyPairServiceImplTest {
private final KeyPairResourceStore keyPairResourceStore = mock();
private final Vault vault = mock();
- private final KeyPairServiceImpl keyPairService = new KeyPairServiceImpl(keyPairResourceStore, vault);
+ private final KeyPairServiceImpl keyPairService = new KeyPairServiceImpl(keyPairResourceStore, vault, mock());
@ParameterizedTest(name = "make default: {0}")
@@ -104,6 +104,22 @@ void rotateKeyPair_withNewKey() {
verifyNoMoreInteractions(vault, keyPairResourceStore);
}
+ @Test
+ void rotateKeyPair_withoutNewKey() {
+ var oldId = "old-id";
+ var oldKey = createKeyPairResource().id(oldId).build();
+
+ when(keyPairResourceStore.query(any())).thenReturn(success(List.of(oldKey)));
+ when(keyPairResourceStore.create(any())).thenReturn(success());
+
+ assertThat(keyPairService.rotateKeyPair(oldId, null, Duration.ofDays(100).toMillis())).isSucceeded();
+
+ verify(keyPairResourceStore).query(any());
+ verify(keyPairResourceStore).update(argThat(kpr -> kpr.getId().equals(oldId)));
+ verify(vault).deleteSecret(eq(oldKey.getPrivateKeyAlias())); //deletes old private key
+ verifyNoMoreInteractions(vault, keyPairResourceStore);
+ }
+
@Test
void rotateKeyPair_withNewKeyGenerate() {
var oldId = "old-id";
diff --git a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/KeyPairResourceApiEndToEndTest.java b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/KeyPairResourceApiEndToEndTest.java
new file mode 100644
index 000000000..0919c74b9
--- /dev/null
+++ b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/KeyPairResourceApiEndToEndTest.java
@@ -0,0 +1,274 @@
+/*
+ * 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.tests;
+
+import com.nimbusds.jose.jwk.Curve;
+import io.restassured.http.Header;
+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.identityhub.spi.model.participant.ParticipantContext;
+import org.eclipse.edc.junit.annotations.EndToEndTest;
+import org.eclipse.edc.spi.EdcException;
+import org.junit.jupiter.api.Test;
+
+import java.util.Map;
+import java.util.UUID;
+
+import static io.restassured.http.ContentType.JSON;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+
+@EndToEndTest
+public class KeyPairResourceApiEndToEndTest extends ManagementApiEndToEndTest {
+
+ @Test
+ void findById_notAuthorized() {
+ var user1 = "user1";
+ createParticipant(user1);
+
+
+ // create second user
+ var user2 = "user2";
+ var user2Context = ParticipantContext.Builder.newInstance()
+ .participantId(user2)
+ .did("did:web:" + user2)
+ .apiTokenAlias(user2 + "-alias")
+ .build();
+ var user2Token = storeParticipant(user2Context);
+
+ var key = createKeyPair(user1);
+
+ // attempt to publish user1's DID document, which should fail
+ RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", user2Token))
+ .get("/v1/keypairs/" + key)
+ .then()
+ .log().ifValidationFails()
+ .statusCode(403)
+ .body(notNullValue());
+ }
+
+ @Test
+ void findById() {
+ var user1 = "user1";
+ var token = createParticipant(user1);
+
+
+ var key = createKeyPair(user1);
+
+ // attempt to publish user1's DID document, which should fail
+ RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", token))
+ .get("/v1/keypairs/" + key)
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(notNullValue());
+ }
+
+ @Test
+ void findForParticipant_notAuthorized() {
+ var user1 = "user1";
+ createParticipant(user1);
+
+
+ // create second user
+ var user2 = "user2";
+ var user2Context = ParticipantContext.Builder.newInstance()
+ .participantId(user2)
+ .did("did:web:" + user2)
+ .apiTokenAlias(user2 + "-alias")
+ .build();
+ var user2Token = storeParticipant(user2Context);
+
+ var key = createKeyPair(user1);
+
+ // attempt to publish user1's DID document, which should fail
+ var res = RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", user2Token))
+ .get("/v1/keypairs?participantId=" + user1)
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .extract().body().as(KeyPairResource[].class);
+
+ assertThat(res).isEmpty();
+
+ }
+
+ @Test
+ void findForParticipant() {
+ var user1 = "user1";
+ var token = createParticipant(user1);
+
+
+ var key = createKeyPair(user1);
+
+ // attempt to publish user1's DID document, which should fail
+ RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", token))
+ .get("/v1/keypairs?participantId=" + user1)
+ .then()
+ .log().ifValidationFails()
+ .statusCode(200)
+ .body(notNullValue());
+ }
+
+ @Test
+ void addKeyPair() {
+ var user1 = "user1";
+ var token = createParticipant(user1);
+
+
+ // attempt to publish user1's DID document, which should fail
+ var keyDesc = createKeyDescriptor(user1).build();
+ RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", token))
+ .body(keyDesc)
+ .put("/v1/keypairs?participantId=" + user1)
+ .then()
+ .log().ifValidationFails()
+ .statusCode(204)
+ .body(notNullValue());
+ }
+
+ @Test
+ void addKeyPair_notAuthorized() {
+ var user1 = "user1";
+ var token = createParticipant(user1);
+
+ var user2 = "user2";
+ var token2 = createParticipant(user2);
+
+
+ // attempt to publish user1's DID document, which should fail
+ var keyDesc = createKeyDescriptor(user1).build();
+ RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", token2))
+ .body(keyDesc)
+ .put("/v1/keypairs?participantId=" + user1)
+ .then()
+ .log().ifValidationFails()
+ .statusCode(403)
+ .body(notNullValue());
+ }
+
+ @Test
+ void rotate() {
+ var user1 = "user1";
+ var token = createParticipant(user1);
+
+ var keyId = createKeyPair(user1);
+
+ // attempt to publish user1's DID document, which should fail
+ var keyDesc = createKeyDescriptor(user1).build();
+ RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", token))
+ .body(keyDesc)
+ .post("/v1/keypairs/%s/rotate".formatted(keyId))
+ .then()
+ .log().ifValidationFails()
+ .statusCode(204)
+ .body(notNullValue());
+ }
+
+ @Test
+ void rotate_notAuthorized() {
+ var user1 = "user1";
+ var token = createParticipant(user1);
+
+ var user2 = "user2";
+ var token2 = createParticipant(user2);
+
+ var keyId = createKeyPair(user1);
+
+ // attempt to publish user1's DID document, which should fail
+ var keyDesc = createKeyDescriptor(user1).build();
+ RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", token2))
+ .body(keyDesc)
+ .post("/v1/keypairs/%s/rotate".formatted(keyId))
+ .then()
+ .log().ifValidationFails()
+ .statusCode(403)
+ .body(notNullValue());
+ }
+
+ @Test
+ void revoke() {
+ var user1 = "user1";
+ var token = createParticipant(user1);
+
+ var keyId = createKeyPair(user1);
+
+ // attempt to publish user1's DID document, which should fail
+ RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", token))
+ .post("/v1/keypairs/%s/revoke".formatted(keyId))
+ .then()
+ .log().ifValidationFails()
+ .statusCode(204)
+ .body(notNullValue());
+ }
+
+ @Test
+ void revoke_notAuthorized() {
+ var user1 = "user1";
+ var token = createParticipant(user1);
+
+ var user2 = "user2";
+ var token2 = createParticipant(user2);
+
+ var keyId = createKeyPair(user1);
+
+ // attempt to publish user1's DID document, which should fail
+ RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest()
+ .contentType(JSON)
+ .header(new Header("x-api-key", token2))
+ .post("/v1/keypairs/%s/revoke".formatted(keyId))
+ .then()
+ .log().ifValidationFails()
+ .statusCode(403)
+ .body(notNullValue());
+ }
+
+ private String createKeyPair(String participantId) {
+
+ var descriptor = createKeyDescriptor(participantId).build();
+
+ var service = RUNTIME.getContext().getService(KeyPairService.class);
+ service.addKeyPair(participantId, descriptor, true)
+ .orElseThrow(f -> new EdcException(f.getFailureDetail()));
+ return descriptor.getKeyId();
+ }
+
+ private static KeyDescriptor.Builder createKeyDescriptor(String participantId) {
+ return KeyDescriptor.Builder.newInstance()
+ .keyId(UUID.randomUUID().toString())
+ .keyGeneratorParams(Map.of("algorithm", "EC", "curve", Curve.P_384.getStdName()))
+ .privateKeyAlias(participantId + "-alias");
+ }
+
+}
diff --git a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/ResolutionApiComponentTest.java b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/ResolutionApiComponentTest.java
index 4d062241f..abb11512e 100644
--- a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/ResolutionApiComponentTest.java
+++ b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/ResolutionApiComponentTest.java
@@ -22,7 +22,7 @@
import org.eclipse.edc.identityhub.tests.fixtures.IdentityHubRuntimeConfiguration;
import org.eclipse.edc.identityhub.tests.fixtures.TestData;
import org.eclipse.edc.identitytrust.model.credentialservice.InputDescriptorMapping;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponse;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponseMessage;
import org.eclipse.edc.identitytrust.model.credentialservice.PresentationSubmission;
import org.eclipse.edc.junit.annotations.ComponentTest;
import org.eclipse.edc.junit.extensions.EdcRuntimeExtension;
@@ -54,7 +54,7 @@ public class ResolutionApiComponentTest {
"https://identity.foundation/presentation-exchange/submission/v1",
"https://w3id.org/tractusx-trust/v0.8"
],
- "@type": "Query",
+ "@type": "PresentationQueryMessage",
"scope":[
"test-scope1"
]
@@ -122,7 +122,7 @@ void query_withPresentationDefinition_shouldReturn503() {
"https://identity.foundation/presentation-exchange/submission/v1",
"https://w3id.org/tractusx-trust/v0.8"
],
- "@type": "Query",
+ "@type": "PresentationQueryMessage",
"presentationDefinition":{
}
}
@@ -204,13 +204,16 @@ void query_success() {
.then()
.statusCode(200)
.log().ifValidationFails()
- .extract().body().as(PresentationResponse.class);
+ .extract().body().as(PresentationResponseMessage.class);
}
- private PresentationResponse createPresentationResponse() {
+ private PresentationResponseMessage createPresentationResponse() {
var submission = new PresentationSubmission("id", "def-id", List.of(new InputDescriptorMapping("input-id", "ldp-vp", "foo")));
- return new PresentationResponse(new Object[] {TestData.VP_EXAMPLE}, submission);
+ return PresentationResponseMessage.Builder.newinstance()
+ .presentation(List.of(TestData.VP_EXAMPLE))
+ .presentationSubmission(submission)
+ .build();
}
diff --git a/extensions/api/keypair-mgmt-api/build.gradle.kts b/extensions/api/keypair-mgmt-api/build.gradle.kts
new file mode 100644
index 000000000..865ad385b
--- /dev/null
+++ b/extensions/api/keypair-mgmt-api/build.gradle.kts
@@ -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))
+}
diff --git a/extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/KeyPairResourceManagementApiExtension.java b/extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/KeyPairResourceManagementApiExtension.java
new file mode 100644
index 000000000..2d7481f4f
--- /dev/null
+++ b/extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/KeyPairResourceManagementApiExtension.java
@@ -0,0 +1,64 @@
+/*
+ * 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.AuthorizationService;
+import org.eclipse.edc.identityhub.spi.KeyPairService;
+import org.eclipse.edc.identityhub.spi.model.KeyPairResource;
+import org.eclipse.edc.identityhub.spi.model.ParticipantResource;
+import org.eclipse.edc.runtime.metamodel.annotation.Extension;
+import org.eclipse.edc.runtime.metamodel.annotation.Inject;
+import org.eclipse.edc.spi.EdcException;
+import org.eclipse.edc.spi.query.Criterion;
+import org.eclipse.edc.spi.query.QuerySpec;
+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;
+ @Inject
+ private AuthorizationService authorizationService;
+
+ @Override
+ public void initialize(ServiceExtensionContext context) {
+ authorizationService.addLoookupFunction(KeyPairResource.class, this::findById);
+ var controller = new KeyPairResourceApiController(authorizationService, keyPairService);
+ webService.registerResource(apiConfiguration.getContextAlias(), controller);
+ }
+
+ private ParticipantResource findById(String keyPairId) {
+ var q = QuerySpec.Builder.newInstance()
+ .filter(new Criterion("id", "=", keyPairId))
+ .build();
+ return keyPairService.query(q)
+ .orElseThrow(f -> new EdcException(f.getFailureDetail()))
+ .stream()
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApi.java b/extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApi.java
new file mode 100644
index 000000000..89ec01e21
--- /dev/null
+++ b/extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApi.java
@@ -0,0 +1,118 @@
+/*
+ * 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 jakarta.ws.rs.core.SecurityContext;
+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, SecurityContext securityContext);
+
+ @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 findForParticipant(String participantId, SecurityContext securityContext);
+
+ @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, SecurityContext securityContext);
+
+ @Tag(name = "KeyPairResources Management API")
+ @Operation(description = "Rotates (=retires) a particular key pair, identified by their ID and optionally 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, SecurityContext securityContext);
+
+ @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, SecurityContext securityContext);
+}
diff --git a/extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApiController.java b/extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApiController.java
new file mode 100644
index 000000000..ce2de4a23
--- /dev/null
+++ b/extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApiController.java
@@ -0,0 +1,111 @@
+/*
+ * 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 jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.SecurityContext;
+import org.eclipse.edc.identityhub.spi.AuthorizationService;
+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.identityhub.spi.model.participant.ParticipantContext;
+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 org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.eclipse.edc.identityhub.spi.AuthorizationResultHandler.exceptionMapper;
+
+@Consumes(APPLICATION_JSON)
+@Produces(APPLICATION_JSON)
+@Path("/v1/keypairs")
+public class KeyPairResourceApiController implements KeyPairResourceApi {
+
+ private final AuthorizationService authorizationService;
+ private final KeyPairService keyPairService;
+
+ public KeyPairResourceApiController(AuthorizationService authorizationService, KeyPairService keyPairService) {
+ this.authorizationService = authorizationService;
+ this.keyPairService = keyPairService;
+ }
+
+ @GET
+ @Path("/{keyPairId}")
+ @Override
+ public KeyPairResource findById(@PathParam("keyPairId") String id, @Context SecurityContext securityContext) {
+
+ authorizationService.isAuthorized(securityContext.getUserPrincipal(), id, KeyPairResource.class)
+ .orElseThrow(exceptionMapper(KeyPairResource.class, 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 findForParticipant(@QueryParam("participantId") String participantId, @Context SecurityContext securityContext) {
+ var query = QuerySpec.Builder.newInstance().filter(new Criterion("participantId", "=", participantId)).build();
+ return keyPairService.query(query)
+ .orElseThrow(exceptionMapper(KeyPairResource.class, participantId))
+ .stream().filter(kpr -> authorizationService.isAuthorized(securityContext.getUserPrincipal(), kpr.getId(), KeyPairResource.class).succeeded())
+ .toList();
+ }
+
+ @PUT
+ @Override
+ public void addKeyPair(@QueryParam("participantId") String participantId, KeyDescriptor keyDescriptor, @QueryParam("makeDefault") boolean makeDefault,
+ @Context SecurityContext securityContext) {
+ authorizationService.isAuthorized(securityContext.getUserPrincipal(), participantId, ParticipantContext.class)
+ .compose(u -> keyPairService.addKeyPair(participantId, keyDescriptor, makeDefault))
+ .orElseThrow(exceptionMapper(KeyPairResource.class));
+ }
+
+ @POST
+ @Path("/{keyPairId}/rotate")
+ @Override
+ public void rotateKeyPair(@PathParam("keyPairId") String id, @Nullable KeyDescriptor newKey, @QueryParam("duration") long duration, @Context SecurityContext securityContext) {
+ authorizationService.isAuthorized(securityContext.getUserPrincipal(), id, KeyPairResource.class)
+ .compose(u -> keyPairService.rotateKeyPair(id, newKey, duration))
+ .orElseThrow(exceptionMapper(KeyPairResource.class, id));
+ }
+
+ @POST
+ @Path("/{keyPairId}/revoke")
+ @Override
+ public void revokeKey(@PathParam("keyPairId") String id, KeyDescriptor newKey, @Context SecurityContext securityContext) {
+ authorizationService.isAuthorized(securityContext.getUserPrincipal(), id, KeyPairResource.class)
+ .compose(u -> keyPairService.revokeKey(id, newKey))
+ .orElseThrow(exceptionMapper(KeyPairResource.class, id));
+ }
+}
diff --git a/extensions/api/keypair-mgmt-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/extensions/api/keypair-mgmt-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension
new file mode 100644
index 000000000..aa9f9c822
--- /dev/null
+++ b/extensions/api/keypair-mgmt-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension
@@ -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
diff --git a/extensions/api/keypair-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApiControllerTest.java b/extensions/api/keypair-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApiControllerTest.java
new file mode 100644
index 000000000..1a4621f60
--- /dev/null
+++ b/extensions/api/keypair-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApiControllerTest.java
@@ -0,0 +1,278 @@
+/*
+ * 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.restassured.http.ContentType;
+import io.restassured.specification.RequestSpecification;
+import org.eclipse.edc.identityhub.spi.AuthorizationService;
+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.result.ServiceResult;
+import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+
+import static io.restassured.RestAssured.given;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+class KeyPairResourceApiControllerTest extends RestControllerTestBase {
+
+ private final KeyPairService keyPairService = mock();
+ private final AuthorizationService authService = mock();
+
+
+ @BeforeEach
+ void setUp() {
+ when(authService.isAuthorized(any(), anyString(), any())).thenReturn(ServiceResult.success());
+ }
+
+ @Test
+ void findById() {
+ var keyPair = createKeyPair().build();
+
+ when(keyPairService.query(any())).thenReturn(ServiceResult.success(List.of(keyPair)));
+
+ var found = baseRequest()
+ .get("/test-keypairId")
+ .then()
+ .statusCode(200)
+ .log().ifError()
+ .extract().body().as(KeyPairResource.class);
+ assertThat(found).usingRecursiveComparison().isEqualTo(keyPair);
+ }
+
+ @Test
+ void findById_notExist() {
+ when(keyPairService.query(any())).thenReturn(ServiceResult.notFound("tst-msg"));
+
+ var found = baseRequest()
+ .get("/test-keypairId")
+ .then()
+ .log().ifValidationFails()
+ .statusCode(404);
+ }
+
+ @Test
+ void findForParticipant() {
+ var keyPair = createKeyPair().build();
+
+ when(keyPairService.query(any())).thenReturn(ServiceResult.success(List.of(keyPair)));
+
+ var found = baseRequest()
+ .get("?participantId=test-participant")
+ .then()
+ .statusCode(200)
+ .log().ifError()
+ .extract().body().as(KeyPairResource[].class);
+ assertThat(found).usingRecursiveFieldByFieldElementComparator().containsExactly(keyPair);
+
+ verify(keyPairService).query(argThat(q -> {
+ var criterion = q.getFilterExpression().get(0);
+ return criterion.getOperandLeft().equals("participantId") &&
+ criterion.getOperator().equals("=") &&
+ criterion.getOperandRight().equals("test-participant");
+ }));
+ }
+
+ @Test
+ void findForParticipant_noResult() {
+ var keyPair = createKeyPair().build();
+
+ when(keyPairService.query(any())).thenReturn(ServiceResult.success(List.of()));
+
+ var found = baseRequest()
+ .get("?participantId=test-participant")
+ .then()
+ .statusCode(200)
+ .log().ifError()
+ .extract().body().as(KeyPairResource[].class);
+ assertThat(found).isEmpty();
+
+ verify(keyPairService).query(argThat(q -> {
+ var criterion = q.getFilterExpression().get(0);
+ return criterion.getOperandLeft().equals("participantId") &&
+ criterion.getOperator().equals("=") &&
+ criterion.getOperandRight().equals("test-participant");
+ }));
+ }
+
+ @Test
+ void findForParticipant_notfound() {
+ when(keyPairService.query(any())).thenReturn(ServiceResult.notFound("test-message"));
+
+ baseRequest()
+ .get("?participantId=test-participant")
+ .then()
+ .statusCode(404)
+ .log().ifError();
+
+ verify(keyPairService).query(argThat(q -> {
+ var criterion = q.getFilterExpression().get(0);
+ return criterion.getOperandLeft().equals("participantId") &&
+ criterion.getOperator().equals("=") &&
+ criterion.getOperandRight().equals("test-participant");
+ }));
+ }
+
+ @ParameterizedTest(name = "Make default: {0}")
+ @ValueSource(booleans = {true, false})
+ void addKeyPair(boolean makeDefault) {
+ var descriptor = createKeyDescriptor()
+ .build();
+ when(keyPairService.addKeyPair(eq("test-participant"), any(), eq(makeDefault))).thenReturn(ServiceResult.success());
+
+ baseRequest()
+ .contentType(ContentType.JSON)
+ .body(descriptor)
+ .put("?participantId=%s&makeDefault=%s".formatted("test-participant", makeDefault))
+ .then()
+ .log().ifError()
+ .statusCode(204);
+
+ verify(keyPairService).addKeyPair(eq("test-participant"), argThat(d -> d.getKeyId().equals(descriptor.getKeyId())), eq(makeDefault));
+ verifyNoMoreInteractions(keyPairService);
+ }
+
+ @Test
+ void rotate() {
+ var duration = Duration.ofDays(100).toMillis();
+ when(keyPairService.rotateKeyPair(eq("old-id"), any(), eq(duration))).thenReturn(ServiceResult.success());
+
+ var descriptor = createKeyDescriptor().build();
+ baseRequest()
+ .contentType(ContentType.JSON)
+ .body(descriptor)
+ .post("/old-id/rotate?duration=" + duration)
+ .then()
+ .log().ifError()
+ .statusCode(204);
+
+ verify(keyPairService).rotateKeyPair(eq("old-id"), argThat(d -> d.getKeyId().equals(descriptor.getKeyId())), eq(duration));
+ verifyNoMoreInteractions(keyPairService);
+ }
+
+ @Test
+ void rotate_idNotFound() {
+ var duration = Duration.ofDays(100).toMillis();
+ when(keyPairService.rotateKeyPair(eq("old-id"), any(), eq(duration))).thenReturn(ServiceResult.notFound("test-message"));
+
+ var descriptor = createKeyDescriptor().build();
+ baseRequest()
+ .contentType(ContentType.JSON)
+ .body(descriptor)
+ .post("/old-id/rotate?duration=" + duration)
+ .then()
+ .log().ifValidationFails()
+ .statusCode(404);
+
+ verify(keyPairService).rotateKeyPair(eq("old-id"), argThat(d -> d.getKeyId().equals(descriptor.getKeyId())), eq(duration));
+ verifyNoMoreInteractions(keyPairService);
+ }
+
+ @Test
+ void rotate_withoutSuccessor() {
+ var duration = Duration.ofDays(100).toMillis();
+ when(keyPairService.rotateKeyPair(eq("old-id"), any(), eq(duration))).thenReturn(ServiceResult.success());
+
+ baseRequest()
+ .contentType(ContentType.JSON)
+ .post("/old-id/rotate?duration=" + duration)
+ .then()
+ .log().ifError()
+ .statusCode(204);
+
+ verify(keyPairService).rotateKeyPair(eq("old-id"), isNull(), eq(duration));
+ verifyNoMoreInteractions(keyPairService);
+ }
+
+ @Test
+ void revoke() {
+ when(keyPairService.revokeKey(eq("old-id"), any())).thenReturn(ServiceResult.success());
+
+ var descriptor = createKeyDescriptor().build();
+ baseRequest()
+ .contentType(ContentType.JSON)
+ .body(descriptor)
+ .post("/old-id/revoke")
+ .then()
+ .log().ifError()
+ .statusCode(204);
+
+ verify(keyPairService).revokeKey(eq("old-id"), argThat(d -> d.getKeyId().equals(descriptor.getKeyId())));
+ verifyNoMoreInteractions(keyPairService);
+ }
+
+ @Test
+ void revoke_notFound() {
+ when(keyPairService.revokeKey(eq("old-id"), any())).thenReturn(ServiceResult.notFound("test-message"));
+
+ var descriptor = createKeyDescriptor().build();
+ baseRequest()
+ .contentType(ContentType.JSON)
+ .body(descriptor)
+ .post("/old-id/revoke")
+ .then()
+ .log().ifError()
+ .statusCode(404);
+
+ verify(keyPairService).revokeKey(eq("old-id"), argThat(d -> d.getKeyId().equals(descriptor.getKeyId())));
+ verifyNoMoreInteractions(keyPairService);
+ }
+
+ @Override
+ protected Object controller() {
+ return new KeyPairResourceApiController(authService, keyPairService);
+ }
+
+ private KeyPairResource.Builder createKeyPair() {
+ return KeyPairResource.Builder.newInstance()
+ .id("test-keypair")
+ .participantId("test-participant")
+ .isDefaultPair(true)
+ .privateKeyAlias("test-alias")
+ .useDuration(Duration.ofDays(365).toMillis());
+ }
+
+ private RequestSpecification baseRequest() {
+ return given()
+ .contentType("application/json")
+ .baseUri("http://localhost:" + port + "/v1/keypairs")
+ .when();
+ }
+
+ @NotNull
+ private static KeyDescriptor.Builder createKeyDescriptor() {
+ return KeyDescriptor.Builder.newInstance()
+ .keyId("new-key-id")
+ .keyGeneratorParams(Map.of("algorithm", "EC", "curve", "secp256r1"));
+ }
+}
\ No newline at end of file
diff --git a/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/VerifiableCredentialApiExtension.java b/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/VerifiableCredentialApiExtension.java
index a8d9a4965..cd63e88bd 100644
--- a/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/VerifiableCredentialApiExtension.java
+++ b/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/VerifiableCredentialApiExtension.java
@@ -18,8 +18,8 @@
import org.eclipse.edc.identityhub.api.verifiablecredentials.v1.VerifiableCredentialsApiController;
import org.eclipse.edc.identityhub.spi.AuthorizationService;
import org.eclipse.edc.identityhub.spi.model.ParticipantResource;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
-import org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.spi.EdcException;
diff --git a/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApi.java b/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApi.java
index 3044fb804..c817ea727 100644
--- a/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApi.java
+++ b/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApi.java
@@ -25,9 +25,9 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.core.SecurityContext;
import org.eclipse.edc.iam.did.spi.document.DidDocument;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.spi.model.participant.ParticipantContext;
import org.eclipse.edc.identityhub.spi.model.participant.ParticipantManifest;
-import org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource;
import org.eclipse.edc.web.spi.ApiErrorDetail;
import java.util.Collection;
diff --git a/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApiController.java b/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApiController.java
index 1c00eb23f..b3d612765 100644
--- a/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApiController.java
+++ b/extensions/api/verifiable-credential-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApiController.java
@@ -24,8 +24,8 @@
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;
import org.eclipse.edc.identityhub.spi.AuthorizationService;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
-import org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource;
import org.eclipse.edc.spi.query.Criterion;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.ServiceResult;
diff --git a/extensions/api/verifiable-credential-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApiControllerTest.java b/extensions/api/verifiable-credential-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApiControllerTest.java
index 3808b1c46..a01777b88 100644
--- a/extensions/api/verifiable-credential-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApiControllerTest.java
+++ b/extensions/api/verifiable-credential-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/VerifiableCredentialsApiControllerTest.java
@@ -16,8 +16,8 @@
import io.restassured.specification.RequestSpecification;
import org.eclipse.edc.identityhub.spi.AuthorizationService;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
-import org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource;
import org.eclipse.edc.identitytrust.model.CredentialFormat;
import org.eclipse.edc.identitytrust.model.CredentialSubject;
import org.eclipse.edc.identitytrust.model.Issuer;
diff --git a/extensions/store/sql/identity-hub-credentials-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/credentials/SqlCredentialStore.java b/extensions/store/sql/identity-hub-credentials-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/credentials/SqlCredentialStore.java
index ebb38d706..90d8026c5 100644
--- a/extensions/store/sql/identity-hub-credentials-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/credentials/SqlCredentialStore.java
+++ b/extensions/store/sql/identity-hub-credentials-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/credentials/SqlCredentialStore.java
@@ -15,9 +15,9 @@
package org.eclipse.edc.identityhub.store.sql.credentials;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.eclipse.edc.identityhub.spi.model.VcState;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
-import org.eclipse.edc.identityhub.spi.store.model.VcState;
-import org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource;
import org.eclipse.edc.identitytrust.model.CredentialFormat;
import org.eclipse.edc.identitytrust.model.VerifiableCredential;
import org.eclipse.edc.identitytrust.model.VerifiableCredentialContainer;
diff --git a/extensions/store/sql/identity-hub-credentials-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/credentials/schema/postgres/VerifiableCredentialResourceMapping.java b/extensions/store/sql/identity-hub-credentials-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/credentials/schema/postgres/VerifiableCredentialResourceMapping.java
index bbcc9e0ea..ea13297d3 100644
--- a/extensions/store/sql/identity-hub-credentials-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/credentials/schema/postgres/VerifiableCredentialResourceMapping.java
+++ b/extensions/store/sql/identity-hub-credentials-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/credentials/schema/postgres/VerifiableCredentialResourceMapping.java
@@ -14,12 +14,13 @@
package org.eclipse.edc.identityhub.store.sql.credentials.schema.postgres;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.store.sql.credentials.CredentialStoreStatements;
import org.eclipse.edc.sql.translation.TranslationMapping;
/**
- * Provides a mapping from the canonical format to SQL column names for a {@link org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource}
+ * Provides a mapping from the canonical format to SQL column names for a {@link VerifiableCredentialResource}
*/
public class VerifiableCredentialResourceMapping extends TranslationMapping {
diff --git a/extensions/store/sql/identity-hub-keypair-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/keypair/SqlKeyPairResourceStore.java b/extensions/store/sql/identity-hub-keypair-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/keypair/SqlKeyPairResourceStore.java
index 677e0ad89..f46bd8a28 100644
--- a/extensions/store/sql/identity-hub-keypair-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/keypair/SqlKeyPairResourceStore.java
+++ b/extensions/store/sql/identity-hub-keypair-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/keypair/SqlKeyPairResourceStore.java
@@ -15,8 +15,8 @@
package org.eclipse.edc.identityhub.store.sql.keypair;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.eclipse.edc.identityhub.spi.model.KeyPairResource;
import org.eclipse.edc.identityhub.spi.store.KeyPairResourceStore;
-import org.eclipse.edc.identityhub.spi.store.model.KeyPairResource;
import org.eclipse.edc.spi.persistence.EdcPersistenceException;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.StoreResult;
diff --git a/extensions/store/sql/identity-hub-participantcontext-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/participantcontext/schema/postgres/ParticipantContextMapping.java b/extensions/store/sql/identity-hub-participantcontext-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/participantcontext/schema/postgres/ParticipantContextMapping.java
index 2f38f0a6b..436c19dca 100644
--- a/extensions/store/sql/identity-hub-participantcontext-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/participantcontext/schema/postgres/ParticipantContextMapping.java
+++ b/extensions/store/sql/identity-hub-participantcontext-store-sql/src/main/java/org/eclipse/edc/identityhub/store/sql/participantcontext/schema/postgres/ParticipantContextMapping.java
@@ -14,12 +14,13 @@
package org.eclipse.edc.identityhub.store.sql.participantcontext.schema.postgres;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.store.sql.participantcontext.ParticipantContextStoreStatements;
import org.eclipse.edc.sql.translation.TranslationMapping;
/**
- * Provides a mapping from the canonical format to SQL column names for a {@link org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource}
+ * Provides a mapping from the canonical format to SQL column names for a {@link VerifiableCredentialResource}
*/
public class ParticipantContextMapping extends TranslationMapping {
diff --git a/launcher/build.gradle.kts b/launcher/build.gradle.kts
index 4ccb766c0..7a2e6ffd1 100644
--- a/launcher/build.gradle.kts
+++ b/launcher/build.gradle.kts
@@ -29,6 +29,7 @@ dependencies {
runtimeOnly(project(":extensions:api:participant-context-mgmt-api"))
runtimeOnly(project(":extensions:api:verifiable-credential-mgmt-api"))
runtimeOnly(project(":extensions:api:identityhub-management-api-configuration"))
+ runtimeOnly(project(":extensions:api:keypair-mgmt-api"))
runtimeOnly(libs.edc.identity.did.core)
runtimeOnly(libs.edc.core.token)
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 0b431c951..f001d5b53 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -47,6 +47,7 @@ include(":extensions:api:identityhub-management-api-configuration")
include(":extensions:api:identityhub-api-auth")
include(":extensions:api:participant-context-mgmt-api")
include(":extensions:api:verifiable-credential-mgmt-api")
+include(":extensions:api:keypair-mgmt-api")
include(":extensions:did:did-management-api")
// other modules
diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/AuthorizationResultHandler.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/AuthorizationResultHandler.java
index 5456ae998..75b5a958f 100644
--- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/AuthorizationResultHandler.java
+++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/AuthorizationResultHandler.java
@@ -35,4 +35,13 @@ public static Function exceptionMapper(@NotNull Cl
return ServiceResultHandler.exceptionMapper(clazz, id).apply(failure);
};
}
+
+ public static Function exceptionMapper(@NotNull Class> clazz) {
+ return failure -> {
+ if (failure.getReason() == ServiceFailure.Reason.UNAUTHORIZED) {
+ return new NotAuthorizedException(failure.getFailureDetail());
+ }
+ return ServiceResultHandler.exceptionMapper(clazz).apply(failure);
+ };
+ }
}
diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/KeyPairService.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/KeyPairService.java
index 9e0422c97..6f85c3796 100644
--- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/KeyPairService.java
+++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/KeyPairService.java
@@ -14,11 +14,15 @@
package org.eclipse.edc.identityhub.spi;
+import org.eclipse.edc.identityhub.spi.model.KeyPairResource;
import org.eclipse.edc.identityhub.spi.model.participant.KeyDescriptor;
+import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.ServiceResult;
import org.eclipse.edc.spi.security.Vault;
import org.jetbrains.annotations.Nullable;
+import java.util.Collection;
+
public interface KeyPairService {
/**
@@ -61,4 +65,6 @@ public interface KeyPairService {
* @return success if rotated, a failure indicated the problem otherwise.
*/
ServiceResult revokeKey(String id, @Nullable KeyDescriptor newKeySpec);
+
+ ServiceResult> query(QuerySpec querySpec);
}
diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/generator/VerifiablePresentationService.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/generator/VerifiablePresentationService.java
index fa804ae08..cc13d601e 100644
--- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/generator/VerifiablePresentationService.java
+++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/generator/VerifiablePresentationService.java
@@ -15,7 +15,7 @@
package org.eclipse.edc.identityhub.spi.generator;
import org.eclipse.edc.identitytrust.model.VerifiableCredentialContainer;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponse;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponseMessage;
import org.eclipse.edc.identitytrust.model.presentationdefinition.PresentationDefinition;
import org.eclipse.edc.spi.result.Result;
import org.jetbrains.annotations.Nullable;
@@ -36,5 +36,5 @@ public interface VerifiablePresentationService {
* @param audience The Participant ID of the party who the presentation is intended for. May not be relevant for all VP formats
* @return A Result object containing a PresentationResponse if the presentation creation is successful, or a failure message if it fails.
*/
- Result createPresentation(List credentials, @Nullable PresentationDefinition presentationDefinition, @Nullable String audience);
+ Result createPresentation(List credentials, @Nullable PresentationDefinition presentationDefinition, @Nullable String audience);
}
diff --git a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/IdentityResource.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/IdentityResource.java
similarity index 89%
rename from spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/IdentityResource.java
rename to spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/IdentityResource.java
index d2a70a944..186909725 100644
--- a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/IdentityResource.java
+++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/IdentityResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * 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
@@ -8,14 +8,13 @@
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
- * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
+ * Metaform Systems, Inc. - initial API and implementation
*
*/
-package org.eclipse.edc.identityhub.spi.store.model;
+package org.eclipse.edc.identityhub.spi.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.eclipse.edc.identityhub.spi.model.ParticipantResource;
import java.time.Clock;
import java.util.Objects;
diff --git a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/KeyPairResource.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairResource.java
similarity index 94%
rename from spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/KeyPairResource.java
rename to spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairResource.java
index 9b34bd282..e119f7be3 100644
--- a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/KeyPairResource.java
+++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairResource.java
@@ -12,10 +12,9 @@
*
*/
-package org.eclipse.edc.identityhub.spi.store.model;
+package org.eclipse.edc.identityhub.spi.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.eclipse.edc.identityhub.spi.model.ParticipantResource;
import org.eclipse.edc.identityhub.spi.model.participant.ParticipantContext;
import org.eclipse.edc.spi.security.KeyParserRegistry;
import org.eclipse.edc.spi.security.Vault;
@@ -31,7 +30,7 @@ public class KeyPairResource extends ParticipantResource {
private long timestamp;
private String keyId;
private String groupName;
- private boolean isDefaultPair;
+ private boolean defaultPair;
private long useDuration;
private long rotationDuration;
private String serializedPublicKey;
@@ -56,7 +55,7 @@ public String getId() {
* Whether this KeyPair is the default for a {@link ParticipantContext}.
*/
public boolean isDefaultPair() {
- return isDefaultPair;
+ return defaultPair;
}
/**
@@ -111,12 +110,12 @@ public int getState() {
public void rotate(long duration) {
state = KeyPairState.ROTATED.code();
rotationDuration = duration;
- isDefaultPair = false;
+ defaultPair = false;
}
public void revoke() {
state = KeyPairState.REVOKED.code();
- isDefaultPair = false;
+ defaultPair = false;
}
public static final class Builder extends ParticipantResource.Builder {
@@ -151,7 +150,7 @@ public Builder keyId(String keyId) {
}
public Builder isDefaultPair(boolean isDefaultPair) {
- entity.isDefaultPair = isDefaultPair;
+ entity.defaultPair = isDefaultPair;
return this;
}
diff --git a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/KeyPairState.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairState.java
similarity index 96%
rename from spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/KeyPairState.java
rename to spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairState.java
index 48127398d..ec4b2952a 100644
--- a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/KeyPairState.java
+++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairState.java
@@ -12,7 +12,7 @@
*
*/
-package org.eclipse.edc.identityhub.spi.store.model;
+package org.eclipse.edc.identityhub.spi.model;
import java.util.Arrays;
diff --git a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/VcState.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/VcState.java
similarity index 77%
rename from spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/VcState.java
rename to spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/VcState.java
index 6304fb48a..9b99440d4 100644
--- a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/VcState.java
+++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/VcState.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * 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
@@ -8,11 +8,11 @@
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
- * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
+ * Metaform Systems, Inc. - initial API and implementation
*
*/
-package org.eclipse.edc.identityhub.spi.store.model;
+package org.eclipse.edc.identityhub.spi.model;
import java.util.Arrays;
diff --git a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/VerifiableCredentialResource.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/VerifiableCredentialResource.java
similarity index 92%
rename from spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/VerifiableCredentialResource.java
rename to spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/VerifiableCredentialResource.java
index 6b0055a5a..afd930507 100644
--- a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/model/VerifiableCredentialResource.java
+++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/VerifiableCredentialResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * 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
@@ -8,11 +8,11 @@
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
- * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
+ * Metaform Systems, Inc. - initial API and implementation
*
*/
-package org.eclipse.edc.identityhub.spi.store.model;
+package org.eclipse.edc.identityhub.spi.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.eclipse.edc.identitytrust.model.VerifiableCredentialContainer;
diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/resolution/CredentialQueryResolver.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/resolution/CredentialQueryResolver.java
index 49e84d185..400bbcafe 100644
--- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/resolution/CredentialQueryResolver.java
+++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/resolution/CredentialQueryResolver.java
@@ -15,12 +15,13 @@
package org.eclipse.edc.identityhub.spi.resolution;
import org.eclipse.edc.identitytrust.model.VerifiableCredentialContainer;
-import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQueryMessage;
+import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponseMessage;
import java.util.List;
/**
- * Resolves a list of {@link VerifiableCredentialContainer} objects based on an incoming {@link PresentationQuery} and a list of scope strings.
+ * Resolves a list of {@link VerifiableCredentialContainer} objects based on an incoming {@link PresentationResponseMessage} and a list of scope strings.
*/
public interface CredentialQueryResolver {
@@ -32,5 +33,5 @@ public interface CredentialQueryResolver {
* @param query The representation of the query to be executed.
* @param issuerScopes The list of issuer scopes to be considered during the query processing.
*/
- QueryResult query(PresentationQuery query, List issuerScopes);
+ QueryResult query(PresentationQueryMessage query, List issuerScopes);
}
\ No newline at end of file
diff --git a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/CredentialStore.java b/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/CredentialStore.java
index 6f9eb7662..38a8209b9 100644
--- a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/CredentialStore.java
+++ b/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/CredentialStore.java
@@ -15,7 +15,7 @@
package org.eclipse.edc.identityhub.spi.store;
-import org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.StoreResult;
diff --git a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/KeyPairResourceStore.java b/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/KeyPairResourceStore.java
index 35c070e91..d88bcaff9 100644
--- a/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/KeyPairResourceStore.java
+++ b/spi/identity-hub-store-spi/src/main/java/org/eclipse/edc/identityhub/spi/store/KeyPairResourceStore.java
@@ -14,7 +14,7 @@
package org.eclipse.edc.identityhub.spi.store;
-import org.eclipse.edc.identityhub.spi.store.model.KeyPairResource;
+import org.eclipse.edc.identityhub.spi.model.KeyPairResource;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.StoreResult;
diff --git a/spi/identity-hub-store-spi/src/test/java/org/eclipse/edc/identityhub/spi/store/model/VerifiableCredentialResourceTest.java b/spi/identity-hub-store-spi/src/test/java/org/eclipse/edc/identityhub/spi/store/model/VerifiableCredentialResourceTest.java
index 5adc3ae4c..4b17d4ebd 100644
--- a/spi/identity-hub-store-spi/src/test/java/org/eclipse/edc/identityhub/spi/store/model/VerifiableCredentialResourceTest.java
+++ b/spi/identity-hub-store-spi/src/test/java/org/eclipse/edc/identityhub/spi/store/model/VerifiableCredentialResourceTest.java
@@ -14,6 +14,8 @@
package org.eclipse.edc.identityhub.spi.store.model;
+import org.eclipse.edc.identityhub.spi.model.VcState;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -45,7 +47,7 @@ void verifyBuilder_assertDefaultValues() {
.build();
assertThat(vc.getClock()).isNotNull();
- assertThat(vc.id).isNotNull();
+ assertThat(vc.getId()).isNotNull();
assertThat(vc.getStateAsEnum()).isEqualTo(VcState.INITIAL);
}
}
\ No newline at end of file
diff --git a/spi/identity-hub-store-spi/src/testFixtures/java/org/eclipse/edc/identityhub/store/test/CredentialStoreTestBase.java b/spi/identity-hub-store-spi/src/testFixtures/java/org/eclipse/edc/identityhub/store/test/CredentialStoreTestBase.java
index 92c952073..9d6f5e4a9 100644
--- a/spi/identity-hub-store-spi/src/testFixtures/java/org/eclipse/edc/identityhub/store/test/CredentialStoreTestBase.java
+++ b/spi/identity-hub-store-spi/src/testFixtures/java/org/eclipse/edc/identityhub/store/test/CredentialStoreTestBase.java
@@ -15,9 +15,9 @@
package org.eclipse.edc.identityhub.store.test;
import org.assertj.core.api.Assertions;
+import org.eclipse.edc.identityhub.spi.model.VcState;
+import org.eclipse.edc.identityhub.spi.model.VerifiableCredentialResource;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
-import org.eclipse.edc.identityhub.spi.store.model.VcState;
-import org.eclipse.edc.identityhub.spi.store.model.VerifiableCredentialResource;
import org.eclipse.edc.identitytrust.model.CredentialFormat;
import org.eclipse.edc.identitytrust.model.CredentialSubject;
import org.eclipse.edc.identitytrust.model.Issuer;
diff --git a/spi/identity-hub-store-spi/src/testFixtures/java/org/eclipse/edc/identityhub/store/test/KeyPairResourceStoreTestBase.java b/spi/identity-hub-store-spi/src/testFixtures/java/org/eclipse/edc/identityhub/store/test/KeyPairResourceStoreTestBase.java
index d2cfa59a3..b90b299b5 100644
--- a/spi/identity-hub-store-spi/src/testFixtures/java/org/eclipse/edc/identityhub/store/test/KeyPairResourceStoreTestBase.java
+++ b/spi/identity-hub-store-spi/src/testFixtures/java/org/eclipse/edc/identityhub/store/test/KeyPairResourceStoreTestBase.java
@@ -15,9 +15,9 @@
package org.eclipse.edc.identityhub.store.test;
import org.assertj.core.api.Assertions;
+import org.eclipse.edc.identityhub.spi.model.KeyPairResource;
+import org.eclipse.edc.identityhub.spi.model.KeyPairState;
import org.eclipse.edc.identityhub.spi.store.KeyPairResourceStore;
-import org.eclipse.edc.identityhub.spi.store.model.KeyPairResource;
-import org.eclipse.edc.identityhub.spi.store.model.KeyPairState;
import org.eclipse.edc.spi.query.Criterion;
import org.eclipse.edc.spi.query.QuerySpec;
import org.junit.jupiter.api.Test;