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 01abc6bee..a62a1dc38 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 @@ -18,6 +18,7 @@ import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; import org.eclipse.edc.identityhub.spi.participantcontext.StsAccountProvisioner; import org.eclipse.edc.identityhub.spi.participantcontext.events.ParticipantContextObservable; +import org.eclipse.edc.identityhub.spi.participantcontext.model.CreateParticipantContextResponse; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContextState; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantManifest; @@ -28,9 +29,8 @@ import org.eclipse.edc.transaction.spi.TransactionContext; import java.util.Collection; -import java.util.HashMap; -import java.util.Map; import java.util.function.Consumer; +import java.util.function.Function; import static org.eclipse.edc.spi.result.ServiceResult.conflict; import static org.eclipse.edc.spi.result.ServiceResult.fromFailure; @@ -70,24 +70,24 @@ public ParticipantContextServiceImpl(ParticipantContextStore participantContextS } @Override - public ServiceResult> createParticipantContext(ParticipantManifest manifest) { + public ServiceResult createParticipantContext(ParticipantManifest manifest) { return transactionContext.execute(() -> { if (didResourceStore.findById(manifest.getDid()) != null) { return ServiceResult.conflict("Another participant with the same DID '%s' already exists.".formatted(manifest.getDid())); } - var response = new HashMap(); var context = convert(manifest); - var res = createParticipantContext(context) - .compose(u -> createTokenAndStoreInVault(context)).onSuccess(k -> response.put("apiKey", k)) - .compose(apiKey -> stsAccountProvisioner.create(manifest)) - .onSuccess(accountInfo -> { - if (accountInfo != null) { - response.put("clientId", accountInfo.clientId()); - response.put("clientSecret", accountInfo.clientSecret()); - } - }) + + return createParticipantContext(context) + .compose(this::createTokenAndStoreInVault) + .compose((Function>) apiKey -> stsAccountProvisioner.create(manifest) + .map(accountInfo -> { + if (accountInfo == null) { + return new CreateParticipantContextResponse(apiKey, null, null); + } else { + return new CreateParticipantContextResponse(apiKey, accountInfo.clientId(), accountInfo.clientSecret()); + } + })) .onSuccess(apiToken -> observable.invokeForEach(l -> l.created(context, manifest))); - return res.map(u -> response); }); } @@ -160,11 +160,9 @@ private ServiceResult createTokenAndStoreInVault(ParticipantContext part } - private ServiceResult createParticipantContext(ParticipantContext context) { - var storeRes = participantContextStore.create(context); - return storeRes.succeeded() ? - success() : - fromFailure(storeRes); + private ServiceResult createParticipantContext(ParticipantContext context) { + var result = participantContextStore.create(context); + return ServiceResult.from(result).map(it -> context); } private ParticipantContext findByIdInternal(String participantId) { diff --git a/core/identity-hub-participants/src/test/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextServiceImplTest.java b/core/identity-hub-participants/src/test/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextServiceImplTest.java index 7f89c0b60..9cfebeb1d 100644 --- a/core/identity-hub-participants/src/test/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextServiceImplTest.java +++ b/core/identity-hub-participants/src/test/java/org/eclipse/edc/identityhub/participantcontext/ParticipantContextServiceImplTest.java @@ -17,9 +17,9 @@ import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.jwk.Curve; import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator; -import org.assertj.core.api.Assertions; import org.eclipse.edc.identithub.spi.did.model.DidResource; import org.eclipse.edc.identithub.spi.did.store.DidResourceStore; +import org.eclipse.edc.identityhub.spi.participantcontext.AccountInfo; import org.eclipse.edc.identityhub.spi.participantcontext.StsAccountProvisioner; import org.eclipse.edc.identityhub.spi.participantcontext.events.ParticipantContextObservable; import org.eclipse.edc.identityhub.spi.participantcontext.model.KeyDescriptor; @@ -45,6 +45,7 @@ import java.util.List; import java.util.Map; +import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -62,15 +63,15 @@ class ParticipantContextServiceImplTest { private final ParticipantContextStore participantContextStore = mock(); private final ParticipantContextObservable observableMock = mock(); private final DidResourceStore didResourceStore = mock(); - private final StsAccountProvisioner provisionerMock = mock(); + private final StsAccountProvisioner stsAccountProvisioner = mock(); private ParticipantContextServiceImpl participantContextService; @BeforeEach void setUp() { var keyParserRegistry = new KeyParserRegistryImpl(); keyParserRegistry.register(new PemParser(mock())); - participantContextService = new ParticipantContextServiceImpl(participantContextStore, didResourceStore, vault, new NoopTransactionContext(), observableMock, provisionerMock); - when(provisionerMock.create(any())).thenReturn(ServiceResult.success()); + participantContextService = new ParticipantContextServiceImpl(participantContextStore, didResourceStore, vault, new NoopTransactionContext(), observableMock, stsAccountProvisioner); + when(stsAccountProvisioner.create(any())).thenReturn(ServiceResult.success()); } @ParameterizedTest(name = "isActive: {0}") @@ -92,8 +93,12 @@ void createParticipantContext_withPublicKeyPem(boolean isActive) { .publicKeyJwk(null) .publicKeyPem(pem) .build()).build(); - assertThat(participantContextService.createParticipantContext(ctx)) - .isSucceeded(); + + assertThat(participantContextService.createParticipantContext(ctx)).isSucceeded().satisfies(response -> { + assertThat(response.apiKey()).isNotBlank(); + assertThat(response.clientId()).isNull(); + assertThat(response.clientSecret()).isNull(); + }); verify(participantContextStore).create(any()); verify(vault).storeSecret(eq(ctx.getParticipantId() + "-apikey"), anyString()); @@ -101,6 +106,35 @@ void createParticipantContext_withPublicKeyPem(boolean isActive) { verify(observableMock).invokeForEach(any()); } + @ParameterizedTest(name = "isActive: {0}") + @ValueSource(booleans = { true, false }) + void shouldCreateParticipantContext_withAccountInfo(boolean isActive) { + when(participantContextStore.create(any())).thenReturn(StoreResult.success()); + when(vault.storeSecret(anyString(), anyString())).thenReturn(Result.success()); + when(stsAccountProvisioner.create(any())).thenReturn(ServiceResult.success(new AccountInfo("clientId", "clientSecret"))); + + var pem = """ + -----BEGIN PUBLIC KEY----- + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE25DvKuU5+gvMdKkyiDDIsx3tcuPX + jgVyAjs1JcfFtvi9I0FemuqymDTu3WWdYmdaJQMJJx3qwEJGTVTxcKGtEg== + -----END PUBLIC KEY----- + """; + + var ctx = createManifest() + .active(isActive) + .key(createKey() + .publicKeyJwk(null) + .publicKeyPem(pem) + .build()).build(); + + var result = participantContextService.createParticipantContext(ctx); + + assertThat(result).isSucceeded().satisfies(response -> { + assertThat(response.apiKey()).isNotBlank(); + assertThat(response.clientId()).isEqualTo("clientId"); + assertThat(response.clientSecret()).isEqualTo("clientSecret"); + }); + } @ParameterizedTest(name = "isActive: {0}") @ValueSource(booleans = { true, false }) @@ -161,7 +195,7 @@ void createParticipantContext_whenExists() { var ctx = createManifest().build(); assertThat(participantContextService.createParticipantContext(ctx)) .isFailed() - .satisfies(f -> Assertions.assertThat(f.getReason()).isEqualTo(ServiceFailure.Reason.CONFLICT)); + .satisfies(f -> assertThat(f.getReason()).isEqualTo(ServiceFailure.Reason.CONFLICT)); verify(participantContextStore).create(any()); verifyNoMoreInteractions(vault, participantContextStore, observableMock); @@ -199,8 +233,8 @@ void getParticipantContext_whenNotExists() { assertThat(participantContextService.getParticipantContext("test-id")) .isFailed() .satisfies(f -> { - Assertions.assertThat(f.getReason()).isEqualTo(ServiceFailure.Reason.NOT_FOUND); - Assertions.assertThat(f.getFailureDetail()).isEqualTo("foo"); + assertThat(f.getReason()).isEqualTo(ServiceFailure.Reason.NOT_FOUND); + assertThat(f.getFailureDetail()).isEqualTo("foo"); }); verify(participantContextStore).findById(anyString()); @@ -213,8 +247,8 @@ void getParticipantContext_whenStorageFails() { assertThat(participantContextService.getParticipantContext("test-id")) .isFailed() .satisfies(f -> { - Assertions.assertThat(f.getReason()).isEqualTo(ServiceFailure.Reason.NOT_FOUND); - Assertions.assertThat(f.getFailureDetail()).isEqualTo("foo bar"); + assertThat(f.getReason()).isEqualTo(ServiceFailure.Reason.NOT_FOUND); + assertThat(f.getFailureDetail()).isEqualTo("foo bar"); }); verify(participantContextStore).findById(anyString()); @@ -244,8 +278,8 @@ void deleteParticipantContext_whenNotExists() { assertThat(participantContextService.deleteParticipantContext("test-id")) .isFailed() .satisfies(f -> { - Assertions.assertThat(f.getReason()).isEqualTo(ServiceFailure.Reason.NOT_FOUND); - Assertions.assertThat(f.getFailureDetail()).isEqualTo("foo bar"); + assertThat(f.getReason()).isEqualTo(ServiceFailure.Reason.NOT_FOUND); + assertThat(f.getFailureDetail()).isEqualTo("foo bar"); }); verify(observableMock, times(2)).invokeForEach(any()); //deleting @@ -333,7 +367,7 @@ void query() { assertThat(participantContextService.query(QuerySpec.max())) .isSucceeded() - .satisfies(res -> Assertions.assertThat(res).hasSize(3)); + .satisfies(res -> assertThat(res).hasSize(3)); verify(participantContextStore).query(any()); verifyNoMoreInteractions(vault); @@ -372,4 +406,4 @@ private Map createJwk() { throw new RuntimeException(e); } } -} \ No newline at end of file +} diff --git a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IdentityHubEndToEndTestContext.java b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IdentityHubEndToEndTestContext.java index 7e6cd6335..84b7a7b52 100644 --- a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IdentityHubEndToEndTestContext.java +++ b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/IdentityHubEndToEndTestContext.java @@ -89,7 +89,9 @@ public String createParticipant(String participantId, List roles, boolea .build()) .build(); var srv = runtime.getService(ParticipantContextService.class); - return srv.createParticipantContext(manifest).orElseThrow(f -> new EdcException(f.getFailureDetail())).get("apiKey").toString(); + return srv.createParticipantContext(manifest) + .orElseThrow(f -> new EdcException(f.getFailureDetail())) + .apiKey(); } diff --git a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/PostgresSqlService.java b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/PostgresSqlService.java index 78e53b7f3..3de4fe310 100644 --- a/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/PostgresSqlService.java +++ b/e2e-tests/api-tests/src/test/java/org/eclipse/edc/identityhub/tests/fixtures/PostgresSqlService.java @@ -73,7 +73,7 @@ public void stop() { } private void createDatabase() { - var postgres = new PostgresqlLocalInstance(PostgresqlEndToEndInstance.USER, PostgresqlEndToEndInstance.PASSWORD, baseJdbcUrl(hostPort), dbName); - postgres.createDatabase(); + var postgres = new PostgresqlLocalInstance(PostgresqlEndToEndInstance.USER, PostgresqlEndToEndInstance.PASSWORD, baseJdbcUrl(hostPort)); + postgres.createDatabase(dbName); } } diff --git a/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json b/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json index e79df49a6..b927a64a2 100644 --- a/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json +++ b/extensions/api/identity-api/api-configuration/src/main/resources/identity-api-version.json @@ -2,7 +2,7 @@ { "version": "1.0.0-alpha", "urlPath": "/v1alpha", - "lastUpdated": "2024-10-02T12:00:00Z", + "lastUpdated": "2024-12-05T14:13:00Z", "maturity": null } -] \ No newline at end of file +] diff --git a/extensions/api/identity-api/participant-context-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApi.java b/extensions/api/identity-api/participant-context-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApi.java index 8b0675f48..3601af233 100644 --- a/extensions/api/identity-api/participant-context-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApi.java +++ b/extensions/api/identity-api/participant-context-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApi.java @@ -25,13 +25,13 @@ 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.participantcontext.model.CreateParticipantContextResponse; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantManifest; import org.eclipse.edc.web.spi.ApiErrorDetail; import java.util.Collection; import java.util.List; -import java.util.Map; @OpenAPIDefinition(info = @Info(description = "This is the Identity API for manipulating ParticipantContexts", title = "ParticipantContext Management API", version = "1")) @Tag(name = "Participant Context") @@ -42,7 +42,8 @@ public interface ParticipantContextApi { operationId = "createParticipant", requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = ParticipantManifest.class), mediaType = "application/json")), responses = { - @ApiResponse(responseCode = "200", description = "The ParticipantContext was created successfully, its API token is returned in the response body."), + @ApiResponse(responseCode = "200", description = "The ParticipantContext was created successfully, its API token is returned in the response body.", + content = @Content(schema = @Schema(implementation = CreateParticipantContextResponse.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.", @@ -51,7 +52,7 @@ public interface ParticipantContextApi { content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetail.class)), mediaType = "application/json")) } ) - Map createParticipant(ParticipantManifest manifest); + CreateParticipantContextResponse createParticipant(ParticipantManifest manifest); @Operation(description = "Gets ParticipantContexts by ID.", diff --git a/extensions/api/identity-api/participant-context-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApiController.java b/extensions/api/identity-api/participant-context-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApiController.java index 988fb8490..7c4b76ec1 100644 --- a/extensions/api/identity-api/participant-context-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApiController.java +++ b/extensions/api/identity-api/participant-context-api/src/main/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApiController.java @@ -32,6 +32,7 @@ import org.eclipse.edc.identityhub.spi.AuthorizationService; import org.eclipse.edc.identityhub.spi.authentication.ServicePrincipal; import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; +import org.eclipse.edc.identityhub.spi.participantcontext.model.CreateParticipantContextResponse; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantManifest; import org.eclipse.edc.spi.query.QuerySpec; @@ -40,7 +41,6 @@ import java.util.Collection; import java.util.List; -import java.util.Map; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; import static org.eclipse.edc.identityhub.spi.AuthorizationResultHandler.exceptionMapper; @@ -64,7 +64,7 @@ public ParticipantContextApiController(ParticipantManifestValidator participantM @Override @POST @RolesAllowed(ServicePrincipal.ROLE_ADMIN) - public Map createParticipant(ParticipantManifest manifest) { + public CreateParticipantContextResponse createParticipant(ParticipantManifest manifest) { participantManifestValidator.validate(manifest).orElseThrow(ValidationFailureException::new); return participantContextService.createParticipantContext(manifest) .orElseThrow(exceptionMapper(ParticipantManifest.class, manifest.getParticipantId())); diff --git a/extensions/api/identity-api/participant-context-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApiControllerTest.java b/extensions/api/identity-api/participant-context-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApiControllerTest.java index c5603eb12..5de18ba7e 100644 --- a/extensions/api/identity-api/participant-context-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApiControllerTest.java +++ b/extensions/api/identity-api/participant-context-api/src/test/java/org/eclipse/edc/identityhub/api/participantcontext/v1/unstable/ParticipantContextApiControllerTest.java @@ -17,12 +17,12 @@ import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.jwk.Curve; import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator; -import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import org.eclipse.edc.identityhub.api.Versions; import org.eclipse.edc.identityhub.api.v1.validation.ParticipantManifestValidator; import org.eclipse.edc.identityhub.spi.AuthorizationService; import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService; +import org.eclipse.edc.identityhub.spi.participantcontext.model.CreateParticipantContextResponse; import org.eclipse.edc.identityhub.spi.participantcontext.model.KeyDescriptor; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContextState; @@ -33,6 +33,7 @@ import org.eclipse.edc.web.jersey.testfixtures.RestControllerTestBase; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import java.time.Instant; @@ -42,9 +43,11 @@ import java.util.stream.IntStream; import static io.restassured.RestAssured.given; +import static io.restassured.http.ContentType.JSON; import static java.util.Collections.emptyList; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; @@ -96,69 +99,78 @@ void getById_whenNotFound() { .log().ifError(); } - @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) - .post() - .then() - .statusCode(204); - verify(participantContextServiceMock).createParticipantContext(any(ParticipantManifest.class)); - } - - @Test - 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); - } - - @Test - void createParticipant_invalidKeyDescriptor() { - var manifest = createManifest() - .key(createKey().publicKeyPem(null).publicKeyJwk(null).keyGeneratorParams(null).build()) - .build(); - when(participantManifestValidator.validate(any())).thenReturn(ValidationResult.failure(emptyList())); + @Nested + class Create { + @Test + void shouldReturnOk_whenParticipantIsCreated() { + var response = new CreateParticipantContextResponse("apiKey", "clientId", "clientSecret"); + when(participantContextServiceMock.createParticipantContext(any())).thenReturn(ServiceResult.success(response)); + when(participantManifestValidator.validate(any())).thenReturn(ValidationResult.success()); + var manifest = createManifest().build(); + + baseRequest() + .accept(JSON) + .contentType(JSON) + .body(manifest) + .post() + .then() + .statusCode(200) + .contentType(JSON) + .body("apiKey", is("apiKey")) + .body("clientId", is("clientId")) + .body("clientSecret", is("clientSecret")); + verify(participantContextServiceMock).createParticipantContext(any(ParticipantManifest.class)); + } - baseRequest() - .contentType(ContentType.JSON) - .body(manifest) - .post() - .then() - .statusCode(400); + @Test + void shouldReturnBadRequest_whenValidationFails() { + var manifest = createManifest() + .participantId(null) + .build(); + when(participantManifestValidator.validate(any())).thenReturn(ValidationResult.failure(emptyList())); + + baseRequest() + .contentType(JSON) + .body(manifest) + .post() + .then() + .statusCode(400); + + verifyNoInteractions(participantContextServiceMock); + } - verifyNoInteractions(participantContextServiceMock); - } + @Test + void shouldReturnBadRequest_whenInvalidKeyDescriptor() { + var manifest = createManifest() + .key(createKey().publicKeyPem(null).publicKeyJwk(null).keyGeneratorParams(null).build()) + .build(); + when(participantManifestValidator.validate(any())).thenReturn(ValidationResult.failure(emptyList())); + + baseRequest() + .contentType(JSON) + .body(manifest) + .post() + .then() + .statusCode(400); + + verifyNoInteractions(participantContextServiceMock); + } - @Test - void createParticipant_alreadyExists() { - when(participantContextServiceMock.createParticipantContext(any())).thenReturn(ServiceResult.conflict("already exists")); - var manifest = createManifest().build(); - when(participantManifestValidator.validate(any())).thenReturn(ValidationResult.success()); + @Test + void shouldReturnConflict_whenAlreadyExists() { + 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); + baseRequest() + .contentType(JSON) + .body(manifest) + .post() + .then() + .statusCode(409); - verify(participantContextServiceMock).createParticipantContext(any(ParticipantManifest.class)); + verify(participantContextServiceMock).createParticipantContext(any(ParticipantManifest.class)); + } } @Test @@ -315,4 +327,4 @@ private Map createJwk() { throw new RuntimeException(e); } } -} \ No newline at end of file +} diff --git a/spi/participant-context-spi/src/main/java/org/eclipse/edc/identityhub/spi/participantcontext/ParticipantContextService.java b/spi/participant-context-spi/src/main/java/org/eclipse/edc/identityhub/spi/participantcontext/ParticipantContextService.java index 143f2e087..c5c745106 100644 --- a/spi/participant-context-spi/src/main/java/org/eclipse/edc/identityhub/spi/participantcontext/ParticipantContextService.java +++ b/spi/participant-context-spi/src/main/java/org/eclipse/edc/identityhub/spi/participantcontext/ParticipantContextService.java @@ -14,13 +14,13 @@ package org.eclipse.edc.identityhub.spi.participantcontext; +import org.eclipse.edc.identityhub.spi.participantcontext.model.CreateParticipantContextResponse; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantContext; import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantManifest; import org.eclipse.edc.spi.query.QuerySpec; import org.eclipse.edc.spi.result.ServiceResult; import java.util.Collection; -import java.util.Map; import java.util.function.Consumer; /** @@ -28,14 +28,13 @@ */ public interface ParticipantContextService { - /** * Creates a new participant context from a manifest. If one with the same ID exists, a failure is returned. * * @param manifest The new participant context * @return success if created, or a failure if already exists. */ - ServiceResult> createParticipantContext(ParticipantManifest manifest); + ServiceResult createParticipantContext(ParticipantManifest manifest); /** * Fetches the {@link ParticipantContext} by ID. diff --git a/spi/participant-context-spi/src/main/java/org/eclipse/edc/identityhub/spi/participantcontext/model/CreateParticipantContextResponse.java b/spi/participant-context-spi/src/main/java/org/eclipse/edc/identityhub/spi/participantcontext/model/CreateParticipantContextResponse.java new file mode 100644 index 000000000..e018959e8 --- /dev/null +++ b/spi/participant-context-spi/src/main/java/org/eclipse/edc/identityhub/spi/participantcontext/model/CreateParticipantContextResponse.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Cofinity-X + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Cofinity-X - initial API and implementation + * + */ + +package org.eclipse.edc.identityhub.spi.participantcontext.model; + +/** + * Response representation for the {@link ParticipantContext} creation + */ +public record CreateParticipantContextResponse(String apiKey, String clientId, String clientSecret) { +}