Add several more ob3 tests

This commit is contained in:
Andy Miller (IMS) 2022-11-16 12:29:22 -08:00
parent bd106f9761
commit 78c1cbe279
7 changed files with 287 additions and 34 deletions

View File

@ -65,57 +65,60 @@ public class EmbeddedProofProbe extends Probe<Credential> {
// The verification method must dereference to an Ed25519VerificationKey2020. // The verification method must dereference to an Ed25519VerificationKey2020.
// Danubetech's Ed25519Signature2020LdVerifier expects the decoded public key // Danubetech's Ed25519Signature2020LdVerifier expects the decoded public key
// from the Ed25519VerificationKey2020 (32 bytes). // from the Ed25519VerificationKey2020 (32 bytes).
//
String publicKeyMultibase;
String controller = null;
// Formats accepted: // Formats accepted:
// //
// [controller]#[publicKeyMultibase] // [controller]#[publicKeyMultibase]
// did:key:[publicKeyMultibase] // did:key:[publicKeyMultibase]
// http/s://[location of a Ed25519VerificationKey2020 document] // http/s://[location of a Ed25519VerificationKey2020 document]
// http/s://[location of a controller document with a 'verificationMethod' with a Ed25519VerificationKey2020] // http/s://[location of a controller document with a 'verificationMethod' with a Ed25519VerificationKey2020]
// [publicKeyMultibase]
String publicKeyMultibase;
String controller = null;
publicKeyMultibase = method.toString(); publicKeyMultibase = method.toString();
if (method.getFragment() != null) { if (method.getFragment() != null && IsValidPublicKeyMultibase(method.getFragment())) {
publicKeyMultibase = method.getFragment(); publicKeyMultibase = method.getFragment();
controller = method.toString().substring(0, method.toString().indexOf("#")); controller = method.toString().substring(0, method.toString().indexOf("#"));
} else { } else {
if (method.getScheme().equals("did")) { if (StringUtils.isBlank(method.getScheme())) {
return error("The verification method must be a valid URI (missing scheme)", ctx);
} else if (method.getScheme().equals("did")) {
if (method.getSchemeSpecificPart().startsWith("key:")) { if (method.getSchemeSpecificPart().startsWith("key:")) {
publicKeyMultibase = method.getSchemeSpecificPart().substring(4); publicKeyMultibase = method.getSchemeSpecificPart().substring("key:".length());
} else { } else {
return error("Unknown verification method: " + method, ctx); return error("Unknown verification method: " + method, ctx);
} }
} else if (method.getScheme().equals("http") || method.getScheme().equals("https")) { } else if (method.getScheme().equals("http") || method.getScheme().equals("https")) {
// TODO: Can we use proof.getDocumentLoader()? try {
ConfigurableDocumentLoader keyDocumentLoader = new ConfigurableDocumentLoader(); Document keyDocument = vc.getDocumentLoader().loadDocument(method, new DocumentLoaderOptions());
keyDocumentLoader.setEnableHttp(true); Optional<JsonStructure> keyStructure = keyDocument.getJsonContent();
keyDocumentLoader.setEnableHttps(true); if (keyStructure.isEmpty()) {
return error("Key document not found at " + method, ctx);
Document keyDocument = keyDocumentLoader.loadDocument(method, new DocumentLoaderOptions());
Optional<JsonStructure> keyStructure = keyDocument.getJsonContent();
if (keyStructure.isEmpty()) {
return error("Key document not found at " + method, ctx);
}
// First look for a Ed25519VerificationKey2020 document
controller = keyStructure.get().asJsonObject().getString("controller");
if (StringUtils.isBlank(controller)) {
// Then look for a controller document (e.g. DID Document) with a 'verificationMethod'
// that is a Ed25519VerificationKey2020 document
JsonObject keyVerificationMethod = keyStructure.get().asJsonObject()
.getJsonObject("verificationMethod");
if (keyVerificationMethod.isEmpty()) {
return error("Cannot parse key document from " + method, ctx);
} }
controller = keyVerificationMethod.getString("controller");
publicKeyMultibase = keyVerificationMethod.getString("publicKeyMultibase"); // First look for a Ed25519VerificationKey2020 document
} else { controller = keyStructure.get().asJsonObject().getString("controller");
publicKeyMultibase = keyStructure.get().asJsonObject().getString("publicKeyMultibase"); if (StringUtils.isBlank(controller)) {
// Then look for a controller document (e.g. DID Document) with a 'verificationMethod'
// that is a Ed25519VerificationKey2020 document
JsonObject keyVerificationMethod = keyStructure.get().asJsonObject()
.getJsonObject("verificationMethod");
if (keyVerificationMethod.isEmpty()) {
return error("Cannot parse key document from " + method, ctx);
}
controller = keyVerificationMethod.getString("controller");
publicKeyMultibase = keyVerificationMethod.getString("publicKeyMultibase");
} else {
publicKeyMultibase = keyStructure.get().asJsonObject().getString("publicKeyMultibase");
}
} catch (Exception e) {
return error("Invalid verification key URL: " + e.getMessage(), ctx);
} }
} else {
return error("Unknown verification method scheme: " + method.getScheme(), ctx);
} }
} }
@ -154,5 +157,16 @@ public class EmbeddedProofProbe extends Probe<Credential> {
return success(ctx); return success(ctx);
} }
private Boolean IsValidPublicKeyMultibase(String publicKeyMultibase) {
try {
byte[] publicKeyMulticodec = Multibase.decode(publicKeyMultibase);
byte[] publicKey = Multicodec.decode(Codec.Ed25519PublicKey, publicKeyMulticodec);
return publicKey.length == 32;
} catch (Exception e) {
return false;
}
}
public static final String ID = EmbeddedProofProbe.class.getSimpleName(); public static final String ID = EmbeddedProofProbe.class.getSimpleName();
} }

View File

@ -21,7 +21,7 @@ import com.google.common.collect.Iterables;
public class OB30Tests { public class OB30Tests {
private static OB30Inspector validator; private static OB30Inspector validator;
private static boolean verbose = false; private static boolean verbose = true;
@BeforeAll @BeforeAll
static void setup() { static void setup() {
@ -40,6 +40,16 @@ public class OB30Tests {
}); });
} }
@Test
@Disabled("Do not have a valid sample")
void testSimpleDidMethodJsonValid() {
assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.SIMPLE_DID_METHOD_JSON.asFileResource());
if(verbose) PrintHelper.print(report, true);
assertValid(report);
});
}
@Test @Test
void testSimplePNGPlainValid() { void testSimplePNGPlainValid() {
assertDoesNotThrow(()->{ assertDoesNotThrow(()->{
@ -90,7 +100,8 @@ public class OB30Tests {
@Test @Test
void testSimpleJsonInvalidProofMethod() { void testSimpleJsonInvalidProofMethod() {
//add some garbage chars to proofValue // add some garbage chars to the verification method fragment
// it will be treated a URL to a verification key, but the URL will not be found
assertDoesNotThrow(()->{ assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_PROOF_METHOD_ERROR.asFileResource()); Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_PROOF_METHOD_ERROR.asFileResource());
if(verbose) PrintHelper.print(report, true); if(verbose) PrintHelper.print(report, true);
@ -100,6 +111,42 @@ public class OB30Tests {
}); });
} }
@Test
void testSimpleJsonInvalidProofMethodNoScheme() {
// The verificationMethod is not a URI (no scheme)
assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_PROOF_METHOD_NO_SCHEME_ERROR.asFileResource());
if(verbose) PrintHelper.print(report, true);
assertInvalid(report);
assertErrorCount(report, 1);
assertHasProbeID(report, EmbeddedProofProbe.ID, true);
});
}
@Test
void testSimpleJsonInvalidProofMethodUnknownScheme() {
// The verificationMethod is not a URI (no scheme)
assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_PROOF_METHOD_UNKNOWN_SCHEME_ERROR.asFileResource());
if(verbose) PrintHelper.print(report, true);
assertInvalid(report);
assertErrorCount(report, 1);
assertHasProbeID(report, EmbeddedProofProbe.ID, true);
});
}
@Test
void testSimpleJsonInvalidProofMethodUnknownDidMethod() {
// The verificationMethod is an unknown DID Method
assertDoesNotThrow(()->{
Report report = validator.run(Samples.OB30.JSON.SIMPLE_JSON_PROOF_METHOD_UNKNOWN_DID_METHOD_ERROR.asFileResource());
if(verbose) PrintHelper.print(report, true);
assertInvalid(report);
assertErrorCount(report, 1);
assertHasProbeID(report, EmbeddedProofProbe.ID, true);
});
}
@Test @Test
void testSimpleJsonInvalidProofValue() { void testSimpleJsonInvalidProofValue() {
//add some garbage chars to proofValue //add some garbage chars to proofValue

View File

@ -11,9 +11,13 @@ public class Samples {
public static final class JSON { public static final class JSON {
public final static Sample COMPLETE_JSON = new Sample("ob30/complete.json", false); 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 = new Sample("ob30/simple.json", true);
public final static Sample SIMPLE_DID_METHOD_JSON = new Sample("ob30/simple-did-method.json", true);
public final static Sample SIMPLE_JSON_NOPROOF = new Sample("ob30/simple-noproof.json", false); public final static Sample SIMPLE_JSON_NOPROOF = new Sample("ob30/simple-noproof.json", false);
public final static Sample SIMPLE_JSON_UNKNOWN_TYPE = new Sample("ob30/simple-err-type.json", false); public final static Sample SIMPLE_JSON_UNKNOWN_TYPE = new Sample("ob30/simple-err-type.json", false);
public final static Sample SIMPLE_JSON_PROOF_METHOD_ERROR = new Sample("ob30/simple-err-proof-method.json", false); public final static Sample SIMPLE_JSON_PROOF_METHOD_ERROR = new Sample("ob30/simple-err-proof-method.json", false);
public final static Sample SIMPLE_JSON_PROOF_METHOD_NO_SCHEME_ERROR = new Sample("ob30/simple-err-proof-method-no-scheme.json", false);
public final static Sample SIMPLE_JSON_PROOF_METHOD_UNKNOWN_SCHEME_ERROR = new Sample("ob30/simple-err-proof-method-unknown-scheme.json", false);
public final static Sample SIMPLE_JSON_PROOF_METHOD_UNKNOWN_DID_METHOD_ERROR = new Sample("ob30/simple-err-proof-method-unknown-did-method.json", false);
public final static Sample SIMPLE_JSON_PROOF_VALUE_ERROR = new Sample("ob30/simple-err-proof-value.json", false); public final static Sample SIMPLE_JSON_PROOF_VALUE_ERROR = new Sample("ob30/simple-err-proof-value.json", false);
public final static Sample SIMPLE_JSON_EXPIRED = new Sample("ob30/simple-err-expired.json", false); public final static Sample SIMPLE_JSON_EXPIRED = new Sample("ob30/simple-err-expired.json", false);
public final static Sample SIMPLE_JSON_ISSUED = new Sample("ob30/simple-err-issued.json", false); public final static Sample SIMPLE_JSON_ISSUED = new Sample("ob30/simple-err-issued.json", false);

View File

@ -0,0 +1,47 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://purl.imsglobal.org/spec/ob/v3p0/context.json",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "http://example.com/credentials/3527",
"type": [
"VerifiableCredential",
"OpenBadgeCredential"
],
"issuer": {
"id": "https://example.com/issuers/876543",
"type": [
"Profile"
],
"name": "Example Corp"
},
"issuanceDate": "2010-01-01T00:00:00Z",
"name": "Teamwork Badge",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"type": [
"AchievementSubject"
],
"achievement": {
"id": "https://example.com/achievements/21st-century-skills/teamwork",
"type": [
"Achievement"
],
"criteria": {
"narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management."
},
"description": "This badge recognizes the development of the capacity to collaborate within a group environment.",
"name": "Teamwork"
}
},
"proof": [
{
"type": "Ed25519Signature2020",
"created": "2022-11-16T18:54:22Z",
"verificationMethod": "did:key:z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv",
"proofPurpose": "assertionMethod",
"proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK"
}
]
}

View File

@ -0,0 +1,47 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://purl.imsglobal.org/spec/ob/v3p0/context.json",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "http://example.com/credentials/3527",
"type": [
"VerifiableCredential",
"OpenBadgeCredential"
],
"issuer": {
"id": "https://example.com/issuers/876543",
"type": [
"Profile"
],
"name": "Example Corp"
},
"issuanceDate": "2010-01-01T00:00:00Z",
"name": "Teamwork Badge",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"type": [
"AchievementSubject"
],
"achievement": {
"id": "https://example.com/achievements/21st-century-skills/teamwork",
"type": [
"Achievement"
],
"criteria": {
"narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management."
},
"description": "This badge recognizes the development of the capacity to collaborate within a group environment.",
"name": "Teamwork"
}
},
"proof": [
{
"type": "Ed25519Signature2020",
"created": "2022-11-16T18:54:22Z",
"verificationMethod": "z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv",
"proofPurpose": "assertionMethod",
"proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK"
}
]
}

View File

@ -0,0 +1,47 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://purl.imsglobal.org/spec/ob/v3p0/context.json",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "http://example.com/credentials/3527",
"type": [
"VerifiableCredential",
"OpenBadgeCredential"
],
"issuer": {
"id": "https://example.com/issuers/876543",
"type": [
"Profile"
],
"name": "Example Corp"
},
"issuanceDate": "2010-01-01T00:00:00Z",
"name": "Teamwork Badge",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"type": [
"AchievementSubject"
],
"achievement": {
"id": "https://example.com/achievements/21st-century-skills/teamwork",
"type": [
"Achievement"
],
"criteria": {
"narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management."
},
"description": "This badge recognizes the development of the capacity to collaborate within a group environment.",
"name": "Teamwork"
}
},
"proof": [
{
"type": "Ed25519Signature2020",
"created": "2022-11-16T18:54:22Z",
"verificationMethod": "did:example:z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv",
"proofPurpose": "assertionMethod",
"proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK"
}
]
}

View File

@ -0,0 +1,47 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://purl.imsglobal.org/spec/ob/v3p0/context.json",
"https://w3id.org/security/suites/ed25519-2020/v1"
],
"id": "http://example.com/credentials/3527",
"type": [
"VerifiableCredential",
"OpenBadgeCredential"
],
"issuer": {
"id": "https://example.com/issuers/876543",
"type": [
"Profile"
],
"name": "Example Corp"
},
"issuanceDate": "2010-01-01T00:00:00Z",
"name": "Teamwork Badge",
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"type": [
"AchievementSubject"
],
"achievement": {
"id": "https://example.com/achievements/21st-century-skills/teamwork",
"type": [
"Achievement"
],
"criteria": {
"narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management."
},
"description": "This badge recognizes the development of the capacity to collaborate within a group environment.",
"name": "Teamwork"
}
},
"proof": [
{
"type": "Ed25519Signature2020",
"created": "2022-11-16T18:54:22Z",
"verificationMethod": "xxx:z6MknNHHrBzPytzu6CUBP9Lg7fg4KSBjzimc2Frh693YbMiv",
"proofPurpose": "assertionMethod",
"proofValue": "z5gJZKchSJEYPGeq6bsqiLKuxT6mXqAovPbqYX66CB7u9CSNFdV41vHtysjHFiitvoyhfPxsaZnWftrZZZW2txPQK"
}
]
}