Added endorsement inspector for OB 2.0
This commit is contained in:
parent
55ef973efe
commit
cb60fd11ed
@ -0,0 +1,138 @@
|
|||||||
|
package org.oneedtech.inspect.vc;
|
||||||
|
|
||||||
|
import static org.oneedtech.inspect.core.probe.RunContext.Key.GENERATED_OBJECT_BUILDER;
|
||||||
|
import static org.oneedtech.inspect.core.probe.RunContext.Key.JACKSON_OBJECTMAPPER;
|
||||||
|
import static org.oneedtech.inspect.core.probe.RunContext.Key.JSONPATH_EVALUATOR;
|
||||||
|
import static org.oneedtech.inspect.core.probe.RunContext.Key.JSON_DOCUMENT_LOADER;
|
||||||
|
import static org.oneedtech.inspect.core.probe.RunContext.Key.JWT_CREDENTIAL_NODE_NAME;
|
||||||
|
import static org.oneedtech.inspect.core.probe.RunContext.Key.PNG_CREDENTIAL_KEY;
|
||||||
|
import static org.oneedtech.inspect.core.probe.RunContext.Key.SVG_CREDENTIAL_QNAME;
|
||||||
|
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 static org.oneedtech.inspect.vc.Credential.CREDENTIAL_KEY;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
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.report.Report;
|
||||||
|
import org.oneedtech.inspect.core.report.ReportItems;
|
||||||
|
import org.oneedtech.inspect.util.json.ObjectMapperCache;
|
||||||
|
import org.oneedtech.inspect.util.resource.Resource;
|
||||||
|
import org.oneedtech.inspect.vc.Assertion.Type;
|
||||||
|
import org.oneedtech.inspect.vc.jsonld.JsonLdGeneratedObject;
|
||||||
|
import org.oneedtech.inspect.vc.payload.PngParser;
|
||||||
|
import org.oneedtech.inspect.vc.payload.SvgParser;
|
||||||
|
import org.oneedtech.inspect.vc.probe.AssertionRevocationListProbe;
|
||||||
|
import org.oneedtech.inspect.vc.probe.ExpirationProbe;
|
||||||
|
import org.oneedtech.inspect.vc.probe.IssuanceProbe;
|
||||||
|
import org.oneedtech.inspect.vc.probe.VerificationDependenciesProbe;
|
||||||
|
|
||||||
|
import com.apicatalog.jsonld.loader.DocumentLoader;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An inspector for EndorsementCredential objects.
|
||||||
|
* @author mgylling
|
||||||
|
*/
|
||||||
|
public class OB20EndorsementInspector extends VCInspector implements SubInspector {
|
||||||
|
|
||||||
|
private DocumentLoader documentLoader;
|
||||||
|
|
||||||
|
protected OB20EndorsementInspector(OB20EndorsementInspector.Builder builder) {
|
||||||
|
super(builder);
|
||||||
|
this.documentLoader = builder.documentLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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.
|
||||||
|
*
|
||||||
|
* The parent inspector is responsible to decode away possible jwt-ness, so that
|
||||||
|
* what we get here is a verbatim json node.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Assertion endorsement = (Assertion) checkNotNull(parentObjects.get(CREDENTIAL_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(GENERATED_OBJECT_BUILDER, new Assertion.Builder())
|
||||||
|
.put(PNG_CREDENTIAL_KEY, PngParser.Keys.OB20)
|
||||||
|
.put(SVG_CREDENTIAL_QNAME, SvgParser.QNames.OB20)
|
||||||
|
.put(JSON_DOCUMENT_LOADER, documentLoader)
|
||||||
|
.put(JWT_CREDENTIAL_NODE_NAME, Assertion.JWT_NODE_NAME)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
parentObjects.entrySet().stream().forEach(entry -> {
|
||||||
|
if (!entry.getKey().equals(CREDENTIAL_KEY)) {
|
||||||
|
ctx.addGeneratedObject(entry.getValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
List<ReportItems> accumulator = new ArrayList<>();
|
||||||
|
int probeCount = 0;
|
||||||
|
try {
|
||||||
|
|
||||||
|
JsonNode endorsementNode = endorsement.getJson();
|
||||||
|
// verification and revocation
|
||||||
|
if (endorsement.getCredentialType() == Type.Endorsement) {
|
||||||
|
for(Probe<JsonLdGeneratedObject> probe : List.of(new VerificationDependenciesProbe(endorsementNode.get("id").asText(), "claim"),
|
||||||
|
new AssertionRevocationListProbe(endorsementNode.get("id").asText(), "claim"))) {
|
||||||
|
probeCount++;
|
||||||
|
accumulator.add(probe.run(new JsonLdGeneratedObject(endorsementNode.toString()), ctx));
|
||||||
|
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// expiration and issuance
|
||||||
|
for(Probe<Credential> probe : List.of(
|
||||||
|
new ExpirationProbe(), new IssuanceProbe())) {
|
||||||
|
probeCount++;
|
||||||
|
accumulator.add(probe.run(endorsement, 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<OB20EndorsementInspector.Builder> {
|
||||||
|
private DocumentLoader documentLoader;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public OB20EndorsementInspector build() {
|
||||||
|
return new OB20EndorsementInspector(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder documentLoader(DocumentLoader documentLoader) {
|
||||||
|
this.documentLoader = documentLoader;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,12 +4,20 @@ 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.CREDENTIAL_KEY;
|
||||||
|
import static org.oneedtech.inspect.vc.util.JsonNodeUtil.asNodeList;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
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.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.RunContext.Key;
|
import org.oneedtech.inspect.core.probe.RunContext.Key;
|
||||||
@ -20,6 +28,7 @@ import org.oneedtech.inspect.schema.JsonSchemaCache;
|
|||||||
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.ResourceType;
|
import org.oneedtech.inspect.util.resource.ResourceType;
|
||||||
|
import org.oneedtech.inspect.util.resource.UriResource;
|
||||||
import org.oneedtech.inspect.util.spec.Specification;
|
import org.oneedtech.inspect.util.spec.Specification;
|
||||||
import org.oneedtech.inspect.vc.Assertion.Type;
|
import org.oneedtech.inspect.vc.Assertion.Type;
|
||||||
import org.oneedtech.inspect.vc.Credential.CredentialEnum;
|
import org.oneedtech.inspect.vc.Credential.CredentialEnum;
|
||||||
@ -41,38 +50,25 @@ import org.oneedtech.inspect.vc.probe.validation.ValidationPropertyProbeFactory;
|
|||||||
import org.oneedtech.inspect.vc.util.CachingDocumentLoader;
|
import org.oneedtech.inspect.vc.util.CachingDocumentLoader;
|
||||||
|
|
||||||
import com.apicatalog.jsonld.loader.DocumentLoader;
|
import com.apicatalog.jsonld.loader.DocumentLoader;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import foundation.identity.jsonld.ConfigurableDocumentLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A verifier for Open Badges 2.0.
|
* A verifier for Open Badges 2.0.
|
||||||
* @author xaracil
|
* @author xaracil
|
||||||
*/
|
*/
|
||||||
public class OB20Inspector extends Inspector {
|
public class OB20Inspector extends VCInspector {
|
||||||
|
|
||||||
protected OB20Inspector(OB20Inspector.Builder builder) {
|
protected <B extends VCInspector.Builder<?>> OB20Inspector(B builder) {
|
||||||
super(builder);
|
super(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Report abort(RunContext ctx, List<ReportItems> accumulator, int probeCount) {
|
/* (non-Javadoc)
|
||||||
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
* @see org.oneedtech.inspect.core.Inspector#run(org.oneedtech.inspect.util.resource.Resource)
|
||||||
}
|
*/
|
||||||
|
|
||||||
protected boolean broken(List<ReportItems> accumulator) {
|
|
||||||
return broken(accumulator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean broken(List<ReportItems> accumulator, boolean force) {
|
|
||||||
if(!force && getBehavior(Inspector.Behavior.VALIDATOR_FAIL_FAST) == Boolean.FALSE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for(ReportItems items : accumulator) {
|
|
||||||
if(items.contains(Outcome.FATAL, Outcome.EXCEPTION)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Report run(Resource resource) {
|
public Report run(Resource resource) {
|
||||||
super.check(resource);
|
super.check(resource);
|
||||||
@ -143,14 +139,6 @@ public class OB20Inspector extends Inspector {
|
|||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// expiration and issuance
|
|
||||||
for(Probe<Credential> probe : List.of(
|
|
||||||
new ExpirationProbe(), new IssuanceProbe())) {
|
|
||||||
probeCount++;
|
|
||||||
accumulator.add(probe.run(assertion, ctx));
|
|
||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// verification and revocation
|
// verification and revocation
|
||||||
if (assertion.getCredentialType() == Type.Assertion) {
|
if (assertion.getCredentialType() == Type.Assertion) {
|
||||||
for(Probe<JsonLdGeneratedObject> probe : List.of(new VerificationDependenciesProbe(assertionNode.get("id").asText()),
|
for(Probe<JsonLdGeneratedObject> probe : List.of(new VerificationDependenciesProbe(assertionNode.get("id").asText()),
|
||||||
@ -168,6 +156,47 @@ public class OB20Inspector extends Inspector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// expiration and issuance
|
||||||
|
for(Probe<Credential> probe : List.of(
|
||||||
|
new ExpirationProbe(), new IssuanceProbe())) {
|
||||||
|
probeCount++;
|
||||||
|
accumulator.add(probe.run(assertion, ctx));
|
||||||
|
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Embedded endorsements. Pass document loader because it has already cached documents, and it has localdomains for testing
|
||||||
|
OB20EndorsementInspector endorsementInspector = new OB20EndorsementInspector.Builder().documentLoader(documentLoader).build();
|
||||||
|
|
||||||
|
// get endorsements for all JSON_LD objects in the graph
|
||||||
|
List<JsonNode> endorsements = ctx.getGeneratedObjects().values().stream()
|
||||||
|
.filter(generatedObject -> generatedObject instanceof JsonLdGeneratedObject)
|
||||||
|
.flatMap(obj -> {
|
||||||
|
JsonNode node;
|
||||||
|
try {
|
||||||
|
node = mapper.readTree(((JsonLdGeneratedObject) obj).getJson());
|
||||||
|
// return endorsement node, filtering out the on inside @context
|
||||||
|
return asNodeList(node, "$..endorsement", jsonPath).stream().filter(endorsementNode -> !endorsementNode.isObject());
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new IllegalArgumentException("Couldn't not parse " + obj.getId() + ": contains invalid JSON");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
for(JsonNode node : endorsements) {
|
||||||
|
probeCount++;
|
||||||
|
// get endorsement json from context
|
||||||
|
UriResource uriResource = resolveUriResource(ctx, node.asText());
|
||||||
|
JsonLdGeneratedObject resolved = (JsonLdGeneratedObject) ctx.getGeneratedObject(JsonLDCompactionProve.getId(uriResource));
|
||||||
|
if (resolved == null) {
|
||||||
|
throw new IllegalArgumentException("endorsement " + node.toString() + " not found in graph");
|
||||||
|
}
|
||||||
|
|
||||||
|
Assertion endorsement = new Assertion.Builder().resource(resource).jsonData(mapper.readTree(resolved.getJson())).build();
|
||||||
|
// pass graph to subinspector
|
||||||
|
Map<String, GeneratedObject> parentObjects = new HashMap<>(ctx.getGeneratedObjects());
|
||||||
|
parentObjects.put(CREDENTIAL_KEY, endorsement);
|
||||||
|
accumulator.add(endorsementInspector.run(resource, parentObjects));
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
accumulator.add(onProbeException(Probe.ID.NO_UNCAUGHT_EXCEPTIONS, resource, e));
|
accumulator.add(onProbeException(Probe.ID.NO_UNCAUGHT_EXCEPTIONS, resource, e));
|
||||||
@ -176,11 +205,7 @@ public class OB20Inspector extends Inspector {
|
|||||||
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
return new Report(ctx, new ReportItems(accumulator), probeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DocumentLoader getDocumentLoader() {
|
public static class Builder extends VCInspector.Builder<OB20Inspector.Builder> {
|
||||||
return new CachingDocumentLoader();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Builder extends Inspector.Builder<OB20Inspector.Builder> {
|
|
||||||
|
|
||||||
public Builder() {
|
public Builder() {
|
||||||
super();
|
super();
|
||||||
@ -204,4 +229,19 @@ public class OB20Inspector extends Inspector {
|
|||||||
public static final String ALLOW_LOCAL_REDIRECTION = "ALLOW_LOCAL_REDIRECTION";
|
public static final String ALLOW_LOCAL_REDIRECTION = "ALLOW_LOCAL_REDIRECTION";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected UriResource resolveUriResource(RunContext ctx, String url) throws URISyntaxException {
|
||||||
|
URI uri = new URI(url);
|
||||||
|
UriResource initialUriResource = new UriResource(uri);
|
||||||
|
UriResource uriResource = initialUriResource;
|
||||||
|
|
||||||
|
// check if uri points to a local resource
|
||||||
|
if (ctx.get(Key.JSON_DOCUMENT_LOADER) instanceof ConfigurableDocumentLoader) {
|
||||||
|
if (ConfigurableDocumentLoader.getDefaultHttpLoader() instanceof CachingDocumentLoader.HttpLoader) {
|
||||||
|
URI resolvedUri = ((CachingDocumentLoader.HttpLoader) ConfigurableDocumentLoader.getDefaultHttpLoader()).resolve(uri);
|
||||||
|
uriResource = new UriResource(resolvedUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uriResource;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,9 @@ 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.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.vc.util.CachingDocumentLoader;
|
||||||
|
|
||||||
|
import com.apicatalog.jsonld.loader.DocumentLoader;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,6 +63,14 @@ public abstract class VCInspector extends Inspector {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a caching document loader for loading json resources
|
||||||
|
* @return document loader for loading json resources
|
||||||
|
*/
|
||||||
|
protected DocumentLoader getDocumentLoader() {
|
||||||
|
return new CachingDocumentLoader();
|
||||||
|
}
|
||||||
|
|
||||||
protected static final String REFRESHED = "is.refreshed.credential";
|
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> {
|
||||||
|
@ -25,10 +25,16 @@ import foundation.identity.jsonld.ConfigurableDocumentLoader;
|
|||||||
|
|
||||||
public class AssertionRevocationListProbe extends Probe<JsonLdGeneratedObject> {
|
public class AssertionRevocationListProbe extends Probe<JsonLdGeneratedObject> {
|
||||||
private final String assertionId;
|
private final String assertionId;
|
||||||
|
private final String propertyName;
|
||||||
|
|
||||||
public AssertionRevocationListProbe(String assertionId) {
|
public AssertionRevocationListProbe(String assertionId) {
|
||||||
|
this(assertionId, "badge");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssertionRevocationListProbe(String assertionId, String propertyName) {
|
||||||
super(ID);
|
super(ID);
|
||||||
this.assertionId = assertionId;
|
this.assertionId = assertionId;
|
||||||
|
this.propertyName = propertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -37,7 +43,7 @@ public class AssertionRevocationListProbe extends Probe<JsonLdGeneratedObject> {
|
|||||||
JsonNode jsonNode = (mapper).readTree(jsonLdGeneratedObject.getJson());
|
JsonNode jsonNode = (mapper).readTree(jsonLdGeneratedObject.getJson());
|
||||||
|
|
||||||
// get badge
|
// get badge
|
||||||
UriResource badgeUriResource = resolveUriResource(ctx, jsonNode.get("badge").asText().strip());
|
UriResource badgeUriResource = resolveUriResource(ctx, getBadgeClaimId(jsonNode));
|
||||||
JsonLdGeneratedObject badgeObject = (JsonLdGeneratedObject) ctx.getGeneratedObject(
|
JsonLdGeneratedObject badgeObject = (JsonLdGeneratedObject) ctx.getGeneratedObject(
|
||||||
JsonLDCompactionProve.getId(badgeUriResource));
|
JsonLDCompactionProve.getId(badgeUriResource));
|
||||||
|
|
||||||
@ -97,5 +103,18 @@ public class AssertionRevocationListProbe extends Probe<JsonLdGeneratedObject> {
|
|||||||
return uriResource;
|
return uriResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the ID of the node with name propertyName
|
||||||
|
* @param jsonNode node
|
||||||
|
* @return ID of the node. If node is textual, the text is returned. If node is an object, its "ID" attribute is returned
|
||||||
|
*/
|
||||||
|
protected String getBadgeClaimId(JsonNode jsonNode) {
|
||||||
|
JsonNode propertyNode = jsonNode.get(propertyName);
|
||||||
|
if (propertyNode.isTextual()) {
|
||||||
|
return propertyNode.asText().strip();
|
||||||
|
}
|
||||||
|
return propertyNode.get("id").asText().strip();
|
||||||
|
}
|
||||||
|
|
||||||
public static final String ID = AssertionRevocationListProbe.class.getSimpleName();
|
public static final String ID = AssertionRevocationListProbe.class.getSimpleName();
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,19 @@ import foundation.identity.jsonld.ConfigurableDocumentLoader;
|
|||||||
*/
|
*/
|
||||||
public class VerificationDependenciesProbe extends Probe<JsonLdGeneratedObject> {
|
public class VerificationDependenciesProbe extends Probe<JsonLdGeneratedObject> {
|
||||||
private final String assertionId;
|
private final String assertionId;
|
||||||
|
private final String propertyName;
|
||||||
|
|
||||||
public VerificationDependenciesProbe(String assertionId) {
|
public VerificationDependenciesProbe(String assertionId) {
|
||||||
|
this(assertionId, "badge");
|
||||||
|
}
|
||||||
|
|
||||||
|
public VerificationDependenciesProbe(String assertionId, String propertyName) {
|
||||||
super(ID);
|
super(ID);
|
||||||
this.assertionId = assertionId;
|
this.assertionId = assertionId;
|
||||||
|
this.propertyName = propertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReportItems run(JsonLdGeneratedObject jsonLdGeneratedObject, RunContext ctx) throws Exception {
|
public ReportItems run(JsonLdGeneratedObject jsonLdGeneratedObject, RunContext ctx) throws Exception {
|
||||||
ObjectMapper mapper = (ObjectMapper) ctx.get(Key.JACKSON_OBJECTMAPPER);
|
ObjectMapper mapper = (ObjectMapper) ctx.get(Key.JACKSON_OBJECTMAPPER);
|
||||||
@ -56,7 +63,7 @@ public class VerificationDependenciesProbe extends Probe<JsonLdGeneratedObject>
|
|||||||
|
|
||||||
if ("HostedBadge".equals(type)) {
|
if ("HostedBadge".equals(type)) {
|
||||||
// get badge
|
// get badge
|
||||||
UriResource badgeUriResource = resolveUriResource(ctx, jsonNode.get("badge").asText().strip());
|
UriResource badgeUriResource = resolveUriResource(ctx, getBadgeClaimId(jsonNode));
|
||||||
JsonLdGeneratedObject badgeObject = (JsonLdGeneratedObject) ctx.getGeneratedObject(
|
JsonLdGeneratedObject badgeObject = (JsonLdGeneratedObject) ctx.getGeneratedObject(
|
||||||
JsonLDCompactionProve.getId(badgeUriResource));
|
JsonLDCompactionProve.getId(badgeUriResource));
|
||||||
JsonNode badgeNode = ((ObjectMapper) ctx.get(Key.JACKSON_OBJECTMAPPER))
|
JsonNode badgeNode = ((ObjectMapper) ctx.get(Key.JACKSON_OBJECTMAPPER))
|
||||||
@ -104,7 +111,7 @@ public class VerificationDependenciesProbe extends Probe<JsonLdGeneratedObject>
|
|||||||
allowedOrigins = List.of(defaultAllowedOrigins);
|
allowedOrigins = List.of(defaultAllowedOrigins);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JsonNodeUtil.asStringList(allowedOriginsNode);
|
allowedOrigins = JsonNodeUtil.asStringList(allowedOriginsNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowedOrigins == null || allowedOrigins.isEmpty() || !issuerId.startsWith("http")) {
|
if (allowedOrigins == null || allowedOrigins.isEmpty() || !issuerId.startsWith("http")) {
|
||||||
@ -147,6 +154,20 @@ public class VerificationDependenciesProbe extends Probe<JsonLdGeneratedObject>
|
|||||||
return uriResource;
|
return uriResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the ID of the node with name propertyName
|
||||||
|
* @param jsonNode node
|
||||||
|
* @return ID of the node. If node is textual, the text is returned. If node is an object, its "ID" attribute is returned
|
||||||
|
*/
|
||||||
|
protected String getBadgeClaimId(JsonNode jsonNode) {
|
||||||
|
JsonNode propertyNode = jsonNode.get(propertyName);
|
||||||
|
if (propertyNode.isTextual()) {
|
||||||
|
return propertyNode.asText().strip();
|
||||||
|
}
|
||||||
|
return propertyNode.get("id").asText().strip();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final String ID = VerificationDependenciesProbe.class.getSimpleName();
|
public static final String ID = VerificationDependenciesProbe.class.getSimpleName();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,16 @@
|
|||||||
"image": "https://example.org/beths-robot-badge.png",
|
"image": "https://example.org/beths-robot-badge.png",
|
||||||
"evidence": "https://example.org/beths-robot-work.html",
|
"evidence": "https://example.org/beths-robot-work.html",
|
||||||
"issuedOn": "2016-12-31T23:59:59Z",
|
"issuedOn": "2016-12-31T23:59:59Z",
|
||||||
"badge": "https://example.org/robotics-badge.json",
|
"badge": {
|
||||||
|
"type": "BadgeClass",
|
||||||
|
"id": "https://example.org/badgeclass-with-endorsements.json",
|
||||||
|
"name": "Awesome Robotics Badge",
|
||||||
|
"description": "For doing awesome things with robots that people think is pretty great.",
|
||||||
|
"image": "https://example.org/robotics-badge.png",
|
||||||
|
"criteria": "https://example.org/badgecriteria.json",
|
||||||
|
"issuer": "https://example.org/organization.json",
|
||||||
|
"endorsement": ["https://example.org/endorsement-3.json", "https://example.org/endorsement-4.json"]
|
||||||
|
},
|
||||||
"verification": {
|
"verification": {
|
||||||
"type": "hosted"
|
"type": "hosted"
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://w3id.org/openbadges/v2",
|
||||||
|
"type": "BadgeClass",
|
||||||
|
"id": "https://example.org/badgeclass-with-endorsements.json",
|
||||||
|
"name": "Awesome Robotics Badge",
|
||||||
|
"description": "For doing awesome things with robots that people think is pretty great.",
|
||||||
|
"image": "https://example.org/robotics-badge.png",
|
||||||
|
"criteria": "https://example.org/badgecriteria.json",
|
||||||
|
"issuer": "https://example.org/organization.json",
|
||||||
|
"endorsement": ["https://example.org/endorsement-3.json", "https://example.org/endorsement-4.json"]
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
"id": "http://example.org/endorsement-1.json",
|
"id": "http://example.org/endorsement-1.json",
|
||||||
"type": "Endorsement",
|
"type": "Endorsement",
|
||||||
"claim": {
|
"claim": {
|
||||||
"id": "https://example.org/robotics-badge.json",
|
"id": "https://example.org/badgeclass-with-endorsements.json",
|
||||||
"endorsementComment": "Pretty good"
|
"endorsementComment": "Pretty good"
|
||||||
},
|
},
|
||||||
"issuedOn": "2017-10-01T00:00Z",
|
"issuedOn": "2017-10-01T00:00Z",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"id": "http://example.org/endorsement-2.json",
|
"id": "http://example.org/endorsement-2.json",
|
||||||
"type": "Endorsement",
|
"type": "Endorsement",
|
||||||
"claim": {
|
"claim": {
|
||||||
"id": "https://example.org/robotics-badge.json",
|
"id": "https://example.org/badgeclass-with-endorsements.json",
|
||||||
"endorsementComment": "Pretty good"
|
"endorsementComment": "Pretty good"
|
||||||
},
|
},
|
||||||
"issuedOn": "2017-10-01T00:00Z",
|
"issuedOn": "2017-10-01T00:00Z",
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://w3id.org/openbadges/v2",
|
||||||
|
"id": "http://example.org/endorsement-3.json",
|
||||||
|
"type": "Endorsement",
|
||||||
|
"claim": {
|
||||||
|
"id": "https://example.org/badgeclass-with-endorsements.json",
|
||||||
|
"endorsementComment": "Pretty good"
|
||||||
|
},
|
||||||
|
"issuedOn": "2017-10-01T00:00Z",
|
||||||
|
"issuer": "http://example.org/issuer1.json",
|
||||||
|
"verification": {
|
||||||
|
"type": "HostedBadge"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://w3id.org/openbadges/v2",
|
||||||
|
"id": "http://example.org/endorsement-4.json",
|
||||||
|
"type": "Endorsement",
|
||||||
|
"claim": {
|
||||||
|
"id": "https://example.org/badgeclass-with-endorsements.json",
|
||||||
|
"endorsementComment": "Pretty good"
|
||||||
|
},
|
||||||
|
"issuedOn": "2017-10-01T00:00Z",
|
||||||
|
"issuer": "http://example.org/issuer1.json",
|
||||||
|
"verification": {
|
||||||
|
"type": "HostedBadge"
|
||||||
|
}
|
||||||
|
}
|
@ -204,6 +204,6 @@
|
|||||||
"email": "me@example.org",
|
"email": "me@example.org",
|
||||||
"url": "http://example.org",
|
"url": "http://example.org",
|
||||||
"verification": {
|
"verification": {
|
||||||
"allowedOrigins": ["example.com"]
|
"allowedOrigins": ["example.com", "example.org"]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -198,7 +198,7 @@
|
|||||||
},
|
},
|
||||||
"verify": "verification"
|
"verify": "verification"
|
||||||
},
|
},
|
||||||
"id": "http://example.org/issuer1",
|
"id": "http://example.org/issuer1.json",
|
||||||
"type": "Issuer",
|
"type": "Issuer",
|
||||||
"name": "Example Issuer",
|
"name": "Example Issuer",
|
||||||
"email": "me@example.org",
|
"email": "me@example.org",
|
||||||
|
Loading…
Reference in New Issue
Block a user