clean up endorsementinspector

This commit is contained in:
Markus Gylling 2022-08-31 19:48:29 +02:00
parent ef74f679fc
commit 5e6a277185
4 changed files with 53 additions and 70 deletions

View File

@ -1,10 +1,10 @@
package org.oneedtech.inspect.vc; package org.oneedtech.inspect.vc;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
import static org.oneedtech.inspect.core.probe.RunContext.Key.*; import static org.oneedtech.inspect.core.probe.RunContext.Key.*;
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
import static org.oneedtech.inspect.core.report.ReportUtil.onProbeException; import static org.oneedtech.inspect.core.report.ReportUtil.onProbeException;
import static org.oneedtech.inspect.util.code.Defensives.checkNotNull;
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
@ -17,19 +17,17 @@ import org.oneedtech.inspect.core.probe.GeneratedObject;
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.probe.json.JsonPathEvaluator; import org.oneedtech.inspect.core.probe.json.JsonPathEvaluator;
import org.oneedtech.inspect.core.probe.json.JsonSchemaProbe;
import org.oneedtech.inspect.core.report.Report; import org.oneedtech.inspect.core.report.Report;
import org.oneedtech.inspect.core.report.ReportItems; import org.oneedtech.inspect.core.report.ReportItems;
import org.oneedtech.inspect.schema.SchemaKey;
import org.oneedtech.inspect.util.json.ObjectMapperCache; import org.oneedtech.inspect.util.json.ObjectMapperCache;
import org.oneedtech.inspect.util.resource.Resource; import org.oneedtech.inspect.util.resource.Resource;
import org.oneedtech.inspect.util.resource.UriResource; import org.oneedtech.inspect.util.resource.UriResource;
import org.oneedtech.inspect.util.resource.context.ResourceContext; import org.oneedtech.inspect.util.resource.context.ResourceContext;
import org.oneedtech.inspect.vc.Credential.Type; import org.oneedtech.inspect.vc.Credential.Type;
import org.oneedtech.inspect.vc.probe.CredentialParseProbe;
import org.oneedtech.inspect.vc.probe.ExpirationVerifierProbe; import org.oneedtech.inspect.vc.probe.ExpirationVerifierProbe;
import org.oneedtech.inspect.vc.probe.InlineJsonSchemaProbe; import org.oneedtech.inspect.vc.probe.InlineJsonSchemaProbe;
import org.oneedtech.inspect.vc.probe.IssuanceVerifierProbe; import org.oneedtech.inspect.vc.probe.IssuanceVerifierProbe;
import org.oneedtech.inspect.vc.probe.ProofVerifierProbe;
import org.oneedtech.inspect.vc.probe.RevocationListProbe; import org.oneedtech.inspect.vc.probe.RevocationListProbe;
import org.oneedtech.inspect.vc.probe.SignatureVerifierProbe; import org.oneedtech.inspect.vc.probe.SignatureVerifierProbe;
import org.oneedtech.inspect.vc.probe.TypePropertyProbe; import org.oneedtech.inspect.vc.probe.TypePropertyProbe;
@ -49,63 +47,47 @@ public class EndorsementInspector extends VCInspector implements SubInspector {
@Override @Override
public Report run(Resource resource, Map<String, GeneratedObject> parentObjects) { public Report run(Resource resource, Map<String, GeneratedObject> parentObjects) {
/* /*
* The resource param is the top-level credential that embeds the endorsement, we * The resource param is the top-level credential that embeds the endorsement, we
* expect parentObjects to provide a pointer to the JsonNode we should check * expect parentObjects to provide a pointer to the JsonNode we should check.
*
* The parent inspector is responsible to decode away possible jwt-ness, so that
* what we get here is a verbatim json node.
*
*/ */
Credential verifiableCredential = (Credential) parentObjects.get(ENDORSEMENT_KEY);
Credential endorsement = (Credential) checkNotNull(parentObjects.get(ENDORSEMENT_KEY));
ObjectMapper mapper = ObjectMapperCache.get(DEFAULT); ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper); JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
RunContext ctx = new RunContext.Builder() RunContext ctx = new RunContext.Builder()
.put(this) .put(this)
.put(resource)
.put(JACKSON_OBJECTMAPPER, mapper) .put(JACKSON_OBJECTMAPPER, mapper)
.put(JSONPATH_EVALUATOR, jsonPath) .put(JSONPATH_EVALUATOR, jsonPath)
.put(ENDORSEMENT_KEY, verifiableCredential)
.build(); .build();
List<ReportItems> accumulator = new ArrayList<>(); List<ReportItems> accumulator = new ArrayList<>();
int probeCount = 0; int probeCount = 0;
try { try {
//detect type (png, svg, json, jwt) and extract json data
probeCount++;
accumulator.add(new CredentialParseProbe().run(resource, ctx));
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
//we expect the above to place a generated object in the context
Credential crd = ctx.getGeneratedObject(Credential.ID);
//type property //type property
probeCount++; probeCount++;
accumulator.add(new TypePropertyProbe(Type.ClrCredential).run(crd.getJson(), ctx)); accumulator.add(new TypePropertyProbe(Type.EndorsementCredential).run(endorsement.getJson(), ctx));
if(broken(accumulator)) return abort(ctx, accumulator, probeCount); if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
//canonical schema and inline schema //inline schema (parent inspector has already validated against canonical)
SchemaKey schema = crd.getSchemaKey().orElseThrow(); accumulator.add(new InlineJsonSchemaProbe().run(endorsement.getJson(), ctx));
for(Probe<JsonNode> probe : List.of(new JsonSchemaProbe(schema), new InlineJsonSchemaProbe(schema))) {
probeCount++;
accumulator.add(probe.run(crd.getJson(), ctx));
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
}
//signatures, proofs //signatures, proofs
probeCount++; probeCount++;
if(crd.getJwt().isPresent()){ if(endorsement.getJwt().isPresent()){
//The credential originally contained in a JWT, validate the jwt and external proof. //The credential originally contained in a JWT, validate the jwt and external proof.
accumulator.add(new SignatureVerifierProbe().run(crd, ctx)); accumulator.add(new SignatureVerifierProbe().run(endorsement, ctx));
} else { } else {
//The credential not contained in a jwt, must have an internal proof. //The credential not contained in a jwt, must have an internal proof.
//TODO: @Miles Need to fix the issuer, Same as with outer CLR accumulator.add(new ProofVerifierProbe().run(endorsement, ctx));
//Swap -> "verificationMethod": "https://example.edu/issuers/565049#z6MkwA1498JfoCS3y4y3zggBDAosQEoCi5gsYH2PMXh1cFWK",
//To be like -> "verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj",
//...but also work properly which old record seems not be doing...
/*
accumulator.add(new ProofVerifierProbe().run(crd, ctx));
*/
} }
if(broken(accumulator)) return abort(ctx, accumulator, probeCount); if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
@ -113,7 +95,7 @@ public class EndorsementInspector extends VCInspector implements SubInspector {
//check refresh service if we are not already refreshed (check just like in external CLR) //check refresh service if we are not already refreshed (check just like in external CLR)
probeCount++; probeCount++;
if(resource.getContext().get(REFRESHED) != TRUE) { if(resource.getContext().get(REFRESHED) != TRUE) {
Optional<String> newID = checkRefreshService(crd, ctx); Optional<String> newID = checkRefreshService(endorsement, ctx);
if(newID.isPresent()) { if(newID.isPresent()) {
//TODO resource.type //TODO resource.type
return this.run( return this.run(
@ -122,11 +104,11 @@ public class EndorsementInspector extends VCInspector implements SubInspector {
} }
} }
//revocation, expiration and issuance (check just like in external CLR) //revocation, expiration and issuance
for(Probe<Credential> probe : List.of(new RevocationListProbe(), for(Probe<Credential> probe : List.of(new RevocationListProbe(),
new ExpirationVerifierProbe(), new IssuanceVerifierProbe())) { new ExpirationVerifierProbe(), new IssuanceVerifierProbe())) {
probeCount++; probeCount++;
accumulator.add(probe.run(crd, ctx)); accumulator.add(probe.run(endorsement, ctx));
if(broken(accumulator)) return abort(ctx, accumulator, probeCount); if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
} }

View File

@ -141,7 +141,7 @@ public class OB30Inspector extends VCInspector {
//embedded endorsements //embedded endorsements
EndorsementInspector endorsementInspector = new EndorsementInspector.Builder().build(); EndorsementInspector endorsementInspector = new EndorsementInspector.Builder().build();
List<JsonNode> endorsements = asNodeList(crd.getJson(), "$..endorsement", jsonPath); List<JsonNode> endorsements = asNodeList(crd.getJson(), "$..endorsement", jsonPath);
for(JsonNode node : endorsements) { for(JsonNode node : endorsements) {
probeCount++; probeCount++;
Credential endorsement = new Credential(resource, node); Credential endorsement = new Credential(resource, node);
@ -149,7 +149,7 @@ public class OB30Inspector extends VCInspector {
} }
//embedded jwt endorsements //embedded jwt endorsements
endorsements = asNodeList(crd.getJson(), "$..endorsementJwt", jsonPath); endorsements = asNodeList(crd.getJson(), "$..endorsementJwt", jsonPath);
for(JsonNode node : endorsements) { for(JsonNode node : endorsements) {
probeCount++; probeCount++;
String jwt = node.asText(); String jwt = node.asText();

View File

@ -51,7 +51,7 @@ public class ProofVerifierProbe extends Probe<Credential> {
} catch (DocumentError e) { } catch (DocumentError e) {
return error(e.getType() + " " + e.getSubject(), ctx); return error(e.getType() + " " + e.getSubject(), ctx);
} catch (VerificationError e) { } catch (VerificationError e) {
System.err.println(e.getCode()); //System.err.println(e.getCode() + " (ProofVerifierProbe)");
if(e.getCode() == Code.Internal) { if(e.getCode() == Code.Internal) {
return exception(e.getMessage(), ctx.getResource()); return exception(e.getMessage(), ctx.getResource());
} else if(e.getCode().equals(Code.Expired)) { } else if(e.getCode().equals(Code.Expired)) {

View File

@ -15,49 +15,50 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
/** /**
* A Probe that verifies a credential's type property. * A Probe that verifies a credential's type property.
*
* @author mgylling * @author mgylling
*/ */
public class TypePropertyProbe extends Probe<JsonNode> { public class TypePropertyProbe extends Probe<JsonNode> {
private final Credential.Type expected; private final Credential.Type expected;
public TypePropertyProbe(Credential.Type expected) { public TypePropertyProbe(Credential.Type expected) {
super(ID); super(ID);
this.expected = checkNotNull(expected); this.expected = checkNotNull(expected);
} }
@Override @Override
public ReportItems run(JsonNode root, RunContext ctx) throws Exception { public ReportItems run(JsonNode root, RunContext ctx) throws Exception {
ArrayNode typeNode = (ArrayNode)root.get("type"); ArrayNode typeNode = (ArrayNode) root.get("type");
if(typeNode == null) return fatal("No type property", ctx); if (typeNode == null)
return fatal("No type property", ctx);
List<String> values = JsonNodeUtil.asStringList(typeNode); List<String> values = JsonNodeUtil.asStringList(typeNode);
if(!values.contains("VerifiableCredential")) { if (!values.contains("VerifiableCredential")) {
return fatal("The type property does not contain the entry 'VerifiableCredential'", ctx); return fatal("The type property does not contain the entry 'VerifiableCredential'", ctx);
} }
if(expected == Credential.Type.OpenBadgeCredential) { if (expected == Credential.Type.OpenBadgeCredential) {
if(!values.contains("OpenBadgeCredential") && !values.contains("AchievementCredential")) { if (!values.contains("OpenBadgeCredential") && !values.contains("AchievementCredential")) {
return fatal( return fatal("The type property does not contain one of 'OpenBadgeCredential' or 'AchievementCredential'", ctx);
"The type property does not contain one of 'OpenBadgeCredential' or 'AchievementCredential'", }
ctx); } else if (expected == Credential.Type.ClrCredential) {
} if (!values.contains("ClrCredential")) {
} return fatal("The type property does not contain the entry 'ClrCredential'", ctx);
else if(expected == Credential.Type.ClrCredential){ }
if(!values.contains("ClrCredential")) { } else if (expected == Credential.Type.EndorsementCredential) {
return fatal( if (!values.contains("EndorsementCredential")) {
"The type property does not contain the entry 'ClrCredential'", return fatal("The type property does not contain the entry 'EndorsementCredential'", ctx);
ctx); }
}
} else { } else {
//TODO implement // TODO implement
throw new IllegalStateException(); throw new IllegalStateException();
} }
return success(ctx); return success(ctx);
} }
public static final String ID = TypePropertyProbe.class.getSimpleName(); public static final String ID = TypePropertyProbe.class.getSimpleName();
} }