Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: moved IATP model classes up from IdentityHub #3612

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
import org.eclipse.edc.runtime.metamodel.annotation.Setting;
import org.eclipse.edc.spi.http.EdcHttpClient;
import org.eclipse.edc.spi.iam.IdentityService;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.spi.types.TypeManager;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.eclipse.edc.verifiablecredentials.jwt.JwtPresentationVerifier;
import org.eclipse.edc.verifiablecredentials.linkeddata.LdpVerifier;
import org.eclipse.edc.verification.jwt.SelfIssuedIdTokenVerifier;
Expand All @@ -51,7 +53,6 @@ public class IdentityAndTrustExtension implements ServiceExtension {
@Inject
private SecureTokenService secureTokenService;

private PresentationVerifier presentationVerifier;

@Inject
private CredentialServiceClient credentialServiceClient;
Expand All @@ -71,11 +72,19 @@ public class IdentityAndTrustExtension implements ServiceExtension {
@Inject
private JsonLd jsonLd;

private JwtValidator jwtValidator;
private JwtVerifier jwtVerifier;
@Inject
private Clock clock;

@Inject
private TypeTransformerRegistry typeTransformerRegistry;

@Inject
private EdcHttpClient httpClient;

private JwtValidator jwtValidator;
private JwtVerifier jwtVerifier;
private PresentationVerifier presentationVerifier;

@Provider
public IdentityService createIdentityService(ServiceExtensionContext context) {
return new IdentityAndTrustService(secureTokenService, getIssuerDid(context), context.getParticipantId(), getPresentationVerifier(context),
Expand Down Expand Up @@ -115,6 +124,12 @@ public JwtVerifier getJwtVerifier() {
return jwtVerifier;
}

@Provider
public CredentialServiceClient createClient(ServiceExtensionContext context) {
context.getMonitor().warning("Using a dummy CredentialServiceClient, that'll return null always. Don't use this in production use cases!");
return (csUrl, siTokenJwt, scopes) -> null;
}

private String getOwnDid(ServiceExtensionContext context) {
// todo: this must be config value
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,6 @@ public Result<ClaimToken> verifyJwtToken(TokenRepresentation tokenRepresentation
return issuerResult.mapTo();
}

//todo: implement actual VP request, currently it's a stub
// https://github.com/eclipse-edc/Connector/issues/3495
var vpResponse = credentialServiceClient.requestPresentation(null, null, null);

if (vpResponse.failed()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies {

testImplementation(project(":extensions:common:json-ld"))
testImplementation(project(":core:common:transform-core")) //for the TransformerContextImpl
testImplementation(project(":core:common:junit")) //for the TestUtils
testImplementation(testFixtures(project(":spi:common:identity-trust-spi")))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.iam.identitytrust.transform.to;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
import org.eclipse.edc.identitytrust.model.credentialservice.PresentationQuery;
import org.eclipse.edc.identitytrust.model.presentationdefinition.PresentationDefinition;
import org.eclipse.edc.jsonld.spi.JsonLdKeywords;
import org.eclipse.edc.jsonld.spi.transformer.AbstractJsonLdTransformer;
import org.eclipse.edc.transform.spi.TransformerContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Transforms a JsonObject into a PresentationQuery object.
*/
public class JsonObjectToPresentationQueryTransformer extends AbstractJsonLdTransformer<JsonObject, PresentationQuery> {

private final ObjectMapper mapper;

public JsonObjectToPresentationQueryTransformer(ObjectMapper mapper) {
super(JsonObject.class, PresentationQuery.class);
this.mapper = mapper;
}

@Override
public @Nullable PresentationQuery transform(@NotNull JsonObject jsonObject, @NotNull TransformerContext context) {
var bldr = PresentationQuery.Builder.newinstance();
visitProperties(jsonObject, (k, v) -> {
switch (k) {
case PresentationQuery.PRESENTATION_QUERY_DEFINITION_PROPERTY ->
bldr.presentationDefinition(readPresentationDefinition(v, context));
case PresentationQuery.PRESENTATION_QUERY_SCOPE_PROPERTY ->
transformArrayOrObject(v, Object.class, o -> bldr.scope(o.toString()), context);
default -> context.reportProblem("Unknown property '%s'".formatted(k));
}
});

return bldr.build();
}

private PresentationDefinition readPresentationDefinition(JsonValue v, TransformerContext context) {
JsonObject jo;
if (v.getValueType() == JsonValue.ValueType.ARRAY && !((JsonArray) v).isEmpty()) {
jo = v.asJsonArray().getJsonObject(0);
} else {
jo = v.asJsonObject();
}
var rawJson = jo.get(JsonLdKeywords.VALUE);
try {
return mapper.readValue(rawJson.toString(), PresentationDefinition.class);
} catch (JsonProcessingException e) {
context.reportProblem("Error reading JSON literal: %s".formatted(e.getMessage()));
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.iam.identitytrust.transform.to;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.json.JsonObject;
import org.eclipse.edc.core.transform.TransformerContextImpl;
import org.eclipse.edc.core.transform.TypeTransformerRegistryImpl;
import org.eclipse.edc.core.transform.transformer.to.JsonValueToGenericTypeTransformer;
import org.eclipse.edc.jsonld.TitaniumJsonLd;
import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.jsonld.util.JacksonJsonLd;
import org.eclipse.edc.junit.testfixtures.TestUtils;
import org.eclipse.edc.transform.spi.TransformerContext;
import org.eclipse.edc.transform.spi.TypeTransformerRegistry;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

class JsonObjectToPresentationQueryTransformerTest {
private final ObjectMapper mapper = JacksonJsonLd.createObjectMapper();
private final JsonObjectToPresentationQueryTransformer transformer = new JsonObjectToPresentationQueryTransformer(mapper);
private final JsonLd jsonLd = new TitaniumJsonLd(mock());
private final TypeTransformerRegistry trr = new TypeTransformerRegistryImpl();
private final TransformerContext context = new TransformerContextImpl(trr);


@BeforeEach
void setUp() {
jsonLd.registerCachedDocument("https://identity.foundation/presentation-exchange/submission/v1", TestUtils.getFileFromResourceName("presentation_ex.json").toURI());
jsonLd.registerCachedDocument("https://w3id.org/tractusx-trust/v0.8", TestUtils.getFileFromResourceName("presentation_query.json").toURI());
// delegate to the generic transformer

trr.register(new JsonValueToGenericTypeTransformer(mapper));
}

@Test
void transform_withScopes() throws JsonProcessingException {
var obj = """
{
"@context": [
"https://identity.foundation/presentation-exchange/submission/v1",
"https://w3id.org/tractusx-trust/v0.8"
],
"@type": "Query",
"scope": [
"org.eclipse.edc.vc.type:TestCredential:read",
"org.eclipse.edc.vc.type:AnotherCredential:all"
]
}
""";
var json = mapper.readValue(obj, JsonObject.class);
var jo = jsonLd.expand(json);
assertThat(jo.succeeded()).withFailMessage(jo::getFailureDetail).isTrue();

var query = transformer.transform(jo.getContent(), context);
assertThat(query).isNotNull();
assertThat(query.getScopes()).hasSize(2)
.containsExactlyInAnyOrder(
"org.eclipse.edc.vc.type:TestCredential:read",
"org.eclipse.edc.vc.type:AnotherCredential:all");
assertThat(query.getPresentationDefinition()).isNull();
}

@Test
void transform_withPresentationDefinition() throws JsonProcessingException {
var json = """
{
"@context": [
"https://identity.foundation/presentation-exchange/submission/v1",
"https://w3id.org/tractusx-trust/v0.8"
],
"@type": "Query",
"presentationDefinition": {
"id": "first simple example",
"input_descriptors": [
{
"id": "descriptor-id-1",
"name": "A specific type of VC",
"purpose": "We want a VC of this type",
"constraints": {
"fields": [
{
"path": [
"$.type"
],
"filter": {
"type": "string",
"pattern": "<the type of VC e.g. degree certificate>"
}
}
]
}
}
]
}
}
""";
var jobj = mapper.readValue(json, JsonObject.class);

var expansion = jsonLd.expand(jobj);
assertThat(expansion.succeeded()).withFailMessage(expansion::getFailureDetail).isTrue();

var query = transformer.transform(expansion.getContent(), context);
assertThat(query).isNotNull();
assertThat(query.getScopes()).isNotNull().isEmpty();
assertThat(query.getPresentationDefinition()).isNotNull();
assertThat(query.getPresentationDefinition().getInputDescriptors()).isNotEmpty()
.allSatisfy(id -> assertThat(id.getId()).isEqualTo("descriptor-id-1"));

}

@Test
void transform_withScopesAndPresDef() throws JsonProcessingException {
var json = """
{
"@context": [
"https://identity.foundation/presentation-exchange/submission/v1",
"https://w3id.org/tractusx-trust/v0.8"
],
"@type": "Query",
"scope": ["test-scope1"],
"presentationDefinition": {
"id": "first simple example",
"input_descriptors": [
{
"id": "descriptor-id-1",
"name": "A specific type of VC",
"purpose": "We want a VC of this type",
"constraints": {
"fields": [
{
"path": [
"$.type"
],
"filter": {
"type": "string",
"pattern": "<the type of VC e.g. degree certificate>"
}
}
]
}
}
]
}
}
""";
var jobj = mapper.readValue(json, JsonObject.class);

var expansion = jsonLd.expand(jobj);
assertThat(expansion.succeeded()).withFailMessage(expansion::getFailureDetail).isTrue();

var query = transformer.transform(expansion.getContent(), context);
assertThat(query).isNotNull();
assertThat(query.getScopes()).isNotNull().containsExactly("test-scope1");
assertThat(query.getPresentationDefinition()).isNotNull();
assertThat(query.getPresentationDefinition().getInputDescriptors()).isNotEmpty()
.allSatisfy(id -> assertThat(id.getId()).isEqualTo("descriptor-id-1"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"@context": {
"@version": 1.1,
"PresentationSubmission": {
"@id": "https://identity.foundation/presentation-exchange/#presentation-submission",
"@context": {
"@version": 1.1,
"presentation_submission": {
"@id": "https://identity.foundation/presentation-exchange/#presentation-submission",
"@type": "@json"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"@context": {
"scope": {
"@id": "https://w3id.org/tractusx-trust/v0.8/scope",
"@container": "@set"
},
"presentationDefinition": {
"@id": "https://w3id.org/tractusx-trust/v0.8/presentationDefinition",
"@type": "@json"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,15 @@ public interface VcConstants {

String VC_PREFIX = "https://www.w3.org/2018/credentials#";
String SCHEMA_ORG_NAMESPACE = "https://schema.org/";

String IATP_CONTEXT_URL = "https://w3id.org/tractusx-trust/v0.8";
String IATP_PREFIX = IATP_CONTEXT_URL + "/";
String PRESENTATION_EXCHANGE_URL = "https://identity.foundation/presentation-exchange/submission/v1";
String W3C_CREDENTIALS_URL = "https://www.w3.org/2018/credentials/v1";
String VERIFIABLE_PRESENTATION_TYPE = "VerifiablePresentation";
String JWS_2020_URL = "https://w3id.org/security/suites/jws-2020/v1";
String DID_CONTEXT_URL = "https://www.w3.org/ns/did/v1";
String PRESENTATION_SUBMISSION_URL = "https://identity.foundation/presentation-exchange/submission/v1/";
String JWS_2020_SIGNATURE_SUITE = "JsonWebSignature2020";
String ED25519_SIGNATURE_SUITE = "Ed25519Signature2020"; // not used right now
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.identitytrust.model.credentialservice;

/**
* Represents the {@code descriptor_map} of a <a href="https://identity.foundation/presentation-exchange/spec/v2.0.0/#presentation-submission">Presentation Submission</a>
*/
public record InputDescriptorMapping(String id, String format, String path) {
}
Loading
Loading