add iron for vc verification, refactor+cleanup

This commit is contained in:
Markus Gylling
2022-07-08 11:33:45 +02:00
parent 092d4eb8f1
commit 9d3110547e
26 changed files with 923 additions and 660 deletions
@@ -1,6 +1,6 @@
package org.oneedtech.inspect.vc;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.*;
import static org.oneedtech.inspect.test.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
@@ -9,12 +9,17 @@ import org.junit.jupiter.api.Test;
import org.oneedtech.inspect.core.Inspector.Behavior;
import org.oneedtech.inspect.core.report.Report;
import org.oneedtech.inspect.test.PrintHelper;
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.ProofVerifierProbe;
import org.oneedtech.inspect.vc.probe.TypePropertyProbe;
import com.google.common.collect.Iterables;
public class OB30Tests {
private static OB30Inspector validator;
private static boolean verbose = true;
private static boolean verbose = false;
@BeforeAll
static void setup() {
@@ -32,6 +37,7 @@ public class OB30Tests {
});
}
@Disabled //TODO @Miles -- this needs update?
@Test
void testSimplePNGPlainValid() {
assertDoesNotThrow(()->{
@@ -50,6 +56,7 @@ public class OB30Tests {
});
}
@Disabled //TODO @Miles -- this needs update?
@Test
void testSimpleJsonSVGPlainValid() {
assertDoesNotThrow(()->{
@@ -58,8 +65,7 @@ public class OB30Tests {
assertValid(report);
});
}
@Disabled
@Test
void testSimpleJsonSVGJWTValid() {
assertDoesNotThrow(()->{
@@ -71,20 +77,60 @@ public class OB30Tests {
@Test
void testSimpleJsonInvalidUnknownType() {
//add a dumb value to .type and remove the ob type
assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_UNKNOWN_TYPE.asFileResource());
if(verbose) PrintHelper.print(report, true);
assertInvalid(report);
assertFatalCount(report, 1);
assertHasProbeID(report, TypePropertyProbe.ID, true);
});
}
@Test
void testCompleteJsonInvalidInlineSchemaRef() throws Exception {
void testSimpleJsonInvalidProof() {
//add some garbage chars to proofValue
assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.COMPLETE_JSON.asFileResource());
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_PROOF_ERROR.asFileResource());
if(verbose) PrintHelper.print(report, true);
assertInvalid(report);
assertErrorCount(report, 1);
assertHasProbeID(report, ProofVerifierProbe.ID, true);
});
}
@Test
void testSimpleJsonExpired() {
//"expirationDate": "2020-01-20T00:00:00Z",
assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_EXPIRED.asFileResource());
if(verbose) PrintHelper.print(report, true);
assertInvalid(report);
assertHasProbeID(report, ExpirationVerifierProbe.ID, true);
});
}
@Test
void testSimpleJsonNotIssued() {
//"issuanceDate": "2040-01-01T00:00:00Z",
//this breaks the proof too
assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_ISSUED.asFileResource());
if(verbose) PrintHelper.print(report, true);
assertInvalid(report);
assertHasProbeID(report, IssuanceVerifierProbe.ID, true);
});
}
@Test
void testCompleteJsonInvalidInlineSchemaRef() throws Exception {
//404 inline schema ref, and 404 refresh uri
assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.COMPLETE_JSON.asFileResource());
if(verbose) PrintHelper.print(report, true);
assertFalse(report.asBoolean());
assertTrue(Iterables.size(report.getErrors()) > 0);
assertTrue(Iterables.size(report.getExceptions()) > 0);
assertHasProbeID(report, InlineJsonSchemaProbe.ID, true);
});
}
@@ -13,6 +13,9 @@ public class Samples {
public final static Sample COMPLETE_JSON = new Sample("ob30/complete.json", false);
public final static Sample SIMPLE_JSON = new Sample("ob30/simple.json", true);
public final static Sample SIMPLE_JSON_UNKNOWN_TYPE = new Sample("ob30/simple-unknown-type.json", false);
public final static Sample SIMPLE_JSON_PROOF_ERROR = new Sample("ob30/simple-proof-error.json", false);
public final static Sample SIMPLE_JSON_EXPIRED = new Sample("ob30/simple-expired.json", false);
public final static Sample SIMPLE_JSON_ISSUED = new Sample("ob30/simple-issued.json", false);
}
public static final class PNG {
public final static Sample SIMPLE_JWT_PNG = new Sample("ob30/simple-jwt.png", true);
@@ -0,0 +1,119 @@
package org.oneedtech.inspect.vc.credential;
import static org.junit.jupiter.api.Assertions.*;
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.oneedtech.inspect.core.probe.RunContext;
import org.oneedtech.inspect.core.probe.RunContext.Key;
import org.oneedtech.inspect.core.probe.json.JsonPathEvaluator;
import org.oneedtech.inspect.util.json.ObjectMapperCache;
import org.oneedtech.inspect.util.resource.Resource;
import org.oneedtech.inspect.util.resource.ResourceType;
import org.oneedtech.inspect.vc.Credential;
import org.oneedtech.inspect.vc.OB30Inspector;
import org.oneedtech.inspect.vc.Samples;
import org.oneedtech.inspect.vc.payload.PayloadParser;
import org.oneedtech.inspect.vc.payload.PayloadParserFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
public class PayloadParserTests {
@Test
void testSvgStringExtract() {
assertDoesNotThrow(()->{
Resource res = Samples.OB30.SVG.SIMPLE_JSON_SVG.asFileResource(ResourceType.SVG);
PayloadParser ext = PayloadParserFactory.of(res);
assertNotNull(ext);
Credential crd = ext.parse(res, mockOB30Context(res));
//System.out.println(crd.getJson().toPrettyString());
assertNotNull(crd);
assertNotNull(crd.getJson());
assertNotNull(crd.getJson().get("@context"));
});
}
@Test
void testSvgJwtExtract() {
assertDoesNotThrow(()->{
Resource res = Samples.OB30.SVG.SIMPLE_JWT_SVG.asFileResource(ResourceType.SVG);
PayloadParser ext = PayloadParserFactory.of(res);
assertNotNull(ext);
Credential crd = ext.parse(res, mockOB30Context(res));
//System.out.println(crd.getJson().toPrettyString());
assertNotNull(crd);
assertNotNull(crd.getJson());
assertNotNull(crd.getJson().get("@context"));
});
}
@Test
void testPngStringExtract() {
assertDoesNotThrow(()->{
Resource res = Samples.OB30.PNG.SIMPLE_JSON_PNG.asFileResource(ResourceType.PNG);
PayloadParser ext = PayloadParserFactory.of(res);
assertNotNull(ext);
Credential crd = ext.parse(res, mockOB30Context(res));
//System.out.println(crd.getJson().toPrettyString());
assertNotNull(crd);
assertNotNull(crd.getJson());
assertNotNull(crd.getJson().get("@context"));
});
}
@Test
void testPngJwtExtract() {
assertDoesNotThrow(()->{
Resource res = Samples.OB30.PNG.SIMPLE_JWT_PNG.asFileResource(ResourceType.PNG);
PayloadParser ext = PayloadParserFactory.of(res);
assertNotNull(ext);
Credential crd = ext.parse(res, mockOB30Context(res));
//System.out.println(crd.getJson().toPrettyString());
assertNotNull(crd);
assertNotNull(crd.getJson());
assertNotNull(crd.getJson().get("@context"));
});
}
@Test
void testJwtExtract() {
assertDoesNotThrow(()->{
Resource res = Samples.OB30.JWT.SIMPLE_JWT.asFileResource(ResourceType.JWT);
PayloadParser ext = PayloadParserFactory.of(res);
assertNotNull(ext);
Credential crd = ext.parse(res, mockOB30Context(res));
//System.out.println(crd.getJson().toPrettyString());
assertNotNull(crd);
assertNotNull(crd.getJson());
assertNotNull(crd.getJson().get("@context"));
});
}
@Test
void testJsonExtract() {
assertDoesNotThrow(()->{
Resource res = Samples.OB30.JSON.SIMPLE_JSON.asFileResource(ResourceType.JSON);
PayloadParser ext = PayloadParserFactory.of(res);
assertNotNull(ext);
Credential crd = ext.parse(res, mockOB30Context(res));
//System.out.println(crd.getJson().toPrettyString());
assertNotNull(crd);
assertNotNull(crd.getJson());
assertNotNull(crd.getJson().get("@context"));
});
}
private RunContext mockOB30Context(Resource res) {
ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
return new RunContext.Builder()
.put(new OB30Inspector.Builder().build())
.put(res)
.put(Key.JACKSON_OBJECTMAPPER, mapper)
.put(Key.JSONPATH_EVALUATOR, jsonPath)
.build();
}
}
@@ -1,6 +1,6 @@
package org.oneedtech.inspect.vc.util;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.oneedtech.inspect.util.json.ObjectMapperCache.Config.DEFAULT;
import java.util.List;
@@ -13,18 +13,31 @@ import org.oneedtech.inspect.vc.Samples;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
public class JsonNodeUtilTests {
static final ObjectMapper mapper = ObjectMapperCache.get(DEFAULT);
static final JsonPathEvaluator jsonPath = new JsonPathEvaluator(mapper);
@Test
void getEndorsementsTest() throws Exception {
assertDoesNotThrow(()->{
JsonNode root = mapper.readTree(Samples.OB30.JSON.COMPLETE_JSON.asBytes());
List<JsonNode> list = JsonNodeUtil.getEndorsements(root, jsonPath);
void testFlattenNodeList() {
Assertions.assertDoesNotThrow(()->{
String json = Samples.OB30.JSON.COMPLETE_JSON.asString();
JsonNode root = mapper.readTree(json);
List<JsonNode> list = JsonNodeUtil.asNodeList(root, "$..endorsement", jsonPath);
Assertions.assertEquals(5, list.size());
});
for(JsonNode node : list) {
ArrayNode types = (ArrayNode) node.get("type");
boolean found = false;
for(JsonNode val : types) {
if(val.asText().equals("EndorsementCredential")) {
found = true;
}
}
assertTrue(found);
}
});
}
}
@@ -0,0 +1,37 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://imsglobal.github.io/openbadges-specification/context.json",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "http://example.edu/credentials/3732",
"type": [
"VerifiableCredential",
"OpenBadgeCredential"
],
"issuer": {
"id": "https://example.edu/issuers/565049",
"type": [
"Profile"
],
"name": "Example University"
},
"issuanceDate": "2010-01-01T00:00:00Z",
"expirationDate": "2020-01-20T00:00:00Z",
"name": "Example University Degree",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"type": [
"AchievementSubject"
]
},
"proof": [
{
"type": "Ed25519Signature2020",
"created": "2022-06-28T16:28:36Z",
"verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj",
"proofPurpose": "assertionMethod",
"proofValue": "z3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnM"
}
]
}
@@ -0,0 +1,37 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://imsglobal.github.io/openbadges-specification/context.json",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "http://example.edu/credentials/3732",
"type": [
"VerifiableCredential",
"OpenBadgeCredential"
],
"issuer": {
"id": "https://example.edu/issuers/565049",
"type": [
"Profile"
],
"name": "Example University"
},
"issuanceDate": "2040-01-01T00:00:00Z",
"expirationDate": "2050-01-20T00:00:00Z",
"name": "Example University Degree",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"type": [
"AchievementSubject"
]
},
"proof": [
{
"type": "Ed25519Signature2020",
"created": "2022-06-28T16:28:36Z",
"verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj",
"proofPurpose": "assertionMethod",
"proofValue": "z3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnM"
}
]
}
@@ -0,0 +1,36 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://imsglobal.github.io/openbadges-specification/context.json",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "http://example.edu/credentials/3732",
"type": [
"VerifiableCredential",
"OpenBadgeCredential"
],
"issuer": {
"id": "https://example.edu/issuers/565049",
"type": [
"Profile"
],
"name": "Example University"
},
"issuanceDate": "2010-01-01T00:00:00Z",
"name": "Example University Degree",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"type": [
"AchievementSubject"
]
},
"proof": [
{
"type": "Ed25519Signature2020",
"created": "2022-06-28T16:28:36Z",
"verificationMethod": "did:key:z6MkkUD3J14nkYzn46QeuaVSnp7dF85QJKwKvJvfsjx79aXj",
"proofPurpose": "assertionMethod",
"proofValue": "XXXz3MUt2ZuU8Byqivxh6GphEM65AFYyNaGYibm97xLTafM7uGufZQLKvJR8itZwxKskvtFM3CUty46v26DZidMNoQnMXXX"
}
]
}