diff --git a/acp/README.md b/acp/README.md index 3fedb5a274..0f73662dd9 100644 --- a/acp/README.md +++ b/acp/README.md @@ -631,7 +631,8 @@ Result: Error: document not found or not authorized to access ``` -Sometimes we might want to give a specific access (form a relationship) not just to one identity, but any identity. +Sometimes we might want to give a specific access (i.e. form a relationship) not just with one identity, but with +any identity (includes even requests with no-identity). In that case we can specify "*" instead of specifying an explicit `actor`: ```sh defradb client acp relationship add \ diff --git a/internal/db/permission/check.go b/internal/db/permission/check.go index ce111bccaf..599329855b 100644 --- a/internal/db/permission/check.go +++ b/internal/db/permission/check.go @@ -67,18 +67,22 @@ func CheckAccessOfDocOnCollectionWithACP( return true, nil } - // At this point if the request is not signatured, then it has no access, because: - // the collection has a policy on it, and the acp is enabled/available, - // and the document is not public (is registered with acp). + var identityValue string if !identity.HasValue() { - return false, nil + // We can't assume that there is no-access just because there is no identity even if the document + // is registered with acp, this is because it is possible that acp has a registered relation targeting + // "*" (any) actor which would mean that even a request without an identity might be able to access + // a document registered with acp. So we pass an empty `did` to accommodate that case. + identityValue = "" + } else { + identityValue = identity.Value().DID } // Now actually check using the signature if this identity has access or not. hasAccess, err := acpSystem.CheckDocAccess( ctx, permission, - identity.Value().DID, + identityValue, policyID, resourceName, docID, diff --git a/tests/integration/acp/relationship/doc_actor/add/with_manager_gql_test.go b/tests/integration/acp/relationship/doc_actor/add/with_manager_gql_test.go index 757053f365..813294a7fd 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_manager_gql_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_manager_gql_test.go @@ -26,10 +26,13 @@ func TestACP_OwnerMakesAManagerThatGivesItSelfReadAndWriteAccess_GQL_ManagerCanR Description: "Test acp, owner makes a manager that gives itself read and write access", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - // GQL mutation will return no error when wrong identity is used so test that separately. - testUtils.GQLRequestMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used (only for update requests), + // so test that separately. + testUtils.GQLRequestMutationType, + }, + ), Actions: []any{ testUtils.AddPolicy{ @@ -274,10 +277,13 @@ func TestACP_OwnerMakesManagerButManagerCanNotPerformOperations_GQL_ManagerCantR Description: "Test acp, owner makes a manager, manager can't read or write", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - // GQL mutation will return no error when wrong identity is used so test that separately. - testUtils.GQLRequestMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used (only for update requests), + // so test that separately. + testUtils.GQLRequestMutationType, + }, + ), Actions: []any{ testUtils.AddPolicy{ @@ -442,10 +448,13 @@ func TestACP_ManagerAddsRelationshipWithRelationItDoesNotManageAccordingToPolicy Description: "Test acp, manager adds relationship with relation it does not manage according to policy, error", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - // GQL mutation will return no error when wrong identity is used so test that separately. - testUtils.GQLRequestMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used (only for update requests), + // so test that separately. + testUtils.GQLRequestMutationType, + }, + ), Actions: []any{ testUtils.AddPolicy{ diff --git a/tests/integration/acp/relationship/doc_actor/add/with_manager_test.go b/tests/integration/acp/relationship/doc_actor/add/with_manager_test.go index 485c130805..0b972acf8e 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_manager_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_manager_test.go @@ -601,10 +601,12 @@ func TestACP_OwnerMakesAManagerThatGivesItSelfReadAndWriteAccess_ManagerCanReadA Description: "Test acp, owner makes a manager that gives itself read and write access", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - testUtils.CollectionNamedMutationType, - testUtils.CollectionSaveMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used with gql (only for update requests), + testUtils.CollectionNamedMutationType, + testUtils.CollectionSaveMutationType, + }), Actions: []any{ testUtils.AddPolicy{ @@ -849,10 +851,12 @@ func TestACP_ManagerAddsRelationshipWithRelationItDoesNotManageAccordingToPolicy Description: "Test acp, manager adds relationship with relation it does not manage according to policy, error", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - testUtils.CollectionNamedMutationType, - testUtils.CollectionSaveMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used with gql (only for update requests), + testUtils.CollectionNamedMutationType, + testUtils.CollectionSaveMutationType, + }), Actions: []any{ testUtils.AddPolicy{ @@ -1017,10 +1021,12 @@ func TestACP_OwnerMakesManagerButManagerCanNotPerformOperations_ManagerCantReadO Description: "Test acp, owner makes a manager, manager can't read or write", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - testUtils.CollectionNamedMutationType, - testUtils.CollectionSaveMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used with gql (only for update requests), + testUtils.CollectionNamedMutationType, + testUtils.CollectionSaveMutationType, + }), Actions: []any{ testUtils.AddPolicy{ diff --git a/tests/integration/acp/relationship/doc_actor/add/with_only_write_gql_test.go b/tests/integration/acp/relationship/doc_actor/add/with_only_write_gql_test.go index 6a3f02f4ba..9391bb5b4d 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_only_write_gql_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_only_write_gql_test.go @@ -26,10 +26,13 @@ func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorWithoutExplicitReadPerm_GQ Description: "Test acp, owner gives write(update) access without explicit read permission, can still update", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - // GQL mutation will return no error when wrong identity is used so test that separately. - testUtils.GQLRequestMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used (only for update requests), + // so test that separately. + testUtils.GQLRequestMutationType, + }, + ), Actions: []any{ testUtils.AddPolicy{ diff --git a/tests/integration/acp/relationship/doc_actor/add/with_only_write_test.go b/tests/integration/acp/relationship/doc_actor/add/with_only_write_test.go index ccac9cd232..dba024e1a4 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_only_write_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_only_write_test.go @@ -26,10 +26,12 @@ func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorWithoutExplicitReadPerm_Ot Description: "Test acp, owner gives write(update) access without explicit read permission, can still update", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - testUtils.CollectionNamedMutationType, - testUtils.CollectionSaveMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used with gql (only for update requests), + testUtils.CollectionNamedMutationType, + testUtils.CollectionSaveMutationType, + }), Actions: []any{ testUtils.AddPolicy{ diff --git a/tests/integration/acp/relationship/doc_actor/add/with_reader_gql_test.go b/tests/integration/acp/relationship/doc_actor/add/with_reader_gql_test.go index f51861ec5c..7ca1c30e09 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_reader_gql_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_reader_gql_test.go @@ -26,10 +26,13 @@ func TestACP_OwnerGivesOnlyReadAccessToAnotherActor_GQL_OtherActorCanReadButNotU Description: "Test acp, owner gives read access to another actor, but the other actor can't update", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - // GQL mutation will return no error when wrong identity is used so test that separately. - testUtils.GQLRequestMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used (only for update requests), + // so test that separately. + testUtils.GQLRequestMutationType, + }, + ), Actions: []any{ testUtils.AddPolicy{ diff --git a/tests/integration/acp/relationship/doc_actor/add/with_reader_test.go b/tests/integration/acp/relationship/doc_actor/add/with_reader_test.go index fd452c2d7d..541b40977e 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_reader_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_reader_test.go @@ -465,10 +465,11 @@ func TestACP_OwnerGivesOnlyReadAccessToAnotherActor_OtherActorCanReadButNotUpdat Description: "Test acp, owner gives read access to another actor, but the other actor can't update", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - testUtils.CollectionNamedMutationType, - testUtils.CollectionSaveMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + testUtils.CollectionNamedMutationType, + testUtils.CollectionSaveMutationType, + }), Actions: []any{ testUtils.AddPolicy{ diff --git a/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_gql_test.go b/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_gql_test.go index c05380d8e0..2a421dc74d 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_gql_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_gql_test.go @@ -28,7 +28,8 @@ func TestACP_OwnerGivesOnlyReadAccessToAllActors_GQL_AllActorsCanReadButNotUpdat SupportedMutationTypes: immutable.Some( []testUtils.MutationType{ - // GQL mutation will return no error when wrong identity is used so test that separately. + // GQL mutation will return no error when wrong identity is used (only for update requests), + // so test that separately. testUtils.GQLRequestMutationType, }, ), @@ -248,3 +249,210 @@ func TestACP_OwnerGivesOnlyReadAccessToAllActors_GQL_AllActorsCanReadButNotUpdat testUtils.ExecuteTestCase(t, test) } + +func TestACP_OwnerGivesOnlyReadAccessToAllActors_GQL_CanReadEvenWithoutIdentityButNotUpdateOrDelete(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to all actors (gql), can read without an identity but can't update or delete", + + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used (only for update requests), + // so test that separately. + testUtils.GQLRequestMutationType, + }, + ), + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: testUtils.ClientIdentity(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: testUtils.ClientIdentity(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: testUtils.NoIdentity(), // Can not read without an identity. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.DeleteDoc{ // Since can't read without identity, can't delete either. + CollectionID: 0, + + Identity: testUtils.NoIdentity(), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.UpdateDoc{ // Since can't read without identity, can't update either. + CollectionID: 0, + + Identity: testUtils.NoIdentity(), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + SkipLocalUpdateEvent: true, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: testUtils.NoIdentity(), // Now any identity can read, even if there is no identity + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.UpdateDoc{ // But doesn't mean they can update. + CollectionID: 0, + + Identity: testUtils.NoIdentity(), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.DeleteDoc{ // But doesn't mean they can delete. + CollectionID: 0, + + Identity: testUtils.NoIdentity(), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_test.go b/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_test.go index 4ee858345b..ad587232f9 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_test.go @@ -28,6 +28,7 @@ func TestACP_OwnerGivesOnlyReadAccessToAllActors_AllActorsCanReadButNotUpdateOrD SupportedMutationTypes: immutable.Some( []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used with gql (only for update requests), testUtils.CollectionNamedMutationType, testUtils.CollectionSaveMutationType, }, @@ -248,3 +249,210 @@ func TestACP_OwnerGivesOnlyReadAccessToAllActors_AllActorsCanReadButNotUpdateOrD testUtils.ExecuteTestCase(t, test) } + +func TestACP_OwnerGivesOnlyReadAccessToAllActors_CanReadEvenWithoutIdentityButNotUpdateOrDelete(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to all actors, can read without an identity but can't update or delete", + + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used with gql (only for update requests), + testUtils.CollectionNamedMutationType, + testUtils.CollectionSaveMutationType, + }, + ), + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: testUtils.ClientIdentity(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: testUtils.ClientIdentity(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: testUtils.NoIdentity(), // Can not read without an identity. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.DeleteDoc{ // Since can't read without identity, can't delete either. + CollectionID: 0, + + Identity: testUtils.NoIdentity(), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.UpdateDoc{ // Since can't read without identity, can't update either. + CollectionID: 0, + + Identity: testUtils.NoIdentity(), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: testUtils.NoIdentity(), // Now any identity can read, even if there is no identity + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.UpdateDoc{ // But doesn't mean they can update. + CollectionID: 0, + + Identity: testUtils.NoIdentity(), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.DeleteDoc{ // But doesn't mean they can delete. + CollectionID: 0, + + Identity: testUtils.NoIdentity(), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/acp/relationship/doc_actor/add/with_update_gql_test.go b/tests/integration/acp/relationship/doc_actor/add/with_update_gql_test.go index eff2be0f7d..6c17ee792b 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_update_gql_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_update_gql_test.go @@ -26,10 +26,11 @@ func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorTwice_GQL_ShowThatTheRelat Description: "Test acp, owner gives write(update) access to another actor twice, no-op", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - // GQL mutation will return no error when wrong identity is used so test that separately. - testUtils.GQLRequestMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used so test that separately. + testUtils.GQLRequestMutationType, + }), Actions: []any{ testUtils.AddPolicy{ @@ -184,10 +185,11 @@ func TestACP_OwnerGivesUpdateWriteAccessToAnotherActor_GQL_OtherActorCanUpdate(t Description: "Test acp, owner gives write(update) access to another actor", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - // GQL mutation will return no error when wrong identity is used so test that separately. - testUtils.GQLRequestMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used so test that separately. + testUtils.GQLRequestMutationType, + }), Actions: []any{ testUtils.AddPolicy{ diff --git a/tests/integration/acp/relationship/doc_actor/add/with_update_test.go b/tests/integration/acp/relationship/doc_actor/add/with_update_test.go index f6bf553356..582f42af01 100644 --- a/tests/integration/acp/relationship/doc_actor/add/with_update_test.go +++ b/tests/integration/acp/relationship/doc_actor/add/with_update_test.go @@ -26,10 +26,12 @@ func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorTwice_ShowThatTheRelations Description: "Test acp, owner gives write(update) access to another actor twice, no-op", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - testUtils.CollectionNamedMutationType, - testUtils.CollectionSaveMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used with gql (only for update requests), + testUtils.CollectionNamedMutationType, + testUtils.CollectionSaveMutationType, + }), Actions: []any{ testUtils.AddPolicy{ @@ -184,10 +186,12 @@ func TestACP_OwnerGivesUpdateWriteAccessToAnotherActor_OtherActorCanUpdate(t *te Description: "Test acp, owner gives write(update) access to another actor", - SupportedMutationTypes: immutable.Some([]testUtils.MutationType{ - testUtils.CollectionNamedMutationType, - testUtils.CollectionSaveMutationType, - }), + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used with gql (only for update requests), + testUtils.CollectionNamedMutationType, + testUtils.CollectionSaveMutationType, + }), Actions: []any{ testUtils.AddPolicy{ diff --git a/tests/integration/acp/relationship/doc_actor/delete/with_target_all_actors_test.go b/tests/integration/acp/relationship/doc_actor/delete/with_target_all_actors_test.go index 14c0121a41..9db120ce91 100644 --- a/tests/integration/acp/relationship/doc_actor/delete/with_target_all_actors_test.go +++ b/tests/integration/acp/relationship/doc_actor/delete/with_target_all_actors_test.go @@ -165,7 +165,7 @@ func TestACP_OwnerRevokesAccessFromAllNonExplicitActors_ActorsCanNotReadAnymore( }, }, - testUtils.DeleteDocActorRelationship{ // Revoke access from all actors, not explictly allowed. + testUtils.DeleteDocActorRelationship{ // Revoke access from all actors, (ones given access through * implicitly). RequestorIdentity: testUtils.ClientIdentity(1), TargetIdentity: testUtils.AllClientIdentities(), @@ -444,7 +444,7 @@ func TestACP_OwnerRevokesAccessFromAllNonExplicitActors_ExplicitActorsCanStillRe }, }, - testUtils.DeleteDocActorRelationship{ // Revoke access from all actors, not explictly allowed. + testUtils.DeleteDocActorRelationship{ // Revoke access from all actors, (ones given access through * implicitly). RequestorIdentity: testUtils.ClientIdentity(1), TargetIdentity: testUtils.AllClientIdentities(), @@ -546,3 +546,164 @@ func TestACP_OwnerRevokesAccessFromAllNonExplicitActors_ExplicitActorsCanStillRe testUtils.ExecuteTestCase(t, test) } + +func TestACP_OwnerRevokesAccessFromAllNonExplicitActors_NonIdentityRequestsCanNotReadAnymore(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner revokes read access from actors that were given read access implicitly, non-identity actors can't read anymore", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: testUtils.ClientIdentity(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: testUtils.ClientIdentity(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), // Give implicit access to all identities. + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: testUtils.NoIdentity(), // Can read even without identity + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.DeleteDocActorRelationship{ // Revoke access from all actors, (ones given access through * implicitly). + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedRecordFound: true, + }, + + testUtils.Request{ + Identity: testUtils.NoIdentity(), // Can not read anymore + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents now + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +}