From 043f4b6a25cc40d65baabd51d2fa91d9c3cde7f1 Mon Sep 17 00:00:00 2001 From: "Andy Miller (IMS)" <48326098+amiller-ims@users.noreply.github.com> Date: Tue, 20 Dec 2022 12:54:59 -0800 Subject: [PATCH] Replace run(resource) override to inspect standalone endorsement --- .../inspect/vc/EndorsementInspector.java | 105 +++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/EndorsementInspector.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/EndorsementInspector.java index 053b08f..1e8efab 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/EndorsementInspector.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/EndorsementInspector.java @@ -1,6 +1,7 @@ package org.oneedtech.inspect.vc; import static java.lang.Boolean.TRUE; +import static org.oneedtech.inspect.core.Inspector.Behavior.RESET_CACHES_ON_RUN; import static org.oneedtech.inspect.core.probe.RunContext.Key.*; import static org.oneedtech.inspect.core.report.ReportUtil.onProbeException; import static org.oneedtech.inspect.util.code.Defensives.checkNotNull; @@ -19,14 +20,19 @@ import org.oneedtech.inspect.core.probe.GeneratedObject; import org.oneedtech.inspect.core.probe.Probe; import org.oneedtech.inspect.core.probe.RunContext; 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.ReportItems; +import org.oneedtech.inspect.schema.JsonSchemaCache; +import org.oneedtech.inspect.schema.SchemaKey; import org.oneedtech.inspect.util.json.ObjectMapperCache; import org.oneedtech.inspect.util.resource.Resource; import org.oneedtech.inspect.util.resource.UriResource; import org.oneedtech.inspect.util.resource.context.ResourceContext; import org.oneedtech.inspect.vc.VerifiableCredential.Type; import org.oneedtech.inspect.vc.probe.ContextPropertyProbe; +import org.oneedtech.inspect.vc.probe.CredentialParseProbe; +import org.oneedtech.inspect.vc.probe.CredentialSubjectProbe; import org.oneedtech.inspect.vc.probe.EmbeddedProofProbe; import org.oneedtech.inspect.vc.probe.ExpirationProbe; import org.oneedtech.inspect.vc.probe.ExternalProofProbe; @@ -34,9 +40,11 @@ import org.oneedtech.inspect.vc.probe.InlineJsonSchemaProbe; import org.oneedtech.inspect.vc.probe.IssuanceProbe; import org.oneedtech.inspect.vc.probe.RevocationListProbe; import org.oneedtech.inspect.vc.probe.TypePropertyProbe; +import org.oneedtech.inspect.vc.util.CachingDocumentLoader; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableList; /** * An inspector for EndorsementCredential objects. @@ -44,8 +52,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; */ public class EndorsementInspector extends VCInspector implements SubInspector { + protected final List> userProbes; + protected > EndorsementInspector(B builder) { super(builder); + this.userProbes = ImmutableList.copyOf(builder.probes); } @Override @@ -127,8 +138,98 @@ public class EndorsementInspector extends VCInspector implements SubInspector { } @Override - public Report run(R resource) { - throw new IllegalStateException("must use #run(resource, map)"); + public Report run(Resource resource) { + super.check(resource); + + if (getBehavior(RESET_CACHES_ON_RUN) == TRUE) { + JsonSchemaCache.reset(); + CachingDocumentLoader.reset(); + } + + ObjectMapper mapper = ObjectMapperCache.get(DEFAULT); + JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper); + + RunContext ctx = new RunContext.Builder() + .put(this) + .put(resource) + .put(JACKSON_OBJECTMAPPER, mapper) + .put(JSONPATH_EVALUATOR, jsonPath) + .put(GENERATED_OBJECT_BUILDER, new VerifiableCredential.Builder()) + .build(); + + List accumulator = new ArrayList<>(); + int probeCount = 0; + + try { + // detect type (png, svg, json, jwt) and extract json data + probeCount++; + accumulator.add(new CredentialParseProbe().run(resource, ctx)); + if (broken(accumulator, true)) + return abort(ctx, accumulator, probeCount); + + // we expect the above to place a generated object in the context + VerifiableCredential endorsement = ctx.getGeneratedObject(VerifiableCredential.ID); + + //context and type properties + VerifiableCredential.Type type = Type.EndorsementCredential; + for(Probe probe : List.of(new ContextPropertyProbe(type), new TypePropertyProbe(type))) { + probeCount++; + accumulator.add(probe.run(endorsement.getJson(), ctx)); + if(broken(accumulator)) return abort(ctx, accumulator, probeCount); + } + + //canonical schema and inline schema + SchemaKey schema = endorsement.getSchemaKey().orElseThrow(); + for(Probe probe : List.of(new JsonSchemaProbe(schema), new InlineJsonSchemaProbe(schema))) { + probeCount++; + accumulator.add(probe.run(endorsement.getJson(), ctx)); + if(broken(accumulator)) return abort(ctx, accumulator, probeCount); + } + + //credentialSubject + probeCount++; + accumulator.add(new CredentialSubjectProbe().run(endorsement.getJson(), ctx)); + + //signatures, proofs + probeCount++; + if(endorsement.getProofType() == EXTERNAL){ + //The credential originally contained in a JWT, validate the jwt and external proof. + accumulator.add(new ExternalProofProbe().run(endorsement, ctx)); + } else { + accumulator.add(new EmbeddedProofProbe().run(endorsement, ctx)); + } + if(broken(accumulator)) return abort(ctx, accumulator, probeCount); + + //check refresh service if we are not already refreshed + probeCount++; + if(resource.getContext().get(REFRESHED) != TRUE) { + Optional newID = checkRefreshService(endorsement, ctx); + if(newID.isPresent()) { + return this.run( + new UriResource(new URI(newID.get())) + .setContext(new ResourceContext(REFRESHED, TRUE))); + } + } + + //revocation, expiration and issuance + for(Probe probe : List.of(new RevocationListProbe(), + new ExpirationProbe(), new IssuanceProbe())) { + probeCount++; + accumulator.add(probe.run(endorsement, ctx)); + if(broken(accumulator)) return abort(ctx, accumulator, probeCount); + } + + //finally, run any user-added probes + for(Probe probe : userProbes) { + probeCount++; + accumulator.add(probe.run(endorsement, ctx)); + } + + } catch (Exception e) { + accumulator.add(onProbeException(Probe.ID.NO_UNCAUGHT_EXCEPTIONS, resource, e)); + } + + return new Report(ctx, new ReportItems(accumulator), probeCount); } public static class Builder extends VCInspector.Builder {