cleanup clr step #1
This commit is contained in:
parent
41f06f85e0
commit
23a34bd470
@ -60,6 +60,11 @@ public class Credential extends GeneratedObject {
|
|||||||
return Optional.ofNullable(jwt);
|
return Optional.ofNullable(jwt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ProofType getProofType() {
|
||||||
|
if(jwt == null) return ProofType.EMBEDDED;
|
||||||
|
return ProofType.EXTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the canonical schema for this credential if such exists.
|
* Get the canonical schema for this credential if such exists.
|
||||||
*/
|
*/
|
||||||
@ -105,6 +110,11 @@ public class Credential extends GeneratedObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ProofType {
|
||||||
|
EXTERNAL,
|
||||||
|
EMBEDDED
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
|
@ -1,175 +0,0 @@
|
|||||||
package org.oneedtech.inspect.vc;
|
|
||||||
|
|
||||||
import static java.lang.Boolean.TRUE;
|
|
||||||
|
|
||||||
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 java.net.URI;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.oneedtech.inspect.core.SubInspector;
|
|
||||||
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.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.Credential.Type;
|
|
||||||
import org.oneedtech.inspect.vc.probe.CredentialParseProbe;
|
|
||||||
import org.oneedtech.inspect.vc.probe.ExpirationVerifierProbe;
|
|
||||||
import org.oneedtech.inspect.vc.probe.InlineJsonSchemaProbe;
|
|
||||||
import org.oneedtech.inspect.vc.probe.IssuanceVerifierProbe;
|
|
||||||
import org.oneedtech.inspect.vc.probe.RevocationListProbe;
|
|
||||||
import org.oneedtech.inspect.vc.probe.SignatureVerifierProbe;
|
|
||||||
import org.oneedtech.inspect.vc.probe.TypePropertyProbe;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An inspector for EndorsementCredential objects.
|
|
||||||
* @author mgylling
|
|
||||||
*/
|
|
||||||
public class EmbeddedVCInspector extends VCInspector implements SubInspector {
|
|
||||||
|
|
||||||
protected <B extends VCInspector.Builder<?>> EmbeddedVCInspector(B builder) {
|
|
||||||
super(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Report run(Resource resource, Map<String, GeneratedObject> parentObjects) {
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
Credential verifiableCredential = (Credential) parentObjects.get(VC_KEY);
|
|
||||||
|
|
||||||
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(VC_KEY, verifiableCredential)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
List<ReportItems> 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)) 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
|
|
||||||
probeCount++;
|
|
||||||
accumulator.add(new TypePropertyProbe(Type.ClrCredential).run(crd.getJson(), ctx));
|
|
||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
|
||||||
|
|
||||||
//canonical schema and inline schema
|
|
||||||
SchemaKey schema = crd.getSchemaKey().orElseThrow();
|
|
||||||
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
|
|
||||||
probeCount++;
|
|
||||||
if(crd.getJwt().isPresent()){
|
|
||||||
//The credential originally contained in a JWT, validate the jwt and external proof.
|
|
||||||
accumulator.add(new SignatureVerifierProbe().run(crd, ctx));
|
|
||||||
} else {
|
|
||||||
//The credential not contained in a jwt, must have an internal proof.
|
|
||||||
//TODO: @Miles Need to fix the issuer, Same as with outer CLR
|
|
||||||
//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);
|
|
||||||
|
|
||||||
//check refresh service if we are not already refreshed (check just like in external CLR)
|
|
||||||
probeCount++;
|
|
||||||
if(resource.getContext().get(REFRESHED) != TRUE) {
|
|
||||||
Optional<String> newID = checkRefreshService(crd, ctx);
|
|
||||||
if(newID.isPresent()) {
|
|
||||||
//TODO resource.type
|
|
||||||
return this.run(
|
|
||||||
new UriResource(new URI(newID.get()))
|
|
||||||
.setContext(new ResourceContext(REFRESHED, TRUE)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//revocation, expiration and issuance (check just like in external CLR)
|
|
||||||
for(Probe<Credential> probe : List.of(new RevocationListProbe(),
|
|
||||||
new ExpirationVerifierProbe(), new IssuanceVerifierProbe())) {
|
|
||||||
probeCount++;
|
|
||||||
accumulator.add(probe.run(crd, ctx));
|
|
||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
accumulator.add(onProbeException(Probe.ID.NO_UNCAUGHT_EXCEPTIONS, resource, e));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <R extends Resource> Report run(R resource) {
|
|
||||||
throw new IllegalStateException("must use #run(resource, map)");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Builder extends VCInspector.Builder<EmbeddedVCInspector.Builder> {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public EmbeddedVCInspector build() {
|
|
||||||
return new EmbeddedVCInspector(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String VC_KEY = "VC_KEY";
|
|
||||||
private static final String REFRESHED = "is.refreshed.credential";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the AchievementCredential or EndorsementCredential has a “refreshService” property and the type of the
|
|
||||||
* RefreshService object is “1EdTechCredentialRefresh”, you should fetch the refreshed credential from the URL
|
|
||||||
* provided, then start the verification process over using the response as input. If the request fails,
|
|
||||||
* the credential is invalid.
|
|
||||||
*/
|
|
||||||
private Optional<String> checkRefreshService(Credential crd, RunContext ctx) {
|
|
||||||
JsonNode refreshServiceNode = crd.getJson().get("refreshService");
|
|
||||||
if(refreshServiceNode != null) {
|
|
||||||
JsonNode serviceTypeNode = refreshServiceNode.get("type");
|
|
||||||
if(serviceTypeNode != null && serviceTypeNode.asText().equals("1EdTechCredentialRefresh")) {
|
|
||||||
JsonNode serviceURINode = refreshServiceNode.get("id");
|
|
||||||
if(serviceURINode != null) {
|
|
||||||
return Optional.of(serviceURINode.asText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
@ -137,25 +137,5 @@ public class EndorsementInspector extends VCInspector implements SubInspector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final String ENDORSEMENT_KEY = "ENDORSEMENT_KEY";
|
public static final String ENDORSEMENT_KEY = "ENDORSEMENT_KEY";
|
||||||
private static final String REFRESHED = "is.refreshed.credential";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the AchievementCredential or EndorsementCredential has a “refreshService” property and the type of the
|
|
||||||
* RefreshService object is “1EdTechCredentialRefresh”, you should fetch the refreshed credential from the URL
|
|
||||||
* provided, then start the verification process over using the response as input. If the request fails,
|
|
||||||
* the credential is invalid.
|
|
||||||
*/
|
|
||||||
private Optional<String> checkRefreshService(Credential crd, RunContext ctx) {
|
|
||||||
JsonNode refreshServiceNode = crd.getJson().get("refreshService");
|
|
||||||
if(refreshServiceNode != null) {
|
|
||||||
JsonNode serviceTypeNode = refreshServiceNode.get("type");
|
|
||||||
if(serviceTypeNode != null && serviceTypeNode.asText().equals("1EdTechCredentialRefresh")) {
|
|
||||||
JsonNode serviceURINode = refreshServiceNode.get("id");
|
|
||||||
if(serviceURINode != null) {
|
|
||||||
return Optional.of(serviceURINode.asText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import static java.lang.Boolean.TRUE;
|
|||||||
import static org.oneedtech.inspect.core.Inspector.Behavior.RESET_CACHES_ON_RUN;
|
import static org.oneedtech.inspect.core.Inspector.Behavior.RESET_CACHES_ON_RUN;
|
||||||
import static org.oneedtech.inspect.core.report.ReportUtil.onProbeException;
|
import static org.oneedtech.inspect.core.report.ReportUtil.onProbeException;
|
||||||
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
|
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
|
||||||
import static org.oneedtech.inspect.vc.Credential.Type.OpenBadgeCredential;
|
import static org.oneedtech.inspect.vc.Credential.ProofType.EXTERNAL;
|
||||||
import static org.oneedtech.inspect.vc.EndorsementInspector.ENDORSEMENT_KEY;
|
import static org.oneedtech.inspect.vc.EndorsementInspector.ENDORSEMENT_KEY;
|
||||||
import static org.oneedtech.inspect.vc.payload.PayloadParser.fromJwt;
|
import static org.oneedtech.inspect.vc.payload.PayloadParser.fromJwt;
|
||||||
import static org.oneedtech.inspect.vc.util.JsonNodeUtil.asNodeList;
|
import static org.oneedtech.inspect.vc.util.JsonNodeUtil.asNodeList;
|
||||||
@ -15,6 +15,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.oneedtech.inspect.core.Inspector;
|
||||||
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.RunContext.Key;
|
import org.oneedtech.inspect.core.probe.RunContext.Key;
|
||||||
@ -31,9 +32,9 @@ 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.util.spec.Specification;
|
import org.oneedtech.inspect.util.spec.Specification;
|
||||||
import org.oneedtech.inspect.vc.Credential.Type;
|
import org.oneedtech.inspect.vc.Credential.Type;
|
||||||
import org.oneedtech.inspect.vc.probe.CredentialSubjectProbe;
|
|
||||||
import org.oneedtech.inspect.vc.probe.ContextPropertyProbe;
|
import org.oneedtech.inspect.vc.probe.ContextPropertyProbe;
|
||||||
import org.oneedtech.inspect.vc.probe.CredentialParseProbe;
|
import org.oneedtech.inspect.vc.probe.CredentialParseProbe;
|
||||||
|
import org.oneedtech.inspect.vc.probe.CredentialSubjectProbe;
|
||||||
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;
|
||||||
@ -54,9 +55,9 @@ import com.google.common.collect.ImmutableList;
|
|||||||
public class OB30Inspector extends VCInspector {
|
public class OB30Inspector extends VCInspector {
|
||||||
protected final List<Probe<Credential>> userProbes;
|
protected final List<Probe<Credential>> userProbes;
|
||||||
|
|
||||||
protected OB30Inspector(OB30Inspector.Builder builder) {
|
protected OB30Inspector(OB30Inspector.Builder builder) {
|
||||||
super(builder);
|
super(builder);
|
||||||
this.userProbes = ImmutableList.copyOf(builder.probes);
|
this.userProbes = ImmutableList.copyOf(builder.probes);
|
||||||
}
|
}
|
||||||
|
|
||||||
//https://docs.google.com/document/d/1_imUl2K-5tMib0AUxwA9CWb0Ap1b3qif0sXydih68J0/edit#
|
//https://docs.google.com/document/d/1_imUl2K-5tMib0AUxwA9CWb0Ap1b3qif0sXydih68J0/edit#
|
||||||
@ -70,7 +71,7 @@ public class OB30Inspector extends VCInspector {
|
|||||||
JsonSchemaCache.reset();
|
JsonSchemaCache.reset();
|
||||||
CachingDocumentLoader.reset();
|
CachingDocumentLoader.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
|
ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
|
||||||
JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
|
JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
|
||||||
|
|
||||||
@ -91,44 +92,43 @@ public class OB30Inspector extends VCInspector {
|
|||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||||
|
|
||||||
//we expect the above to place a generated object in the context
|
//we expect the above to place a generated object in the context
|
||||||
Credential crd = ctx.getGeneratedObject(Credential.ID);
|
Credential ob = ctx.getGeneratedObject(Credential.ID);
|
||||||
|
|
||||||
//context and type properties
|
//context and type properties
|
||||||
Credential.Type type = Type.OpenBadgeCredential;
|
Credential.Type type = Type.OpenBadgeCredential;
|
||||||
for(Probe<JsonNode> probe : List.of(new ContextPropertyProbe(type), new TypePropertyProbe(type))) {
|
for(Probe<JsonNode> probe : List.of(new ContextPropertyProbe(type), new TypePropertyProbe(type))) {
|
||||||
probeCount++;
|
probeCount++;
|
||||||
accumulator.add(probe.run(crd.getJson(), ctx));
|
accumulator.add(probe.run(ob.getJson(), ctx));
|
||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
//canonical schema and inline schemata
|
//canonical schema and inline schemata
|
||||||
SchemaKey schema = crd.getSchemaKey().orElseThrow();
|
SchemaKey schema = ob.getSchemaKey().orElseThrow();
|
||||||
for(Probe<JsonNode> probe : List.of(new JsonSchemaProbe(schema), new InlineJsonSchemaProbe(schema))) {
|
for(Probe<JsonNode> probe : List.of(new JsonSchemaProbe(schema), new InlineJsonSchemaProbe(schema))) {
|
||||||
probeCount++;
|
probeCount++;
|
||||||
accumulator.add(probe.run(crd.getJson(), ctx));
|
accumulator.add(probe.run(ob.getJson(), ctx));
|
||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
//credentialSubject
|
//credentialSubject
|
||||||
accumulator.add(new CredentialSubjectProbe().run(crd.getJson(), ctx));
|
accumulator.add(new CredentialSubjectProbe().run(ob.getJson(), ctx));
|
||||||
|
|
||||||
//signatures, proofs
|
//signatures, proofs
|
||||||
probeCount++;
|
probeCount++;
|
||||||
if(crd.getJwt().isPresent()){
|
if(ob.getProofType() == EXTERNAL){
|
||||||
//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(ob, 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.
|
||||||
accumulator.add(new ProofVerifierProbe().run(crd, ctx));
|
accumulator.add(new ProofVerifierProbe().run(ob, ctx));
|
||||||
}
|
}
|
||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||||
|
|
||||||
//check refresh service if we are not already refreshed
|
//check refresh service if we are not already refreshed
|
||||||
probeCount++;
|
probeCount++;
|
||||||
if(resource.getContext().get(REFRESHED) != TRUE) {
|
if(resource.getContext().get(REFRESHED) != TRUE) {
|
||||||
Optional<String> newID = checkRefreshService(crd, ctx);
|
Optional<String> newID = checkRefreshService(ob, ctx);
|
||||||
if(newID.isPresent()) {
|
if(newID.isPresent()) {
|
||||||
//TODO resource.type
|
|
||||||
return this.run(
|
return this.run(
|
||||||
new UriResource(new URI(newID.get()))
|
new UriResource(new URI(newID.get()))
|
||||||
.setContext(new ResourceContext(REFRESHED, TRUE)));
|
.setContext(new ResourceContext(REFRESHED, TRUE)));
|
||||||
@ -139,14 +139,14 @@ public class OB30Inspector extends VCInspector {
|
|||||||
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(ob, ctx));
|
||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
//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(ob.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);
|
||||||
@ -154,7 +154,7 @@ public class OB30Inspector extends VCInspector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//embedded jwt endorsements
|
//embedded jwt endorsements
|
||||||
endorsements = asNodeList(crd.getJson(), "$..endorsementJwt", jsonPath);
|
endorsements = asNodeList(ob.getJson(), "$..endorsementJwt", jsonPath);
|
||||||
for(JsonNode node : endorsements) {
|
for(JsonNode node : endorsements) {
|
||||||
probeCount++;
|
probeCount++;
|
||||||
String jwt = node.asText();
|
String jwt = node.asText();
|
||||||
@ -166,7 +166,7 @@ public class OB30Inspector extends VCInspector {
|
|||||||
//finally, run any user-added probes
|
//finally, run any user-added probes
|
||||||
for(Probe<Credential> probe : userProbes) {
|
for(Probe<Credential> probe : userProbes) {
|
||||||
probeCount++;
|
probeCount++;
|
||||||
accumulator.add(probe.run(crd, ctx));
|
accumulator.add(probe.run(ob, ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -175,29 +175,7 @@ public class OB30Inspector extends VCInspector {
|
|||||||
|
|
||||||
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If the AchievementCredential or EndorsementCredential has a “refreshService” property and the type of the
|
|
||||||
* RefreshService object is “1EdTechCredentialRefresh”, you should fetch the refreshed credential from the URL
|
|
||||||
* provided, then start the verification process over using the response as input. If the request fails,
|
|
||||||
* the credential is invalid.
|
|
||||||
*/
|
|
||||||
private Optional<String> checkRefreshService(Credential crd, RunContext ctx) {
|
|
||||||
JsonNode refreshServiceNode = crd.getJson().get("refreshService");
|
|
||||||
if(refreshServiceNode != null) {
|
|
||||||
JsonNode serviceTypeNode = refreshServiceNode.get("type");
|
|
||||||
if(serviceTypeNode != null && serviceTypeNode.asText().equals("1EdTechCredentialRefresh")) {
|
|
||||||
JsonNode serviceURINode = refreshServiceNode.get("id");
|
|
||||||
if(serviceURINode != null) {
|
|
||||||
return Optional.of(serviceURINode.asText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String REFRESHED = "is.refreshed.credential";
|
|
||||||
|
|
||||||
public static class Builder extends VCInspector.Builder<OB30Inspector.Builder> {
|
public static class Builder extends VCInspector.Builder<OB30Inspector.Builder> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,6 +2,7 @@ package org.oneedtech.inspect.vc;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.oneedtech.inspect.core.Inspector;
|
import org.oneedtech.inspect.core.Inspector;
|
||||||
import org.oneedtech.inspect.core.probe.Outcome;
|
import org.oneedtech.inspect.core.probe.Outcome;
|
||||||
@ -10,6 +11,8 @@ import org.oneedtech.inspect.core.probe.RunContext;
|
|||||||
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 com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base for verifiable credentials inspectors/verifiers.
|
* Abstract base for verifiable credentials inspectors/verifiers.
|
||||||
* @author mgylling
|
* @author mgylling
|
||||||
@ -25,12 +28,37 @@ public abstract class VCInspector extends Inspector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected boolean broken(List<ReportItems> accumulator) {
|
protected boolean broken(List<ReportItems> accumulator) {
|
||||||
|
if(getBehavior(Inspector.Behavior.VALIDATOR_FAIL_FAST) == Boolean.FALSE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
for(ReportItems items : accumulator) {
|
for(ReportItems items : accumulator) {
|
||||||
if(items.contains(Outcome.FATAL, Outcome.EXCEPTION, Outcome.NOT_RUN)) return true;
|
if(items.contains(Outcome.FATAL, Outcome.EXCEPTION, Outcome.NOT_RUN)) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the AchievementCredential or EndorsementCredential has a “refreshService” property and the type of the
|
||||||
|
* RefreshService object is “1EdTechCredentialRefresh”, you should fetch the refreshed credential from the URL
|
||||||
|
* provided, then start the verification process over using the response as input. If the request fails,
|
||||||
|
* the credential is invalid.
|
||||||
|
*/
|
||||||
|
protected Optional<String> checkRefreshService(Credential crd, RunContext ctx) {
|
||||||
|
JsonNode refreshServiceNode = crd.getJson().get("refreshService");
|
||||||
|
if(refreshServiceNode != null) {
|
||||||
|
JsonNode serviceTypeNode = refreshServiceNode.get("type");
|
||||||
|
if(serviceTypeNode != null && serviceTypeNode.asText().equals("1EdTechCredentialRefresh")) {
|
||||||
|
JsonNode serviceURINode = refreshServiceNode.get("id");
|
||||||
|
if(serviceURINode != null) {
|
||||||
|
return Optional.of(serviceURINode.asText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final String REFRESHED = "is.refreshed.credential";
|
||||||
|
|
||||||
public abstract static class Builder<B extends VCInspector.Builder<B>> extends Inspector.Builder<B> {
|
public abstract static class Builder<B extends VCInspector.Builder<B>> extends Inspector.Builder<B> {
|
||||||
final List<Probe<Credential>> probes;
|
final List<Probe<Credential>> probes;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ public class ContextPropertyProbe extends Probe<JsonNode> {
|
|||||||
|
|
||||||
ArrayNode contextNode = (ArrayNode) root.get("@context");
|
ArrayNode contextNode = (ArrayNode) root.get("@context");
|
||||||
if (contextNode == null) {
|
if (contextNode == null) {
|
||||||
return fatal("No @context property", ctx);
|
return notRun("No @context property", ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> expected = values.get(values.keySet()
|
List<String> expected = values.get(values.keySet()
|
||||||
@ -59,10 +59,14 @@ public class ContextPropertyProbe extends Probe<JsonNode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final static Map<Set<Credential.Type>, List<String>> values = new ImmutableMap.Builder<Set<Credential.Type>, List<String>>()
|
private final static Map<Set<Credential.Type>, List<String>> values = new ImmutableMap.Builder<Set<Credential.Type>, List<String>>()
|
||||||
|
// TODO uris will change
|
||||||
.put(Set.of(OpenBadgeCredential, AchievementCredential, EndorsementCredential),
|
.put(Set.of(OpenBadgeCredential, AchievementCredential, EndorsementCredential),
|
||||||
List.of("https://www.w3.org/2018/credentials/v1",
|
List.of("https://www.w3.org/2018/credentials/v1",
|
||||||
"https://imsglobal.github.io/openbadges-specification/context.json")) // TODO will change
|
"https://imsglobal.github.io/openbadges-specification/context.json"))
|
||||||
// (https://purl.imsglobal.org/spec/ob/v3p0/context/ob_v3p0.jsonld)
|
.put(Set.of(ClrCredential),
|
||||||
|
List.of("https://www.w3.org/2018/credentials/v1",
|
||||||
|
"https://dc.imsglobal.org/draft/clr/v2p0/context",
|
||||||
|
"https://imsglobal.github.io/openbadges-specification/context.json"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final String ID = ContextPropertyProbe.class.getSimpleName();
|
public static final String ID = ContextPropertyProbe.class.getSimpleName();
|
||||||
|
@ -26,7 +26,8 @@ public class OB30Tests {
|
|||||||
@BeforeAll
|
@BeforeAll
|
||||||
static void setup() {
|
static void setup() {
|
||||||
validator = new OB30Inspector.Builder()
|
validator = new OB30Inspector.Builder()
|
||||||
.set(Behavior.TEST_INCLUDE_SUCCESS, true)
|
.set(Behavior.TEST_INCLUDE_SUCCESS, true)
|
||||||
|
.set(Behavior.VALIDATOR_FAIL_FAST, true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user