Skip to content

Commit

Permalink
fix: use RevocationServiceRegistry (new EDC feature) (#428)
Browse files Browse the repository at this point in the history
* chore: use RevocationServiceRegistry (new EDC feature)

* trigger ci

* DEPENDENCIES
paullatzelsperger authored Aug 23, 2024
1 parent 2cd53b0 commit 0cbe1cf
Showing 8 changed files with 52 additions and 53 deletions.
7 changes: 0 additions & 7 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
@@ -339,10 +339,6 @@ maven/mavencentral/org.hamcrest/hamcrest-core/1.3, BSD-2-Clause, approved, CQ114
maven/mavencentral/org.hamcrest/hamcrest-core/2.2, BSD-3-Clause, approved, clearlydefined
maven/mavencentral/org.hamcrest/hamcrest/2.1, BSD-3-Clause, approved, clearlydefined
maven/mavencentral/org.hamcrest/hamcrest/2.2, BSD-3-Clause, approved, clearlydefined
maven/mavencentral/org.jacoco/org.jacoco.agent/0.8.11, EPL-2.0, approved, CQ23285
maven/mavencentral/org.jacoco/org.jacoco.ant/0.8.11, EPL-2.0, approved, #1068
maven/mavencentral/org.jacoco/org.jacoco.core/0.8.11, EPL-2.0, approved, CQ23283
maven/mavencentral/org.jacoco/org.jacoco.report/0.8.11, EPL-2.0 AND Apache-2.0, approved, CQ23284
maven/mavencentral/org.javassist/javassist/3.28.0-GA, Apache-2.0 OR LGPL-2.1-or-later OR MPL-1.1, approved, #327
maven/mavencentral/org.javassist/javassist/3.30.2-GA, Apache-2.0 AND LGPL-2.1-or-later AND MPL-1.1, approved, #12108
maven/mavencentral/org.jetbrains.kotlin/kotlin-stdlib-common/1.9.10, Apache-2.0, approved, #14186
@@ -368,12 +364,9 @@ maven/mavencentral/org.mockito/mockito-core/5.2.0, MIT AND (Apache-2.0 AND MIT)
maven/mavencentral/org.mozilla/rhino/1.7.7.2, MPL-2.0 AND BSD-3-Clause AND ISC, approved, CQ16320
maven/mavencentral/org.objenesis/objenesis/3.3, Apache-2.0, approved, clearlydefined
maven/mavencentral/org.opentest4j/opentest4j/1.3.0, Apache-2.0, approved, #9713
maven/mavencentral/org.ow2.asm/asm-commons/9.6, BSD-3-Clause, approved, #10775
maven/mavencentral/org.ow2.asm/asm-commons/9.7, BSD-3-Clause, approved, #14075
maven/mavencentral/org.ow2.asm/asm-tree/9.6, BSD-3-Clause, approved, #10773
maven/mavencentral/org.ow2.asm/asm-tree/9.7, BSD-3-Clause, approved, #14073
maven/mavencentral/org.ow2.asm/asm/9.1, BSD-3-Clause, approved, CQ23029
maven/mavencentral/org.ow2.asm/asm/9.6, BSD-3-Clause, approved, #10776
maven/mavencentral/org.ow2.asm/asm/9.7, BSD-3-Clause, approved, #14076
maven/mavencentral/org.postgresql/postgresql/42.7.3, BSD-2-Clause AND Apache-2.0, approved, #11681
maven/mavencentral/org.reflections/reflections/0.10.2, Apache-2.0 AND WTFPL, approved, clearlydefined
Original file line number Diff line number Diff line change
@@ -15,8 +15,12 @@
package org.eclipse.edc.identityhub;

import org.eclipse.edc.iam.identitytrust.spi.verification.SignatureSuiteRegistry;
import org.eclipse.edc.iam.verifiablecredentials.StatusList2021RevocationService;
import org.eclipse.edc.iam.verifiablecredentials.spi.RevocationListService;
import org.eclipse.edc.iam.verifiablecredentials.revocation.RevocationServiceRegistryImpl;
import org.eclipse.edc.iam.verifiablecredentials.revocation.bitstring.BitstringStatusListRevocationService;
import org.eclipse.edc.iam.verifiablecredentials.revocation.statuslist2021.StatusList2021RevocationService;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.RevocationServiceRegistry;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.revocation.bitstringstatuslist.BitstringStatusListStatus;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.revocation.statuslist2021.StatusList2021Status;
import org.eclipse.edc.identityhub.accesstoken.rules.ClaimIsPresentRule;
import org.eclipse.edc.identityhub.defaults.InMemoryCredentialStore;
import org.eclipse.edc.identityhub.defaults.InMemoryKeyPairResourceStore;
@@ -56,7 +60,7 @@ public class DefaultServicesExtension implements ServiceExtension {
private TokenValidationRulesRegistry registry;
@Inject
private TypeManager typeManager;
private RevocationListService revocationService;
private RevocationServiceRegistry revocationService;
@Inject
private PrivateKeyResolver privateKeyResolver;

@@ -98,10 +102,12 @@ public ScopeToCriterionTransformer createScopeTransformer(ServiceExtensionContex
}

@Provider(isDefault = true)
public RevocationListService createRevocationListService(ServiceExtensionContext context) {
public RevocationServiceRegistry createRevocationListService(ServiceExtensionContext context) {
if (revocationService == null) {
revocationService = new RevocationServiceRegistryImpl(context.getMonitor());
var validity = context.getConfig().getLong(REVOCATION_CACHE_VALIDITY, DEFAULT_REVOCATION_CACHE_VALIDITY_MILLIS);
revocationService = new StatusList2021RevocationService(typeManager.getMapper(), validity);
revocationService.addService(StatusList2021Status.TYPE, new StatusList2021RevocationService(typeManager.getMapper(), validity));
revocationService.addService(BitstringStatusListStatus.TYPE, new BitstringStatusListRevocationService(typeManager.getMapper(), validity));
}
return revocationService;
}
Original file line number Diff line number Diff line change
@@ -16,8 +16,8 @@

import org.eclipse.edc.iam.did.spi.resolution.DidPublicKeyResolver;
import org.eclipse.edc.iam.identitytrust.spi.verification.SignatureSuiteRegistry;
import org.eclipse.edc.iam.verifiablecredentials.spi.RevocationListService;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialFormat;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.RevocationServiceRegistry;
import org.eclipse.edc.identithub.verifiablecredential.CredentialStatusCheckServiceImpl;
import org.eclipse.edc.identithub.verifiablepresentation.PresentationCreatorRegistryImpl;
import org.eclipse.edc.identithub.verifiablepresentation.VerifiablePresentationServiceImpl;
@@ -113,7 +113,7 @@ public class CoreServicesExtension implements ServiceExtension {
@Inject
private KeyPairService keyPairService;
@Inject
private RevocationListService revocationService;
private RevocationServiceRegistry revocationServiceRegistry;
@Inject
private KeyPairResourceStore store;

@@ -144,7 +144,7 @@ public AccessTokenVerifier createAccessTokenVerifier(ServiceExtensionContext con

@Provider
public CredentialQueryResolver createCredentialQueryResolver(ServiceExtensionContext context) {
return new CredentialQueryResolverImpl(credentialStore, transformer, revocationService, context.getMonitor().withPrefix("Credential Query"));
return new CredentialQueryResolverImpl(credentialStore, transformer, revocationServiceRegistry, context.getMonitor().withPrefix("Credential Query"));
}

@Provider
@@ -169,7 +169,7 @@ public VerifiablePresentationService presentationGenerator(ServiceExtensionConte

@Provider
public CredentialStatusCheckService createStatusCheckService() {
return new CredentialStatusCheckServiceImpl(revocationService, clock);
return new CredentialStatusCheckServiceImpl(revocationServiceRegistry, clock);
}

private void cacheContextDocuments(ClassLoader classLoader) {
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
package org.eclipse.edc.identityhub.query;

import org.eclipse.edc.iam.identitytrust.spi.model.PresentationQueryMessage;
import org.eclipse.edc.iam.verifiablecredentials.spi.RevocationListService;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.RevocationServiceRegistry;
import org.eclipse.edc.identityhub.spi.ScopeToCriterionTransformer;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.model.VcStatus;
@@ -43,13 +43,13 @@ public class CredentialQueryResolverImpl implements CredentialQueryResolver {

private final CredentialStore credentialStore;
private final ScopeToCriterionTransformer scopeTransformer;
private final RevocationListService revocationService;
private final RevocationServiceRegistry revocationServiceRegistry;
private final Monitor monitor;

public CredentialQueryResolverImpl(CredentialStore credentialStore, ScopeToCriterionTransformer scopeTransformer, RevocationListService revocationService, Monitor monitor) {
public CredentialQueryResolverImpl(CredentialStore credentialStore, ScopeToCriterionTransformer scopeTransformer, RevocationServiceRegistry revocationServiceRegistry, Monitor monitor) {
this.credentialStore = credentialStore;
this.scopeTransformer = scopeTransformer;
this.revocationService = revocationService;
this.revocationServiceRegistry = revocationServiceRegistry;
this.monitor = monitor;
}

@@ -132,7 +132,7 @@ private boolean filterInvalidCredentials(VerifiableCredentialResource verifiable
return false;
}
var credentialStatus = credential.getCredentialStatus();
var revocationResult = (credentialStatus == null || credentialStatus.isEmpty()) ? Result.success() : revocationService.checkValidity(credential);
var revocationResult = (credentialStatus == null || credentialStatus.isEmpty()) ? Result.success() : revocationServiceRegistry.checkValidity(credential);
if (revocationResult.failed()) {
monitor.warning("Credential '%s' not valid: %s".formatted(credential.getId(), revocationResult.getFailureDetail()));
return false;
Original file line number Diff line number Diff line change
@@ -15,11 +15,11 @@
package org.eclipse.edc.identityhub.query;

import org.eclipse.edc.iam.identitytrust.spi.model.PresentationQueryMessage;
import org.eclipse.edc.iam.verifiablecredentials.spi.RevocationListService;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialFormat;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialStatus;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialSubject;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.Issuer;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.RevocationServiceRegistry;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredential;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredentialContainer;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.presentationdefinition.PresentationDefinition;
@@ -56,13 +56,13 @@ class CredentialQueryResolverImplTest {

public static final String TEST_PARTICIPANT_CONTEXT_ID = "test-participant";
private final CredentialStore storeMock = mock();
private final RevocationListService revocationServiceMock = mock();
private final RevocationServiceRegistry revocationServiceRegistry = mock();
private final Monitor monitor = mock();
private final CredentialQueryResolverImpl resolver = new CredentialQueryResolverImpl(storeMock, new EdcScopeToCriterionTransformer(), revocationServiceMock, monitor);
private final CredentialQueryResolverImpl resolver = new CredentialQueryResolverImpl(storeMock, new EdcScopeToCriterionTransformer(), revocationServiceRegistry, monitor);

@BeforeEach
void setUp() {
when(revocationServiceMock.checkValidity(any())).thenReturn(Result.success());
when(revocationServiceRegistry.checkValidity(any())).thenReturn(Result.success());
}

@Test
@@ -318,7 +318,7 @@ void query_whenNotYetValidCredential_doesNotInclude() {

@Test
void query_whenRevokedCredential_doesNotInclude() {
when(revocationServiceMock.checkValidity(any())).thenReturn(Result.failure("revoked"));
when(revocationServiceRegistry.checkValidity(any())).thenReturn(Result.failure("revoked"));
var credential = createCredential("TestCredential")
.credentialStatus(new CredentialStatus("test-cred-stat-id", "StatusList2021Entry",
Map.of("statusListCredential", "https://university.example/credentials/status/3",
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@

package org.eclipse.edc.identithub.verifiablecredential;

import org.eclipse.edc.iam.verifiablecredentials.spi.RevocationListService;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.RevocationServiceRegistry;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.CredentialStatusCheckService;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.model.VcStatus;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.model.VerifiableCredentialResource;
@@ -31,12 +31,12 @@
public class CredentialStatusCheckServiceImpl implements CredentialStatusCheckService {
private static final String SUSPENSION = "suspension";
private static final String REVOCATION = "revocation";
private final RevocationListService revocationListService;
private final RevocationServiceRegistry revocationServiceRegistry;
private final Clock clock;


public CredentialStatusCheckServiceImpl(RevocationListService revocationListService, Clock clock) {
this.revocationListService = revocationListService;
public CredentialStatusCheckServiceImpl(RevocationServiceRegistry revocationServiceRegistry, Clock clock) {
this.revocationServiceRegistry = revocationServiceRegistry;
this.clock = clock;
}

@@ -107,7 +107,7 @@ private String fetchRevocationStatus(VerifiableCredentialResource resource) {
if (cred == null) {
return null;
}
return revocationListService.getStatusPurpose(cred)
return revocationServiceRegistry.getRevocationStatus(cred)
.orElseThrow(f -> new EdcException(f.getFailureDetail()));
}
}
Original file line number Diff line number Diff line change
@@ -14,10 +14,10 @@

package org.eclipse.edc.identithub.verifiablecredential;

import org.eclipse.edc.iam.verifiablecredentials.spi.RevocationListService;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialFormat;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialSubject;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.Issuer;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.RevocationServiceRegistry;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredential;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredentialContainer;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.model.VcStatus;
@@ -40,13 +40,13 @@

class CredentialStatusCheckServiceImplTest {

private final RevocationListService revocationListService = mock();
private final RevocationServiceRegistry revocationServiceRegistry = mock();
private final Clock clock = Clock.systemUTC();
private final CredentialStatusCheckServiceImpl service = new CredentialStatusCheckServiceImpl(revocationListService, clock);
private final CredentialStatusCheckServiceImpl service = new CredentialStatusCheckServiceImpl(revocationServiceRegistry, clock);

@BeforeEach
void setUp() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success(null));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success(null));
}

@Test
@@ -77,7 +77,7 @@ void checkStatus_notYetValid_becomesValid() {

@Test
void checkStatus_suspended_becomesSuspended() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success("suspension"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success("suspension"));
var credential = createVerifiableCredential()
.build();

@@ -90,7 +90,7 @@ void checkStatus_suspended_becomesSuspended() {

@Test
void checkStatus_suspended_becomesNotSuspended() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success(null));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success(null));
var credential = createVerifiableCredential()
.build();

@@ -103,7 +103,7 @@ void checkStatus_suspended_becomesNotSuspended() {

@Test
void checkStatus_whenRevoked() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success("revocation"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success("revocation"));
var credential = createCredentialBuilder(createVerifiableCredential().build()).build();

assertThat(service.checkStatus(credential))
@@ -113,7 +113,7 @@ void checkStatus_whenRevoked() {

@Test
void checkStatus_whenSuspended() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success("suspension"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success("suspension"));
var credential = createCredentialBuilder(createVerifiableCredential().build()).build();

assertThat(service.checkStatus(credential))
@@ -123,7 +123,7 @@ void checkStatus_whenSuspended() {

@Test
void checkStatus_whenUnknownRevocationStatus() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success("foo-status"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success("foo-status"));
var credential = createCredentialBuilder(createVerifiableCredential().build()).build();

assertThat(service.checkStatus(credential))
@@ -133,7 +133,7 @@ void checkStatus_whenUnknownRevocationStatus() {

@Test
void checkStatus_whenMultipleRules() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success("revocation"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success("revocation"));
var credential = createVerifiableCredential()
.expirationDate(Instant.now(clock).minus(10, ChronoUnit.MINUTES))
.build();
@@ -144,7 +144,7 @@ void checkStatus_whenMultipleRules() {

@Test
void checkStatus_revocationCheckThrows() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.failure("failed"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.failure("failed"));
var credential = createCredentialBuilder(createVerifiableCredential().build()).build();

assertThat(service.checkStatus(credential))
@@ -164,7 +164,7 @@ void checkStatus_suspended_becomesExpired() {

@Test
void checkStatus_notYetValid_becomesSuspended() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success("suspension"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success("suspension"));
var now = Instant.now();
var tenSecondsAgo = now.minus(10, ChronoUnit.SECONDS);

@@ -216,7 +216,7 @@ void checkStatus_notYetValid_becomesExpired() {

@Test
void checkStatus_suspended_becomesRevoked() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success("revocation"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success("revocation"));
var credential = createVerifiableCredential()
.build();

@@ -227,28 +227,28 @@ void checkStatus_suspended_becomesRevoked() {

@Test
void checkStatus_expired_becomesRevoked() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success("revocation"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success("revocation"));
var credential = createVerifiableCredential()
.expirationDate(Instant.now(clock).minus(10, ChronoUnit.MINUTES))
.build();

assertThat(service.checkStatus(createCredentialBuilder(credential).state(VcStatus.ISSUED).build()))
.isSucceeded()
.isEqualTo(VcStatus.EXPIRED);
verifyNoInteractions(revocationListService);
verifyNoInteractions(revocationServiceRegistry);
}

@Test
void checkStatus_expired_becomesSuspended() {
when(revocationListService.getStatusPurpose(any())).thenReturn(Result.success("suspension"));
when(revocationServiceRegistry.getRevocationStatus(any())).thenReturn(Result.success("suspension"));
var credential = createVerifiableCredential()
.expirationDate(Instant.now(clock).minus(10, ChronoUnit.MINUTES))
.build();

assertThat(service.checkStatus(createCredentialBuilder(credential).state(VcStatus.ISSUED).build()))
.isSucceeded()
.isEqualTo(VcStatus.EXPIRED);
verifyNoInteractions(revocationListService);
verifyNoInteractions(revocationServiceRegistry);
}

private VerifiableCredentialResource.Builder createCredentialBuilder(VerifiableCredential credential) {
Original file line number Diff line number Diff line change
@@ -26,9 +26,9 @@
import jakarta.json.JsonString;
import jakarta.json.JsonValue;
import org.eclipse.edc.iam.did.spi.resolution.DidPublicKeyResolver;
import org.eclipse.edc.iam.verifiablecredentials.spi.RevocationListService;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialFormat;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialStatus;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.RevocationServiceRegistry;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredential;
import org.eclipse.edc.iam.verifiablecredentials.spi.model.VerifiableCredentialContainer;
import org.eclipse.edc.identityhub.spi.participantcontext.ParticipantContextService;
@@ -90,7 +90,7 @@ public class PresentationApiEndToEndTest {
abstract static class Tests {

protected static final DidPublicKeyResolver DID_PUBLIC_KEY_RESOLVER = mock();
protected static final RevocationListService REVOCATION_LIST_SERVICE = mock();
protected static final RevocationServiceRegistry REVOCATION_LIST_REGISTRY = mock();
private static final String VALID_QUERY_WITH_SCOPE = """
{
"@context": [
@@ -373,7 +373,7 @@ void query_shouldFilterOutInvalidCreds(int vcStateCode, IdentityHubEndToEndTestC
Map.of("statusListCredential", "https://university.example/credentials/status/3",
"statusPurpose", "suspension",
"statusListIndex", 69)));
when(REVOCATION_LIST_SERVICE.checkValidity(any(VerifiableCredential.class)))
when(REVOCATION_LIST_REGISTRY.checkValidity(any(VerifiableCredential.class)))
.thenReturn(Result.failure("suspended"));
}
// create the credential in the store
@@ -530,7 +530,7 @@ class InMemory extends Tests {
static {
var ctx = IdentityHubEndToEndExtension.InMemory.context();
ctx.getRuntime().registerServiceMock(DidPublicKeyResolver.class, DID_PUBLIC_KEY_RESOLVER);
ctx.getRuntime().registerServiceMock(RevocationListService.class, REVOCATION_LIST_SERVICE);
ctx.getRuntime().registerServiceMock(RevocationServiceRegistry.class, REVOCATION_LIST_REGISTRY);
runtime = new IdentityHubCustomizableEndToEndExtension(ctx);
}
}
@@ -556,7 +556,7 @@ class Postgres extends Tests {
static {
var ctx = IdentityHubEndToEndExtension.Postgres.context(DB_NAME, DB_PORT);
ctx.getRuntime().registerServiceMock(DidPublicKeyResolver.class, DID_PUBLIC_KEY_RESOLVER);
ctx.getRuntime().registerServiceMock(RevocationListService.class, REVOCATION_LIST_SERVICE);
ctx.getRuntime().registerServiceMock(RevocationServiceRegistry.class, REVOCATION_LIST_REGISTRY);
runtime = new IdentityHubCustomizableEndToEndExtension(ctx);
}

0 comments on commit 0cbe1cf

Please sign in to comment.