diff --git a/.github/workflows/ci-config.yml b/.github/workflows/ci-config.yml index d7108c580e3..b1b505ed88d 100644 --- a/.github/workflows/ci-config.yml +++ b/.github/workflows/ci-config.yml @@ -41,7 +41,7 @@ jobs: INRUPT_TEST_REQUEST_METADATA_HEADERS_THAT_PROPAGATE: ${{ secrets.INRUPT_PROD_HEADERS_THAT_PROPAGATE }} - name: Dev Integration tests - if: ${{ github.actor != 'dependabot[bot]' && matrix.java == 11 }} + if: ${{ github.actor != 'dependabot[bot]' && matrix.java == 17 }} continue-on-error: true run: mvn -B -ntp verify -Pci -pl integration/uma,integration/openid env: diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessCredentialQuery.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessCredentialQuery.java deleted file mode 100644 index 12a424b729a..00000000000 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessCredentialQuery.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright Inrupt Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.inrupt.client.accessgrant; - -import java.net.URI; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -/** - * An object to represent an access credential query. - * - * @param The access credential type - * @deprecated As of 1.3, replaced by {@link CredentialFilter} - */ -@Deprecated -public class AccessCredentialQuery { - - private final Set purposes; - private final Set modes; - private final URI resource; - private final URI creator; - private final URI recipient; - private final Class clazz; - - /** - * Create an access credential query. - * - * @param resource the resource, may be {@code null} - * @param creator the creator, may be {@code null} - * @param recipient the recipient, may be {@code null} - * @param purposes the purposes, never {@code null} - * @param modes the access modes, never {@code null} - * @param clazz the credential type, never {@code null} - */ - AccessCredentialQuery(final URI resource, final URI creator, final URI recipient, - final Set purposes, final Set modes, final Class clazz) { - this.clazz = Objects.requireNonNull(clazz, "The clazz parameter must not be null!"); - this.resource = resource; - this.creator = creator; - this.recipient = recipient; - this.purposes = purposes; - this.modes = modes; - } - - /** - * Get the requested resource. - * - * @return the resource, may be {@code null} - */ - public URI getResource() { - return resource; - } - - /** - * Get the requested creator. - * - * @return the creator, may be {@code null} - */ - public URI getCreator() { - return creator; - } - - /** - * Get the requested recipient. - * - * @return the recipient, may be {@code null} - */ - public URI getRecipient() { - return recipient; - } - - /** - * Get the requested purposes. - * - * @return the purpose identifiers, never {@code null} - */ - public Set getPurposes() { - return purposes; - } - - /** - * Get the requested access modes. - * - * @return the access modes, never {@code null} - */ - public Set getModes() { - return modes; - } - - /* package private */ - Class getAccessCredentialType() { - return clazz; - } - - /** - * Create a new access credential query builder. - * - * @return the builder - */ - public static Builder newBuilder() { - return new Builder(); - } - - /** - * A builder class for access credential queries. - */ - public static class Builder { - - private final Set purposes = new HashSet<>(); - private final Set modes = new HashSet<>(); - private URI builderResource; - private URI builderCreator; - private URI builderRecipient; - - /** - * Set the resource identifier. - * - * @param resource the resource identifier, may be {@code null} - * @return this builder - */ - public Builder resource(final URI resource) { - builderResource = resource; - return this; - } - - /** - * Add a purpose identifier. - * - * @param purpose a purpose identifier; {@code null} values have no effect. - * @return this builder - */ - public Builder purpose(final URI purpose) { - if (purpose != null) { - purposes.add(purpose); - } - return this; - } - - /** - * Add an access mode value. - * - * @param mode a mode value; {@code null} values have no effect. - * @return this builder - */ - public Builder mode(final String mode) { - if (mode != null) { - modes.add(mode); - } - return this; - } - - /** - * Set the creator identifier. - * - * @param creator the creator identifier, may be {@code null} - * @return this builder - */ - public Builder creator(final URI creator) { - builderCreator = creator; - return this; - } - - /** - * Set the recipient identifier. - * - * @param recipient the recipient identifier, may be {@code null} - * @return this builder - */ - public Builder recipient(final URI recipient) { - builderRecipient = recipient; - return this; - } - - /** - * Build the access credential query. - * - * @param the credential type - * @param clazz the credential type - * @return the query object - */ - public AccessCredentialQuery build(final Class clazz) { - return new AccessCredentialQuery<>(builderResource, builderCreator, builderRecipient, purposes, modes, - clazz); - } - } -} 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 75293228141..41fd98596aa 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 @@ -461,90 +461,6 @@ T cast(final Map data, final Class< return null; } - /** - * Perform an Access Credentials query and returns 0 to N matching access credentials. - * - * @param the AccessCredential type - * @param resource the resource identifier, may be {@code null} - * @param creator the identifier for the agent who created the credential, may be {@code null} - * @param recipient the identifier for the agent who is the recipient for the credential, may be {@code null} - * @param purpose the access purpose, may be {@code null} - * @param mode the access mode, may be {@code null} - * @param clazz the AccessCredential type, either {@link AccessGrant} or {@link AccessRequest} - * @return the next stage of completion, including the matched Access Credentials - * @deprecated As of 1.3, replaced by {@link #query(CredentialFilter)} - */ - @Deprecated - public CompletionStage> query(final URI resource, final URI creator, - final URI recipient, final URI purpose, final String mode, final Class clazz) { - - final Set modes = mode != null ? Collections.singleton(mode) : Collections.emptySet(); - final Set purposes = purpose != null ? Collections.singleton(purpose) : Collections.emptySet(); - - return query(resource, creator, recipient, purposes, modes, clazz); - } - - /** - * Perform an Access Credentials query and returns 0 to N matching access credentials. - * - * @param the AccessCredential type - * @param query the access credential query, never {@code null} - * @return the next stage of completion, including the matched Access Credentials - * @deprecated As of 1.3, replaced by {@link #query(CredentialFilter)} - */ - @Deprecated - public CompletionStage> query(final AccessCredentialQuery query) { - Objects.requireNonNull(query, "The query may not be null!"); - return query(query.getResource(), query.getCreator(), query.getRecipient(), query.getPurposes(), - query.getModes(), query.getAccessCredentialType()); - } - - private CompletionStage> query(final URI resource, final URI creator, - final URI recipient, final Set purposes, final Set modes, final Class clazz) { - Objects.requireNonNull(clazz, "The clazz parameter must not be null!"); - - final URI type; - final Set supportedTypes; - if (AccessGrant.class.isAssignableFrom(clazz)) { - type = URI.create(SOLID_ACCESS_GRANT); - supportedTypes = ACCESS_GRANT_TYPES; - } else if (AccessRequest.class.isAssignableFrom(clazz)) { - type = URI.create(SOLID_ACCESS_REQUEST); - supportedTypes = ACCESS_REQUEST_TYPES; - } else if (AccessDenial.class.isAssignableFrom(clazz)) { - type = URI.create(SOLID_ACCESS_DENIAL); - supportedTypes = ACCESS_DENIAL_TYPES; - } else { - throw new AccessGrantException("Unsupported type " + clazz + " in query request"); - } - - return v1Metadata().thenApply(metadata -> { - if (metadata.deriveEndpoint == null) { - throw new AccessGrantException("Server does not support queries via AccessCredentialQuery objects"); - } - final List responses = new ArrayList<>(); - for (final Map data : - buildQuery(config.getIssuer(), type, resource, creator, recipient, purposes, modes)) { - final Request req = Request.newBuilder(metadata.deriveEndpoint) - .header(CONTENT_TYPE, APPLICATION_JSON) - .POST(Request.BodyPublishers.ofByteArray(serialize(data))).build(); - final Response response = client.send(req, Response.BodyHandlers.ofInputStream()) - .toCompletableFuture().join(); - - try (final InputStream input = response.body()) { - final int status = response.statusCode(); - if (isSuccess(status)) { - responses.addAll(processQueryResponse(input, supportedTypes, clazz)); - } - } catch (final IOException ex) { - throw new AccessGrantException( - "Unexpected I/O exception while processing Access Grant query", ex); - } - } - return responses; - }); - } - /** * Revoke an access credential. * @@ -682,7 +598,6 @@ CompletionStage v1Metadata() { }) .thenApply(metadata -> { final Metadata m = new Metadata(); - m.deriveEndpoint = asUri(metadata.get("derivationService")); m.queryEndpoint = asUri(metadata.get("queryService")); m.issueEndpoint = asUri(metadata.get("issuerService")); m.verifyEndpoint = asUri(metadata.get("verifierService")); diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/Metadata.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/Metadata.java index a0b49977066..185772e63f4 100644 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/Metadata.java +++ b/access-grant/src/main/java/com/inrupt/client/accessgrant/Metadata.java @@ -27,5 +27,4 @@ class Metadata { public URI issueEndpoint; public URI statusEndpoint; public URI verifyEndpoint; - public URI deriveEndpoint; } diff --git a/access-grant/src/test/java/com/inrupt/client/accessgrant/AccessGrantClientTest.java b/access-grant/src/test/java/com/inrupt/client/accessgrant/AccessGrantClientTest.java index 9feec403509..e977a10e072 100644 --- a/access-grant/src/test/java/com/inrupt/client/accessgrant/AccessGrantClientTest.java +++ b/access-grant/src/test/java/com/inrupt/client/accessgrant/AccessGrantClientTest.java @@ -33,10 +33,8 @@ import java.io.UncheckedIOException; import java.net.URI; import java.time.Instant; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -236,7 +234,7 @@ void testIssueRequest() { final URI recipient = URI.create("https://id.test/agent"); final Instant expiration = Instant.parse("2022-08-27T12:00:00Z"); - final Set modes = new HashSet<>(Arrays.asList("Read", "Append")); + final Set modes = Set.of("Read", "Append"); final Set purposes = Collections.singleton(URI.create("https://purpose.test/Purpose1")); final Set resources = Collections.singleton(URI.create("https://storage.test/data/")); @@ -264,7 +262,7 @@ void testIssueRequestBuilder() { final URI recipient = URI.create("https://id.test/agent"); final Instant expiration = Instant.parse("2022-08-27T12:00:00Z"); - final Set modes = new HashSet<>(Arrays.asList("Read", "Append")); + final Set modes = Set.of("Read", "Append"); final Set purposes = Collections.singleton(URI.create("https://purpose.test/Purpose1")); final Set resources = Collections.singleton(URI.create("https://storage.test/data/")); @@ -290,7 +288,7 @@ void testIssueRequestBuilder() { void testRequestAccessNoAuth() { final URI recipient = URI.create("https://id.test/agent"); final Instant expiration = Instant.parse("2022-08-27T12:00:00Z"); - final Set modes = new HashSet<>(Arrays.asList("Read", "Append")); + final Set modes = Set.of("Read", "Append"); final Set purposes = Collections.singleton(URI.create("https://purpose.test/Purpose1")); final Set resources = Collections.singleton(URI.create("https://storage.test/data/")); @@ -313,7 +311,7 @@ void testGrantAccess() { final URI recipient = URI.create("https://id.test/agent"); final Instant expiration = Instant.parse("2022-08-27T12:00:00Z"); - final Set modes = new HashSet<>(Arrays.asList("Read", "Append")); + final Set modes = Set.of("Read", "Append"); final Set purposes = Collections.singleton(URI.create("https://purpose.test/Purpose1")); final Set resources = Collections.singleton(URI.create("https://storage.test/data/")); @@ -343,7 +341,7 @@ void testDenyAccess() { final URI recipient = URI.create("https://id.test/agent"); final Instant expiration = Instant.parse("2022-09-12T12:00:00Z"); - final Set modes = new HashSet<>(Arrays.asList("Read", "Append")); + final Set modes = Set.of("Read", "Append"); final Set purposes = Collections.singleton(URI.create("https://purpose.test/Purpose1")); final Set resources = Collections.singleton(URI.create("https://storage.test/data/")); @@ -378,7 +376,7 @@ void testGrantAccessNoAuth() { final URI recipient = URI.create("https://id.test/agent"); final Instant expiration = Instant.parse("2022-08-27T12:00:00Z"); - final Set modes = new HashSet<>(Arrays.asList("Read", "Append")); + final Set modes = Set.of("Read", "Append"); final Set purposes = Collections.singleton(URI.create("https://purpose.test/Purpose1")); final Set resources = Collections.singleton(URI.create("https://storage.test/data/")); @@ -513,246 +511,6 @@ void testServerUnsupportedFilterQuery() { assertInstanceOf(AccessGrantException.class, err.getCause()); } - @Test - void testServerUnsupportedDeriveQuery() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient altAgClient = new AccessGrantClient(URIBuilder.newBuilder(baseUri).path("alternative") - .build()); - - final AccessGrantClient client = altAgClient.session(OpenIdSession.ofIdToken(token)); - - final URI resource = URI.create("https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/a/b/c"); - final AccessCredentialQuery query = AccessCredentialQuery.newBuilder() - .resource(resource).mode("Read").build(AccessGrant.class); - - final CompletionException err = assertThrows(CompletionException.class, - client.query(query).toCompletableFuture()::join); - assertInstanceOf(AccessGrantException.class, err.getCause()); - } - - @Test - void testQueryGrant() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final URI resource = URI.create("https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/a/b/c"); - final List grants = client.query(resource, null, null, null, "Read", AccessGrant.class) - .toCompletableFuture().join(); - assertEquals(4, grants.size()); - } - - @Test - void testQueryGrantBuilder() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final URI resource = URI.create("https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/a/b/c"); - final AccessCredentialQuery query = AccessCredentialQuery.newBuilder() - .resource(resource).mode("Read").build(AccessGrant.class); - final List grants = client.query(query).toCompletableFuture().join(); - assertEquals(4, grants.size()); - } - - @Test - void testQueryGrantRecipient() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final List grants = client.query(null, null, URI.create("https://id.test/user"), - null, "Read", AccessGrant.class).toCompletableFuture().join(); - assertEquals(1, grants.size()); - } - - @Test - void testQueryGrantCreator() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - // A query is always done with the agent making the query as the creator. - final List grants = client.query( - null, URI.create("https://id.test/user"), null, null, "Read", AccessGrant.class - ).toCompletableFuture().join(); - assertEquals(1, grants.size()); - } - - @Test - void testQueryGrantModesPurposesBuilder() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final AccessCredentialQuery query = AccessCredentialQuery.newBuilder() - .resource(URI.create("https://storage.example/")) - .mode("Read").mode("Write").purpose(URI.create("https://id.example/Purpose8")) - .purpose(URI.create("https://id.example/Purpose9")).build(AccessGrant.class); - final List grants = client.query(query).toCompletableFuture().join(); - assertEquals(1, grants.size()); - } - - @Test - void testQueryGrantModesPurposesNoMatchBuilder() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final AccessCredentialQuery query1 = AccessCredentialQuery.newBuilder() - .resource(URI.create("https://storage.example/")) - .mode("Read").mode(null).purpose(URI.create("https://id.example/Purpose8")) - .purpose(URI.create("https://id.example/Purpose9")).purpose(null).build(AccessGrant.class); - final List grants1 = client.query(query1).toCompletableFuture().join(); - assertEquals(0, grants1.size()); - - final AccessCredentialQuery query2 = AccessCredentialQuery.newBuilder() - .resource(URI.create("https://storage.example/")).mode("Read").mode("Write") - .purpose(URI.create("https://id.example/Purpose9")).build(AccessGrant.class); - final List grants2 = client.query(query2).toCompletableFuture().join(); - assertEquals(0, grants2.size()); - } - - @Test - void testQueryRequestRecipient() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final List requests = client.query(null, null, URI.create("https://id.test/user"), - null, "Read", AccessRequest.class).toCompletableFuture().join(); - assertEquals(1, requests.size()); - } - - @Test - void testQueryRequestRecipientBuilder() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final AccessCredentialQuery query = AccessCredentialQuery.newBuilder() - .recipient(URI.create("https://id.test/user")).mode("Read").build(AccessRequest.class); - final List requests = client.query(query).toCompletableFuture().join(); - assertEquals(1, requests.size()); - } - - @Test - void testQueryRequest() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final URI resource = URI.create("https://storage.example/f1759e6d-4dda-4401-be61-d90d070a5474/a/b/c"); - final List requests = client.query(resource, null, null, null, "Read", AccessRequest.class) - .toCompletableFuture().join(); - assertEquals(1, requests.size()); - } - - @Test - void testQueryRequestBuilder() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final URI resource = URI.create("https://storage.example/f1759e6d-4dda-4401-be61-d90d070a5474/a/b/c"); - final AccessCredentialQuery query = AccessCredentialQuery.newBuilder() - .resource(resource).mode("Read").build(AccessRequest.class); - final List requests = client.query(query).toCompletableFuture().join(); - assertEquals(1, requests.size()); - } - - @Test - void testQueryDenial() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final URI resource = URI.create("https://storage.example/ef9c4b90-0459-408d-bfa9-1c61d46e1eaf/e/f/g"); - final List grants = client.query(resource, null, null, null, "Read", AccessDenial.class) - .toCompletableFuture().join(); - assertEquals(1, grants.size()); - } - - @Test - void testQueryDenialBuilder() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final URI resource = URI.create("https://storage.example/ef9c4b90-0459-408d-bfa9-1c61d46e1eaf/e/f/g"); - final AccessCredentialQuery query = AccessCredentialQuery.newBuilder() - .resource(resource).mode("Read").build(AccessDenial.class); - final List grants = client.query(query).toCompletableFuture().join(); - assertEquals(1, grants.size()); - } - - @Test - void testQueryInvalidType() { - final Map claims = new HashMap<>(); - claims.put("webid", WEBID); - claims.put("sub", SUB); - claims.put("iss", ISS); - claims.put("azp", AZP); - final String token = generateIdToken(claims); - final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token)); - - final URI uri = URI.create("https://storage.example/f1759e6d-4dda-4401-be61-d90d070a5474/a/b/c"); - assertThrows(AccessGrantException.class, () -> - client.query(uri, null, null, null, "Read", AccessCredential.class)); - } - @Test void testParentUri() { final URI root = URI.create("https://storage.test/"); @@ -799,7 +557,7 @@ void checkAsUri() { final String uri = "https://example.com/"; assertNull(AccessGrantClient.asUri(null)); assertNull(AccessGrantClient.asUri(5)); - assertNull(AccessGrantClient.asUri(Arrays.asList(uri))); + assertNull(AccessGrantClient.asUri(List.of(uri))); assertEquals(URI.create(uri), AccessGrantClient.asUri(uri)); } diff --git a/access-grant/src/test/java/com/inrupt/client/accessgrant/MockAccessGrantServer.java b/access-grant/src/test/java/com/inrupt/client/accessgrant/MockAccessGrantServer.java index 370f98b9f89..dda3e6423a8 100644 --- a/access-grant/src/test/java/com/inrupt/client/accessgrant/MockAccessGrantServer.java +++ b/access-grant/src/test/java/com/inrupt/client/accessgrant/MockAccessGrantServer.java @@ -340,94 +340,6 @@ private void setupMocks() { .willReturn(aResponse() .withStatus(401) .withHeader("WWW-Authenticate", "Bearer,DPoP algs=\"ES256\""))); - - wireMockServer.stubFor(post(urlEqualTo("/derive")) - .atPriority(1) - .withHeader("Authorization", containing("Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.")) - .withRequestBody(containing("SolidAccessGrant")) - .withRequestBody(containing("\"https://id.example/Purpose8\"")) - .withRequestBody(containing("\"https://id.example/Purpose9\"")) - .withRequestBody(containing("\"Read\"")) - .withRequestBody(containing("\"Write\"")) - .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(getResource("/query_response7.json", wireMockServer.baseUrl())))); - - wireMockServer.stubFor(post(urlEqualTo("/derive")) - .atPriority(1) - .withHeader("Authorization", containing("Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.")) - .withRequestBody(containing("SolidAccessDenial")) - .withRequestBody(containing( - "\"https://storage.example/ef9c4b90-0459-408d-bfa9-1c61d46e1eaf/\"")) - .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(getResource("/query_response6.json", wireMockServer.baseUrl())))); - - wireMockServer.stubFor(post(urlEqualTo("/derive")) - .atPriority(1) - .withHeader("Authorization", containing("Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.")) - .withRequestBody(containing("SolidAccessRequest")) - .withRequestBody(containing( - "\"https://storage.example/f1759e6d-4dda-4401-be61-d90d070a5474/\"")) - .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(getResource("/query_response3.json", wireMockServer.baseUrl())))); - - wireMockServer.stubFor(post(urlEqualTo("/derive")) - .atPriority(1) - .withHeader("Authorization", containing("Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.")) - .withRequestBody(containing("SolidAccessGrant")) - .withRequestBody(containing( - "\"https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/\"")) - .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(getResource("/query_response1.json", wireMockServer.baseUrl())))); - - wireMockServer.stubFor(post(urlEqualTo("/derive")) - .atPriority(2) - .withHeader("Authorization", containing("Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.")) - .withRequestBody(containing("\"isProvidedTo\":\"https://id.test/user\"")) - .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(getResource("/query_response4.json", wireMockServer.baseUrl())))); - - wireMockServer.stubFor(post(urlEqualTo("/derive")) - .atPriority(2) - .withHeader("Authorization", containing("Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.")) - .withRequestBody(containing("\"isConsentForDataSubject\":\"https://id.test/user\"")) - .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(getResource("/query_response5.json", wireMockServer.baseUrl())))); - - wireMockServer.stubFor(post(urlEqualTo("/derive")) - .atPriority(2) - .withHeader("Authorization", containing("Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.")) - .withRequestBody(containing("\"id\":\"https://id.test/user\"")) - .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(getResource("/query_response4.json", wireMockServer.baseUrl())))); - - wireMockServer.stubFor(post(urlEqualTo("/derive")) - .atPriority(2) - .withHeader("Authorization", containing("Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.")) - .withRequestBody(containing("\"https://storage.example/")) - .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(getResource("/query_response2.json", wireMockServer.baseUrl())))); - - wireMockServer.stubFor(post(urlEqualTo("/derive")) - .atPriority(3) - .willReturn(aResponse() - .withStatus(401) - .withHeader("WWW-Authenticate", "Bearer,DPoP algs=\"ES256\""))); } private static String getResource(final String path) { diff --git a/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java b/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java index 29d37ef43e8..cf164129fb5 100644 --- a/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java +++ b/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java @@ -20,6 +20,7 @@ */ package com.inrupt.client.integration.base; +import static com.inrupt.client.accessgrant.CredentialFilter.CredentialStatus.ACTIVE; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assumptions.assumeFalse; @@ -41,9 +42,7 @@ import java.nio.charset.StandardCharsets; import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.UUID; import java.util.stream.Stream; @@ -225,10 +224,10 @@ void accessGrantIssuanceLifecycleTest(final Session resourceOwnerSession, final URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_READ)); + final Set modes = Set.of(GRANT_MODE_READ); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(sharedTextFileURI)), modes, PURPOSES, expiration) + Set.of(sharedTextFileURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( @@ -313,10 +312,10 @@ void accessGrantWithRequestOverridesTest(final Session resourceOwnerSession, fin URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_READ, GRANT_MODE_APPEND)); + final Set modes = Set.of(GRANT_MODE_READ, GRANT_MODE_APPEND); final Instant expiration = Instant.now().plus(90, ChronoUnit.DAYS); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(sharedTextFileURI)), modes, PURPOSES, expiration) + Set.of(sharedTextFileURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( @@ -345,10 +344,10 @@ void accessGrantQueryByRequesterTest(final Session resourceOwnerSession, final S URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND)); + final Set modes = Set.of(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(sharedTextFileURI)), modes, PURPOSES, expiration) + Set.of(sharedTextFileURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( @@ -357,18 +356,12 @@ void accessGrantQueryByRequesterTest(final Session resourceOwnerSession, final S final AccessGrant grant = resourceOwnerAccessGrantClient.grantAccess(request) .toCompletableFuture().join(); - final AccessCredentialQuery query = AccessCredentialQuery.newBuilder() - .recipient(URI.create(requesterWebidUrl)).resource(sharedTextFileURI) - .mode(GRANT_MODE_READ).mode(GRANT_MODE_WRITE).mode(GRANT_MODE_APPEND).build(AccessGrant.class); - final List grants = resourceOwnerAccessGrantClient.query(query).toCompletableFuture().join(); - assertEquals(1, grants.size()); - - final AccessCredentialQuery query2 = AccessCredentialQuery.newBuilder() - .recipient(URI.create("https://someuser.test")).resource(sharedTextFileURI).build(AccessGrant.class); - final List randomGrants = - resourceOwnerAccessGrantClient.query(query2).toCompletableFuture().join(); - - assertEquals(0, randomGrants.size()); + final CredentialFilter query = CredentialFilter.newBuilder().status(ACTIVE) + .toAgent(URI.create(requesterWebidUrl)).resource(sharedTextFileURI) + .build(AccessGrant.class); + final CredentialResult results = resourceOwnerAccessGrantClient.query(query) + .toCompletableFuture().join(); + assertEquals(1, results.getItems().size()); //cleanup assertDoesNotThrow(resourceOwnerAccessGrantClient.revoke(grant).toCompletableFuture()::join); @@ -385,10 +378,10 @@ void accessGrantGrantAccessByIdTest(final Session resourceOwnerSession, final Se URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_READ)); + final Set modes = Set.of(GRANT_MODE_READ); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(webidUrl), - new HashSet<>(Arrays.asList(sharedTextFileURI)), modes, PURPOSES, expiration) + Set.of(sharedTextFileURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final var grantId = request.getIdentifier(); @@ -424,13 +417,14 @@ void accessGrantGrantAccessByIdTest(final Session resourceOwnerSession, final Se AccessGrant.class).toCompletableFuture().join(); //check that the approved grant is the same we find when querying for all grants - final AccessCredentialQuery query = AccessCredentialQuery.newBuilder() - .recipient(URI.create(requesterWebidUrl)).resource(sharedTextFileURI) - .mode(GRANT_MODE_READ).build(AccessGrant.class); - final List grants = resourceOwnerAccessGrantClient.query(query).toCompletableFuture().join(); - assertEquals(1, grants.size()); - assertEquals(grant.getIdentifier(), grants.get(0).getIdentifier()); - assertEquals(accessGrant.getIdentifier(), grants.get(0).getIdentifier()); + final CredentialFilter query = CredentialFilter.newBuilder().status(ACTIVE) + .toAgent(URI.create(requesterWebidUrl)).resource(sharedTextFileURI) + .build(AccessGrant.class); + final CredentialResult results = resourceOwnerAccessGrantClient.query(query) + .toCompletableFuture().join(); + assertEquals(1, results.getItems().size()); + assertEquals(grant.getIdentifier(), results.getItems().get(0).getIdentifier()); + assertEquals(accessGrant.getIdentifier(), results.getItems().get(0).getIdentifier()); //cleanup assertDoesNotThrow(resourceOwnerAccessGrantClient.revoke(grant).toCompletableFuture()::join); @@ -447,10 +441,10 @@ void accessGrantQueryByPurposeTest(final Session resourceOwnerSession, final Ses URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_APPEND)); + final Set modes = Set.of(GRANT_MODE_APPEND); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(sharedTextFileURI)), modes, PURPOSES, expiration) + Set.of(sharedTextFileURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( @@ -460,17 +454,11 @@ void accessGrantQueryByPurposeTest(final Session resourceOwnerSession, final Ses .toCompletableFuture().join(); //query for all grants with a dedicated purpose - final AccessCredentialQuery query = AccessCredentialQuery.newBuilder() - .resource(sharedTextFileURI).purpose(PURPOSE1).mode(GRANT_MODE_APPEND).build(AccessGrant.class); - final List grants = resourceOwnerAccessGrantClient.query(query).toCompletableFuture().join(); - assertEquals(1, grants.size()); - - //query for all grants of dedicated purpose combinations - final AccessCredentialQuery query2 = AccessCredentialQuery.newBuilder() - .resource(sharedTextFileURI).purpose(PURPOSE1).mode(GRANT_MODE_WRITE).build(AccessGrant.class); - final List randomGrants = - resourceOwnerAccessGrantClient.query(query2).toCompletableFuture().join(); - assertEquals(0, randomGrants.size()); //our grant is actually a APPEND + final CredentialFilter query = CredentialFilter.newBuilder().status(ACTIVE) + .resource(sharedTextFileURI).purpose(PURPOSE1).build(AccessGrant.class); + final CredentialResult results = resourceOwnerAccessGrantClient.query(query) + .toCompletableFuture().join(); + assertEquals(1, results.getItems().size()); //cleanup assertDoesNotThrow(resourceOwnerAccessGrantClient.revoke(grant).toCompletableFuture()::join); @@ -501,10 +489,10 @@ void accessGrantGetRdfTest(final Session resourceOwnerSession, final Session req URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND)); + final Set modes = Set.of(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(testRDFresourceURI)), modes, PURPOSES, expiration) + Set.of(testRDFresourceURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( @@ -548,11 +536,10 @@ void accessGrantSetRdfTest(final Session resourceOwnerSession, final Session req URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList( - GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND)); + final Set modes = Set.of(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(testRDFresourceURI)), modes, PURPOSES, expiration) + Set.of(testRDFresourceURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( @@ -602,10 +589,10 @@ void accessGrantCreateRdfTest(final Session resourceOwnerSession, final Session URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND)); + final Set modes = Set.of(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(newTestFileURI)), modes, PURPOSES, expiration) + Set.of(newTestFileURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( @@ -652,10 +639,10 @@ void accessGrantGetNonRdfTest(final Session resourceOwnerSession, final Session URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND)); + final Set modes = Set.of(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(newTestFileURI)), modes, PURPOSES, expiration) + Set.of(newTestFileURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( @@ -701,10 +688,10 @@ void accessGrantSetNonRdfTest(final Session resourceOwnerSession, final Session URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND)); + final Set modes = Set.of(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(newTestFileURI)), modes, PURPOSES, expiration) + Set.of(newTestFileURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( @@ -757,10 +744,10 @@ void accessGrantCreateNonRdfTest(final Session resourceOwnerSession, final Sessi URI.create(ACCESS_GRANT_PROVIDER) ).session(requesterSession); - final Set modes = new HashSet<>(Arrays.asList(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND)); + final Set modes = Set.of(GRANT_MODE_READ, GRANT_MODE_WRITE, GRANT_MODE_APPEND); final Instant expiration = Instant.parse(GRANT_EXPIRATION); final AccessRequest request = requesterAccessGrantClient.requestAccess(URI.create(requesterWebidUrl), - new HashSet<>(Arrays.asList(newTestFileURI)), modes, PURPOSES, expiration) + Set.of(newTestFileURI), modes, PURPOSES, expiration) .toCompletableFuture().join(); final AccessGrantClient resourceOwnerAccessGrantClient = new AccessGrantClient( diff --git a/integration/base/src/main/java/com/inrupt/client/integration/base/MockAccessGrantServer.java b/integration/base/src/main/java/com/inrupt/client/integration/base/MockAccessGrantServer.java index 900c9c34b25..8c035c7ca47 100644 --- a/integration/base/src/main/java/com/inrupt/client/integration/base/MockAccessGrantServer.java +++ b/integration/base/src/main/java/com/inrupt/client/integration/base/MockAccessGrantServer.java @@ -43,13 +43,14 @@ class MockAccessGrantServer { private static final String USER_AGENT = "InruptJavaClient/" + Request.class .getPackage().getImplementationVersion(); private static final String DERIVE = "/derive"; + private static final String QUERY = "/query"; private static final String ISSUE = "/issue"; - private static final String VERIFY = "/verify"; private static final String HEADER_AUTHORIZATION = "Authorization"; private static final String SCHEME_BEARER = "Bearer"; + private static final String SOLID_ACCESS_GRANT = "SolidAccessGrant"; // An identifier to enable statefulness in Wiremock, useful to manage revocation and verification. private static final String SCENARIO_ACCESS_GRANT = "AccessGrant"; @@ -225,6 +226,37 @@ private void setupMocks() { .willReturn(aResponse() .withStatus(Utils.NO_CONTENT))); + wireMockServer.stubFor(get(urlPathEqualTo(QUERY)) + .atPriority(1) + .withQueryParam("type", equalTo(SOLID_ACCESS_GRANT)) + .withQueryParam("resource", equalTo(this.sharedResource)) + .withQueryParam("purpose", equalTo(purpose.toString())) + .withHeader(USER_AGENT_HEADER, equalTo(USER_AGENT)) + .willReturn(aResponse() + .withStatus(Utils.SUCCESS) + .withHeader(Utils.CONTENT_TYPE, Utils.APPLICATION_JSON) + .withBody(getResource("/query_endpoint_response.json", wireMockServer.baseUrl(), + this.requesterWebId, this.ownerWebId, this.sharedResource)))); + + wireMockServer.stubFor(get(urlPathEqualTo(QUERY)) + .atPriority(2) + .withQueryParam("type", equalTo(SOLID_ACCESS_GRANT)) + .withQueryParam("resource", equalTo(this.sharedResource)) + .withHeader(USER_AGENT_HEADER, equalTo(USER_AGENT)) + .willReturn(aResponse() + .withStatus(Utils.SUCCESS) + .withHeader(Utils.CONTENT_TYPE, Utils.APPLICATION_JSON) + .withBody(getResource("/query_endpoint_response.json", wireMockServer.baseUrl(), + this.requesterWebId, this.ownerWebId, this.sharedResource)))); + + wireMockServer.stubFor(get(urlPathEqualTo(QUERY)) + .atPriority(3) + .withHeader(USER_AGENT_HEADER, equalTo(USER_AGENT)) + .willReturn(aResponse() + .withStatus(Utils.SUCCESS) + .withHeader(Utils.CONTENT_TYPE, Utils.APPLICATION_JSON) + .withBody(getResource("/query_endpoint_response_empty.json")))); + wireMockServer.stubFor(post(urlEqualTo(DERIVE)) .atPriority(1) .withHeader(USER_AGENT_HEADER, equalTo(USER_AGENT)) diff --git a/integration/base/src/main/resources/query_endpoint_response.json b/integration/base/src/main/resources/query_endpoint_response.json new file mode 100644 index 00000000000..255db3217d8 --- /dev/null +++ b/integration/base/src/main/resources/query_endpoint_response.json @@ -0,0 +1,36 @@ +{ + "items": [{ + "@context":[ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/ed25519-2020/v1", + "https://w3id.org/vc-revocation-list-2020/v1", + "https://schema.inrupt.com/credentials/v1.jsonld"], + "id":"{{baseUrl}}/vc-grant", + "type":["VerifiableCredential","SolidAccessGrant"], + "issuer":"{{baseUrl}}", + "expirationDate":"2024-08-27T12:00:00Z", + "issuanceDate":"2022-08-25T20:34:05.153Z", + "credentialStatus":{ + "id":"https://accessgrant.example/status/CVAM#2832", + "revocationListCredential":"https://accessgrant.example/status/CVAM", + "revocationListIndex":"2832", + "type":"RevocationList2020Status"}, + "credentialSubject":{ + "id":"{{ownerWebId}}", + "providedConsent":{ + "mode":["Read","Append"], + "hasStatus":"https://w3id.org/GConsent#ConsentStatusExplicitlyGiven", + "isProvidedTo":"{{requesterWebId}}", + "forPurpose":["https://purpose.example/Purpose1"], + "forPersonalData":["{{sharedFile}}"]}}, + "proof":{ + "created":"2022-08-25T20:34:05.236Z", + "proofPurpose":"assertionMethod", + "proofValue":"nIeQF44XVik7onnAbdkbp8xxJ2C8JoTw6-VtCkAzxuWYRFsSfYpft5MuAJaivyeKDmaK82Lj_YsME2xgL2WIBQ", + "type":"Ed25519Signature2020", + "verificationMethod":"https://accessgrant.example/key/1e332728-4af5-46e4-a5db-4f7b89e3f378"} + }], + "summary": { + "total": 1 + } +} diff --git a/integration/base/src/main/resources/query_endpoint_response_empty.json b/integration/base/src/main/resources/query_endpoint_response_empty.json new file mode 100644 index 00000000000..a1441d94816 --- /dev/null +++ b/integration/base/src/main/resources/query_endpoint_response_empty.json @@ -0,0 +1,6 @@ +{ + "items": [], + "summary": { + "total": 0 + } +} diff --git a/integration/base/src/main/resources/query_response.json b/integration/base/src/main/resources/query_response.json index f97ee47155c..9d411c6355d 100644 --- a/integration/base/src/main/resources/query_response.json +++ b/integration/base/src/main/resources/query_response.json @@ -30,4 +30,4 @@ "type":"Ed25519Signature2020", "verificationMethod":"https://accessgrant.example/key/1e332728-4af5-46e4-a5db-4f7b89e3f378"} }] -} \ No newline at end of file +} diff --git a/integration/base/src/main/resources/query_response_empty.json b/integration/base/src/main/resources/query_response_empty.json index 0ea0f73ccdf..d19d57ed7f3 100644 --- a/integration/base/src/main/resources/query_response_empty.json +++ b/integration/base/src/main/resources/query_response_empty.json @@ -1,4 +1,37 @@ { - "verifiableCredential": [] + "items": [{ + "@context":[ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/ed25519-2020/v1", + "https://w3id.org/vc-revocation-list-2020/v1", + "https://schema.inrupt.com/credentials/v1.jsonld"], + "id":"{{baseUrl}}/vc-grant", + "type":["VerifiableCredential","SolidAccessGrant"], + "issuer":"{{baseUrl}}", + "expirationDate":"2024-08-27T12:00:00Z", + "issuanceDate":"2022-08-25T20:34:05.153Z", + "credentialStatus":{ + "id":"https://accessgrant.example/status/CVAM#2832", + "revocationListCredential":"https://accessgrant.example/status/CVAM", + "revocationListIndex":"2832", + "type":"RevocationList2020Status"}, + "credentialSubject":{ + "id":"{{ownerWebId}}", + "providedConsent":{ + "mode":["Read","Append"], + "hasStatus":"https://w3id.org/GConsent#ConsentStatusExplicitlyGiven", + "isProvidedTo":"{{requesterWebId}}", + "forPurpose":["https://purpose.example/Purpose1"], + "forPersonalData":["{{sharedFile}}"]}}, + "proof":{ + "created":"2022-08-25T20:34:05.236Z", + "proofPurpose":"assertionMethod", + "proofValue":"nIeQF44XVik7onnAbdkbp8xxJ2C8JoTw6-VtCkAzxuWYRFsSfYpft5MuAJaivyeKDmaK82Lj_YsME2xgL2WIBQ", + "type":"Ed25519Signature2020", + "verificationMethod":"https://accessgrant.example/key/1e332728-4af5-46e4-a5db-4f7b89e3f378"} + }], + "summary": { + "total": 3 + } } diff --git a/integration/base/src/main/resources/vc-configuration.json b/integration/base/src/main/resources/vc-configuration.json index 4a8398cdfe7..b9ac9c58582 100644 --- a/integration/base/src/main/resources/vc-configuration.json +++ b/integration/base/src/main/resources/vc-configuration.json @@ -9,5 +9,6 @@ "supportedSignatureTypes": [ "Ed25519Signature2020" ], - "verifierService": "{{baseUrl}}/verify" + "verifierService": "{{baseUrl}}/verify", + "queryService": "{{baseUrl}}/query" } diff --git a/solid/src/main/java/com/inrupt/client/solid/SolidClient.java b/solid/src/main/java/com/inrupt/client/solid/SolidClient.java index 1370e30c47e..736f1f39a11 100644 --- a/solid/src/main/java/com/inrupt/client/solid/SolidClient.java +++ b/solid/src/main/java/com/inrupt/client/solid/SolidClient.java @@ -406,16 +406,6 @@ static T construct(final URI identifier, final Class cla // no-op } - // Next, try an arity-3 ctor with metadata - // TODO: this construct is deprecated and can be removed in a future version - try { - final Metadata metadata = Metadata.of(identifier, headers); - return clazz.getConstructor(URI.class, Dataset.class, Metadata.class) - .newInstance(identifier, dataset, metadata); - } catch (final NoSuchMethodException ex) { - // no-op - } - // Fall back to an arity-2 ctor return clazz.getConstructor(URI.class, Dataset.class) .newInstance(identifier, dataset); @@ -432,16 +422,6 @@ static T construct(final URI identifier, final Class cla // no-op } - // Next try an arity-4 ctor with metadata - // TODO: this construct is deprecated and can be removed in a future version - try { - final Metadata metadata = Metadata.of(identifier, headers); - return clazz.getConstructor(URI.class, String.class, InputStream.class, Metadata.class) - .newInstance(identifier, contentType, entity, metadata); - } catch (final NoSuchMethodException ex) { - // no-op - } - // Fall back to an arity-3 ctor return clazz.getConstructor(URI.class, String.class, InputStream.class) .newInstance(identifier, contentType, entity); diff --git a/solid/src/main/java/com/inrupt/client/solid/SolidContainer.java b/solid/src/main/java/com/inrupt/client/solid/SolidContainer.java index a09c98823f4..58343e6c18d 100644 --- a/solid/src/main/java/com/inrupt/client/solid/SolidContainer.java +++ b/solid/src/main/java/com/inrupt/client/solid/SolidContainer.java @@ -66,19 +66,6 @@ public SolidContainer(final URI identifier, final Dataset dataset) { this(identifier, dataset, (Headers) null); } - /** - * Create a new SolidContainer. - * - * @param identifier the container's unique identifier - * @param dataset the dataset for this container, may be {@code null} - * @param metadata the container's metadata, may be {@code null} - * @deprecated use {@link #SolidContainer(URI, Dataset, Headers)} instead - */ - @Deprecated - public SolidContainer(final URI identifier, final Dataset dataset, final Metadata metadata) { - super(identifier, dataset, metadata); - } - /** * Create a new SolidContainer. * diff --git a/solid/src/main/java/com/inrupt/client/solid/SolidNonRDFSource.java b/solid/src/main/java/com/inrupt/client/solid/SolidNonRDFSource.java index 66b805bbf5c..58e4759786c 100644 --- a/solid/src/main/java/com/inrupt/client/solid/SolidNonRDFSource.java +++ b/solid/src/main/java/com/inrupt/client/solid/SolidNonRDFSource.java @@ -44,26 +44,6 @@ public SolidNonRDFSource(final URI identifier, final String contentType, final I this(identifier, contentType, entity, (Headers) null); } - /** - * Create a non-RDF-bearing Solid Resource. - * - * @param identifier the resource identifier - * @param contentType the content type - * @param entity the entity - * @param metadata the metadata, may be {@code null} - * @deprecated use {@link #SolidNonRDFSource(URI, String, InputStream, Headers)} instead - */ - @Deprecated - public SolidNonRDFSource(final URI identifier, final String contentType, final InputStream entity, - final Metadata metadata) { - super(identifier, contentType, entity); - if (metadata == null) { - this.metadata = Metadata.newBuilder().build(); - } else { - this.metadata = metadata; - } - } - /** * Create a non-RDF-bearing Solid Resource. * diff --git a/solid/src/main/java/com/inrupt/client/solid/SolidRDFSource.java b/solid/src/main/java/com/inrupt/client/solid/SolidRDFSource.java index 2d2503ea7fa..b10b9cd3795 100644 --- a/solid/src/main/java/com/inrupt/client/solid/SolidRDFSource.java +++ b/solid/src/main/java/com/inrupt/client/solid/SolidRDFSource.java @@ -53,24 +53,6 @@ public SolidRDFSource(final URI identifier, final Dataset dataset) { this(identifier, dataset, (Headers) null); } - /** - * Create a Solid resource. - * - * @param identifier the Solid Resource identifier - * @param dataset the resource dataset, may be {@code null} - * @param metadata metadata associated with this resource, may be {@code null} - * @deprecated use {@link #SolidRDFSource(URI, Dataset, Headers)} instead - */ - @Deprecated - public SolidRDFSource(final URI identifier, final Dataset dataset, final Metadata metadata) { - super(identifier, dataset); - if (metadata == null) { - this.metadata = Metadata.newBuilder().build(); - } else { - this.metadata = metadata; - } - } - /** * Create a Solid resource. * diff --git a/solid/src/test/java/com/inrupt/client/solid/DeprecatedBinary.java b/solid/src/test/java/com/inrupt/client/solid/DeprecatedBinary.java deleted file mode 100644 index 08d46762a8c..00000000000 --- a/solid/src/test/java/com/inrupt/client/solid/DeprecatedBinary.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Inrupt Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.inrupt.client.solid; - -import java.io.InputStream; -import java.net.URI; - -public class DeprecatedBinary extends SolidNonRDFSource { - public DeprecatedBinary(final URI identifier, final String contentType, final InputStream entity, - final Metadata metadata) { - super(identifier, contentType, entity, metadata); - } -} diff --git a/solid/src/test/java/com/inrupt/client/solid/DeprecatedType.java b/solid/src/test/java/com/inrupt/client/solid/DeprecatedType.java deleted file mode 100644 index 2390f5ddb8b..00000000000 --- a/solid/src/test/java/com/inrupt/client/solid/DeprecatedType.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright Inrupt Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.inrupt.client.solid; - -import com.inrupt.rdf.wrapping.commons.TermMappings; -import com.inrupt.rdf.wrapping.commons.ValueMappings; -import com.inrupt.rdf.wrapping.commons.WrapperIRI; - -import java.net.URI; -import java.util.Set; - -import org.apache.commons.rdf.api.Dataset; -import org.apache.commons.rdf.api.Graph; -import org.apache.commons.rdf.api.IRI; -import org.apache.commons.rdf.api.RDFTerm; - -public class DeprecatedType extends SolidRDFSource { - - private final IRI dcTitle; - private final IRI exIngredient; - private final IRI exStep; - private final Node subject; - - public DeprecatedType(final URI identifier, final Dataset dataset, final Metadata metadata) { - super(identifier, dataset, metadata); - - this.subject = new Node(rdf.createIRI(identifier.toString()), getGraph()); - this.dcTitle = rdf.createIRI("http://purl.org/dc/terms/title"); - this.exStep = rdf.createIRI("https://example.com/step"); - this.exIngredient = rdf.createIRI("https://example.com/ingredient"); - } - - public String getTitle() { - return subject.getTitle(); - } - - public void setTitle(final String value) { - subject.setTitle(value); - } - - public Set getIngredients() { - return subject.getIngredients(); - } - - public Set getSteps() { - return subject.getSteps(); - } - - class Node extends WrapperIRI { - - Node(final RDFTerm original, final Graph graph) { - super(original, graph); - } - - String getTitle() { - return anyOrNull(dcTitle, ValueMappings::literalAsString); - } - - void setTitle(final String value) { - overwriteNullable(dcTitle, value, TermMappings::asStringLiteral); - } - - Set getIngredients() { - return objects(exIngredient, TermMappings::asStringLiteral, ValueMappings::literalAsString); - } - - Set getSteps() { - return objects(exStep, TermMappings::asStringLiteral, ValueMappings::literalAsString); - } - } -} - diff --git a/solid/src/test/java/com/inrupt/client/solid/SolidClientTest.java b/solid/src/test/java/com/inrupt/client/solid/SolidClientTest.java index 292552cb660..52e096b4537 100644 --- a/solid/src/test/java/com/inrupt/client/solid/SolidClientTest.java +++ b/solid/src/test/java/com/inrupt/client/solid/SolidClientTest.java @@ -219,20 +219,6 @@ void testGetContainer() throws IOException, InterruptedException { } - @Test - void testGetDeprecatedBinaryFetch() { - final URI uri = URI.create(config.get("solid_resource_uri") + "/binary"); - - client.read(uri, DeprecatedBinary.class).thenAccept(binary -> { - try (final DeprecatedBinary b = binary) { - assertEquals(uri, b.getIdentifier()); - assertEquals(TEXT_PLAIN, b.getContentType()); - - assertTrue(b.getHeaders().asMap().isEmpty()); - } - }).toCompletableFuture().join(); - } - @Test void testGetBinaryFetch() { final URI uri = URI.create(config.get("solid_resource_uri") + "/binary"); @@ -347,22 +333,6 @@ void testGetRecipeType() { .toCompletableFuture().join(); } - @Test - void testGetDeprecatedType() { - final URI uri = URI.create(config.get("solid_resource_uri") + "/recipe"); - - client.read(uri, DeprecatedType.class).thenAccept(recipe -> { - try (final DeprecatedType r = recipe) { - assertEquals(uri, r.getIdentifier()); - assertEquals("Molasses Cookies", r.getTitle()); - assertEquals(11, r.getIngredients().size()); - assertEquals(7, r.getSteps().size()); - assertFalse(r.getHeaders().firstValue("allow").isPresent()); - } - }) - .toCompletableFuture().join(); - } - @ParameterizedTest @MethodSource void testExceptionalResources(