Skip to content

Commit

Permalink
chore: minor IATP fixes for E2E tests (#3808)
Browse files Browse the repository at this point in the history
  • Loading branch information
wolf4ood committed Jan 30, 2024
1 parent ec37822 commit 1a476a4
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
import com.apicatalog.ld.schema.LdTerm;
import com.apicatalog.ld.signature.LinkedDataSignature;
import com.apicatalog.ld.signature.SignatureSuite;
import com.apicatalog.ld.signature.SignatureSuiteMapper;
import com.apicatalog.ld.signature.SignatureSuiteProvider;
import com.apicatalog.ld.signature.VerificationError;
import com.apicatalog.ld.signature.VerificationError.Code;
import com.apicatalog.ld.signature.key.VerificationKey;
Expand Down Expand Up @@ -65,7 +63,7 @@ public class LdpVerifier implements CredentialVerifier {

private JsonLd jsonLd;
private ObjectMapper jsonLdMapper;
private SignatureSuiteProvider suiteProvider;
private SignatureSuiteRegistry suiteRegistry;
private Map<String, Object> params;
private Collection<MethodResolver> methodResolvers = new ArrayList<>(List.of(new HttpMethodResolver()));
private DocumentLoader loader;
Expand Down Expand Up @@ -217,9 +215,9 @@ private Result<Void> verifyProofs(JsonObject expanded) throws VerificationError,
}

var signatureSuite = proofType.stream()
.filter(suiteProvider::isSupported)
.map(suiteRegistry::getForId)
.filter(Objects::nonNull)
.findFirst()
.map(suiteProvider::find)
.orElseThrow(() -> new VerificationError(Code.UnsupportedCryptoSuite));

if (signatureSuite.getSchema() == null) {
Expand Down Expand Up @@ -364,20 +362,8 @@ public static Builder newInstance() {
return new Builder();
}

public Builder signatureSuite(SignatureSuite signatureSuiteProvider) {
this.verifier.suiteProvider = new SignatureSuiteMapper().add(signatureSuiteProvider);
return this;
}

public Builder signatureSuites(SignatureSuiteProvider provider) {
this.verifier.suiteProvider = provider;
return this;
}

public Builder signatureSuites(SignatureSuiteRegistry registry) {
var provider = new SignatureSuiteMapper();
registry.getAllSuites().forEach(provider::add);
this.verifier.suiteProvider = provider;
this.verifier.suiteRegistry = registry;
return this;
}

Expand Down Expand Up @@ -429,7 +415,7 @@ public Builder loader(DocumentLoader loader) {
public LdpVerifier build() {
Objects.requireNonNull(this.verifier.jsonLd, "Must have a JsonLD service!");
Objects.requireNonNull(this.verifier.jsonLdMapper, "Must have an ObjectMapper!");
Objects.requireNonNull(this.verifier.suiteProvider, "Must have a SignatureSuite!");
Objects.requireNonNull(this.verifier.suiteRegistry, "Must have a Signature registry!");
return this.verifier;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
import jakarta.json.JsonObject;
import org.eclipse.edc.identitytrust.verification.SignatureSuiteRegistry;
import org.eclipse.edc.identitytrust.verification.VerifierContext;
import org.eclipse.edc.jsonld.TitaniumJsonLd;
import org.eclipse.edc.security.signature.jws2020.JwkMethod;
Expand Down Expand Up @@ -62,6 +63,8 @@ class LdpVerifierTest {
private final ObjectMapper mapper = createObjectMapper();
private final TestDocumentLoader testDocLoader = new TestDocumentLoader("https://org.eclipse.edc/", "", SchemeRouter.defaultInstance());
private final MethodResolver mockDidResolver = mock();

private final SignatureSuiteRegistry suiteRegistry = mock();
private VerifierContext context = null;
private LdpVerifier ldpVerifier;
private TitaniumJsonLd jsonLd;
Expand All @@ -80,13 +83,15 @@ void setUp() throws URISyntaxException {
jsonLd.registerCachedDocument("https://www.w3.org/2018/credentials/v1", Thread.currentThread().getContextClassLoader().getResource("credentials.v1.json").toURI());
jsonLd.registerCachedDocument("https://www.w3.org/2018/credentials/examples/v1", Thread.currentThread().getContextClassLoader().getResource("examples.v1.json").toURI());
ldpVerifier = LdpVerifier.Builder.newInstance()
.signatureSuite(jwsSignatureSuite)
.signatureSuites(suiteRegistry)
.jsonLd(jsonLd)
.objectMapper(mapper)
.methodResolvers(List.of(mockDidResolver))
.loader(testDocLoader)
.build();
context = VerifierContext.Builder.newInstance().verifier(ldpVerifier).build();

when(suiteRegistry.getForId(any())).thenReturn(jwsSignatureSuite);
}

private DataIntegrityProofOptions generateEmbeddedProofOptions(ECKey vcKey, String id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
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.security.signature.jws2020.JwsSignature2020Suite;
import org.eclipse.edc.spi.http.EdcHttpClient;
import org.eclipse.edc.spi.iam.IdentityService;
import org.eclipse.edc.spi.result.Result;
Expand Down Expand Up @@ -67,6 +68,8 @@ public class IdentityAndTrustExtension implements ServiceExtension {
public static final String CONNECTOR_DID_PROPERTY = "edc.iam.issuer.id";
public static final String IATP_SELF_ISSUED_TOKEN_CONTEXT = "iatp-si";

public static final String JSON_2020_SIGNATURE_SUITE = "JsonWebSignature2020";


@Inject
private SecureTokenService secureTokenService;
Expand Down Expand Up @@ -125,6 +128,9 @@ public void initialize(ServiceExtensionContext context) {
rulesRegistry.addRule("iatp-vp", (toVerify, additional) -> Optional.ofNullable(toVerify.getStringClaim(JWTClaimNames.SUBJECT)).map(s ->
Result.success()).orElseGet(() -> Result.failure("Token could not be verified: Claim verification failed. JWT missing required claims: [sub]")).mapTo());


// TODO move in a separated extension?
signatureSuiteRegistry.register(JSON_2020_SIGNATURE_SUITE, new JwsSignature2020Suite(typeManager.getMapper(JSON_LD)));
}

@Provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ private JsonObject createPresentationQuery(List<String> scopes) {
.add(JsonLdKeywords.CONTEXT, jsonFactory.createArrayBuilder()
.add(VcConstants.PRESENTATION_EXCHANGE_URL)
.add(VcConstants.IATP_CONTEXT_URL))
.add(JsonLdKeywords.TYPE, PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY)
.add(JsonLdKeywords.TYPE, PresentationQueryMessage.PRESENTATION_QUERY_MESSAGE_TYPE)
.add("scope", scopeArray.build())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class InMemorySignatureSuiteRegistry implements SignatureSuiteRegistry {
@Override
public void register(String w3cIdentifier, SignatureSuite suite) {
registry.put(w3cIdentifier, suite);
registry.put(suite.getId().uri(), suite);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Instant;
import java.util.Collections;
import java.util.Map;

import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat;
Expand Down Expand Up @@ -87,7 +86,7 @@ class MultiFormatPresentationVerifierTest {

@BeforeAll
static void prepare() throws URISyntaxException, JOSEException {
when(SIGNATURE_SUITE_REGISTRY.getAllSuites()).thenReturn(Collections.singleton(JWS_SIGNATURE_SUITE));
when(SIGNATURE_SUITE_REGISTRY.getForId(any())).thenReturn(JWS_SIGNATURE_SUITE);
jsonLd = new TitaniumJsonLd(mock());
jsonLd.registerCachedDocument("https://www.w3.org/ns/odrl.jsonld", Thread.currentThread().getContextClassLoader().getResource("odrl.jsonld").toURI());
jsonLd.registerCachedDocument("https://www.w3.org/ns/did/v1", Thread.currentThread().getContextClassLoader().getResource("jws2020.json").toURI());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.EXPIRATION_TIME;
import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.ISSUED_AT;
import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.JWT_ID;
import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.NOT_BEFORE;

/**
* Decorator for Self-Issued ID token and Access Token. It appends input claims and
Expand All @@ -45,6 +46,7 @@ class SelfIssuedTokenDecorator implements TokenDecorator {
public TokenParameters.Builder decorate(TokenParameters.Builder tokenParameters) {
this.claims.forEach(tokenParameters::claims);
return tokenParameters.claims(ISSUED_AT, Date.from(clock.instant()))
.claims(NOT_BEFORE, Date.from(clock.instant()))
.claims(EXPIRATION_TIME, Date.from(clock.instant().plusSeconds(validity)))
.claims(JWT_ID, UUID.randomUUID().toString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import jakarta.json.Json;
import jakarta.json.JsonObject;
import org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponseMessage;
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;
Expand All @@ -36,12 +37,19 @@ public JsonObjectFromPresentationResponseMessageTransformer() {
}

@Override
public @Nullable JsonObject transform(@NotNull PresentationResponseMessage presentationQueryMessage, @NotNull TransformerContext context) {
public @Nullable JsonObject transform(@NotNull PresentationResponseMessage responseMessage, @NotNull TransformerContext context) {
// Presentation Submission not supported yet
return Json.createObjectBuilder()
.add(TYPE, PRESENTATION_RESPONSE_MESSAGE_TYPE_PROPERTY)
.add(PRESENTATION_RESPONSE_MESSAGE_PRESENTATION_PROPERTY, Json.createArrayBuilder(presentationQueryMessage.getPresentation()).build())
.add(PRESENTATION_RESPONSE_MESSAGE_PRESENTATION_PROPERTY, createJson(responseMessage))
.build();
}

private JsonObject createJson(PresentationResponseMessage responseMessage) {
var jo = Json.createObjectBuilder();
jo.add(JsonLdKeywords.VALUE, Json.createArrayBuilder(responseMessage.getPresentation()).build());
jo.add(JsonLdKeywords.TYPE, JsonLdKeywords.JSON);
return jo.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import static org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponseMessage.PRESENTATION_RESPONSE_MESSAGE_PRESENTATION_PROPERTY;
import static org.eclipse.edc.identitytrust.model.credentialservice.PresentationResponseMessage.PRESENTATION_RESPONSE_MESSAGE_TYPE_PROPERTY;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE;
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.VALUE;
import static org.mockito.Mockito.mock;

public class JsonObjectFromPresentationResponseMessageTransformerTest {
Expand All @@ -43,10 +44,14 @@ void transform() {

assertThat(json).isNotNull();
assertThat(json.getJsonString(TYPE).getString()).isEqualTo(PRESENTATION_RESPONSE_MESSAGE_TYPE_PROPERTY);
assertThat(json.getJsonArray(PRESENTATION_RESPONSE_MESSAGE_PRESENTATION_PROPERTY))
.hasSize(1)
.first()
.isEqualTo(Json.createValue("jwt"));

assertThat(json.getJsonObject(PRESENTATION_RESPONSE_MESSAGE_PRESENTATION_PROPERTY))
.extracting(object -> object.get(VALUE).asJsonArray())
.satisfies(arr -> {
assertThat(arr).hasSize(1)
.first()
.isEqualTo(Json.createValue("jwt"));
});

}

Expand All @@ -65,10 +70,14 @@ void transform_withJson() {
.add("@context", Json.createArrayBuilder().build())
.build();

assertThat(json.getJsonArray(PRESENTATION_RESPONSE_MESSAGE_PRESENTATION_PROPERTY))
.hasSize(1)
.first()
.isEqualTo(expected);

assertThat(json.getJsonObject(PRESENTATION_RESPONSE_MESSAGE_PRESENTATION_PROPERTY))
.extracting(object -> object.get(VALUE).asJsonArray())
.satisfies(arr -> {
assertThat(arr).hasSize(1)
.first()
.isEqualTo(expected);
});

}

Expand All @@ -86,9 +95,11 @@ void transform_withStringAndJson() {
.add("@context", Json.createArrayBuilder().build())
.build();

assertThat(json.getJsonArray(PRESENTATION_RESPONSE_MESSAGE_PRESENTATION_PROPERTY))
.hasSize(2)
.containsExactly(Json.createValue("jwt"), complex);
assertThat(json.getJsonObject(PRESENTATION_RESPONSE_MESSAGE_PRESENTATION_PROPERTY))
.extracting(object -> object.get(VALUE).asJsonArray())
.satisfies(arr -> {
assertThat(arr).hasSize(2).containsExactly(Json.createValue("jwt"), complex);
});

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2024 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.serde;

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.iam.identitytrust.transform.from.JsonObjectFromPresentationResponseMessageTransformer;
import org.eclipse.edc.iam.identitytrust.transform.to.JsonObjectToPresentationResponseMessageTransformer;
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.eclipse.edc.identitytrust.VcConstants.IATP_CONTEXT_URL;
import static org.mockito.Mockito.mock;

public class PresentationResponseMessageSerdeTest {

private final JsonLd jsonLd = new TitaniumJsonLd(mock());

private final ObjectMapper mapper = JacksonJsonLd.createObjectMapper();

private final TypeTransformerRegistry trr = new TypeTransformerRegistryImpl();
private final TransformerContext context = new TransformerContextImpl(trr);
private final JsonObjectFromPresentationResponseMessageTransformer fromTransformer = new JsonObjectFromPresentationResponseMessageTransformer();
private final JsonObjectToPresentationResponseMessageTransformer toTransformer = new JsonObjectToPresentationResponseMessageTransformer(mapper);

@BeforeEach
void setUp() {
jsonLd.registerCachedDocument("https://identity.foundation/presentation-exchange/submission/v1", TestUtils.getFileFromResourceName("presentation_ex.json").toURI());
jsonLd.registerCachedDocument(IATP_CONTEXT_URL, TestUtils.getFileFromResourceName("document/iatp.v08.jsonld").toURI());
jsonLd.registerContext(IATP_CONTEXT_URL);
// delegate to the generic transformer

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


@Test
void serde() throws JsonProcessingException {

var obj = """
{
"@context": [
"https://w3id.org/tractusx-trust/v0.8"
],
"@type": "PresentationResponseMessage",
"presentation": [
{
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"type": [
"VerifiablePresentation"
]
},
"jwtPresentation"
]
}
""";

var json = mapper.readValue(obj, JsonObject.class);
var jo = jsonLd.expand(json);

var query = toTransformer.transform(jo.getContent(), context);
assertThat(query).isNotNull();

var expandedJson = fromTransformer.transform(query, context);

var compacted = jsonLd.compact(expandedJson).getContent();

assertThat(json.getJsonArray("@context")).isEqualTo(compacted.getJsonArray("@context"));
assertThat(json.getJsonArray("presentation")).isEqualTo(compacted.getJsonArray("presentation"));
assertThat(json.getJsonString("@type")).isEqualTo(compacted.getJsonString("type"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
public class PresentationQueryMessage {
public static final String PRESENTATION_QUERY_MESSAGE_SCOPE_PROPERTY = IATP_PREFIX + "scope";
public static final String PRESENTATION_QUERY_MESSAGE_DEFINITION_PROPERTY = IATP_PREFIX + "presentationDefinition";
public static final String PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY = IATP_PREFIX + "PresentationQueryMessage";
public static final String PRESENTATION_QUERY_MESSAGE_TYPE = "PresentationQueryMessage";
public static final String PRESENTATION_QUERY_MESSAGE_TYPE_PROPERTY = IATP_PREFIX + PRESENTATION_QUERY_MESSAGE_TYPE;

private final List<String> scopes = new ArrayList<>();
private PresentationDefinition presentationDefinition;

Expand Down

0 comments on commit 1a476a4

Please sign in to comment.