diff --git a/DEPENDENCIES b/DEPENDENCIES index da8bca199..e488ebcd6 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -302,26 +302,26 @@ maven/mavencentral/org.eclipse.edc/version-api/0.10.0-SNAPSHOT, Apache-2.0, appr maven/mavencentral/org.eclipse.edc/web-spi/0.10.0-SNAPSHOT, Apache-2.0, approved, technology.edc maven/mavencentral/org.eclipse.jetty.toolchain/jetty-jakarta-servlet-api/5.0.2, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty.toolchain/jetty-jakarta-websocket-api/2.0.0, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty.websocket/websocket-core-client/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty.websocket/websocket-core-common/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty.websocket/websocket-core-server/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty.websocket/websocket-jakarta-client/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty.websocket/websocket-jakarta-common/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty.websocket/websocket-jakarta-server/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty.websocket/websocket-servlet/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-alpn-client/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-annotations/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-client/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-http/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-io/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-jndi/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-plus/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-security/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-server/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-servlet/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-util/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-webapp/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-xml/11.0.23, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty.websocket/websocket-core-client/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty.websocket/websocket-core-common/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty.websocket/websocket-core-server/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty.websocket/websocket-jakarta-client/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty.websocket/websocket-jakarta-common/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty.websocket/websocket-jakarta-server/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty.websocket/websocket-servlet/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-alpn-client/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-annotations/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-client/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-http/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-io/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-jndi/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-plus/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-security/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-server/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-servlet/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-util/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-webapp/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-xml/11.0.24, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.parsson/parsson/1.1.7, EPL-2.0, approved, ee4j.parsson maven/mavencentral/org.glassfish.hk2.external/aopalliance-repackaged/3.0.6, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish maven/mavencentral/org.glassfish.hk2/hk2-api/3.0.6, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish 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 9a4824fa3..e57799361 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 @@ -126,8 +126,8 @@ public ServiceResult publish(String did) { success() : ServiceResult.badRequest(publishResult.getFailureDetail()); } - return ServiceResult.badRequest(("Cannot publish DID '%s' for participant '%s' because the ParticipantContext is not state '%s' state, " + - "but was '%s'.") + return ServiceResult.badRequest(("Cannot publish DID '%s' for participant '%s' because the ParticipantContext state is not '%s', " + + "but '%s'.") .formatted(did, participantId, ParticipantContextState.ACTIVATED, state)); }); }); @@ -158,10 +158,10 @@ public ServiceResult unpublish(String did) { success() : ServiceResult.badRequest(publishResult.getFailureDetail()); } - monitor.info("Unpublishing DID Document '%s': not in state '%s', unpublishing is a NOOP.".formatted(did, existingResource.getStateAsEnum())); + monitor.info("Unpublishing DID Document '%s' in state '%s', unpublishing is a NOOP.".formatted(did, existingResource.getStateAsEnum())); return success(); } - return ServiceResult.badRequest(("Cannot un-publish DID '%s' for participant '%s' because the ParticipantContext is not state '%s' state, " + + return ServiceResult.badRequest(("Cannot un-publish DID '%s' for participant '%s' because the ParticipantContext is not '%s' state, " + "but was '%s'.") .formatted(did, participantId, ParticipantContextState.DEACTIVATED, state)); }); diff --git a/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextCoordinatorExtension.java b/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextCoordinatorExtension.java index 683695514..7de2425da 100644 --- a/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextCoordinatorExtension.java +++ b/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextCoordinatorExtension.java @@ -16,6 +16,7 @@ import org.eclipse.edc.identithub.spi.did.DidDocumentService; import org.eclipse.edc.identityhub.spi.keypair.KeyPairService; +import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; import org.eclipse.edc.identityhub.spi.participantcontext.events.ParticipantContextCreated; import org.eclipse.edc.identityhub.spi.participantcontext.events.ParticipantContextDeleting; import org.eclipse.edc.runtime.metamodel.annotation.Extension; @@ -40,6 +41,8 @@ public class ParticipantContextCoordinatorExtension implements ServiceExtension private Clock clock; @Inject private EventRouter eventRouter; + @Inject + private ParticipantContextService participantContextService; @Override public String name() { @@ -49,7 +52,7 @@ public String name() { @Override public void initialize(ServiceExtensionContext context) { var coordinator = new ParticipantContextEventCoordinator(context.getMonitor().withPrefix("ParticipantContextEventCoordinator"), - didDocumentService, keyPairService); + didDocumentService, keyPairService, participantContextService); eventRouter.registerSync(ParticipantContextCreated.class, coordinator); eventRouter.registerSync(ParticipantContextDeleting.class, coordinator); diff --git a/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextEventCoordinator.java b/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextEventCoordinator.java index a1726ae2f..2827091fa 100644 --- a/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextEventCoordinator.java +++ b/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextEventCoordinator.java @@ -18,8 +18,10 @@ import org.eclipse.edc.identithub.spi.did.DidDocumentService; import org.eclipse.edc.identityhub.spi.keypair.KeyPairService; import org.eclipse.edc.identityhub.spi.keypair.model.KeyPairResource; +import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; import org.eclipse.edc.identityhub.spi.participantcontext.events.ParticipantContextCreated; import org.eclipse.edc.identityhub.spi.participantcontext.events.ParticipantContextDeleting; +import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.spi.event.Event; import org.eclipse.edc.spi.event.EventEnvelope; import org.eclipse.edc.spi.event.EventSubscriber; @@ -47,11 +49,13 @@ class ParticipantContextEventCoordinator implements EventSubscriber { private final Monitor monitor; private final DidDocumentService didDocumentService; private final KeyPairService keyPairService; + private final ParticipantContextService participantContextService; - ParticipantContextEventCoordinator(Monitor monitor, DidDocumentService didDocumentService, KeyPairService keyPairService) { + ParticipantContextEventCoordinator(Monitor monitor, DidDocumentService didDocumentService, KeyPairService keyPairService, ParticipantContextService participantContextService) { this.monitor = monitor; this.didDocumentService = didDocumentService; this.keyPairService = keyPairService; + this.participantContextService = participantContextService; } @Override @@ -71,9 +75,11 @@ public void on(EventEnvelope event) { } didDocumentService.store(doc, manifest.getParticipantId()) - // adding the keypair event will cause the DidDocumentService to update the DID. + // adding the keypair event will cause the DidDocumentService to update the DID .compose(u -> keyPairService.addKeyPair(createdEvent.getParticipantId(), createdEvent.getManifest().getKey(), true)) - .compose(u -> manifest.isActive() ? didDocumentService.publish(doc.getId()) : success()) + .compose(u -> manifest.isActive() + ? participantContextService.updateParticipant(manifest.getParticipantId(), ParticipantContext::activate) //implicitly publishes the did document + : success()) .onFailure(f -> monitor.warning("%s".formatted(f.getFailureDetail()))); } else if (payload instanceof ParticipantContextDeleting deletionEvent) { diff --git a/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextServiceImpl.java b/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextServiceImpl.java index 89e553834..587c4d693 100644 --- a/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextServiceImpl.java +++ b/core/identity-hub-participants/src/main/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextServiceImpl.java @@ -173,7 +173,7 @@ private ParticipantContext convert(ParticipantManifest manifest) { .roles(manifest.getRoles()) .did(manifest.getDid()) .apiTokenAlias("%s-%s".formatted(manifest.getParticipantId(), API_KEY_ALIAS_SUFFIX)) - .state(manifest.isActive() ? ParticipantContextState.ACTIVATED : ParticipantContextState.CREATED) + .state(ParticipantContextState.CREATED) .build(); } } diff --git a/core/identity-hub-participants/src/test/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextEventCoordinatorTest.java b/core/identity-hub-participants/src/test/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextEventCoordinatorTest.java index 59dae5647..0936a9465 100644 --- a/core/identity-hub-participants/src/test/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextEventCoordinatorTest.java +++ b/core/identity-hub-participants/src/test/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextEventCoordinatorTest.java @@ -16,6 +16,7 @@ import org.eclipse.edc.identithub.spi.did.DidDocumentService; import org.eclipse.edc.identityhub.spi.keypair.KeyPairService; +import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; import org.eclipse.edc.identityhub.spi.participantcontext.events.ParticipantContextCreated; import org.eclipse.edc.identityhub.spi.participantcontext.model.KeyDescriptor; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantManifest; @@ -24,6 +25,7 @@ import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.edc.spi.result.ServiceResult; import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.time.Instant; @@ -44,7 +46,14 @@ class ParticipantContextEventCoordinatorTest { private final Monitor monitor = mock(); private final DidDocumentService didDocumentService = mock(); private final KeyPairService keyPairService = mock(); - private final ParticipantContextEventCoordinator coordinator = new ParticipantContextEventCoordinator(monitor, didDocumentService, keyPairService); + private final ParticipantContextService participantContextService = mock(); + private final ParticipantContextEventCoordinator coordinator = new ParticipantContextEventCoordinator(monitor, didDocumentService, keyPairService, participantContextService); + + @BeforeEach + void setup() { + when(participantContextService.updateParticipant(anyString(), any())) + .thenReturn(ServiceResult.success()); + } @Test void onParticipantCreated() { @@ -59,7 +68,6 @@ void onParticipantCreated() { .build())); verify(didDocumentService).store(any(), eq(participantId)); - verify(didDocumentService).publish(eq("did:web:" + participantId)); verify(keyPairService).addKeyPair(eq(participantId), any(), eq(true)); verifyNoMoreInteractions(keyPairService, didDocumentService, monitor); } @@ -84,7 +92,6 @@ void onParticipantCreated_active_didDocumentServicePublishFailure() { var participantId = "test-id"; when(didDocumentService.store(any(), eq(participantId))).thenReturn(ServiceResult.success()); when(keyPairService.addKeyPair(eq(participantId), any(), anyBoolean())).thenReturn(ServiceResult.success()); - when(didDocumentService.publish(anyString())).thenReturn(ServiceResult.badRequest("foobar")); coordinator.on(envelope(ParticipantContextCreated.Builder.newInstance() .participantId(participantId) @@ -93,8 +100,6 @@ void onParticipantCreated_active_didDocumentServicePublishFailure() { verify(didDocumentService).store(any(), eq(participantId)); verify(keyPairService).addKeyPair(eq(participantId), any(), eq(true)); - verify(didDocumentService).publish(anyString()); - verify(monitor).warning("foobar"); verifyNoMoreInteractions(didDocumentService); } diff --git a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/DidManagementApiEndToEndTest.java b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/DidManagementApiEndToEndTest.java index 1b2670618..6dd84abdb 100644 --- a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/DidManagementApiEndToEndTest.java +++ b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/DidManagementApiEndToEndTest.java @@ -165,7 +165,7 @@ void publishDid_participantNotActivated_expect400(IdentityHubEndToEndTestContext .then() .log().ifValidationFails() .statusCode(400) - .body(Matchers.containsString("Cannot publish DID 'did:web:test-user' for participant 'test-user' because the ParticipantContext is not state 'ACTIVATED' state, but was 'CREATED'.")); + .body(Matchers.containsString("Cannot publish DID 'did:web:test-user' for participant 'test-user' because the ParticipantContext state is not 'ACTIVATED', but 'CREATED'.")); // verify that the publish event was fired twice verifyNoInteractions(subscriber); @@ -291,7 +291,7 @@ void unpublishDid_participantActive_expect400(IdentityHubEndToEndTestContext con .then() .log().ifValidationFails() .statusCode(400) - .body(Matchers.containsString("Cannot un-publish DID 'did:web:test-user' for participant 'test-user' because the ParticipantContext is not state 'DEACTIVATED' state, but was 'ACTIVATED'.")); + .body(Matchers.containsString("Cannot un-publish DID 'did:web:test-user' for participant 'test-user' because the ParticipantContext is not 'DEACTIVATED' state, but was 'ACTIVATED'.")); // verify that the unpublish event was fired verifyNoInteractions(subscriber); diff --git a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/ParticipantContextApiEndToEndTest.java b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/ParticipantContextApiEndToEndTest.java index e09fce92c..2bc105583 100644 --- a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/ParticipantContextApiEndToEndTest.java +++ b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/ParticipantContextApiEndToEndTest.java @@ -20,6 +20,7 @@ import org.eclipse.edc.identithub.spi.did.DidConstants; import org.eclipse.edc.identithub.spi.did.DidDocumentPublisher; import org.eclipse.edc.identithub.spi.did.DidDocumentPublisherRegistry; +import org.eclipse.edc.identithub.spi.did.events.DidDocumentPublished; import org.eclipse.edc.identithub.spi.did.model.DidResource; import org.eclipse.edc.identithub.spi.did.model.DidState; import org.eclipse.edc.identithub.spi.did.store.DidResourceStore; @@ -65,6 +66,7 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @@ -166,6 +168,8 @@ void createNewUser_whenKeyPairActive(IdentityHubEndToEndTestContext context, Eve .key(context.createKeyDescriptor().active(true).build()) .build(); + router.registerSync(DidDocumentPublished.class, subscriber); + context.getIdentityApiEndpoint().baseRequest() .header(new Header("x-api-key", apikey)) .contentType(ContentType.JSON) @@ -176,7 +180,8 @@ void createNewUser_whenKeyPairActive(IdentityHubEndToEndTestContext context, Eve .statusCode(anyOf(equalTo(200), equalTo(204))) .body(notNullValue()); - verify(subscriber).on(argThat(env -> ((ParticipantContextCreated) env.getPayload()).getParticipantId().equals(manifest.getParticipantId()))); + verify(subscriber).on(argThat(env -> env.getPayload() instanceof ParticipantContextCreated created && created.getParticipantId().equals(manifest.getParticipantId()))); + verify(subscriber, times(1)).on(argThat(evt -> evt.getPayload() instanceof DidDocumentPublished)); assertThat(context.getKeyPairsForParticipant(manifest.getParticipantId())).hasSize(1) .allSatisfy(kpr -> assertThat(kpr.getState()).isEqualTo(KeyPairState.ACTIVATED.code()));