Skip to content

Commit

Permalink
feat: various minor improvements / patches for IATP
Browse files Browse the repository at this point in the history
  • Loading branch information
paullatzelsperger committed Nov 26, 2023
1 parent a3ef0f1 commit 3f9316c
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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.util.uri;

import java.net.URI;

public class UriUtils {
/**
* Compares two URIs to check if they are equal after ignoring the fragment part.
*
* @param u1 The first URI to compare.
* @param u2 The second URI to compare.
* @return {@code true} if the URIs are equal after ignoring the fragment part, {@code false} otherwise.
*/
public static boolean equalsIgnoreFragment(URI u1, URI u2) {
var str1 = stripFragment(u1.toString());
var str2 = stripFragment(u2.toString());

return str1.equals(str2);
}

/**
* Removes the fragment part from a given string representation of a URI.
*
* @param uri The string representation of the URI.
* @return The string with the fragment part removed, if it exists, otherwise the original string.
*/
private static String stripFragment(String uri) {
var ix = uri.indexOf("#");
return ix >= 0 ? uri.substring(0, ix) : uri;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.util.uri;

import org.junit.jupiter.api.Test;

import java.net.URI;

import static org.assertj.core.api.Assertions.assertThat;

class UriUtilsTest {

@Test
void verifyEquality() {
var u1 = URI.create("https://some.url/path/foo#position1");
var u2 = URI.create("https://some.url/path/foo");
assertThat(UriUtils.equalsIgnoreFragment(u1, u2)).isTrue();

var u3 = URI.create("https://some.url/path");
assertThat(UriUtils.equalsIgnoreFragment(u1, u3)).isFalse();
assertThat(UriUtils.equalsIgnoreFragment(u2, u3)).isFalse();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public VerificationMethod resolve(URI id, DocumentLoader loader, SignatureSuite
return didDocument.getVerificationMethod().stream()
.map(verificationMethod -> DataIntegrityKeyPair.createVerificationKey(
URI.create(verificationMethod.getId()),
URI.create(verificationMethod.getController()),
URI.create(verificationMethod.getType()),
URI.create(verificationMethod.getController()),
verificationMethod.serializePublicKey())
)
.findFirst()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.jsonld.spi.JsonLdKeywords;
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.util.uri.UriUtils;

import java.io.IOException;
import java.net.URI;
Expand Down Expand Up @@ -132,7 +133,7 @@ private Result<Void> validateCredentialIssuer(JsonObject expanded, VerificationM
if (issuerUri.isEmpty()) {
return failure("Document must contain an 'issuer' property.");
}
if (!issuerUri.get().equals(verificationMethod.id())) {
if (!UriUtils.equalsIgnoreFragment(issuerUri.get(), verificationMethod.id())) {
return failure("Issuer and proof.verificationMethod mismatch: %s <> %s".formatted(issuerUri.get(), verificationMethod.id()));
}
} catch (InvalidJsonLdValue e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import com.apicatalog.ld.DocumentError;
import com.apicatalog.ld.signature.SigningError;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.jwk.Curve;
Expand All @@ -26,6 +27,7 @@
import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator;
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
import org.eclipse.edc.jsonld.TitaniumJsonLd;
import org.eclipse.edc.jsonld.spi.JsonLdKeywords;
Expand Down Expand Up @@ -242,5 +244,58 @@ void signCompactedPresentation() throws JOSEException {
assertThat(verificationMethod.getValueType()).describedAs("Expected a String!").isEqualTo(JsonValue.ValueType.ARRAY);
assertThat(verificationMethod.asJsonArray().get(0).asJsonObject().toString()).contains(verificationMethodUrl);
}

@Test
void signMembership() throws JsonProcessingException, JOSEException {
var json = """
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
{
"ex": "http://org.yourdataspace.com#",
"schema": "http://schema.org/",
"MembershipCredential": "ex:MembershipCredential",
"membership": "ex:membership",
"since": "ex:since",
"website": "ex:website",
"contact": "ex:contact",
"membershipType": "ex:membershipType"
}
],
"id": "http://org.yourdataspace.com/credentials/1234",
"type": [
"VerifiableCredential",
"MembershipCredential"
],
"issuer": "did:web:dataspace-issuer",
"issuanceDate": "2023-10-18T00:00:00Z",
"credentialSubject": {
"id": "did:web:connector1",
"membership": {
"membershipType": "FullMember",
"since": "2023-05-08T00:00:00Z",
"website": "www.thatsyourexample.com",
"contact": "[email protected]"
}
}
}
""";
var jo = mapper.readValue(json, JsonObject.class);
var pem = """
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIARDUGJgKy1yzxkueIJ1k3MPUWQ/tbQWQNqW6TjyHpdcoAoGCCqGSM49
AwEHoUQDQgAE1l0Lof0a1yBc8KXhesAnoBvxZw5roYnkAXuqCYfNK3ex+hMWFuiX
GUxHlzShAehR6wvwzV23bbC0tcFcVgW//A==
-----END EC PRIVATE KEY-----
""";
var ecKey = ECKey.parseFromPEMEncodedObjects(pem).toECKey();
var kp = createKeyPair(ecKey);
var signed = issuer.signDocument(jo, kp, jws2020suite.createOptions()
.purpose(URI.create("https://w3id.org/security#assertionMethod"))
.verificationMethod(new JwkMethod(URI.create("did:web:dataspace-issuer#key-1"), null, null, null))
.created(Instant.now()));
System.out.println(signed.getContent().toString());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.eclipse.edc.identitytrust.CredentialServiceUrlResolver;
import org.eclipse.edc.identitytrust.SecureTokenService;
import org.eclipse.edc.identitytrust.TrustedIssuerRegistry;
import org.eclipse.edc.identitytrust.model.CredentialSubject;
import org.eclipse.edc.identitytrust.model.Issuer;
import org.eclipse.edc.identitytrust.model.VerifiableCredential;
import org.eclipse.edc.identitytrust.validation.CredentialValidationRule;
Expand All @@ -36,6 +37,7 @@
import org.eclipse.edc.spi.iam.TokenRepresentation;
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.util.string.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.text.ParseException;
import java.time.Clock;
Expand Down Expand Up @@ -111,7 +113,7 @@ public Result<TokenRepresentation> obtainClientCredentials(TokenParameters param
.scope(parameters.getScope())
.additional(parameters.getAdditional())
.build();

var scope = parameters.getScope();
var scopeValidationResult = validateScope(scope);

Expand Down Expand Up @@ -200,12 +202,21 @@ public Result<ClaimToken> verifyJwtToken(TokenRepresentation tokenRepresentation

//todo: at this point we have established what the other participant's DID is, and that it's authentic
// so we need to make sure that `iss == sub == DID`
return result.map(u -> extractClaimToken(credentials));
return result.compose(u -> extractClaimToken(credentials));
}


private ClaimToken extractClaimToken(List<VerifiableCredential> credentials) {
return null;
@NotNull
private Result<ClaimToken> extractClaimToken(List<VerifiableCredential> credentials) {
if (credentials.isEmpty()) {
return failure("No VerifiableCredentials were found on VP");
}
var b = ClaimToken.Builder.newInstance();
credentials.stream().flatMap(vc -> vc.getCredentialSubject().stream())
.map(CredentialSubject::getClaims)
.forEach(claimSet -> claimSet.forEach(b::claim));

return success(b.build());
}

private Collection<? extends CredentialValidationRule> getAdditionalValidations() {
Expand Down

0 comments on commit 3f9316c

Please sign in to comment.