generic IssuanceProbe

This commit is contained in:
Xavi Aracil 2022-12-01 12:30:34 +01:00
parent 739facfe06
commit ce89968837
9 changed files with 121 additions and 18 deletions

View File

@ -26,8 +26,8 @@ public class Assertion extends Credential {
final Assertion.Type assertionType; final Assertion.Type assertionType;
protected Assertion(Resource resource, JsonNode data, String jwt, Map<CredentialEnum, SchemaKey> schemas) { protected Assertion(Resource resource, JsonNode data, String jwt, Map<CredentialEnum, SchemaKey> schemas, String issuedOnPropertyName) {
super(resource.getID(), resource, data, jwt, schemas); super(resource.getID(), resource, data, jwt, schemas, issuedOnPropertyName);
JsonNode typeNode = jsonData.get("type"); JsonNode typeNode = jsonData.get("type");
this.assertionType = Assertion.Type.valueOf(typeNode); this.assertionType = Assertion.Type.valueOf(typeNode);
@ -60,7 +60,7 @@ public class Assertion extends Credential {
public Assertion build() { public Assertion build() {
// transform key of schemas map to string because the type of the key in the base map is generic // transform key of schemas map to string because the type of the key in the base map is generic
// and our specific key is an Enum // and our specific key is an Enum
return new Assertion(getResource(), getJsonData(), getJwt(), schemas); return new Assertion(getResource(), getJsonData(), getJwt(), schemas, ISSUED_ON_PROPERTY_NAME);
} }
} }
@ -300,4 +300,5 @@ public class Assertion extends Credential {
.build(); .build();
public static final String ID = Assertion.class.getCanonicalName(); public static final String ID = Assertion.class.getCanonicalName();
private static final String ISSUED_ON_PROPERTY_NAME = "issuedOn";
} }

View File

@ -29,14 +29,16 @@ public abstract class Credential extends GeneratedObject {
final Resource resource; final Resource resource;
final JsonNode jsonData; final JsonNode jsonData;
final String jwt; final String jwt;
final String issuedOnPropertyName;
final Map<CredentialEnum, SchemaKey> schemas; final Map<CredentialEnum, SchemaKey> schemas;
protected Credential(String id, Resource resource, JsonNode data, String jwt, Map<CredentialEnum, SchemaKey> schemas) { protected Credential(String id, Resource resource, JsonNode data, String jwt, Map<CredentialEnum, SchemaKey> schemas, String issuedOnPropertyName) {
super(id, GeneratedObject.Type.INTERNAL); super(id, GeneratedObject.Type.INTERNAL);
this.resource = checkNotNull(resource); this.resource = checkNotNull(resource);
this.jsonData = checkNotNull(data); this.jsonData = checkNotNull(data);
this.jwt = jwt; //may be null this.jwt = jwt; //may be null
this.schemas = schemas; this.schemas = schemas;
this.issuedOnPropertyName = issuedOnPropertyName;
checkTrue(RECOGNIZED_PAYLOAD_TYPES.contains(resource.getType())); checkTrue(RECOGNIZED_PAYLOAD_TYPES.contains(resource.getType()));
} }
@ -53,6 +55,10 @@ public abstract class Credential extends GeneratedObject {
return Optional.ofNullable(jwt); return Optional.ofNullable(jwt);
} }
public String getIssuedOnPropertyName() {
return issuedOnPropertyName;
}
/** /**
* Get the canonical schema for this credential if such exists. * Get the canonical schema for this credential if such exists.
*/ */

View File

@ -111,7 +111,7 @@ public class EndorsementInspector extends VCInspector implements SubInspector {
} }
//revocation, expiration and issuance //revocation, expiration and issuance
for(Probe<VerifiableCredential> probe : List.of(new RevocationListProbe(), for(Probe<Credential> probe : List.of(new RevocationListProbe(),
new ExpirationProbe(), new IssuanceProbe())) { new ExpirationProbe(), new IssuanceProbe())) {
probeCount++; probeCount++;
accumulator.add(probe.run(endorsement, ctx)); accumulator.add(probe.run(endorsement, ctx));

View File

@ -194,7 +194,7 @@ public class OB30Inspector extends VCInspector implements SubInspector {
} }
//revocation, expiration and issuance //revocation, expiration and issuance
for(Probe<VerifiableCredential> probe : List.of(new RevocationListProbe(), for(Probe<Credential> probe : List.of(new RevocationListProbe(),
new ExpirationProbe(), new IssuanceProbe())) { new ExpirationProbe(), new IssuanceProbe())) {
probeCount++; probeCount++;
accumulator.add(probe.run(ob, ctx)); accumulator.add(probe.run(ob, ctx));

View File

@ -28,8 +28,8 @@ import com.google.common.collect.ImmutableMap;
public class VerifiableCredential extends Credential { public class VerifiableCredential extends Credential {
final VerifiableCredential.Type credentialType; final VerifiableCredential.Type credentialType;
protected VerifiableCredential(Resource resource, JsonNode data, String jwt, Map<CredentialEnum, SchemaKey> schemas) { protected VerifiableCredential(Resource resource, JsonNode data, String jwt, Map<CredentialEnum, SchemaKey> schemas, String issuedOnPropertyName) {
super(ID, resource, data, jwt, schemas); super(ID, resource, data, jwt, schemas, issuedOnPropertyName);
JsonNode typeNode = jsonData.get("type"); JsonNode typeNode = jsonData.get("type");
this.credentialType = VerifiableCredential.Type.valueOf(typeNode); this.credentialType = VerifiableCredential.Type.valueOf(typeNode);
@ -133,9 +133,10 @@ public class VerifiableCredential extends Credential {
public static class Builder extends Credential.Builder<VerifiableCredential> { public static class Builder extends Credential.Builder<VerifiableCredential> {
@Override @Override
public VerifiableCredential build() { public VerifiableCredential build() {
return new VerifiableCredential(getResource(), getJsonData(), getJwt(), schemas); return new VerifiableCredential(getResource(), getJsonData(), getJwt(), schemas, ISSUED_ON_PROPERTY_NAME);
} }
} }
public static final String ID = VerifiableCredential.class.getCanonicalName(); public static final String ID = VerifiableCredential.class.getCanonicalName();
private static final String ISSUED_ON_PROPERTY_NAME = "issuanceDate";
} }

View File

@ -5,7 +5,7 @@ import java.time.ZonedDateTime;
import org.oneedtech.inspect.core.probe.Probe; import org.oneedtech.inspect.core.probe.Probe;
import org.oneedtech.inspect.core.probe.RunContext; import org.oneedtech.inspect.core.probe.RunContext;
import org.oneedtech.inspect.core.report.ReportItems; import org.oneedtech.inspect.core.report.ReportItems;
import org.oneedtech.inspect.vc.VerifiableCredential; import org.oneedtech.inspect.vc.Credential;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@ -13,14 +13,14 @@ import com.fasterxml.jackson.databind.JsonNode;
* A Probe that verifies a credential's expiration status * A Probe that verifies a credential's expiration status
* @author mgylling * @author mgylling
*/ */
public class ExpirationProbe extends Probe<VerifiableCredential> { public class ExpirationProbe extends Probe<Credential> {
public ExpirationProbe() { public ExpirationProbe() {
super(ID); super(ID);
} }
@Override @Override
public ReportItems run(VerifiableCredential crd, RunContext ctx) throws Exception { public ReportItems run(Credential crd, RunContext ctx) throws Exception {
/* /*
* If the AchievementCredential or EndorsementCredential has an expirationDate property * If the AchievementCredential or EndorsementCredential has an expirationDate property
* and the expiration date is prior to the current date, the credential has expired. * and the expiration date is prior to the current date, the credential has expired.

View File

@ -5,7 +5,7 @@ import java.time.ZonedDateTime;
import org.oneedtech.inspect.core.probe.Probe; import org.oneedtech.inspect.core.probe.Probe;
import org.oneedtech.inspect.core.probe.RunContext; import org.oneedtech.inspect.core.probe.RunContext;
import org.oneedtech.inspect.core.report.ReportItems; import org.oneedtech.inspect.core.report.ReportItems;
import org.oneedtech.inspect.vc.VerifiableCredential; import org.oneedtech.inspect.vc.Credential;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@ -13,19 +13,19 @@ import com.fasterxml.jackson.databind.JsonNode;
* A Probe that verifies a credential's issuance status * A Probe that verifies a credential's issuance status
* @author mgylling * @author mgylling
*/ */
public class IssuanceProbe extends Probe<VerifiableCredential> { public class IssuanceProbe extends Probe<Credential> {
public IssuanceProbe() { public IssuanceProbe() {
super(ID); super(ID);
} }
@Override @Override
public ReportItems run(VerifiableCredential crd, RunContext ctx) throws Exception { public ReportItems run(Credential crd, RunContext ctx) throws Exception {
/* /*
* If the AchievementCredential or EndorsementCredential issuanceDate * If the AchievementCredential or EndorsementCredential issuanceDate
* property after the current date, the credential is not yet valid. * property after the current date, the credential is not yet valid.
*/ */
JsonNode node = crd.getJson().get("issuanceDate"); JsonNode node = crd.getJson().get(crd.getIssuedOnPropertyName());
if(node != null) { if(node != null) {
try { try {
ZonedDateTime issuanceDate = ZonedDateTime.parse(node.textValue()); ZonedDateTime issuanceDate = ZonedDateTime.parse(node.textValue());

View File

@ -10,6 +10,7 @@ import java.util.List;
import org.oneedtech.inspect.core.probe.Probe; import org.oneedtech.inspect.core.probe.Probe;
import org.oneedtech.inspect.core.probe.RunContext; import org.oneedtech.inspect.core.probe.RunContext;
import org.oneedtech.inspect.core.report.ReportItems; import org.oneedtech.inspect.core.report.ReportItems;
import org.oneedtech.inspect.vc.Credential;
import org.oneedtech.inspect.vc.VerifiableCredential; import org.oneedtech.inspect.vc.VerifiableCredential;
import org.oneedtech.inspect.vc.util.JsonNodeUtil; import org.oneedtech.inspect.vc.util.JsonNodeUtil;
@ -20,14 +21,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
* A Probe that verifies a credential's revocation status. * A Probe that verifies a credential's revocation status.
* @author mgylling * @author mgylling
*/ */
public class RevocationListProbe extends Probe<VerifiableCredential> { public class RevocationListProbe extends Probe<Credential> {
public RevocationListProbe() { public RevocationListProbe() {
super(ID); super(ID);
} }
@Override @Override
public ReportItems run(VerifiableCredential crd, RunContext ctx) throws Exception { public ReportItems run(Credential crd, RunContext ctx) throws Exception {
/* /*
* If the AchievementCredential or EndorsementCredential has a credentialStatus property * If the AchievementCredential or EndorsementCredential has a credentialStatus property

View File

@ -0,0 +1,94 @@
package org.oneedtech.inspect.vc.probe.validation;
import java.util.UUID;
import org.oneedtech.inspect.core.probe.RunContext;
import org.oneedtech.inspect.core.probe.RunContext.Key;
import org.oneedtech.inspect.core.report.ReportItems;
import org.oneedtech.inspect.util.resource.UriResource;
import org.oneedtech.inspect.vc.Validation;
import org.oneedtech.inspect.vc.jsonld.JsonLdGeneratedObject;
import org.oneedtech.inspect.vc.jsonld.probe.JsonLDCompactionProve;
import org.oneedtech.inspect.vc.util.PrimitiveValueValidator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.google.common.io.Resources;
public class ValidationFlattenEmbeddedResourcePropertyProbe extends ValidationPropertyProbe {
public ValidationFlattenEmbeddedResourcePropertyProbe(Validation validation) {
super(validation);
}
public ValidationFlattenEmbeddedResourcePropertyProbe(Validation validation, boolean fullValidate) {
super(validation, fullValidate);
}
@Override
protected ReportItems reportForNonExistentProperty(JsonNode node, RunContext ctx) {
return notRun("Expected property " + validation.getName() + " was missing in node " + node.toString(), ctx);
}
@Override
protected ReportItems validate(JsonNode node, RunContext ctx) {
try {
UriResource uriResource = resolveUriResource(ctx, node.asText());
JsonLdGeneratedObject resolved = (JsonLdGeneratedObject) ctx.getGeneratedObject(JsonLDCompactionProve.getId(uriResource));
ObjectMapper mapper = (ObjectMapper) ctx.get(Key.JACKSON_OBJECTMAPPER);
JsonNode fetchedNode = mapper.readTree(resolved.getJson());
if (fetchedNode.isTextual()) {
return notRun("Property " + validation.getName() + " referenced from " + node.toString() + " is not embedded in need of flattening", ctx);
}
if (!fetchedNode.isObject()) {
return error("Property " + validation.getName() + " referenced from " + node.toString() + " is not a JSON object or string as expected", ctx);
}
JsonNode idNode = fetchedNode.get("id");
if (idNode == null) {
// add a new node to the graph
JsonNode newNode = mapper.readTree(Resources.getResource("contexts/ob-v2p0.json"));
ObjectReader readerForUpdating = mapper.readerForUpdating(newNode);
UUID newId = UUID.randomUUID();
JsonNode merged = readerForUpdating.readValue("{\"id\": \"_:" + newId + "\"}");
ctx.addGeneratedObject(new JsonLdGeneratedObject(JsonLDCompactionProve.getId(newId.toString()), merged.toString()));
return warning("Node id missing at " + node.toString() + ". A blank node ID has been assigned", ctx);
} else if (!idNode.isTextual() && !PrimitiveValueValidator.validateIri(idNode)) {
return error("Embedded JSON object at " + node.asText() + " has no proper assigned id.", ctx);
} else if (/*node_class == Assertion && */ !PrimitiveValueValidator.validateUrl(idNode)) {
/*
if not re.match(URN_REGEX, embedded_node_id, re.IGNORECASE):
actions.append(report_message(
'ID format for {} at {} not in an expected HTTP or URN:UUID scheme'.format(
embedded_node_id, abv_node(node_path=[node_id, prop_name])
)))
new_node = value.copy()
new_node['@context'] = OPENBADGES_CONTEXT_V2_URI
actions.append(add_node(embedded_node_id, data=value))
actions.append(patch_node(node_id, {prop_name: embedded_node_id}))
*/
} else {
/*
actions.append(patch_node(node_id, {prop_name: embedded_node_id}))
if not node_match_exists(state, embedded_node_id) and not filter_tasks(
state, node_id=embedded_node_id, task_type=FETCH_HTTP_NODE):
# fetch
actions.append(add_task(FETCH_HTTP_NODE, url=embedded_node_id))
*/
}
} catch (Throwable t) {
return fatal(t.getMessage(), ctx);
}
return success(ctx);
}
}