Skip to content

Commit

Permalink
fix: IdentityAndTrustService handle multiple VPs
Browse files Browse the repository at this point in the history
  • Loading branch information
paullatzelsperger committed Nov 30, 2023
1 parent cd9dbec commit eeac824
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import static com.nimbusds.jwt.JWTClaimNames.AUDIENCE;
import static com.nimbusds.jwt.JWTClaimNames.EXPIRATION_TIME;
Expand Down Expand Up @@ -182,27 +183,32 @@ public Result<ClaimToken> verifyJwtToken(TokenRepresentation tokenRepresentation
return vpResponse.mapTo();
}

var verifiablePresentation = vpResponse.getContent().get(0);
var credentials = verifiablePresentation.presentation().getCredentials();
// verify, that the VP and all VPs are cryptographically OK
var result = presentationVerifier.verifyPresentation(verifiablePresentation)
.compose(u -> {
// in addition, verify that all VCs are valid
var filters = new ArrayList<>(List.of(
new IsNotExpired(clock),
new HasValidSubjectIds(issuer),
new IsRevoked(null),
new HasValidIssuer(getTrustedIssuerIds())));

filters.addAll(getAdditionalValidations());
var results = credentials.stream().map(c -> filters.stream().reduce(t -> Result.success(), CredentialValidationRule::and).apply(c)).reduce(Result::merge);

return results.orElseGet(() -> failure("Could not determine the status of the VC validation"));
});

var presentations = vpResponse.getContent();
var result = presentations.stream().map(verifiablePresentation -> {
var credentials = verifiablePresentation.presentation().getCredentials();
// verify, that the VP and all VPs are cryptographically OK
return presentationVerifier.verifyPresentation(verifiablePresentation)
.compose(u -> validateVerifiableCredentials(credentials, issuer));
}).reduce(Result.success(), Result::merge);
//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.compose(u -> extractClaimToken(credentials, intendedAudience));
return result.compose(u -> extractClaimToken(presentations.stream().map(p -> p.presentation().getCredentials().stream())
.reduce(Stream.empty(), Stream::concat)
.toList(), intendedAudience));
}

@NotNull
private Result<Void> validateVerifiableCredentials(List<VerifiableCredential> credentials, String issuer) {
// in addition, verify that all VCs are valid
var filters = new ArrayList<>(List.of(
new IsNotExpired(clock),
new HasValidSubjectIds(issuer),
new IsRevoked(null),
new HasValidIssuer(getTrustedIssuerIds())));

filters.addAll(getAdditionalValidations());
var results = credentials.stream().map(c -> filters.stream().reduce(t -> Result.success(), CredentialValidationRule::and).apply(c)).reduce(Result::merge);
return results.orElseGet(() -> failure("Could not determine the status of the VC validation"));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@


import com.nimbusds.jwt.JWTClaimsSet;
import org.assertj.core.api.Assertions;
import org.eclipse.edc.iam.identitytrust.IdentityAndTrustService;
import org.eclipse.edc.identitytrust.CredentialServiceClient;
import org.eclipse.edc.identitytrust.CredentialServiceUrlResolver;
Expand Down Expand Up @@ -46,8 +47,10 @@
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.eclipse.edc.identitytrust.SelfIssuedTokenConstants.PRESENTATION_ACCESS_TOKEN_CLAIM;
import static org.eclipse.edc.identitytrust.TestFunctions.TRUSTED_ISSUER;
import static org.eclipse.edc.identitytrust.TestFunctions.createCredentialBuilder;
import static org.eclipse.edc.identitytrust.TestFunctions.createJwt;
import static org.eclipse.edc.identitytrust.TestFunctions.createPresentationBuilder;
Expand Down Expand Up @@ -258,5 +261,106 @@ void cannotResolveCredentialServiceUrl() {

verifyNoInteractions(mockedClient);
}

@Test
void verify_singlePresentation_singleCredential() {
var presentation = createPresentationBuilder()
.type("VerifiablePresentation")
.credentials(List.of(createCredentialBuilder()
.credentialSubjects(List.of(CredentialSubject.Builder.newInstance()
.id(CONSUMER_DID)
.claim("some-claim", "some-val")
.build()))
.build()))
.build();
var vpContainer = new VerifiablePresentationContainer("test-vp", CredentialFormat.JSON_LD, presentation);
when(mockedVerifier.verifyPresentation(any())).thenReturn(success());
when(mockedClient.requestPresentation(any(), any(), any())).thenReturn(success(List.of(vpContainer)));
when(trustedIssuerRegistryMock.getTrustedIssuers()).thenReturn(Set.of(TRUSTED_ISSUER));
var token = createJwt(CONSUMER_DID, EXPECTED_OWN_DID);
var result = service.verifyJwtToken(token, "test-audience");
assertThat(result).isSucceeded()
.satisfies(ct -> Assertions.assertThat(ct.getClaims()).containsEntry("some-claim", "some-val"));
}

@Test
void verify_singlePresentation_multipleCredentials() {
var presentation = createPresentationBuilder()
.type("VerifiablePresentation")
.credentials(List.of(createCredentialBuilder()
.credentialSubjects(List.of(CredentialSubject.Builder.newInstance()
.id(CONSUMER_DID)
.claim("some-claim", "some-val")
.build()))
.build(),
createCredentialBuilder()
.credentialSubjects(List.of(CredentialSubject.Builder.newInstance()
.id(CONSUMER_DID)
.claim("some-other-claim", "some-other-val")
.build()))
.build()))
.build();
var vpContainer = new VerifiablePresentationContainer("test-vp", CredentialFormat.JSON_LD, presentation);
when(mockedVerifier.verifyPresentation(any())).thenReturn(success());
when(mockedClient.requestPresentation(any(), any(), any())).thenReturn(success(List.of(vpContainer)));
when(trustedIssuerRegistryMock.getTrustedIssuers()).thenReturn(Set.of(TRUSTED_ISSUER));
var token = createJwt(CONSUMER_DID, EXPECTED_OWN_DID);
var result = service.verifyJwtToken(token, "test-audience");
assertThat(result).isSucceeded()
.satisfies(ct -> Assertions.assertThat(ct.getClaims())
.containsEntry("some-claim", "some-val")
.containsEntry("some-other-claim", "some-other-val"));
}

@Test
void verify_multiplePresentations_multipleCredentialsEach() {
var presentation1 = createPresentationBuilder()
.type("VerifiablePresentation")
.credentials(List.of(createCredentialBuilder()
.credentialSubjects(List.of(CredentialSubject.Builder.newInstance()
.id(CONSUMER_DID)
.claim("some-claim", "some-val")
.build()))
.build(),
createCredentialBuilder()
.credentialSubjects(List.of(CredentialSubject.Builder.newInstance()
.id(CONSUMER_DID)
.claim("some-other-claim", "some-other-val")
.build()))
.build()))
.build();
var vpContainer1 = new VerifiablePresentationContainer("test-vp", CredentialFormat.JSON_LD, presentation1);

var presentation2 = createPresentationBuilder()
.type("VerifiablePresentation")
.credentials(List.of(createCredentialBuilder()
.credentialSubjects(List.of(CredentialSubject.Builder.newInstance()
.id(CONSUMER_DID)
.claim("some-claim-2", "some-val-2")
.build()))
.build(),
createCredentialBuilder()
.credentialSubjects(List.of(CredentialSubject.Builder.newInstance()
.id(CONSUMER_DID)
.claim("some-other-claim-2", "some-other-val-2")
.build()))
.build()))
.build();
var vpContainer2 = new VerifiablePresentationContainer("test-vp", CredentialFormat.JSON_LD, presentation2);

when(mockedVerifier.verifyPresentation(any())).thenReturn(success());
when(mockedClient.requestPresentation(any(), any(), any())).thenReturn(success(List.of(vpContainer1, vpContainer2)));
when(trustedIssuerRegistryMock.getTrustedIssuers()).thenReturn(Set.of(TRUSTED_ISSUER));


var token = createJwt(CONSUMER_DID, EXPECTED_OWN_DID);
var result = service.verifyJwtToken(token, "test-audience");
assertThat(result).isSucceeded()
.satisfies(ct -> Assertions.assertThat(ct.getClaims())
.containsEntry("some-claim", "some-val")
.containsEntry("some-other-claim", "some-other-val")
.containsEntry("some-claim-2", "some-val-2")
.containsEntry("some-other-claim-2", "some-other-val-2"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@

public class TestFunctions {

public static final Issuer TRUSTED_ISSUER = new Issuer("http://test.issuer", Map.of());

public static VerifiableCredential createCredential() {
return createCredentialBuilder().build();
}
Expand All @@ -51,7 +53,7 @@ public static VerifiableCredential.Builder createCredentialBuilder() {
.claim("test-claim", "test-value")
.build())
.type("test-type")
.issuer(new Issuer("http://test.issuer", Map.of()))
.issuer(TRUSTED_ISSUER)
.issuanceDate(now());
}

Expand Down

0 comments on commit eeac824

Please sign in to comment.