From 75d7deffda679e77ab5142a604657f800e932096 Mon Sep 17 00:00:00 2001 From: Xavi Aracil Date: Tue, 22 Nov 2022 18:03:06 +0100 Subject: [PATCH] Added Assertion as a sibling of Credential --- .../inspect/vc/AbstractBaseCredential.java | 110 ++++++++++++++++++ .../org/oneedtech/inspect/vc/Assertion.java | 81 +++++++++++++ .../org/oneedtech/inspect/vc/Credential.java | 107 +++++++---------- 3 files changed, 232 insertions(+), 66 deletions(-) create mode 100644 inspector-vc/src/main/java/org/oneedtech/inspect/vc/AbstractBaseCredential.java create mode 100644 inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/AbstractBaseCredential.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/AbstractBaseCredential.java new file mode 100644 index 0000000..1262919 --- /dev/null +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/AbstractBaseCredential.java @@ -0,0 +1,110 @@ +package org.oneedtech.inspect.vc; + +import static org.oneedtech.inspect.util.code.Defensives.*; +import static org.oneedtech.inspect.util.resource.ResourceType.*; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.oneedtech.inspect.core.probe.GeneratedObject; +import org.oneedtech.inspect.schema.SchemaKey; +import org.oneedtech.inspect.util.resource.Resource; +import org.oneedtech.inspect.util.resource.ResourceType; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.google.common.base.MoreObjects; + + +/** + * Base credential class for OB 2.0 Assertions and OB 3.0 and CLR 2.0 Credentials. + * This contains e.g. the origin resource and the extracted JSON data. + * @author xaracil + */ +public abstract class AbstractBaseCredential extends GeneratedObject { + final Resource resource; + final JsonNode jsonData; + final String jwt; + final Map schemas; + + protected AbstractBaseCredential(String id, Resource resource, JsonNode data, String jwt, Map schemas) { + super(id, GeneratedObject.Type.INTERNAL); + this.resource = checkNotNull(resource); + this.jsonData = checkNotNull(data); + this.jwt = jwt; //may be null + this.schemas = schemas; + + checkTrue(RECOGNIZED_PAYLOAD_TYPES.contains(resource.getType())); + } + + public Resource getResource() { + return resource; + } + + public JsonNode getJson() { + return jsonData; + } + + public Optional getJwt() { + return Optional.ofNullable(jwt); + } + + /** + * Get the canonical schema for this credential if such exists. + */ + public Optional getSchemaKey() { + return Optional.ofNullable(schemas.get(getCredentialType())); + } + + public abstract String getCredentialType(); + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("resource", resource.getID()) + .add("resourceType", resource.getType()) + .add("json", jsonData) + .add("jwt", jwt) + .toString(); + } + + public static final List RECOGNIZED_PAYLOAD_TYPES = List.of(SVG, PNG, JSON, JWT); + public static final String CREDENTIAL_KEY = "CREDENTIAL_KEY"; + + public abstract static class Builder { + private Resource resource; + private JsonNode jsonData; + private String jwt; + + public abstract B build(); + + public Builder resource(Resource resource) { + this.resource = resource; + return this; + } + + public Builder jsonData(JsonNode node) { + this.jsonData = node; + return this; + } + + public Builder jwt(String jwt) { + this.jwt = jwt; + return this; + } + + protected Resource getResource() { + return resource; + } + + protected JsonNode getJsonData() { + return jsonData; + } + + protected String getJwt() { + return jwt; + } + } + +} diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java new file mode 100644 index 0000000..8cec78b --- /dev/null +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Assertion.java @@ -0,0 +1,81 @@ +package org.oneedtech.inspect.vc; + +import java.util.Iterator; +import java.util.Map; +import java.util.stream.Collectors; + +import org.oneedtech.inspect.schema.Catalog; +import org.oneedtech.inspect.schema.SchemaKey; +import org.oneedtech.inspect.util.resource.Resource; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; + +/** + * A wrapper object for a OB 2.0 assertion. This contains e.g. the origin resource + * and the extracted JSON data plus any other stuff Probes need. + * @author xaracil + */ +public class Assertion extends AbstractBaseCredential { + + final Assertion.Type assertionType; + + protected Assertion(Resource resource, JsonNode data, String jwt, Map schemas) { + super(ID, resource, data, jwt, schemas); + + ArrayNode typeNode = (ArrayNode)jsonData.get("type"); + this.assertionType = Assertion.Type.valueOf(typeNode); + } + + @Override + public String getCredentialType() { + return assertionType.toString(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("super", super.toString()) + .add("assertionType", assertionType) + .toString(); + } + + private static final Map schemas = new ImmutableMap.Builder() + .put(Type.Assertion, Catalog.OB_21_ASSERTION_JSON) + .build(); + + public static class Builder extends AbstractBaseCredential.Builder { + + @Override + public Assertion build() { + // transform key of schemas map to string because the type of the key in the base map is generic + // and our specific key is an Enum + return new Assertion(getResource(), getJsonData(), getJwt(), + schemas.entrySet().stream().collect(Collectors.toMap( + entry -> entry.getKey().toString(), + entry -> entry.getValue()))); + } + } + + public enum Type { + Assertion, + Unknown; + + public static Assertion.Type valueOf (ArrayNode typeArray) { + if(typeArray != null) { + Iterator iter = typeArray.iterator(); + while(iter.hasNext()) { + String value = iter.next().asText(); + if(value.equals("Assertion")) { + return Assertion; + } + } + } + return Unknown; + } + } + + public static final String ID = Assertion.class.getCanonicalName(); +} diff --git a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Credential.java b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Credential.java index 1b3c501..ecd1722 100644 --- a/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Credential.java +++ b/inspector-vc/src/main/java/org/oneedtech/inspect/vc/Credential.java @@ -1,19 +1,17 @@ package org.oneedtech.inspect.vc; -import static org.oneedtech.inspect.util.code.Defensives.*; -import static org.oneedtech.inspect.util.resource.ResourceType.*; -import static org.oneedtech.inspect.vc.Credential.Type.*; +import static org.oneedtech.inspect.vc.Credential.Type.AchievementCredential; +import static org.oneedtech.inspect.vc.Credential.Type.ClrCredential; +import static org.oneedtech.inspect.vc.Credential.Type.EndorsementCredential; +import static org.oneedtech.inspect.vc.Credential.Type.VerifiablePresentation; import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.stream.Collectors; -import org.oneedtech.inspect.core.probe.GeneratedObject; import org.oneedtech.inspect.schema.Catalog; import org.oneedtech.inspect.schema.SchemaKey; import org.oneedtech.inspect.util.resource.Resource; -import org.oneedtech.inspect.util.resource.ResourceType; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -21,76 +19,45 @@ import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableMap; /** - * A wrapper object for a verifiable credential. This contains e.g. the origin resource - * and the extracted JSON data plus any other stuff Probes need. + * A wrapper object for a verifiable credential. This contains e.g. the origin resource + * and the extracted JSON data plus any other stuff Probes need. * @author mgylling */ -public class Credential extends GeneratedObject { - final Resource resource; - final JsonNode jsonData; +public class Credential extends AbstractBaseCredential { final Credential.Type credentialType; - final String jwt; - - public Credential(Resource resource, JsonNode data, String jwt) { - super(ID, GeneratedObject.Type.INTERNAL); - this.resource = checkNotNull(resource); - this.jsonData = checkNotNull(data); - this.jwt = jwt; //may be null - - checkTrue(RECOGNIZED_PAYLOAD_TYPES.contains(resource.getType())); - + + protected Credential(Resource resource, JsonNode data, String jwt, Map schemas) { + super(ID, resource, data, jwt, schemas); + ArrayNode typeNode = (ArrayNode)jsonData.get("type"); this.credentialType = Credential.Type.valueOf(typeNode); - } - - public Credential(Resource resource, JsonNode data) { - this(resource, data, null); - } - - public Resource getResource() { - return resource; - } - - public JsonNode getJson() { - return jsonData; + } + + public String getCredentialType() { + return credentialType.toString(); } - public Credential.Type getCredentialType() { - return credentialType; - } - - public Optional getJwt() { - return Optional.ofNullable(jwt); - } - public ProofType getProofType() { return jwt == null ? ProofType.EMBEDDED : ProofType.EXTERNAL; } - - + private static final Map schemas = new ImmutableMap.Builder() .put(AchievementCredential, Catalog.OB_30_ACHIEVEMENTCREDENTIAL_JSON) .put(ClrCredential, Catalog.CLR_20_CLRCREDENTIAL_JSON) .put(VerifiablePresentation, Catalog.CLR_20_CLRCREDENTIAL_JSON) - .put(EndorsementCredential, Catalog.OB_30_ENDORSEMENTCREDENTIAL_JSON) + .put(EndorsementCredential, Catalog.OB_30_ENDORSEMENTCREDENTIAL_JSON) .build(); - - /** - * Get the canonical schema for this credential if such exists. - */ - public Optional getSchemaKey() { - return Optional.ofNullable(schemas.get(credentialType)); - } - + + public enum Type { AchievementCredential, OpenBadgeCredential, //treated as an alias of AchievementCredential - ClrCredential, + ClrCredential, EndorsementCredential, VerifiablePresentation, VerifiableCredential, //this is an underspecifier in our context - Unknown; - + Unknown; + public static Credential.Type valueOf (ArrayNode typeArray) { if(typeArray != null) { Iterator iter = typeArray.iterator(); @@ -110,24 +77,32 @@ public class Credential extends GeneratedObject { return Unknown; } } - + public enum ProofType { EXTERNAL, EMBEDDED } - + @Override public String toString() { - return MoreObjects.toStringHelper(this) - .add("resource", resource.getID()) - .add("resourceType", resource.getType()) + return MoreObjects.toStringHelper(this) + .add("super", super.toString()) .add("credentialType", credentialType) - .add("json", jsonData) .toString(); } - + + public static class Builder extends AbstractBaseCredential.Builder { + @Override + public Credential build() { + // transform key of schemas map to string because the type of the key in the base map is generic + // and our specific key is an Enum + return new Credential(getResource(), getJsonData(), getJwt(), + schemas.entrySet().stream().collect(Collectors.toMap( + entry -> entry.getKey().toString(), + entry -> entry.getValue()))); + } + } + public static final String ID = Credential.class.getCanonicalName(); - public static final List RECOGNIZED_PAYLOAD_TYPES = List.of(SVG, PNG, JSON, JWT); - public static final String CREDENTIAL_KEY = "CREDENTIAL_KEY"; - + }