diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessCredential.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessCredential.java index 0f6bf37af87..efb00a47394 100644 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessCredential.java +++ b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessCredential.java @@ -315,7 +315,7 @@ static CredentialMetadata extractMetadata(final Map data) { statusTypes.contains(REVOCATION_LIST_2020_STATUS)).map(x -> asRevocationList2020(credentialStatus))).orElse(null); - final Map subject = asMap(data.get("credentialSubject")).orElseThrow(() -> + final Map subject = asMap(data.get("credentialSubject")).orElseThrow(() -> new IllegalArgumentException("Missing or invalid credentialSubject field")); final URI creator = asUri(subject.get("id")).orElseThrow(() -> @@ -324,8 +324,8 @@ static CredentialMetadata extractMetadata(final Map data) { return new CredentialMetadata(issuer, creator, types, expiration, status); } - static Map extractConsent(final Map data, final String property) { - final Map subject = asMap(data.get("credentialSubject")).orElseThrow(() -> + static Map extractConsent(final Map data, final String property) { + final Map subject = asMap(data.get("credentialSubject")).orElseThrow(() -> new IllegalArgumentException("Missing or invalid credentialSubject field")); return asMap(subject.get(property)).orElseThrow(() -> // Unsupported structure diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessDenial.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessDenial.java index 742a11d6a21..b4ffb3fecd5 100644 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessDenial.java +++ b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessDenial.java @@ -103,12 +103,12 @@ static AccessDenial parse(final String serialization) throws IOException { final Map data = jsonService.fromJson(in, new HashMap(){}.getClass().getGenericSuperclass()); - final List vcs = getCredentialsFromPresentation(data, supportedTypes); + final List> vcs = getCredentialsFromPresentation(data, supportedTypes); if (vcs.size() != 1) { throw new IllegalArgumentException( "Invalid Access Denial: ambiguous number of verifiable credentials"); } - final Map vc = vcs.get(0); + final Map vc = vcs.get(0); if (asSet(data.get(TYPE)).orElseGet(Collections::emptySet).contains("VerifiablePresentation")) { final URI identifier = asUri(vc.get("id")).orElseThrow(() -> @@ -119,7 +119,7 @@ static AccessDenial parse(final String serialization) throws IOException { // Extract V1 Access Denial data, using gConsent - final Map consent = extractConsent(vc, "providedConsent"); + final Map consent = extractConsent(vc, "providedConsent"); final Optional person = asUri(consent.get("isProvidedToPerson")); final Optional controller = asUri(consent.get("isProvidedToController")); diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrant.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrant.java index 8169cfacd9c..05975c377eb 100644 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrant.java +++ b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrant.java @@ -171,12 +171,12 @@ static AccessGrant parse(final String serialization) throws IOException { final Map data = jsonService.fromJson(in, new HashMap(){}.getClass().getGenericSuperclass()); - final List vcs = getCredentialsFromPresentation(data, supportedTypes); + final List> vcs = getCredentialsFromPresentation(data, supportedTypes); if (vcs.size() != 1) { throw new IllegalArgumentException( "Invalid Access Grant: ambiguous number of verifiable credentials"); } - final Map vc = vcs.get(0); + final Map vc = vcs.get(0); if (asSet(data.get(TYPE)).orElseGet(Collections::emptySet).contains("VerifiablePresentation")) { final URI identifier = asUri(vc.get("id")).orElseThrow(() -> @@ -186,7 +186,7 @@ static AccessGrant parse(final String serialization) throws IOException { final CredentialMetadata credentialMetadata = extractMetadata(vc); // Extract V1 Access Grant data, using gConsent - final Map consent = extractConsent(vc, "providedConsent"); + final Map consent = extractConsent(vc, "providedConsent"); final Optional person = asUri(consent.get("isProvidedToPerson")); final Optional controller = asUri(consent.get("isProvidedToController")); diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantClient.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantClient.java index a87f72d199c..2d13c43b517 100644 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantClient.java +++ b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantClient.java @@ -97,6 +97,10 @@ public class AccessGrantClient { private static final String FOR_PERSONAL_DATA = "forPersonalData"; private static final String HAS_STATUS = "hasStatus"; private static final String MODE = "mode"; + private static final String PROVIDED_CONSENT = "providedConsent"; + private static final String FOR_PURPOSE = "forPurpose"; + private static final String EXPIRATION_DATE = "expirationDate"; + private static final String CREDENTIAL = "credential"; private static final URI ACCESS_GRANT = URI.create("http://www.w3.org/ns/solid/vc#SolidAccessGrant"); private static final URI ACCESS_REQUEST = URI.create("http://www.w3.org/ns/solid/vc#SolidAccessRequest"); private static final URI ACCESS_DENIAL = URI.create("http://www.w3.org/ns/solid/vc#SolidAccessDenial"); @@ -592,26 +596,24 @@ List processQueryResponse(final InputStream inpu final Map data = jsonService.fromJson(input, new HashMap(){}.getClass().getGenericSuperclass()); final List grants = new ArrayList<>(); - if (data.get(VERIFIABLE_CREDENTIAL) instanceof Collection) { - for (final Object item : (Collection) data.get(VERIFIABLE_CREDENTIAL)) { - Utils.asMap(item).ifPresent(credential -> - Utils.asSet(credential.get(TYPE)).ifPresent(types -> { - types.retainAll(validTypes); - if (!types.isEmpty()) { - final Map presentation = new HashMap<>(); - presentation.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI)); - presentation.put(TYPE, Arrays.asList("VerifiablePresentation")); - presentation.put(VERIFIABLE_CREDENTIAL, Arrays.asList(credential)); - if (AccessGrant.class.equals(clazz)) { - grants.add((T) AccessGrant.of(new String(serialize(presentation), UTF_8))); - } else if (AccessRequest.class.equals(clazz)) { - grants.add((T) AccessRequest.of(new String(serialize(presentation), UTF_8))); - } else if (AccessDenial.class.equals(clazz)) { - grants.add((T) AccessDenial.of(new String(serialize(presentation), UTF_8))); - } + for (final Object item : getCredentials(data)) { + Utils.asMap(item).ifPresent(credential -> + Utils.asSet(credential.get(TYPE)).ifPresent(types -> { + types.retainAll(validTypes); + if (!types.isEmpty()) { + final Map presentation = new HashMap<>(); + presentation.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI)); + presentation.put(TYPE, Arrays.asList("VerifiablePresentation")); + presentation.put(VERIFIABLE_CREDENTIAL, Arrays.asList(credential)); + if (AccessGrant.class.equals(clazz)) { + grants.add((T) AccessGrant.of(new String(serialize(presentation), UTF_8))); + } else if (AccessRequest.class.equals(clazz)) { + grants.add((T) AccessRequest.of(new String(serialize(presentation), UTF_8))); + } else if (AccessDenial.class.equals(clazz)) { + grants.add((T) AccessDenial.of(new String(serialize(presentation), UTF_8))); } - })); - } + } + })); } return grants; @@ -661,6 +663,14 @@ byte[] serialize(final Map data) { } } + static Collection getCredentials(final Map data) { + final Object credential = data.get(VERIFIABLE_CREDENTIAL); + if (credential instanceof Collection) { + return (Collection) credential; + } + return Collections.emptyList(); + } + static List> buildQuery(final URI issuer, final URI type, final URI agent, final URI resource, final String mode) { final List> queries = new ArrayList<>(); @@ -693,7 +703,7 @@ static void buildQuery(final List> queries, final URI issuer final Map subject = new HashMap<>(); if (!consent.isEmpty()) { if (isAccessGrant(type) || isAccessDenial(type)) { - subject.put("providedConsent", consent); + subject.put(PROVIDED_CONSENT, consent); } else if (isAccessRequest(type)) { subject.put("hasConsent", consent); } @@ -745,21 +755,21 @@ static Map buildAccessDenialv1(final URI agent, final Set r consent.put(FOR_PERSONAL_DATA, resources); consent.put(IS_PROVIDED_TO_PERSON, agent); if (!purposes.isEmpty()) { - consent.put("forPurpose", purposes); + consent.put(FOR_PURPOSE, purposes); } final Map subject = new HashMap<>(); - subject.put("providedConsent", consent); + subject.put(PROVIDED_CONSENT, consent); final Map credential = new HashMap<>(); credential.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI, INRUPT_CONTEXT_URI)); if (expiration != null) { - credential.put("expirationDate", expiration.truncatedTo(ChronoUnit.SECONDS).toString()); + credential.put(EXPIRATION_DATE, expiration.truncatedTo(ChronoUnit.SECONDS).toString()); } credential.put(CREDENTIAL_SUBJECT, subject); final Map data = new HashMap<>(); - data.put("credential", credential); + data.put(CREDENTIAL, credential); return data; } @@ -772,21 +782,21 @@ static Map buildAccessGrantv1(final URI agent, final Set re consent.put(FOR_PERSONAL_DATA, resources); consent.put(IS_PROVIDED_TO_PERSON, agent); if (!purposes.isEmpty()) { - consent.put("forPurpose", purposes); + consent.put(FOR_PURPOSE, purposes); } final Map subject = new HashMap<>(); - subject.put("providedConsent", consent); + subject.put(PROVIDED_CONSENT, consent); final Map credential = new HashMap<>(); credential.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI, INRUPT_CONTEXT_URI)); if (expiration != null) { - credential.put("expirationDate", expiration.truncatedTo(ChronoUnit.SECONDS).toString()); + credential.put(EXPIRATION_DATE, expiration.truncatedTo(ChronoUnit.SECONDS).toString()); } credential.put(CREDENTIAL_SUBJECT, subject); final Map data = new HashMap<>(); - data.put("credential", credential); + data.put(CREDENTIAL, credential); return data; } @@ -800,7 +810,7 @@ static Map buildAccessRequestv1(final URI agent, final Set consent.put(IS_CONSENT_FOR_DATA_SUBJECT, agent); } if (!purposes.isEmpty()) { - consent.put("forPurpose", purposes); + consent.put(FOR_PURPOSE, purposes); } final Map subject = new HashMap<>(); @@ -809,12 +819,12 @@ static Map buildAccessRequestv1(final URI agent, final Set final Map credential = new HashMap<>(); credential.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI, INRUPT_CONTEXT_URI)); if (expiration != null) { - credential.put("expirationDate", expiration.truncatedTo(ChronoUnit.SECONDS).toString()); + credential.put(EXPIRATION_DATE, expiration.truncatedTo(ChronoUnit.SECONDS).toString()); } credential.put(CREDENTIAL_SUBJECT, subject); final Map data = new HashMap<>(); - data.put("credential", credential); + data.put(CREDENTIAL, credential); return data; } diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantSession.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantSession.java index e22dde779ce..49d00d6191d 100644 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantSession.java +++ b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantSession.java @@ -128,7 +128,7 @@ public Optional getCredential(final URI name, final URI uri) { if (isAncestor(entry.getKey(), uri)) { final AccessGrant grant = entry.getValue(); return Optional.of(new Credential("", grant.getIssuer(), Base64.getUrlEncoder().withoutPadding() - .encodeToString(grant.getRawGrant().getBytes(UTF_8)), + .encodeToString(grant.serialize().getBytes(UTF_8)), grant.getExpiration(), session.getPrincipal().orElse(null), null)); } } diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessRequest.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessRequest.java index d6dc22424f0..87fca1fb895 100644 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessRequest.java +++ b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessRequest.java @@ -102,12 +102,12 @@ static AccessRequest parse(final String serialization) throws IOException { final Map data = jsonService.fromJson(in, new HashMap(){}.getClass().getGenericSuperclass()); - final List vcs = getCredentialsFromPresentation(data, supportedTypes); + final List> vcs = getCredentialsFromPresentation(data, supportedTypes); if (vcs.size() != 1) { throw new IllegalArgumentException( "Invalid Access Request: ambiguous number of verifiable credentials"); } - final Map vc = vcs.get(0); + final Map vc = vcs.get(0); if (asSet(data.get(TYPE)).orElseGet(Collections::emptySet).contains("VerifiablePresentation")) { final URI identifier = asUri(vc.get("id")).orElseThrow(() -> @@ -117,7 +117,7 @@ static AccessRequest parse(final String serialization) throws IOException { final CredentialMetadata credentialMetadata = extractMetadata(vc); // V1 Access Request, using gConsent - final Map consent = extractConsent(vc, "hasConsent"); + final Map consent = extractConsent(vc, "hasConsent"); final URI recipient = asUri(consent.get("isConsentForDataSubject")).orElse(null); final Set modes = asSet(consent.get("mode")).orElseGet(Collections::emptySet); diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/Utils.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/Utils.java index e9887df7ba4..5f80704526f 100644 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/Utils.java +++ b/access-grant/src/main/java/com/inrupt/client/accessgrant/Utils.java @@ -36,7 +36,7 @@ final class Utils { private static final String TYPE = "type"; private static final String REVOCATION_LIST_2020_STATUS = "RevocationList2020Status"; - public static Status asRevocationList2020(final Map credentialStatus) { + public static Status asRevocationList2020(final Map credentialStatus) { try { int idx = -1; final Object index = credentialStatus.get("revocationListIndex"); @@ -72,9 +72,11 @@ public static Optional asUri(final Object value) { return Optional.empty(); } - public static Optional asMap(final Object value) { + public static Optional> asMap(final Object value) { if (value instanceof Map) { - return Optional.of((Map) value); + @SuppressWarnings("unchecked") + final Map v = (Map) value; + return Optional.of(v); } return Optional.empty(); } @@ -96,13 +98,14 @@ public static Optional> asSet(final Object value) { return Optional.empty(); } - public static List getCredentialsFromPresentation(final Map data, + public static List> getCredentialsFromPresentation(final Map data, final Set supportedTypes) { - final List credentials = new ArrayList<>(); + final List> credentials = new ArrayList<>(); if (data.get("verifiableCredential") instanceof Collection) { for (final Object item : (Collection) data.get("verifiableCredential")) { if (item instanceof Map) { - final Map vc = (Map) item; + @SuppressWarnings("unchecked") + final Map vc = (Map) item; if (asSet(vc.get(TYPE)).filter(types -> types.stream().anyMatch(supportedTypes::contains)).isPresent()) { credentials.add(vc); @@ -113,7 +116,6 @@ public static List getCredentialsFromPresentation(final Map return credentials; } - private Utils() { // prevent instantiation }