Check required values for type attribute

added attributes for required type and achievement

return error instead of notRun
This commit is contained in:
Xavi Aracil
2023-01-05 10:48:15 +01:00
parent 677e547add
commit 1fe23b7278
11 changed files with 711 additions and 65 deletions
@@ -188,8 +188,8 @@ public class EndorsementInspector extends VCInspector implements SubInspector {
//credentialSubject
probeCount++;
accumulator.add(new CredentialSubjectProbe().run(endorsement.getJson(), ctx));
accumulator.add(new CredentialSubjectProbe("EndorsementSubject").run(endorsement.getJson(), ctx));
//signatures, proofs
probeCount++;
if(endorsement.getProofType() == EXTERNAL){
@@ -170,7 +170,7 @@ public class OB30Inspector extends VCInspector implements SubInspector {
//credentialSubject
probeCount++;
accumulator.add(new CredentialSubjectProbe().run(ob.getJson(), ctx));
accumulator.add(new CredentialSubjectProbe("AchievementSubject", true).run(ob.getJson(), ctx));
//signatures, proofs
probeCount++;
@@ -1,21 +1,36 @@
package org.oneedtech.inspect.vc.probe;
import java.util.List;
import org.oneedtech.inspect.core.probe.Probe;
import org.oneedtech.inspect.core.probe.RunContext;
import org.oneedtech.inspect.core.report.ReportItems;
import org.oneedtech.inspect.vc.util.JsonNodeUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
/**
* A Probe that checks credential subject specifics not capturable by schemata.
*
*
* @author mgylling
*/
public class CredentialSubjectProbe extends Probe<JsonNode> {
public CredentialSubjectProbe() {
/**
* Required type to be present.
*/
private final String requiredType;
private boolean achivementRequired;
public CredentialSubjectProbe(String requiredType) {
this(requiredType, false);
}
public CredentialSubjectProbe(String requiredType, boolean achivementRequired) {
super(ID);
this.requiredType = requiredType;
this.achivementRequired = achivementRequired;
}
@Override
@@ -24,18 +39,86 @@ public class CredentialSubjectProbe extends Probe<JsonNode> {
JsonNode subject = root.get("credentialSubject");
if(subject == null) return notRun("no credentialSubject node found", ctx); //error reported by schema
/*
* Check that we have either .id or .identifier populated
/**
* Check that type contains AchievementSubject
*/
if (!JsonNodeUtil.asStringList(subject.get("type")).contains(requiredType)) {
return error("credentialSubject is not of type \"" + requiredType + "\"", ctx);
}
/*
* Check that we have either .id or .identifier populated
*/
if (idAndIdentifierEmpty(subject)) {
return error("no id in credentialSubject", ctx);
}
/**
* if .identifier is provider, check its type
*/
if (subject.hasNonNull("identifier")) {
List<JsonNode> identifiers = JsonNodeUtil.asNodeList(subject.get("identifier"));
for (JsonNode identifier : identifiers) {
// check that type contains "IdentityObject"
if (!JsonNodeUtil.asStringList(identifier.get("type")).contains("IdentityObject")) {
return error("identifier in credentialSubject is not of type \"IdentityObject\"", ctx);
}
}
}
/*
* Check results
*/
if (subject.hasNonNull("result")) {
List<JsonNode> results = JsonNodeUtil.asNodeList(subject.get("result"));
for (JsonNode result : results) {
// check that type contains "Result"
if (!JsonNodeUtil.asStringList(result.get("type")).contains("Result")) {
return error("result in credentialSubject is not of type \"Result\"", ctx);
}
}
}
/*
* Check achievement result description
*/
if (subject.hasNonNull("achievement")) {
JsonNode achievement = subject.get("achievement");
if (achievement.hasNonNull("resultDescription")) {
List<JsonNode> resultDescriptions = JsonNodeUtil.asNodeList(achievement.get("resultDescription"));
for (JsonNode resultDescription : resultDescriptions) {
// check that type contains "ResultDescription"
if (!JsonNodeUtil.asStringList(resultDescription.get("type")).contains("ResultDescription")) {
return error("resultDescription in achievement of credentialSubject is not of type \"ResultDescription\"", ctx);
}
}
}
} else if (achivementRequired) {
return error("missing required achievement in credentialSubject", ctx);
}
/**
* Check that source type contains "Profile"
*/
if (subject.hasNonNull("source")) {
JsonNode source = subject.get("source");
// check that type contains "Profile"
if (!JsonNodeUtil.asStringList(source.get("type")).contains("Profile")) {
return error("source in credentialSubject is not of type \"Profile\"", ctx);
}
}
return success(ctx);
}
private boolean idAndIdentifierEmpty(JsonNode root) {
JsonNode id = root.get("id");
if (id != null && id.textValue().strip().length() > 0) return success(ctx);
JsonNode identifier = root.get("identifier");
if(identifier != null && identifier instanceof ArrayNode
&& ((ArrayNode)identifier).size() > 0) return success(ctx);
return error("no id in credentialSubject", ctx);
if (id != null && id.textValue().strip().length() > 0) return false;
JsonNode identifier = root.get("identifier");
if(identifier != null && identifier instanceof ArrayNode
&& ((ArrayNode)identifier).size() > 0) return false;
return true;
}
public static final String ID = CredentialSubjectProbe.class.getSimpleName();
@@ -0,0 +1,66 @@
package org.oneedtech.inspect.vc.probe;
import java.net.URI;
import java.util.List;
import org.oneedtech.inspect.core.probe.Probe;
import org.oneedtech.inspect.core.probe.RunContext;
import org.oneedtech.inspect.core.report.ReportItems;
import org.oneedtech.inspect.util.resource.UriResource;
import org.oneedtech.inspect.vc.util.JsonNodeUtil;
import com.fasterxml.jackson.databind.JsonNode;
public class IssuerProbe extends Probe<JsonNode> {
public IssuerProbe() {
super(ID);
}
@Override
public ReportItems run(JsonNode root, RunContext ctx) throws Exception {
JsonNode issuer = root.get("issuer");
if(issuer == null) return error("no issuer node found", ctx);
// check that type contains "Profile"
if (!JsonNodeUtil.asStringList(issuer.get("type")).contains("Profile")) {
return error("issuer is not of type \"Profile\"", ctx);
}
// check url is accessible
if (issuer.hasNonNull("url")) {
try {
UriResource urlResource = new UriResource(new URI(issuer.get("url").asText().strip()));
if (!urlResource.exists()) {
return warning("url \"" + issuer.get("url").asText().strip() + "\" in issuer is not accessible", ctx);
}
} catch (Exception e) {
return warning("url \"" + issuer.get("url").asText().strip() + "\" in issuer is not accessible", ctx);
}
}
// check other identifier
if (issuer.hasNonNull("otherIdentifier")) {
List<JsonNode> otherIdentifiers = JsonNodeUtil.asNodeList(issuer.get("otherIdentifier"));
for (JsonNode otherIdentifier : otherIdentifiers) {
// check that type contains "IdentityObject"
if (!JsonNodeUtil.asStringList(otherIdentifier.get("type")).contains("IdentityObject")) {
return error("otherIdentifier in issuer is not of type \"IdentityObject\"", ctx);
}
}
}
// check parent issuer
if (issuer.hasNonNull("parentOrg")) {
JsonNode parentOrg = issuer.get("parentOrg");
// check that type contains "Profile"
if (!JsonNodeUtil.asStringList(parentOrg.get("type")).contains("Profile")) {
return error("parentOrg in issuer is not of type \"Profile\"", ctx);
}
}
return success(ctx);
}
public static final String ID = IssuerProbe.class.getSimpleName();
}