From df57cd7e1a7c3ec6fa6ac2315f66214fc2f3fecf Mon Sep 17 00:00:00 2001 From: Benjamin SCHOLTES Date: Thu, 8 Feb 2024 17:53:50 +0100 Subject: [PATCH] fix: add missing mapping of VerificationMethod type --- .../did/DidDocumentServiceImpl.java | 1 + .../keypairs/KeyPairEventPublisher.java | 4 +- .../keypairs/KeyPairServiceImpl.java | 3 +- .../tests/KeyPairResourceApiEndToEndTest.java | 20 +++-- extensions/api/did-mgmt-api/build.gradle.kts | 1 + .../v1/validation/DidRequestValidator.java | 57 ------------ .../build.gradle.kts | 13 +++ .../v1/validation/KeyDescriptorValidator.java | 16 +++- .../ParticipantManifestValidator.java | 9 +- .../KeyDescriptorValidatorTest.java | 8 +- .../ParticipantManifestValidatorTest.java | 41 ++++----- .../api/keypair-mgmt-api/build.gradle.kts | 1 + ...KeyPairResourceManagementApiExtension.java | 12 ++- .../v1/KeyPairResourceApi.java | 2 +- .../v1/KeyPairResourceApiController.java | 13 ++- ...rg.eclipse.edc.spi.system.ServiceExtension | 2 +- .../v1/KeyPairResourceApiControllerTest.java | 90 +++++++++++++++---- .../build.gradle.kts | 1 + ...ticipantContextManagementApiExtension.java | 7 +- .../v1/ParticipantContextApiController.java | 2 +- .../ParticipantContextApiControllerTest.java | 18 +++- settings.gradle.kts | 1 + .../spi/events/keypair/KeyPairAdded.java | 18 ++-- .../events/keypair/KeyPairEventListener.java | 7 +- .../spi/model/KeyPairResource.java | 9 +- .../spi/model/participant/KeyDescriptor.java | 28 ++++-- 26 files changed, 241 insertions(+), 143 deletions(-) delete mode 100644 extensions/api/did-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/didmanagement/v1/validation/DidRequestValidator.java create mode 100644 extensions/api/identityhub-management-api-validators/build.gradle.kts rename extensions/api/{participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext => identityhub-management-api-validators/src/main/java/org/eclipse/edc/identityhub/api}/v1/validation/KeyDescriptorValidator.java (85%) rename extensions/api/{participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext => identityhub-management-api-validators/src/main/java/org/eclipse/edc/identityhub/api}/v1/validation/ParticipantManifestValidator.java (85%) rename extensions/api/{participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext => identityhub-management-api-validators/src/test/java/org/eclipse/edc/identityhub/api}/v1/validation/KeyDescriptorValidatorTest.java (96%) rename extensions/api/{participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext => identityhub-management-api-validators/src/test/java/org/eclipse/edc/identityhub/api}/v1/validation/ParticipantManifestValidatorTest.java (95%) rename extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/{verifiablecredentials => keypair}/KeyPairResourceManagementApiExtension.java (83%) rename extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/{verifiablecredentials => keypair}/v1/KeyPairResourceApi.java (99%) rename extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/{verifiablecredentials => keypair}/v1/KeyPairResourceApiController.java (87%) rename extensions/api/keypair-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/{verifiablecredentials => keypair}/v1/KeyPairResourceApiControllerTest.java (77%) diff --git a/core/identity-hub-did/src/main/java/org/eclipse/edc/identityhub/did/DidDocumentServiceImpl.java b/core/identity-hub-did/src/main/java/org/eclipse/edc/identityhub/did/DidDocumentServiceImpl.java index e07482b93..2b032b071 100644 --- a/core/identity-hub-did/src/main/java/org/eclipse/edc/identityhub/did/DidDocumentServiceImpl.java +++ b/core/identity-hub-did/src/main/java/org/eclipse/edc/identityhub/did/DidDocumentServiceImpl.java @@ -264,6 +264,7 @@ private void keypairAdded(KeyPairAdded event) { .id(event.getKeyId()) .publicKeyJwk(jwk.toJSONObject()) .controller(dd.getDocument().getId()) + .type(event.getType()) .build())) .map(didResourceStore::update) .filter(StoreResult::failed) diff --git a/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairEventPublisher.java b/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairEventPublisher.java index ab3486250..a73d0cbe5 100644 --- a/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairEventPublisher.java +++ b/core/identity-hub-keypairs/src/main/java/org/eclipse/edc/identityhub/keypairs/KeyPairEventPublisher.java @@ -35,11 +35,11 @@ public KeyPairEventPublisher(Clock clock, EventRouter eventRouter) { } @Override - public void added(KeyPairResource keyPair) { + public void added(KeyPairResource keyPair, String type) { var event = KeyPairAdded.Builder.newInstance() .participantId(keyPair.getParticipantId()) .keyId(keyPair.getId()) - .publicKey(keyPair.getSerializedPublicKey()) + .publicKey(keyPair.getSerializedPublicKey(), type) .build(); publish(event); } 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 21295dab6..f40378894 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 @@ -74,7 +74,8 @@ public ServiceResult addKeyPair(String participantId, KeyDescriptor keyDes .participantId(participantId) .build(); - return ServiceResult.from(keyPairResourceStore.create(newResource)).onSuccess(v -> observable.invokeForEach(l -> l.added(newResource))); + return ServiceResult.from(keyPairResourceStore.create(newResource)) + .onSuccess(v -> observable.invokeForEach(l -> l.added(newResource, keyDescriptor.getType()))); } @Override 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 index ee2c60f34..e664b047d 100644 --- 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 @@ -44,6 +44,14 @@ @EndToEndTest public class KeyPairResourceApiEndToEndTest extends ManagementApiEndToEndTest { + private static KeyDescriptor.Builder createKeyDescriptor(String participantId) { + var id = UUID.randomUUID().toString(); + return KeyDescriptor.Builder.newInstance() + .keyId(id) + .keyGeneratorParams(Map.of("algorithm", "EC", "curve", Curve.P_384.getStdName())) + .privateKeyAlias("%s-%s-alias".formatted(participantId, id)); + } + @Test void findById_notAuthorized() { var user1 = "user1"; @@ -288,9 +296,11 @@ void revoke() { assertThat(Arrays.asList(token, getSuperUserApiKey())) .allSatisfy(t -> { + var keyDesc = createKeyDescriptor(user1).build(); RUNTIME_CONFIGURATION.getManagementEndpoint().baseRequest() .contentType(JSON) .header(new Header("x-api-key", t)) + .body(keyDesc) .post("/v1/participants/%s/keypairs/%s/revoke".formatted(user1, keyId)) .then() .log().ifValidationFails() @@ -313,9 +323,11 @@ void revoke_notAuthorized() { 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/participants/%s/keypairs/%s/revoke".formatted(user1, keyId)) .then() .log().ifValidationFails() @@ -333,12 +345,4 @@ private String createKeyPair(String participantId) { return descriptor.getKeyId(); } - private static KeyDescriptor.Builder createKeyDescriptor(String participantId) { - var id = UUID.randomUUID().toString(); - return KeyDescriptor.Builder.newInstance() - .keyId(id) - .keyGeneratorParams(Map.of("algorithm", "EC", "curve", Curve.P_384.getStdName())) - .privateKeyAlias("%s-%s-alias".formatted(participantId, id)); - } - } diff --git a/extensions/api/did-mgmt-api/build.gradle.kts b/extensions/api/did-mgmt-api/build.gradle.kts index 2cbf4b4de..b9b6b0f0c 100644 --- a/extensions/api/did-mgmt-api/build.gradle.kts +++ b/extensions/api/did-mgmt-api/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { api(project(":spi:identity-hub-spi")) api(project(":spi:identity-hub-did-spi")) implementation(project(":extensions:api:identityhub-management-api-configuration")) + implementation(project(":extensions:api:identityhub-management-api-validators")) implementation(libs.edc.spi.validator) implementation(libs.edc.spi.web) implementation(libs.edc.core.jerseyproviders) diff --git a/extensions/api/did-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/didmanagement/v1/validation/DidRequestValidator.java b/extensions/api/did-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/didmanagement/v1/validation/DidRequestValidator.java deleted file mode 100644 index 23bb434b5..000000000 --- a/extensions/api/did-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/didmanagement/v1/validation/DidRequestValidator.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 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.didmanagement.v1.validation; - -import org.eclipse.edc.iam.did.spi.document.DidDocument; -import org.eclipse.edc.validator.spi.ValidationResult; -import org.eclipse.edc.validator.spi.Validator; - -import java.net.URI; - -import static org.eclipse.edc.validator.spi.ValidationResult.failure; -import static org.eclipse.edc.validator.spi.Violation.violation; - -/** - * Validates that a {@link DidDocument} is valid by checking all mandatory properties. - */ -public class DidRequestValidator implements Validator { - - @Override - public ValidationResult validate(DidDocument input) { - if (input == null) { - return failure(violation("input was null", ".")); - } - - if (input.getId() == null) { - return failure(violation("ID was null", "id")); - } - - if (!isValidUri(input.getId())) { - return failure(violation("ID is not a valid URI", "id")); - } - - return ValidationResult.success(); - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - private boolean isValidUri(String supposedUri) { - try { - URI.create(supposedUri); - return true; - } catch (IllegalArgumentException ex) { - return false; - } - } -} diff --git a/extensions/api/identityhub-management-api-validators/build.gradle.kts b/extensions/api/identityhub-management-api-validators/build.gradle.kts new file mode 100644 index 000000000..aa3a9277e --- /dev/null +++ b/extensions/api/identityhub-management-api-validators/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + `java-library` + `maven-publish` +} + +dependencies { + api(libs.edc.spi.core) + api(project(":spi:identity-hub-spi")) + api(project(":spi:identity-hub-did-spi")) + implementation(libs.edc.util) + + testImplementation(libs.edc.junit) +} diff --git a/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/KeyDescriptorValidator.java b/extensions/api/identityhub-management-api-validators/src/main/java/org/eclipse/edc/identityhub/api/v1/validation/KeyDescriptorValidator.java similarity index 85% rename from extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/KeyDescriptorValidator.java rename to extensions/api/identityhub-management-api-validators/src/main/java/org/eclipse/edc/identityhub/api/v1/validation/KeyDescriptorValidator.java index 78f3ea5d4..29f8e1047 100644 --- a/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/KeyDescriptorValidator.java +++ b/extensions/api/identityhub-management-api-validators/src/main/java/org/eclipse/edc/identityhub/api/v1/validation/KeyDescriptorValidator.java @@ -12,9 +12,11 @@ * */ -package org.eclipse.edc.identityhub.api.participantcontext.v1.validation; +package org.eclipse.edc.identityhub.api.v1.validation; +import org.eclipse.edc.iam.did.spi.document.DidConstants; import org.eclipse.edc.identityhub.spi.model.participant.KeyDescriptor; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.util.string.StringUtils; import org.eclipse.edc.validator.spi.ValidationResult; import org.eclipse.edc.validator.spi.Validator; @@ -22,6 +24,7 @@ import java.util.Objects; import java.util.stream.Stream; +import static java.lang.String.format; 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; @@ -37,6 +40,13 @@ * */ public class KeyDescriptorValidator implements Validator { + + private final Monitor monitor; + + public KeyDescriptorValidator(Monitor monitor) { + this.monitor = monitor; + } + @Override public ValidationResult validate(KeyDescriptor input) { if (input == null) { @@ -47,6 +57,10 @@ public ValidationResult validate(KeyDescriptor input) { return failure(violation("keyId cannot be null.", "keyId")); } + if (!DidConstants.ALLOWED_VERIFICATION_TYPES.contains(input.getType())) { + monitor.warning(format("Provided type %s is not supported.", input.getType())); + } + if (StringUtils.isNullOrBlank(input.getPrivateKeyAlias())) { return failure(violation("privateKeyAlias cannot be null.", "privateKeyAlias")); } diff --git a/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/ParticipantManifestValidator.java b/extensions/api/identityhub-management-api-validators/src/main/java/org/eclipse/edc/identityhub/api/v1/validation/ParticipantManifestValidator.java similarity index 85% rename from extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/ParticipantManifestValidator.java rename to extensions/api/identityhub-management-api-validators/src/main/java/org/eclipse/edc/identityhub/api/v1/validation/ParticipantManifestValidator.java index c3d32ea34..f51dc6dad 100644 --- a/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/ParticipantManifestValidator.java +++ b/extensions/api/identityhub-management-api-validators/src/main/java/org/eclipse/edc/identityhub/api/v1/validation/ParticipantManifestValidator.java @@ -12,9 +12,10 @@ * */ -package org.eclipse.edc.identityhub.api.participantcontext.v1.validation; +package org.eclipse.edc.identityhub.api.v1.validation; import org.eclipse.edc.identityhub.spi.model.participant.ParticipantManifest; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.util.string.StringUtils; import org.eclipse.edc.validator.spi.ValidationResult; import org.eclipse.edc.validator.spi.Validator; @@ -24,7 +25,11 @@ import static org.eclipse.edc.validator.spi.Violation.violation; public class ParticipantManifestValidator implements Validator { - private final KeyDescriptorValidator keyDescriptorValidator = new KeyDescriptorValidator(); + private final KeyDescriptorValidator keyDescriptorValidator; + + public ParticipantManifestValidator(Monitor monitor) { + this.keyDescriptorValidator = new KeyDescriptorValidator(monitor); + } @Override public ValidationResult validate(ParticipantManifest input) { diff --git a/extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/KeyDescriptorValidatorTest.java b/extensions/api/identityhub-management-api-validators/src/test/java/org/eclipse/edc/identityhub/api/v1/validation/KeyDescriptorValidatorTest.java similarity index 96% rename from extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/KeyDescriptorValidatorTest.java rename to extensions/api/identityhub-management-api-validators/src/test/java/org/eclipse/edc/identityhub/api/v1/validation/KeyDescriptorValidatorTest.java index c4497a15f..11fa6f146 100644 --- a/extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/KeyDescriptorValidatorTest.java +++ b/extensions/api/identityhub-management-api-validators/src/test/java/org/eclipse/edc/identityhub/api/v1/validation/KeyDescriptorValidatorTest.java @@ -12,9 +12,10 @@ * */ -package org.eclipse.edc.identityhub.api.participantcontext.v1.validation; +package org.eclipse.edc.identityhub.api.v1.validation; import org.eclipse.edc.identityhub.spi.model.participant.KeyDescriptor; +import org.eclipse.edc.spi.monitor.ConsoleMonitor; import org.junit.jupiter.api.Test; import java.util.Map; @@ -23,7 +24,7 @@ class KeyDescriptorValidatorTest { - private final KeyDescriptorValidator validator = new KeyDescriptorValidator(); + private final KeyDescriptorValidator validator = new KeyDescriptorValidator(new ConsoleMonitor()); @Test void validate_success() { @@ -110,6 +111,5 @@ void validate_publicKeyPemAndGeneratorParams() { assertThat(validator.validate(descriptor)).isFailed() .detail().isEqualTo("Either the public key is specified (PEM or JWK), or the generator params are provided, not both."); } - - + } \ No newline at end of file diff --git a/extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/ParticipantManifestValidatorTest.java b/extensions/api/identityhub-management-api-validators/src/test/java/org/eclipse/edc/identityhub/api/v1/validation/ParticipantManifestValidatorTest.java similarity index 95% rename from extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/ParticipantManifestValidatorTest.java rename to extensions/api/identityhub-management-api-validators/src/test/java/org/eclipse/edc/identityhub/api/v1/validation/ParticipantManifestValidatorTest.java index 481f592d7..85a869cd2 100644 --- a/extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/validation/ParticipantManifestValidatorTest.java +++ b/extensions/api/identityhub-management-api-validators/src/test/java/org/eclipse/edc/identityhub/api/v1/validation/ParticipantManifestValidatorTest.java @@ -12,11 +12,12 @@ * */ -package org.eclipse.edc.identityhub.api.participantcontext.v1.validation; +package org.eclipse.edc.identityhub.api.v1.validation; import org.eclipse.edc.iam.did.spi.document.Service; import org.eclipse.edc.identityhub.spi.model.participant.KeyDescriptor; import org.eclipse.edc.identityhub.spi.model.participant.ParticipantManifest; +import org.eclipse.edc.spi.monitor.ConsoleMonitor; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -29,7 +30,25 @@ class ParticipantManifestValidatorTest { - private final ParticipantManifestValidator validator = new ParticipantManifestValidator(); + private final ParticipantManifestValidator validator = new ParticipantManifestValidator(new ConsoleMonitor()); + + @NotNull + private static ParticipantManifest.Builder createManifest() { + return ParticipantManifest.Builder.newInstance() + .serviceEndpoint(new Service("id", "type", "foobar")) + .active(true) + .did("did:web:test-did") + .participantId("test-id") + .key(createKeyDescriptor().build()); + } + + @NotNull + private static KeyDescriptor.Builder createKeyDescriptor() { + return KeyDescriptor.Builder.newInstance() + .keyId("key-id") + .privateKeyAlias("alias") + .publicKeyJwk(Map.of("foo", "bar")); + } @Test void validate_success() { @@ -75,22 +94,4 @@ void validate_participantIdNull(String participantId) { assertThat(validator.validate(manifest)).isFailed() .detail().isEqualTo("participantId cannot be null or empty."); } - - @NotNull - private static ParticipantManifest.Builder createManifest() { - return ParticipantManifest.Builder.newInstance() - .serviceEndpoint(new Service("id", "type", "foobar")) - .active(true) - .did("did:web:test-did") - .participantId("test-id") - .key(createKeyDescriptor().build()); - } - - @NotNull - private static KeyDescriptor.Builder createKeyDescriptor() { - return KeyDescriptor.Builder.newInstance() - .keyId("key-id") - .privateKeyAlias("alias") - .publicKeyJwk(Map.of("foo", "bar")); - } } \ No newline at end of file diff --git a/extensions/api/keypair-mgmt-api/build.gradle.kts b/extensions/api/keypair-mgmt-api/build.gradle.kts index 865ad385b..d041483f2 100644 --- a/extensions/api/keypair-mgmt-api/build.gradle.kts +++ b/extensions/api/keypair-mgmt-api/build.gradle.kts @@ -9,6 +9,7 @@ dependencies { api(project(":spi:identity-hub-spi")) api(project(":spi:identity-hub-store-spi")) implementation(project(":extensions:api:identityhub-management-api-configuration")) + implementation(project(":extensions:api:identityhub-management-api-validators")) implementation(libs.edc.spi.web) implementation(libs.edc.util) implementation(libs.jakarta.rsApi) 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/keypair/KeyPairResourceManagementApiExtension.java similarity index 83% rename from extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/KeyPairResourceManagementApiExtension.java rename to extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/keypair/KeyPairResourceManagementApiExtension.java index baa12d74a..e7b80c492 100644 --- 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/keypair/KeyPairResourceManagementApiExtension.java @@ -12,9 +12,10 @@ * */ -package org.eclipse.edc.identityhub.api.verifiablecredentials; +package org.eclipse.edc.identityhub.api.keypair; -import org.eclipse.edc.identityhub.api.verifiablecredentials.v1.KeyPairResourceApiController; +import org.eclipse.edc.identityhub.api.keypair.v1.KeyPairResourceApiController; +import org.eclipse.edc.identityhub.api.v1.validation.KeyDescriptorValidator; import org.eclipse.edc.identityhub.spi.AuthorizationService; import org.eclipse.edc.identityhub.spi.KeyPairService; import org.eclipse.edc.identityhub.spi.ManagementApiConfiguration; @@ -23,13 +24,14 @@ 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.monitor.Monitor; 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; +import static org.eclipse.edc.identityhub.api.keypair.KeyPairResourceManagementApiExtension.NAME; @Extension(NAME) public class KeyPairResourceManagementApiExtension implements ServiceExtension { @@ -43,6 +45,8 @@ public class KeyPairResourceManagementApiExtension implements ServiceExtension { private KeyPairService keyPairService; @Inject private AuthorizationService authorizationService; + @Inject + private Monitor monitor; @Override public String name() { @@ -52,7 +56,7 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { authorizationService.addLookupFunction(KeyPairResource.class, this::findById); - var controller = new KeyPairResourceApiController(authorizationService, keyPairService); + var controller = new KeyPairResourceApiController(authorizationService, keyPairService, new KeyDescriptorValidator(monitor)); webService.registerResource(managementApiConfiguration.getContextAlias(), controller); } 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/keypair/v1/KeyPairResourceApi.java similarity index 99% rename from extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApi.java rename to extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/keypair/v1/KeyPairResourceApi.java index ee80c16d1..8e93a4439 100644 --- 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/keypair/v1/KeyPairResourceApi.java @@ -12,7 +12,7 @@ * */ -package org.eclipse.edc.identityhub.api.verifiablecredentials.v1; +package org.eclipse.edc.identityhub.api.keypair.v1; import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.Operation; 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/keypair/v1/KeyPairResourceApiController.java similarity index 87% rename from extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApiController.java rename to extensions/api/keypair-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/keypair/v1/KeyPairResourceApiController.java index 6b57e3b6e..8c47bfb2b 100644 --- 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/keypair/v1/KeyPairResourceApiController.java @@ -12,7 +12,7 @@ * */ -package org.eclipse.edc.identityhub.api.verifiablecredentials.v1; +package org.eclipse.edc.identityhub.api.keypair.v1; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.GET; @@ -24,6 +24,7 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.SecurityContext; +import org.eclipse.edc.identityhub.api.v1.validation.KeyDescriptorValidator; import org.eclipse.edc.identityhub.spi.AuthorizationService; import org.eclipse.edc.identityhub.spi.KeyPairService; import org.eclipse.edc.identityhub.spi.model.KeyPairResource; @@ -33,6 +34,7 @@ import org.eclipse.edc.spi.query.Criterion; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.web.spi.exception.ObjectNotFoundException; +import org.eclipse.edc.web.spi.exception.ValidationFailureException; import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -47,17 +49,18 @@ public class KeyPairResourceApiController implements KeyPairResourceApi { private final AuthorizationService authorizationService; private final KeyPairService keyPairService; + private final KeyDescriptorValidator keyDescriptorValidator; - public KeyPairResourceApiController(AuthorizationService authorizationService, KeyPairService keyPairService) { + public KeyPairResourceApiController(AuthorizationService authorizationService, KeyPairService keyPairService, KeyDescriptorValidator keyDescriptorValidator) { this.authorizationService = authorizationService; this.keyPairService = keyPairService; + this.keyDescriptorValidator = keyDescriptorValidator; } @GET @Path("/{keyPairId}") @Override public KeyPairResource findById(@PathParam("keyPairId") String id, @Context SecurityContext securityContext) { - authorizationService.isAuthorized(securityContext, id, KeyPairResource.class) .orElseThrow(exceptionMapper(KeyPairResource.class, id)); @@ -75,7 +78,6 @@ public KeyPairResource findById(@PathParam("keyPairId") String id, @Context Secu @GET @Override public Collection findForParticipant(@PathParam("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)) @@ -87,6 +89,7 @@ public Collection findForParticipant(@PathParam("participantId" @Override public void addKeyPair(@PathParam("participantId") String participantId, KeyDescriptor keyDescriptor, @QueryParam("makeDefault") boolean makeDefault, @Context SecurityContext securityContext) { + keyDescriptorValidator.validate(keyDescriptor).orElseThrow(ValidationFailureException::new); authorizationService.isAuthorized(securityContext, participantId, ParticipantContext.class) .compose(u -> keyPairService.addKeyPair(participantId, keyDescriptor, makeDefault)) .orElseThrow(exceptionMapper(KeyPairResource.class)); @@ -96,6 +99,7 @@ public void addKeyPair(@PathParam("participantId") String participantId, KeyDesc @Path("/{keyPairId}/rotate") @Override public void rotateKeyPair(@PathParam("keyPairId") String id, @Nullable KeyDescriptor newKey, @QueryParam("duration") long duration, @Context SecurityContext securityContext) { + keyDescriptorValidator.validate(newKey).orElseThrow(ValidationFailureException::new); authorizationService.isAuthorized(securityContext, id, KeyPairResource.class) .compose(u -> keyPairService.rotateKeyPair(id, newKey, duration)) .orElseThrow(exceptionMapper(KeyPairResource.class, id)); @@ -105,6 +109,7 @@ public void rotateKeyPair(@PathParam("keyPairId") String id, @Nullable KeyDescri @Path("/{keyPairId}/revoke") @Override public void revokeKey(@PathParam("keyPairId") String id, KeyDescriptor newKey, @Context SecurityContext securityContext) { + keyDescriptorValidator.validate(newKey).orElseThrow(ValidationFailureException::new); authorizationService.isAuthorized(securityContext, 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 index aa9f9c822..768f97b79 100644 --- 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 @@ -12,4 +12,4 @@ # # -org.eclipse.edc.identityhub.api.verifiablecredentials.KeyPairResourceManagementApiExtension +org.eclipse.edc.identityhub.api.keypair.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/keypair/v1/KeyPairResourceApiControllerTest.java similarity index 77% rename from extensions/api/keypair-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/verifiablecredentials/v1/KeyPairResourceApiControllerTest.java rename to extensions/api/keypair-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/keypair/v1/KeyPairResourceApiControllerTest.java index b7a0703ff..096e37626 100644 --- 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/keypair/v1/KeyPairResourceApiControllerTest.java @@ -12,15 +12,17 @@ * */ -package org.eclipse.edc.identityhub.api.verifiablecredentials.v1; +package org.eclipse.edc.identityhub.api.keypair.v1; import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; +import org.eclipse.edc.identityhub.api.v1.validation.KeyDescriptorValidator; 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.validator.spi.ValidationResult; import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; @@ -33,6 +35,7 @@ import java.util.Map; import static io.restassured.RestAssured.given; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -41,6 +44,7 @@ import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @@ -48,7 +52,14 @@ class KeyPairResourceApiControllerTest extends RestControllerTestBase { private final KeyPairService keyPairService = mock(); private final AuthorizationService authService = mock(); + private final KeyDescriptorValidator validator = mock(); + @NotNull + private static KeyDescriptor.Builder createKeyDescriptor() { + return KeyDescriptor.Builder.newInstance() + .keyId("new-key-id") + .keyGeneratorParams(Map.of("algorithm", "EC", "curve", "secp256r1")); + } @BeforeEach void setUp() { @@ -98,8 +109,8 @@ void findForParticipant() { verify(keyPairService).query(argThat(q -> { var criterion = q.getFilterExpression().get(0); return criterion.getOperandLeft().equals("participantId") && - criterion.getOperator().equals("=") && - criterion.getOperandRight().equals("test-participant"); + criterion.getOperator().equals("=") && + criterion.getOperandRight().equals("test-participant"); })); } @@ -120,8 +131,8 @@ void findForParticipant_noResult() { verify(keyPairService).query(argThat(q -> { var criterion = q.getFilterExpression().get(0); return criterion.getOperandLeft().equals("participantId") && - criterion.getOperator().equals("=") && - criterion.getOperandRight().equals("test-participant"); + criterion.getOperator().equals("=") && + criterion.getOperandRight().equals("test-participant"); })); } @@ -138,8 +149,8 @@ void findForParticipant_notfound() { verify(keyPairService).query(argThat(q -> { var criterion = q.getFilterExpression().get(0); return criterion.getOperandLeft().equals("participantId") && - criterion.getOperator().equals("=") && - criterion.getOperandRight().equals("test-participant"); + criterion.getOperator().equals("=") && + criterion.getOperandRight().equals("test-participant"); })); } @@ -148,6 +159,7 @@ void findForParticipant_notfound() { void addKeyPair(boolean makeDefault) { var descriptor = createKeyDescriptor() .build(); + when(validator.validate(any())).thenReturn(ValidationResult.success()); when(keyPairService.addKeyPair(eq("test-participant"), any(), eq(makeDefault))).thenReturn(ServiceResult.success()); baseRequest() @@ -162,9 +174,27 @@ void addKeyPair(boolean makeDefault) { verifyNoMoreInteractions(keyPairService); } + @Test + void addKeyPair_invalidInput() { + var descriptor = createKeyDescriptor() + .build(); + when(validator.validate(any())).thenReturn(ValidationResult.failure(emptyList())); + + baseRequest() + .contentType(ContentType.JSON) + .body(descriptor) + .put("?participantId=%s&makeDefault=%s".formatted("test-participant", true)) + .then() + .log().ifError() + .statusCode(400); + + verifyNoInteractions(keyPairService); + } + @Test void rotate() { var duration = Duration.ofDays(100).toMillis(); + when(validator.validate(any())).thenReturn(ValidationResult.success()); when(keyPairService.rotateKeyPair(eq("old-id"), any(), eq(duration))).thenReturn(ServiceResult.success()); var descriptor = createKeyDescriptor().build(); @@ -180,9 +210,27 @@ void rotate() { verifyNoMoreInteractions(keyPairService); } + @Test + void rotate_invalidInput() { + var duration = Duration.ofDays(100).toMillis(); + when(validator.validate(any())).thenReturn(ValidationResult.failure(emptyList())); + + var descriptor = createKeyDescriptor().build(); + baseRequest() + .contentType(ContentType.JSON) + .body(descriptor) + .post("/old-id/rotate?duration=" + duration) + .then() + .log().ifError() + .statusCode(400); + + verifyNoInteractions(keyPairService); + } + @Test void rotate_idNotFound() { var duration = Duration.ofDays(100).toMillis(); + when(validator.validate(any())).thenReturn(ValidationResult.success()); when(keyPairService.rotateKeyPair(eq("old-id"), any(), eq(duration))).thenReturn(ServiceResult.notFound("test-message")); var descriptor = createKeyDescriptor().build(); @@ -201,6 +249,7 @@ void rotate_idNotFound() { @Test void rotate_withoutSuccessor() { var duration = Duration.ofDays(100).toMillis(); + when(validator.validate(any())).thenReturn(ValidationResult.success()); when(keyPairService.rotateKeyPair(eq("old-id"), any(), eq(duration))).thenReturn(ServiceResult.success()); baseRequest() @@ -216,6 +265,7 @@ void rotate_withoutSuccessor() { @Test void revoke() { + when(validator.validate(any())).thenReturn(ValidationResult.success()); when(keyPairService.revokeKey(eq("old-id"), any())).thenReturn(ServiceResult.success()); var descriptor = createKeyDescriptor().build(); @@ -231,8 +281,25 @@ void revoke() { verifyNoMoreInteractions(keyPairService); } + @Test + void revoke_invalidInput() { + when(validator.validate(any())).thenReturn(ValidationResult.failure(emptyList())); + + var descriptor = createKeyDescriptor().build(); + baseRequest() + .contentType(ContentType.JSON) + .body(descriptor) + .post("/old-id/revoke") + .then() + .log().ifError() + .statusCode(400); + + verifyNoInteractions(keyPairService); + } + @Test void revoke_notFound() { + when(validator.validate(any())).thenReturn(ValidationResult.success()); when(keyPairService.revokeKey(eq("old-id"), any())).thenReturn(ServiceResult.notFound("test-message")); var descriptor = createKeyDescriptor().build(); @@ -250,7 +317,7 @@ void revoke_notFound() { @Override protected Object controller() { - return new KeyPairResourceApiController(authService, keyPairService); + return new KeyPairResourceApiController(authService, keyPairService, validator); } private KeyPairResource.Builder createKeyPair() { @@ -268,11 +335,4 @@ private RequestSpecification baseRequest() { .baseUri("http://localhost:" + port + "/v1/participants/test-participant/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/participant-context-mgmt-api/build.gradle.kts b/extensions/api/participant-context-mgmt-api/build.gradle.kts index 298c4080d..6461acbc7 100644 --- a/extensions/api/participant-context-mgmt-api/build.gradle.kts +++ b/extensions/api/participant-context-mgmt-api/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { api(project(":spi:identity-hub-spi")) api(project(":spi:identity-hub-did-spi")) implementation(project(":extensions:api:identityhub-management-api-configuration")) + implementation(project(":extensions:api:identityhub-management-api-validators")) implementation(libs.edc.spi.validator) implementation(libs.edc.spi.web) implementation(libs.edc.util) diff --git a/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/ParticipantContextManagementApiExtension.java b/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/ParticipantContextManagementApiExtension.java index 648dc67c4..adb554aa4 100644 --- a/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/ParticipantContextManagementApiExtension.java +++ b/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/ParticipantContextManagementApiExtension.java @@ -15,13 +15,14 @@ package org.eclipse.edc.identityhub.api.participantcontext; import org.eclipse.edc.identityhub.api.participantcontext.v1.ParticipantContextApiController; -import org.eclipse.edc.identityhub.api.participantcontext.v1.validation.ParticipantManifestValidator; +import org.eclipse.edc.identityhub.api.v1.validation.ParticipantManifestValidator; import org.eclipse.edc.identityhub.spi.AuthorizationService; import org.eclipse.edc.identityhub.spi.ManagementApiConfiguration; import org.eclipse.edc.identityhub.spi.ParticipantContextService; import org.eclipse.edc.identityhub.spi.model.participant.ParticipantContext; import org.eclipse.edc.runtime.metamodel.annotation.Extension; import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; import org.eclipse.edc.web.spi.WebService; @@ -41,6 +42,8 @@ public class ParticipantContextManagementApiExtension implements ServiceExtensio private ManagementApiConfiguration webServiceConfiguration; @Inject private AuthorizationService authorizationService; + @Inject + private Monitor monitor; @Override public String name() { @@ -50,7 +53,7 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { authorizationService.addLookupFunction(ParticipantContext.class, s -> participantContextService.getParticipantContext(s).orElseThrow(exceptionMapper(ParticipantContext.class, s))); - var controller = new ParticipantContextApiController(new ParticipantManifestValidator(), participantContextService, authorizationService); + var controller = new ParticipantContextApiController(new ParticipantManifestValidator(monitor), participantContextService, authorizationService); webService.registerResource(webServiceConfiguration.getContextAlias(), controller); } } diff --git a/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/ParticipantContextApiController.java b/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/ParticipantContextApiController.java index 778278141..51713fa6c 100644 --- a/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/ParticipantContextApiController.java +++ b/extensions/api/participant-context-mgmt-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/ParticipantContextApiController.java @@ -26,7 +26,7 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.SecurityContext; -import org.eclipse.edc.identityhub.api.participantcontext.v1.validation.ParticipantManifestValidator; +import org.eclipse.edc.identityhub.api.v1.validation.ParticipantManifestValidator; import org.eclipse.edc.identityhub.spi.AuthorizationService; import org.eclipse.edc.identityhub.spi.ParticipantContextService; import org.eclipse.edc.identityhub.spi.authentication.ServicePrincipal; diff --git a/extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/ParticipantContextApiControllerTest.java b/extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/ParticipantContextApiControllerTest.java index 815c94dc0..790d7dcb0 100644 --- a/extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/ParticipantContextApiControllerTest.java +++ b/extensions/api/participant-context-mgmt-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/ParticipantContextApiControllerTest.java @@ -19,7 +19,7 @@ import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator; import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; -import org.eclipse.edc.identityhub.api.participantcontext.v1.validation.ParticipantManifestValidator; +import org.eclipse.edc.identityhub.api.v1.validation.ParticipantManifestValidator; import org.eclipse.edc.identityhub.spi.AuthorizationService; import org.eclipse.edc.identityhub.spi.ParticipantContextService; import org.eclipse.edc.identityhub.spi.model.participant.KeyDescriptor; @@ -28,6 +28,7 @@ import org.eclipse.edc.identityhub.spi.model.participant.ParticipantManifest; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.spi.result.ServiceResult; +import org.eclipse.edc.validator.spi.ValidationResult; import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; @@ -38,6 +39,7 @@ import java.util.Map; import static io.restassured.RestAssured.given; +import static java.util.Collections.emptyList; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; @@ -54,6 +56,7 @@ class ParticipantContextApiControllerTest extends RestControllerTestBase { private final ParticipantContextService participantContextServiceMock = mock(); private final AuthorizationService authService = mock(); + private final ParticipantManifestValidator participantManifestValidator = mock(); @BeforeEach void setUp() { @@ -90,7 +93,9 @@ void getById_whenNotFound() { @Test void createParticipant_success() { when(participantContextServiceMock.createParticipantContext(any())).thenReturn(ServiceResult.success()); + when(participantManifestValidator.validate(any())).thenReturn(ValidationResult.success()); var manifest = createManifest().build(); + baseRequest() .contentType(ContentType.JSON) .body(manifest) @@ -105,12 +110,15 @@ void createParticipant_invalidManifest() { var manifest = createManifest() .participantId(null) .build(); + when(participantManifestValidator.validate(any())).thenReturn(ValidationResult.failure(emptyList())); + baseRequest() .contentType(ContentType.JSON) .body(manifest) .post() .then() .statusCode(400); + verifyNoInteractions(participantContextServiceMock); } @@ -119,12 +127,15 @@ void createParticipant_invalidKeyDescriptor() { var manifest = createManifest() .key(createKey().publicKeyPem(null).publicKeyJwk(null).keyGeneratorParams(null).build()) .build(); + when(participantManifestValidator.validate(any())).thenReturn(ValidationResult.failure(emptyList())); + baseRequest() .contentType(ContentType.JSON) .body(manifest) .post() .then() .statusCode(400); + verifyNoInteractions(participantContextServiceMock); } @@ -132,12 +143,15 @@ void createParticipant_invalidKeyDescriptor() { void createParticipant_alreadyExists() { when(participantContextServiceMock.createParticipantContext(any())).thenReturn(ServiceResult.conflict("already exists")); var manifest = createManifest().build(); + when(participantManifestValidator.validate(any())).thenReturn(ValidationResult.success()); + baseRequest() .contentType(ContentType.JSON) .body(manifest) .post() .then() .statusCode(409); + verify(participantContextServiceMock).createParticipantContext(any(ParticipantManifest.class)); } @@ -236,7 +250,7 @@ void updateRoles_notFound() { @Override protected Object controller() { - return new ParticipantContextApiController(new ParticipantManifestValidator(), participantContextServiceMock, authService); + return new ParticipantContextApiController(participantManifestValidator, participantContextServiceMock, authService); } private ParticipantContext.Builder createParticipantContext() { diff --git a/settings.gradle.kts b/settings.gradle.kts index 6d00b39dd..48e30632e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -43,6 +43,7 @@ include(":extensions:store:sql:identity-hub-keypair-store-sql") include(":extensions:did:local-did-publisher") // management APIs +include(":extensions:api:identityhub-management-api-validators") include(":extensions:api:identityhub-management-api-configuration") include(":extensions:api:identityhub-api-authentication") include(":extensions:api:identityhub-api-authorization") diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/events/keypair/KeyPairAdded.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/events/keypair/KeyPairAdded.java index f8b2f03ed..b9949b333 100644 --- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/events/keypair/KeyPairAdded.java +++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/events/keypair/KeyPairAdded.java @@ -24,6 +24,7 @@ @JsonDeserialize(builder = KeyPairAdded.Builder.class) public class KeyPairAdded extends KeyPairEvent { private String publicKeySerialized; + private String type; @Override public String name() { @@ -34,6 +35,10 @@ public String getPublicKeySerialized() { return publicKeySerialized; } + public String getType() { + return type; + } + @JsonPOJOBuilder(withPrefix = "") public static class Builder extends KeyPairEvent.Builder { @@ -41,19 +46,20 @@ private Builder() { super(new KeyPairAdded()); } + @JsonCreator + public static Builder newInstance() { + return new KeyPairAdded.Builder(); + } + @Override public KeyPairAdded.Builder self() { return this; } - public Builder publicKey(String publicKey) { + public Builder publicKey(String publicKey, String type) { event.publicKeySerialized = publicKey; + event.type = type; return this; } - - @JsonCreator - public static Builder newInstance() { - return new KeyPairAdded.Builder(); - } } } diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/events/keypair/KeyPairEventListener.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/events/keypair/KeyPairEventListener.java index fc0f8532d..521a0d7ef 100644 --- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/events/keypair/KeyPairEventListener.java +++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/events/keypair/KeyPairEventListener.java @@ -28,13 +28,14 @@ public interface KeyPairEventListener { * by simply adding a keypair, or after a keypair was revoked, and a successor was specified. * * @param keypair The new (added) key pair + * @param type Verification type specifying the cryptographic context in which the public key is used, e.g. JsonWebKey2020... */ - default void added(KeyPairResource keypair) { + default void added(KeyPairResource keypair, String type) { } /** - * A {@link KeyPairResource} was rotated (=phased out). If the rotation was done with a successor keypair, this would be communicated using the {@link KeyPairEventListener#added(KeyPairResource)} + * A {@link KeyPairResource} was rotated (=phased out). If the rotation was done with a successor keypair, this would be communicated using the {@link KeyPairEventListener#added(KeyPairResource, String)} * callback. * * @param keyPair the old (outgoing) {@link KeyPairResource} @@ -44,7 +45,7 @@ default void rotated(KeyPairResource keyPair) { } /** - * A {@link KeyPairResource} was revoked (=deleted). If the revocation was done with a successor keypair, this would be communicated using the {@link KeyPairEventListener#added(KeyPairResource)} + * A {@link KeyPairResource} was revoked (=deleted). If the revocation was done with a successor keypair, this would be communicated using the {@link KeyPairEventListener#added(KeyPairResource, String)} * callback. * * @param keyPair the old (outgoing) {@link KeyPairResource} diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairResource.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairResource.java index e119f7be3..b3d88e93a 100644 --- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairResource.java +++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/KeyPairResource.java @@ -51,6 +51,7 @@ public String getId() { return id; } + /** * Whether this KeyPair is the default for a {@link ParticipantContext}. */ @@ -124,6 +125,10 @@ private Builder() { super(new KeyPairResource()); } + public static Builder newInstance() { + return new Builder(); + } + public Builder groupName(String groupName) { entity.groupName = groupName; return this; @@ -190,9 +195,5 @@ public KeyPairResource build() { } return super.build(); } - - public static Builder newInstance() { - return new Builder(); - } } } diff --git a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/participant/KeyDescriptor.java b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/participant/KeyDescriptor.java index e5cd2ea0b..8a7a5d6b2 100644 --- a/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/participant/KeyDescriptor.java +++ b/spi/identity-hub-spi/src/main/java/org/eclipse/edc/identityhub/spi/model/participant/KeyDescriptor.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import org.eclipse.edc.iam.did.spi.document.DidConstants; import org.eclipse.edc.spi.security.Vault; import java.util.Map; @@ -33,6 +34,7 @@ @JsonDeserialize(builder = KeyDescriptor.Builder.class) public class KeyDescriptor { private String keyId; + private String type; private String privateKeyAlias; private Map publicKeyJwk; private String publicKeyPem; @@ -48,6 +50,14 @@ public String getKeyId() { return keyId; } + /** + * The type of the verification method associated with this key. + * It specifies in which cryptographic context the key will be used. + */ + public String getType() { + return type; + } + /** * Alias under which the private key is stored in the vault. If keys are to be generated, the new private key will get stored * under the that alias. @@ -87,11 +97,21 @@ private Builder() { keyDescriptor = new KeyDescriptor(); } + @JsonCreator + public static Builder newInstance() { + return new Builder(); + } + public Builder keyId(String keyId) { keyDescriptor.keyId = keyId; return this; } + public Builder type(String type) { + keyDescriptor.type = type; + return this; + } + public Builder privateKeyAlias(String privateKeyAlias) { keyDescriptor.privateKeyAlias = privateKeyAlias; return this; @@ -113,12 +133,10 @@ public Builder keyGeneratorParams(Map keyGeneratorParams) { } public KeyDescriptor build() { + if (keyDescriptor.type == null) { + keyDescriptor.type = DidConstants.JSON_WEB_KEY_2020; + } return keyDescriptor; } - - @JsonCreator - public static Builder newInstance() { - return new Builder(); - } } }