Skip to content

Commit

Permalink
feat: Add support for participant context in IssuanceProcess
Browse files Browse the repository at this point in the history
  • Loading branch information
wolf4ood committed Feb 18, 2025
1 parent 1b7f9d1 commit 87e0583
Show file tree
Hide file tree
Showing 35 changed files with 256 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ private ServiceResult<Void> internalUpdate(CredentialDefinition credentialDefini
}

private ServiceResult<Void> validateAttestations(CredentialDefinition credentialDefinition) {
if (credentialDefinition.getAttestations().isEmpty()) {
return ServiceResult.success();
}
var query = QuerySpec.Builder.newInstance()
.filter(Criterion.criterion("id", "in", credentialDefinition.getAttestations()))
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ private IssuanceProcess createIssuanceProcess() {
.id("id")
.state(IssuanceProcessStates.APPROVED.code())
.participantId("participantId")
.issuerContextId("issuerContextId")
.build();
}
}
3 changes: 3 additions & 0 deletions dist/bom/issuerservice-feature-sql-bom/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ plugins {
dependencies {
// sql modules
api(project(":extensions:store:sql:issuerservice-participant-store-sql"))
api(project(":extensions:store:sql:issuerservice-attestation-definition-store-sql"))
api(project(":extensions:store:sql:issuerservice-credential-definition-store-sql"))
api(project(":extensions:store:sql:issuance-process-store-sql"))

api(libs.edc.sql.core)
api(libs.edc.transaction.local)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.validator.spi.ValidationResult;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import java.util.Base64;
import java.util.Map;

import static io.restassured.http.ContentType.JSON;
Expand All @@ -69,6 +71,10 @@ abstract static class Tests {
public static final String DID_WEB_PARTICIPANT_KEY_1 = "did:web:participant#key1";
public static final ECKey PARTICIPANT_KEY = generateEcKey(DID_WEB_PARTICIPANT_KEY_1);
protected static final AttestationSourceFactory ATTESTATION_SOURCE_FACTORY = mock();

protected static final String ISSUER_ID = "issuer";
private static final String ISSUER_ID_ENCODED = Base64.getUrlEncoder().encodeToString(ISSUER_ID.getBytes());

private static final String VALID_CREDENTIAL_REQUEST_MESSAGE = """
{
"@context": [
Expand Down Expand Up @@ -98,6 +104,11 @@ static void beforeAll(IssuerServiceEndToEndTestContext context) {
var validationRegistry = context.getRuntime().getService(AttestationDefinitionValidatorRegistry.class);
pipelineFactory.registerFactory("Attestation", ATTESTATION_SOURCE_FACTORY);
validationRegistry.registerValidator("Attestation", def -> ValidationResult.success());
context.createParticipant(ISSUER_ID);
}

private static @NotNull String issuanceUrl() {
return "/v1alpha/participants/%s/credentials".formatted(ISSUER_ID_ENCODED);
}

@AfterEach
Expand Down Expand Up @@ -150,14 +161,14 @@ void requestCredential(IssuerServiceEndToEndTestContext context, ParticipantServ
.contentType(JSON)
.header(AUTHORIZATION, token)
.body(VALID_CREDENTIAL_REQUEST_MESSAGE)
.post("/v1alpha/credentials")
.post(issuanceUrl())
.then()
.log().ifValidationFails()
.statusCode(201)
.extract()
.header("Location");

assertThat(location).contains("/v1alpha/requests/");
assertThat(location).contains("/v1alpha/participants/%s/requests".formatted(ISSUER_ID_ENCODED));

var processId = location.substring(location.lastIndexOf('/') + 1);
var issuanceProcess = issuanceProcessStore.findById(processId);
Expand All @@ -167,6 +178,7 @@ void requestCredential(IssuerServiceEndToEndTestContext context, ParticipantServ
assertThat(process.getParticipantId()).isEqualTo(PARTICIPANT_DID);
assertThat(process.getCredentialDefinitions()).containsExactly("credential-id");
assertThat(process.getClaims()).containsAllEntriesOf(claims);
assertThat(process.getIssuerContextId()).isEqualTo(ISSUER_ID);
});

}
Expand All @@ -179,7 +191,7 @@ void requestCredential_validationError_shouldReturn400(IssuerServiceEndToEndTest
.contentType(JSON)
.header(AUTHORIZATION, token)
.body(FAULTY_CREDENTIAL_REQUEST_MESSAGE)
.post("/v1alpha/credentials")
.post(issuanceUrl())
.then()
.log().ifValidationFails()
.statusCode(400);
Expand All @@ -191,7 +203,7 @@ void requestCredential_tokenNotPresent_shouldReturn401(IssuerServiceEndToEndTest
context.getDcpIssuanceEndpoint().baseRequest()
.contentType(JSON)
.body(VALID_CREDENTIAL_REQUEST_MESSAGE)
.post("/v1alpha/credentials")
.post(issuanceUrl())
.then()
.log().ifValidationFails()
.statusCode(401);
Expand All @@ -206,7 +218,7 @@ void requestCredential_participantNotFound_shouldReturn401(IssuerServiceEndToEnd
.contentType(JSON)
.header(AUTHORIZATION, token)
.body(VALID_CREDENTIAL_REQUEST_MESSAGE)
.post("/v1alpha/credentials")
.post(issuanceUrl())
.then()
.log().ifValidationFails()
.statusCode(401);
Expand All @@ -228,7 +240,7 @@ void requestCredential_tokenVerificationFails_shouldReturn401(IssuerServiceEndTo
.contentType(JSON)
.header(AUTHORIZATION, token)
.body(VALID_CREDENTIAL_REQUEST_MESSAGE)
.post("/v1alpha/credentials")
.post(issuanceUrl())
.then()
.log().ifValidationFails()
.statusCode(401);
Expand All @@ -248,7 +260,7 @@ void requestCredential_wrongTokenAudience_shouldReturn401(IssuerServiceEndToEndT
.contentType(JSON)
.header(AUTHORIZATION, token)
.body(VALID_CREDENTIAL_REQUEST_MESSAGE)
.post("/v1alpha/credentials")
.post(issuanceUrl())
.then()
.log().ifValidationFails()
.statusCode(401);
Expand All @@ -268,7 +280,7 @@ void requestCredential_definitionNotFound_shouldReturn400(IssuerServiceEndToEndT
.contentType(JSON)
.header(AUTHORIZATION, token)
.body(VALID_CREDENTIAL_REQUEST_MESSAGE)
.post("/v1alpha/credentials")
.post(issuanceUrl())
.then()
.log().ifValidationFails()
.statusCode(400);
Expand Down Expand Up @@ -314,7 +326,7 @@ void requestCredential_attestationsNotFulfilled_shouldReturn403(IssuerServiceEnd
.contentType(JSON)
.header(AUTHORIZATION, token)
.body(VALID_CREDENTIAL_REQUEST_MESSAGE)
.post("/v1alpha/credentials")
.post(issuanceUrl())
.then()
.log().ifValidationFails()
.statusCode(403);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static IssuerServiceEndToEndTestContext context() {
var runtime = new EmbeddedRuntime(
"issuerservice",
configuration.config(),
":dist:bom:issuerservice-bom"
":dist:bom:issuerservice-with-sts-bom"
);

return new IssuerServiceEndToEndTestContext(runtime, configuration);
Expand Down Expand Up @@ -112,7 +112,7 @@ public static IssuerServiceEndToEndTestContext context(String dbName, Integer po
var runtime = new EmbeddedRuntime(
"issuerservice-pg",
cfg,
":dist:bom:issuerservice-bom",
":dist:bom:issuerservice-with-sts-bom",
":dist:bom:issuerservice-feature-sql-bom"

);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@

package org.eclipse.edc.identityhub.tests.fixtures;

import org.eclipse.edc.iam.did.spi.document.Service;
import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService;
import org.eclipse.edc.identityhub.spi.participantcontext.model.KeyDescriptor;
import org.eclipse.edc.identityhub.spi.participantcontext.model.ParticipantManifest;
import org.eclipse.edc.junit.extensions.EmbeddedRuntime;
import org.eclipse.edc.spi.EdcException;

import java.util.List;
import java.util.Map;

/**
* IssuerService end to end context used in tests extended with {@link IssuerServiceEndToEndExtension}
Expand Down Expand Up @@ -42,4 +50,34 @@ public IssuerServiceRuntimeConfiguration.Endpoint getAdminEndpoint() {
public IssuerServiceRuntimeConfiguration.Endpoint getDcpIssuanceEndpoint() {
return configuration.getIssuerApiEndpoint();
}

public String createParticipant(String participantContextId) {
return createParticipant(participantContextId, List.of());
}

public String createParticipant(String participantContextId, List<String> roles, boolean isActive) {
var manifest = ParticipantManifest.Builder.newInstance()
.participantId(participantContextId)
.active(isActive)
.roles(roles)
.serviceEndpoint(new Service("test-service-id", "test-type", "http://foo.bar.com"))
.did("did:web:" + participantContextId)
.key(KeyDescriptor.Builder.newInstance()
.privateKeyAlias(participantContextId + "-alias")
.resourceId(participantContextId + "-resource")
.keyId(participantContextId + "-key")
.keyGeneratorParams(Map.of("algorithm", "EC", "curve", "secp256r1"))
.build())
.build();
var srv = runtime.getService(ParticipantContextService.class);
return srv.createParticipantContext(manifest)
.orElseThrow(f -> new EdcException(f.getFailureDetail()))
.apiKey();
}


public String createParticipant(String participantContextId, List<String> roles) {
return createParticipant(participantContextId, roles, true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,14 @@ public Map<String, String> config() {
put("web.http.version.path", "/.well-known/api");
put("web.http.did.port", String.valueOf(getFreePort()));
put("web.http.did.path", "/");
put("edc.ih.iam.id", "did:web:issuer");
put("edc.sql.schema.autocreate", "true");
put("edc.sts.account.api.url", "http://sts.com/accounts");
put("edc.sts.accounts.api.auth.header.value", "password");
put("edc.iam.accesstoken.jti.validation", String.valueOf(false));
put("edc.issuer.statuslist.signing.key.alias", "signing-key");
// config for the remote STS
put("edc.iam.sts.oauth.token.url", "https://sts.com/oauth/token");
put("edc.iam.sts.oauth.client.secret.alias", "secret");
put("edc.iam.sts.oauth.client.id", "clientId");
// config for the embedded STS
put("edc.iam.sts.publickey.id", "test-public-key");
put("edc.iam.sts.privatekey.alias", "issuer-alias");
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ class IssuerService extends SmokeTest {
put("edc.sts.account.api.url", "https://sts.com/accounts");
put("edc.sts.accounts.api.auth.header.value", "password");
put("edc.issuer.statuslist.signing.key.alias", "signing-key");
put("edc.ih.iam.id", "did:web:issuer");
// config for the remote STS
put("edc.iam.sts.oauth.token.url", "https://sts.com/oauth/token");
put("edc.iam.sts.oauth.client.secret.alias", "secret");
Expand Down Expand Up @@ -170,7 +169,6 @@ class IssuerServiceWithSts extends SmokeTest {
put("edc.sts.account.api.url", "https://sts.com/accounts");
put("edc.sts.accounts.api.auth.header.value", "password");
put("edc.issuer.statuslist.signing.key.alias", "signing-key");
put("edc.ih.iam.id", "did:web:issuer");
// interaction with embedded STS
put("edc.iam.sts.publickey.id", "test-public-key");
put("edc.iam.sts.privatekey.alias", "test-private-key");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public String getInsertTemplate() {
.jsonColumn(getTraceContextColumn())
.column(getErrorDetailColumn())
.column(getParticipantIdColumn())
.column(getIssuerContextIdColumn())
.jsonColumn(getClaimsColumn())
.jsonColumn(getCredentialDefinitionsColumn())
.insertInto(getIssuanceProcessTable());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ default String getParticipantIdColumn() {
return "participant_id";
}

default String getIssuerContextIdColumn() {
return "issuer_context_id";
}

String getInsertTemplate();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ private void insert(Connection conn, IssuanceProcess process) {
toJson(process.getTraceContext()),
process.getErrorDetail(),
process.getParticipantId(),
process.getIssuerContextId(),
toJson(process.getClaims()),
toJson(process.getCredentialDefinitions())
);
Expand Down Expand Up @@ -198,6 +199,7 @@ private IssuanceProcess mapResultSet(ResultSet resultSet) throws Exception {
.traceContext(fromJson(resultSet.getString(statements.getTraceContextColumn()), getTypeRef()))
.errorDetail(resultSet.getString(statements.getErrorDetailColumn()))
.participantId(resultSet.getString(statements.getParticipantIdColumn()))
.issuerContextId(resultSet.getString(statements.getIssuerContextIdColumn()))
.claims(fromJson(resultSet.getString(statements.getClaimsColumn()), getTypeRef()))
.credentialDefinitions(fromJson(resultSet.getString(statements.getCredentialDefinitionsColumn()), ATTESTATIONS_LIST_REF))
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ public class IssuanceProcessMapping extends StatefulEntityMapping {

public static final String FIELD_ID = "id";
public static final String FIELD_PARTICIPANT_ID = "participantId";
public static final String FIELD_ISSUER_CONTEXT_ID = "issuerContextId";
public static final String FIELD_CLAIMS = "claims";
public static final String FIELD_CREDENTIAL_DEFINITIONS = "credentialDefinitions";

public IssuanceProcessMapping(IssuanceProcessStoreStatements statements) {
super(statements);
add(FIELD_ID, statements.getIdColumn());
add(FIELD_PARTICIPANT_ID, statements.getParticipantIdColumn());
add(FIELD_ISSUER_CONTEXT_ID, statements.getIssuerContextIdColumn());
add(FIELD_CLAIMS, new JsonFieldTranslator(FIELD_CLAIMS));
add(FIELD_CREDENTIAL_DEFINITIONS, new JsonArrayTranslator(statements.getCredentialDefinitionsColumn()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ CREATE TABLE IF NOT EXISTS edc_issuance_process
pending BOOLEAN DEFAULT FALSE,
lease_id VARCHAR CONSTRAINT issuance_process_lease_lease_id_fk REFERENCES edc_lease ON DELETE SET NULL,
participant_id VARCHAR NOT NULL,
issuer_context_id VARCHAR NOT NULL,
claims JSON NOT NULL,
credential_definitions JSONB NOT NULL
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
*
*/

package org.eclipse.edc.issuerservice.store.sql.attestationdefinition;
package org.eclipse.edc.issuerservice.store.sql.credentialdefinition;

import org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres.CredentialDefinitionMapping;
import org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres.CredentialDefinitionMapping;
import org.eclipse.edc.spi.query.QuerySpec;
import org.eclipse.edc.sql.translation.PostgresqlOperatorTranslator;
import org.eclipse.edc.sql.translation.SqlQueryStatement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
*/

package org.eclipse.edc.issuerservice.store.sql.attestationdefinition;
package org.eclipse.edc.issuerservice.store.sql.credentialdefinition;

import org.eclipse.edc.issuerservice.spi.issuance.model.CredentialDefinition;
import org.eclipse.edc.spi.query.QuerySpec;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
*/

package org.eclipse.edc.issuerservice.store.sql.attestationdefinition;
package org.eclipse.edc.issuerservice.store.sql.credentialdefinition;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
*
*/

package org.eclipse.edc.issuerservice.store.sql.attestationdefinition;
package org.eclipse.edc.issuerservice.store.sql.credentialdefinition;

import org.eclipse.edc.issuerservice.spi.issuance.credentialdefinition.store.CredentialDefinitionStore;
import org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres.PostgresDialectStatements;
import org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres.PostgresDialectStatements;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
Expand All @@ -30,7 +30,7 @@

import java.time.Clock;

import static org.eclipse.edc.issuerservice.store.sql.attestationdefinition.SqlCredentialDefinitionStoreExtension.NAME;
import static org.eclipse.edc.issuerservice.store.sql.credentialdefinition.SqlCredentialDefinitionStoreExtension.NAME;

@Extension(value = NAME)
public class SqlCredentialDefinitionStoreExtension implements ServiceExtension {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
*
*/

package org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres;
package org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres;

import org.eclipse.edc.issuerservice.store.sql.attestationdefinition.CredentialDefinitionStoreStatements;
import org.eclipse.edc.issuerservice.store.sql.credentialdefinition.CredentialDefinitionStoreStatements;
import org.eclipse.edc.sql.translation.JsonArrayTranslator;
import org.eclipse.edc.sql.translation.JsonFieldTranslator;
import org.eclipse.edc.sql.translation.TranslationMapping;

import static org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres.PostgresDialectStatements.MAPPING_ALIAS;
import static org.eclipse.edc.issuerservice.store.sql.attestationdefinition.schema.postgres.PostgresDialectStatements.RULES_ALIAS;
import static org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres.PostgresDialectStatements.MAPPING_ALIAS;
import static org.eclipse.edc.issuerservice.store.sql.credentialdefinition.schema.postgres.PostgresDialectStatements.RULES_ALIAS;


/**
Expand Down
Loading

0 comments on commit 87e0583

Please sign in to comment.