Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@
AccessGrantClient client = new AccessGrantClient(issuer).session(session);

URI resource = URI.create("https://storage.example/data/resource");
client.query(null, resource, null, AccessGrant.class)
URI purpose = URI.create("https://purpose.example/1");
client.query(null, resource, purpose, "Read", AccessGrant.class)
.thenApply(grants -> AccessGrantSession.ofAccessGrant(openid, grants.toArray(new AccessGrant[0])))
.thenApply(session -> SolidClient.getClient().session(session))
.thenAccept(cl -> {
Expand Down Expand Up @@ -378,12 +379,13 @@ public CompletionStage<AccessCredentialVerification> verify(final AccessCredenti
* @param <T> the AccessCredential type
* @param agent the agent identifier, may be {@code null}
* @param resource the resource identifier, 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 Grants
*/
public <T extends AccessCredential> CompletionStage<List<T>> query(final URI agent, final URI resource,
final String mode, final Class<T> clazz) {
final URI purpose, final String mode, final Class<T> clazz) {
Objects.requireNonNull(clazz, "The clazz parameter must not be null!");

final URI type;
Expand All @@ -403,7 +405,7 @@ public <T extends AccessCredential> CompletionStage<List<T>> query(final URI age

return v1Metadata().thenCompose(metadata -> {
final List<CompletableFuture<List<T>>> futures = buildQuery(config.getIssuer(), type,
agent, resource, mode).stream()
agent, resource, purpose, mode).stream()
.map(data -> Request.newBuilder(metadata.queryEndpoint)
.header(CONTENT_TYPE, APPLICATION_JSON)
.POST(Request.BodyPublishers.ofByteArray(serialize(data))).build())
Expand Down Expand Up @@ -449,7 +451,7 @@ public CompletionStage<List<AccessGrant>> query(final URI type, final URI agent,
Objects.requireNonNull(type, "The type parameter must not be null!");
return v1Metadata().thenCompose(metadata -> {
final List<CompletableFuture<List<AccessGrant>>> futures = buildQuery(config.getIssuer(), type,
agent, resource, mode).stream()
agent, resource, null, mode).stream()
.map(data -> Request.newBuilder(metadata.queryEndpoint)
.header(CONTENT_TYPE, APPLICATION_JSON)
.POST(Request.BodyPublishers.ofByteArray(serialize(data))).build())
Expand Down Expand Up @@ -680,14 +682,14 @@ static Collection<Object> getCredentials(final Map<String, Object> data) {
}

static List<Map<String, Object>> buildQuery(final URI issuer, final URI type, final URI agent, final URI resource,
final String mode) {
final URI purpose, final String mode) {
final List<Map<String, Object>> queries = new ArrayList<>();
buildQuery(queries, issuer, type, agent, resource, mode);
buildQuery(queries, issuer, type, agent, resource, purpose, mode);
return queries;
}

static void buildQuery(final List<Map<String, Object>> queries, final URI issuer, final URI type, final URI agent,
final URI resource, final String mode) {
final URI resource, final URI purpose, final String mode) {
final Map<String, Object> credential = new HashMap<>();
credential.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI, INRUPT_CONTEXT_URI));
credential.put("issuer", issuer);
Expand All @@ -704,6 +706,9 @@ static void buildQuery(final List<Map<String, Object>> queries, final URI issuer
if (resource != null) {
consent.put(FOR_PERSONAL_DATA, resource);
}
if (purpose != null) {
consent.put(FOR_PURPOSE, purpose);
}
if (mode != null) {
consent.put(MODE, mode);
}
Expand All @@ -726,7 +731,7 @@ static void buildQuery(final List<Map<String, Object>> queries, final URI issuer
// Recurse
final URI parent = getParent(resource);
if (parent != null) {
buildQuery(queries, issuer, type, agent, parent, mode);
buildQuery(queries, issuer, type, agent, parent, purpose, mode);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ void testQueryGrant() {
final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));

final List<AccessGrant> grants = client.query(null,
URI.create("https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/a/b/c"), "Read",
URI.create("https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/a/b/c"), null, "Read",
AccessGrant.class)
.toCompletableFuture().join();
assertEquals(1, grants.size());
Expand All @@ -526,7 +526,7 @@ void testQueryGrantAgent() {
final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));

final List<AccessGrant> grants = client.query(URI.create("https://id.test/user"),
null, "Read", AccessGrant.class)
null, null, "Read", AccessGrant.class)
.toCompletableFuture().join();
assertEquals(1, grants.size());
}
Expand All @@ -542,7 +542,7 @@ void testQueryRequestAgent() {
final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));

final List<AccessRequest> requests = client.query(URI.create("https://id.test/user"),
null, "Read", AccessRequest.class)
null, null, "Read", AccessRequest.class)
.toCompletableFuture().join();
assertEquals(1, requests.size());
}
Expand All @@ -558,7 +558,7 @@ void testQueryRequest() {
final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));

final List<AccessRequest> requests = client.query(null,
URI.create("https://storage.example/f1759e6d-4dda-4401-be61-d90d070a5474/a/b/c"), "Read",
URI.create("https://storage.example/f1759e6d-4dda-4401-be61-d90d070a5474/a/b/c"), null, "Read",
AccessRequest.class)
.toCompletableFuture().join();
assertEquals(1, requests.size());
Expand All @@ -575,7 +575,7 @@ void testQueryDenial() {
final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));

final List<AccessDenial> grants = client.query(null,
URI.create("https://storage.example/ef9c4b90-0459-408d-bfa9-1c61d46e1eaf/e/f/g"), "Read",
URI.create("https://storage.example/ef9c4b90-0459-408d-bfa9-1c61d46e1eaf/e/f/g"), null, "Read",
AccessDenial.class)
.toCompletableFuture().join();
assertEquals(1, grants.size());
Expand All @@ -592,14 +592,14 @@ void testQueryInvalidType() {
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(null, uri, "Read", AccessCredential.class));
assertThrows(AccessGrantException.class, () -> client.query(null, uri, null, "Read", AccessCredential.class));
}


@Test
void testQueryInvalidAuth() {
final CompletionException err = assertThrows(CompletionException.class,
agClient.query(URI.create("SolidAccessGrant"), (URI) null, (URI) null, null)
agClient.query(URI.create("SolidAccessGrant"), null, null, null)
.toCompletableFuture()::join);

assertInstanceOf(AccessGrantException.class, err.getCause());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ public class AccessGrantScenarios {
private static final String GRANT_MODE_READ = "Read";
private static final String GRANT_MODE_APPEND = "Append";
private static final String GRANT_MODE_WRITE = "Write";
private static final Set<URI> PURPOSES = new HashSet<>(Arrays.asList(
URI.create("https://some.purpose/not-a-nefarious-one/i-promise"),
URI.create("https://some.other.purpose/")));
private static final URI PURPOSE1 = URI.create("https://purpose.example/212efdf4-e1a4-4dcd-9d3b-d6eb92e0205f");
private static final URI PURPOSE2 = URI.create("https://purpose.example/de605b08-76c7-4f04-9cec-a438810b0c03");
private static final Set<URI> PURPOSES = new HashSet<>(Arrays.asList(PURPOSE1, PURPOSE2));
private static final String GRANT_EXPIRATION = "2024-04-03T12:00:00Z";

private static URI testContainerURI;
Expand Down Expand Up @@ -316,7 +316,7 @@ void accessGrantQueryByRequestorTest(final Session session) {

//query for all grants issued by the user
final List<AccessRequest> grants = accessGrantClient.query(URI.create(webidUrl),
sharedTextFileURI, GRANT_MODE_READ, AccessRequest.class)
sharedTextFileURI, PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
.toCompletableFuture().join();
// result is 4 because we retrieve the grants for each path
// sharedTextFileURI =
Expand All @@ -325,7 +325,7 @@ void accessGrantQueryByRequestorTest(final Session session) {

//query for all grants issued by a random user
final List<AccessRequest> randomGrants = accessGrantClient.query(URI.create("https://someuser.test"),
sharedTextFileURI, GRANT_MODE_READ, AccessRequest.class)
sharedTextFileURI, PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
.toCompletableFuture().join();
assertEquals(0, randomGrants.size());
}
Expand All @@ -340,13 +340,13 @@ void accessGrantQueryByResourceTest(final Session session) {

//query for all grants of a dedicated resource
final List<AccessRequest> requests = accessGrantClient.query(URI.create(webidUrl),
sharedTextFileURI, GRANT_MODE_READ, AccessRequest.class)
sharedTextFileURI, PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
.toCompletableFuture().join();
assertEquals(1, requests.size());

//query for all grants of a random resource
final List<AccessRequest> randomGrants = accessGrantClient.query(URI.create(webidUrl),
URI.create("https://somerandom.test"), GRANT_MODE_READ, AccessRequest.class)
URI.create("https://somerandom.test"), PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
.toCompletableFuture().join();
assertEquals(0, randomGrants.size());
}
Expand All @@ -359,15 +359,16 @@ void accessGrantQueryByPurposeTest(final Session session) {

final AccessGrantClient accessGrantClient = new AccessGrantClient(URI.create(VC_PROVIDER)).session(session);

//query for all grants of existent purposes
//query for all grants with a dedicated purpose
final List<AccessRequest> requests = accessGrantClient.query(URI.create(webidUrl),
sharedTextFileURI, GRANT_MODE_READ, AccessRequest.class)
sharedTextFileURI, PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
.toCompletableFuture().join();
assertEquals(1, requests.size());

//query for all grants of dedicated purpose combinations
//query for all grants of an unsupported purpose
final URI purpose = URI.create("https://example.com/12");
final List<AccessRequest> randomGrants = accessGrantClient.query(URI.create(webidUrl),
sharedTextFileURI, GRANT_MODE_WRITE, AccessRequest.class)
sharedTextFileURI, purpose, GRANT_MODE_READ, AccessRequest.class)
.toCompletableFuture().join();
assertEquals(0, randomGrants.size()); //our grant is actually a Read
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ private void setupMocks() {
wireMockServer.stubFor(post(urlEqualTo(DERIVE))
.atPriority(1)
.withRequestBody(containing("\"Read\""))
.withRequestBody(containing("\"https://purpose.example/212efdf4-e1a4-4dcd-9d3b-d6eb92e0205f\""))
.withRequestBody(containing("\"" + this.webId + "\""))
.withRequestBody(containing("\"" + this.sharedFile + "\""))
.willReturn(aResponse()
Expand Down
4 changes: 3 additions & 1 deletion integration/base/src/main/resources/query_response.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
"mode":["Read"],
"hasStatus":"https://w3id.org/GConsent#ConsentStatusRequested",
"isProvidedToPerson":"{{webId}}",
"forPurpose":["https://some.purpose/not-a-nefarious-one/i-promise", "https://some.other.purpose/"],
"forPurpose":[
"https://purpose.example/212efdf4-e1a4-4dcd-9d3b-d6eb92e0205f",
"https://purpose.example/de605b08-76c7-4f04-9cec-a438810b0c03"],
"forPersonalData":["{{sharedFile}}"]}},
"proof":{
"created":"2022-08-25T20:34:05.236Z",
Expand Down
4 changes: 3 additions & 1 deletion integration/base/src/main/resources/vc-grant.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"mode":["Read"],
"hasStatus":"https://w3id.org/GConsent#ConsentStatusExplicitlyGiven",
"isProvidedToPerson":"{{webId}}",
"forPurpose":["https://purpose.example/1", "https://purpose.example/2"],
"forPurpose":[
"https://purpose.example/212efdf4-e1a4-4dcd-9d3b-d6eb92e0205f",
"https://purpose.example/de605b08-76c7-4f04-9cec-a438810b0c03"],
"forPersonalData":["{{sharedFile}}"]}},
"proof":{
"created":"2022-08-25T20:34:05.236Z",
Expand Down
4 changes: 3 additions & 1 deletion integration/base/src/main/resources/vc-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"mode":["Read"],
"hasStatus":"https://w3id.org/GConsent#ConsentStatusRequested",
"isConsentForDataSubject":"{{webId}}",
"forPurpose":["https://some.purpose/not-a-nefarious-one/i-promise", "https://some.other.purpose/"],
"forPurpose":[
"https://purpose.example/212efdf4-e1a4-4dcd-9d3b-d6eb92e0205f",
"https://purpose.example/de605b08-76c7-4f04-9cec-a438810b0c03"],
"forPersonalData":["{{sharedFile}}"]}},
"proof":{
"created":"2022-08-25T20:34:05.236Z",
Expand Down