Skip to content

Commit

Permalink
feat: add Credential Watchdog extension (#346)
Browse files Browse the repository at this point in the history
* add watchdog thread (wip)

* wip not suspended

* introduce separate extension

* added tests for the watchdog thread

* refactor check service

* simplified credential check

* DEPENDENCIES

* javadoc

* DEPENDENCIES
  • Loading branch information
paullatzelsperger authored May 14, 2024
1 parent 65e9baf commit a188d79
Show file tree
Hide file tree
Showing 15 changed files with 963 additions and 8 deletions.
7 changes: 3 additions & 4 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ maven/mavencentral/com.github.java-json-tools/json-schema-core/1.2.14, Apache-2.
maven/mavencentral/com.github.java-json-tools/json-schema-validator/2.2.14, Apache-2.0 OR LGPL-3.0-or-later, approved, CQ20779
maven/mavencentral/com.github.java-json-tools/msg-simple/1.2, Apache-2.0 OR LGPL-3.0-or-later, approved, #2720
maven/mavencentral/com.github.java-json-tools/uri-template/0.10, Apache-2.0 OR LGPL-3.0-only, approved, #2723
maven/mavencentral/com.github.stephenc.jcip/jcip-annotations/1.0-1, Apache-2.0, approved, CQ21949
maven/mavencentral/com.google.code.findbugs/jsr305/2.0.1, BSD-3-Clause AND CC-BY-2.5 AND LGPL-2.1+, approved, CQ13390
maven/mavencentral/com.google.code.findbugs/jsr305/3.0.2, Apache-2.0, approved, #20
maven/mavencentral/com.google.code.gson/gson/2.10.1, Apache-2.0, approved, #6159
Expand All @@ -76,9 +75,9 @@ maven/mavencentral/com.jcraft/jzlib/1.1.3, BSD-2-Clause, approved, CQ6218
maven/mavencentral/com.lmax/disruptor/3.4.4, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.networknt/json-schema-validator/1.0.76, Apache-2.0, approved, CQ22638
maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.28, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.37.3, Apache-2.0, approved, #11701
maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.38, , restricted, clearlydefined
maven/mavencentral/com.puppycrawl.tools/checkstyle/10.16.0, , restricted, clearlydefined
maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.38, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.39, Apache-2.0, approved, clearlydefined
maven/mavencentral/com.puppycrawl.tools/checkstyle/10.16.0, LGPL-2.1-or-later AND (Apache-2.0 AND LGPL-2.1-or-later) AND Apache-2.0, approved, #14689
maven/mavencentral/com.samskivert/jmustache/1.15, BSD-2-Clause, approved, clearlydefined
maven/mavencentral/com.squareup.okhttp3/okhttp-dnsoverhttps/4.12.0, Apache-2.0, approved, #11159
maven/mavencentral/com.squareup.okhttp3/okhttp/4.12.0, Apache-2.0, approved, #11156
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public ScopeToCriterionTransformer createScopeTransformer(ServiceExtensionContex
return new EdcScopeToCriterionTransformer();
}

@Provider
@Provider(isDefault = true)
public RevocationListService createRevocationListService(ServiceExtensionContext context) {
if (revocationService == null) {
var validity = context.getConfig().getLong(REVOCATION_CACHE_VALIDITY, DEFAULT_REVOCATION_CACHE_VALIDITY_MILLIS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
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.identithub.verifiablecredential.CredentialStatusCheckServiceImpl;
import org.eclipse.edc.identithub.verifiablepresentation.PresentationCreatorRegistryImpl;
import org.eclipse.edc.identithub.verifiablepresentation.VerifiablePresentationServiceImpl;
import org.eclipse.edc.identithub.verifiablepresentation.generators.JwtPresentationGenerator;
Expand All @@ -28,6 +29,7 @@
import org.eclipse.edc.identityhub.spi.keypair.KeyPairService;
import org.eclipse.edc.identityhub.spi.model.IdentityHubConstants;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.CredentialStatusCheckService;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.generator.PresentationCreatorRegistry;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.generator.VerifiablePresentationService;
import org.eclipse.edc.identityhub.spi.verifiablecredentials.resolution.CredentialQueryResolver;
Expand Down Expand Up @@ -131,15 +133,13 @@ public void initialize(ServiceExtensionContext context) {
// Setup API
cacheContextDocuments(getClass().getClassLoader());
suiteRegistry.register(IdentityHubConstants.JWS_2020_SIGNATURE_SUITE, new Jws2020SignatureSuite(JacksonJsonLd.createObjectMapper()));

}

@Provider
public AccessTokenVerifier createAccessTokenVerifier(ServiceExtensionContext context) {
return new AccessTokenVerifierImpl(tokenValidationService, createPublicKey(context), tokenValidationRulesRegistry, context.getMonitor(), publicKeyResolver);
}


@Provider
public CredentialQueryResolver createCredentialQueryResolver(ServiceExtensionContext context) {
return new CredentialQueryResolverImpl(credentialStore, transformer, revocationService, context.getMonitor().withPrefix("Credential Query"));
Expand All @@ -165,6 +165,11 @@ public VerifiablePresentationService presentationGenerator(ServiceExtensionConte
}


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

private String getOwnDid(ServiceExtensionContext context) {
return context.getConfig().getString(OWN_DID_PROPERTY);
}
Expand Down
2 changes: 1 addition & 1 deletion core/lib/verifiable-presentation-lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ dependencies {
implementation(libs.edc.common.crypto) // for the CryptoConverter
implementation(libs.edc.lib.jws2020)
implementation(libs.edc.vc.ldp)
implementation(libs.edc.verifiablecredentials)

testImplementation(libs.edc.junit)
testImplementation(libs.edc.lib.jsonld)
testImplementation(testFixtures(project(":spi:identity-hub-spi")))
testImplementation(testFixtures(libs.edc.vc.jwt)) // JWT generator
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2024 Metaform Systems, Inc.
*
* 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:
* Metaform Systems, Inc. - initial API and implementation
*
*/

package org.eclipse.edc.identithub.verifiablecredential;

import org.eclipse.edc.iam.verifiablecredentials.spi.RevocationListService;
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;
import org.eclipse.edc.spi.EdcException;
import org.eclipse.edc.spi.result.Result;
import org.jetbrains.annotations.Nullable;

import java.time.Clock;

import static org.eclipse.edc.spi.result.Result.failure;
import static org.eclipse.edc.spi.result.Result.success;


public class CredentialStatusCheckServiceImpl implements CredentialStatusCheckService {
private static final String SUSPENSION = "suspension";
private static final String REVOCATION = "revocation";
private final RevocationListService revocationListService;
private final Clock clock;


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

@Override
public Result<VcStatus> checkStatus(VerifiableCredentialResource resource) {

if (isExpired(resource)) {
return success(VcStatus.EXPIRED);
}
VcStatus targetStatus;
if (isNotYetValid(resource)) {
targetStatus = VcStatus.NOT_YET_VALID;
} else {
targetStatus = VcStatus.ISSUED;
}

try {
if (isRevoked(resource)) {
return success(VcStatus.REVOKED); //irreversible, cannot be overwritten
}
if (isSuspended(resource)) {
targetStatus = VcStatus.SUSPENDED;
}

} catch (EdcException ex) {
return failure(ex.getMessage());
}
return success(targetStatus);
}

// returns true if the expiration date is not null and is before NOW
private boolean isExpired(VerifiableCredentialResource resource) {
var cred = resource.getVerifiableCredential().credential();

if (cred == null) {
return false;
}

var now = clock.instant();
return cred.getExpirationDate() != null && cred.getExpirationDate().isBefore(now);
}

// returns true if the issuance date is after NOW
private boolean isNotYetValid(VerifiableCredentialResource resource) {
var cred = resource.getVerifiableCredential().credential();
if (cred == null) {
return false;
}

var now = clock.instant();
// issuance date can not be null, due to builder validation
return cred.getIssuanceDate().isAfter(now);
}

// returns true if the revocation service returns "suspension"
private boolean isSuspended(VerifiableCredentialResource resource) {
return SUSPENSION.equalsIgnoreCase(fetchRevocationStatus(resource));
}

// returns true if the revocation service returns "revocation"
private boolean isRevoked(VerifiableCredentialResource resource) {
return REVOCATION.equalsIgnoreCase(fetchRevocationStatus(resource));
}

@Nullable
private String fetchRevocationStatus(VerifiableCredentialResource resource) {
var cred = resource.getVerifiableCredential().credential();
if (cred == null) {
return null;
}
return revocationListService.getStatusPurpose(cred)
.orElseThrow(f -> new EdcException(f.getFailureDetail()));
}
}
Loading

0 comments on commit a188d79

Please sign in to comment.