diff --git a/config-generators/cosmosdb_nosql-commands.txt b/config-generators/cosmosdb_nosql-commands.txt index e790d5c5f7..52a1198abf 100644 --- a/config-generators/cosmosdb_nosql-commands.txt +++ b/config-generators/cosmosdb_nosql-commands.txt @@ -8,13 +8,25 @@ update StarAlias --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.s add TagAlias --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.tag" --permissions "anonymous:create,read,update,delete" --graphql "Tag:Tags" add Moon --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moon" --permissions "anonymous:create,read,update,delete" --graphql true update Moon --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moon" --permissions "authenticated:create,read,update,delete" -add Earth --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.earth" --permissions "anonymous:delete" --graphql "Earth:Earths" -update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:create" --fields.include "id" --fields.exclude "name" -update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:read" --fields.include "id,type" --fields.exclude "name" -update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:update" --fields.exclude "*" +add Earth --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.earth" --permissions "field-mutation-with-read-permission:read" --graphql "Earth:Earths" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "field-mutation-with-read-permission:create" --fields.include "id" --fields.exclude "name" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "field-mutation-with-read-permission:delete" --fields.include "id,type" --fields.exclude "name" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "field-mutation-with-read-permission:update" --fields.include "id,type" --fields.exclude "name" update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "authenticated:create,read,update,delete" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "limited-read-role:read" --fields.include "id,type" --fields.exclude "name" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "wildcard-exclude-fields-role:create" --fields.exclude "*" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "wildcard-exclude-fields-role:update" --fields.exclude "*" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "wildcard-exclude-fields-role:delete" --fields.exclude "*" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "wildcard-exclude-fields-role:read" --fields.exclude "*" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "only-create-role:create" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "only-update-role:update" +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "only-delete-role:delete" add Sun --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.sun" --permissions "anonymous:create,update,delete" --graphql true update Sun --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:read" --fields.include "*" --fields.exclude "name" add AdditionalAttribute --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.additionalAttribute" --permissions "anonymous:*" --graphql "AdditionalAttribute:AdditionalAttributes" add MoonAdditionalAttribute --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moonAdditionalAttributes" --permissions "anonymous:*" --graphql "MoonAdditionalAttribute:MoonAdditionalAttributes" -add MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moreAttribute" --permissions "anonymous:*" --graphql "MoreAttribute:MoreAttributes" +add MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moreAttribute" --permissions "anonymous:delete" --graphql "MoreAttribute:MoreAttributes" +update MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:create" --fields.include "id" --fields.exclude "name" +update MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:read" --fields.include "id" --fields.exclude "name" +update MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:update" --fields.exclude "*" +update MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --permissions "authenticated:create,read,update,delete" diff --git a/src/Service.Tests/CosmosTests/MutationTests.cs b/src/Service.Tests/CosmosTests/MutationTests.cs index f8c8d90667..a5dd6bad2b 100644 --- a/src/Service.Tests/CosmosTests/MutationTests.cs +++ b/src/Service.Tests/CosmosTests/MutationTests.cs @@ -31,6 +31,7 @@ public class MutationTests : TestBase name } }"; + private static readonly string _deletePlanetMutation = @" mutation ($id: ID!, $partitionKeyValue: String!) { deletePlanet (id: $id, _partitionKeyValue: $partitionKeyValue) { @@ -38,6 +39,8 @@ public class MutationTests : TestBase name } }"; + private const string USER_NOT_AUTHORIZED = "The current user is not authorized to access this resource"; + private const string NO_ERROR_MESSAGE = null; /// /// Executes once for the test. @@ -252,62 +255,78 @@ public async Task MutationMissingRequiredPartitionKeyValueReturnError() } /// - /// Mutation can be performed on the authorized fields because the - /// field `id` is an included field for the create operation on the anonymous role defined - /// for entity 'earth' + /// Create Mutation performed on the fields with different auth permissions + /// It throws permission denied error if role doesn't have permission to perform the operation /// [TestMethod] - public async Task CanCreateItemWithAuthorizedFields() + [DataRow("field-mutation-with-read-permission", DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE, DisplayName = "AuthZ failure for create mutation because of reference to excluded/disallowed fields.")] + [DataRow("authenticated", MutationTests.NO_ERROR_MESSAGE, DisplayName = "AuthZ success when role has no create/read operation restrictions.")] + [DataRow("only-create-role", "The mutation operation createEarth was successful " + + "but the current user is unauthorized to view the response due to lack of read permissions", DisplayName = "Successful create operation but AuthZ failure for read when role has ONLY create permission and NO read permission.")] + [DataRow("wildcard-exclude-fields-role", DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE, DisplayName = "AuthZ failure for create mutation because of reference to excluded/disallowed field using wildcard.")] + [DataRow("only-update-role", MutationTests.USER_NOT_AUTHORIZED, DisplayName = "AuthZ failure when create permission is NOT there.")] + public async Task CreateItemWithAuthPermissions(string roleName, string expectedErrorMessage) { // Run mutation Add Earth; string id = Guid.NewGuid().ToString(); + const string name = "test_name"; string mutation = $@" mutation {{ - createEarth (item: {{ id: ""{id}"" }}) {{ + createEarth (item: {{ id: ""{id}"", name: ""{name}"" }}) {{ id + name }} }}"; - JsonElement response = await ExecuteGraphQLRequestAsync("createEarth", mutation, variables: new()); + string authtoken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: roleName); + JsonElement response = await ExecuteGraphQLRequestAsync("createEarth", mutation, variables: new(), authToken: authtoken, clientRoleHeader: roleName); - // Validate results - Assert.AreEqual(id, response.GetProperty("id").GetString()); + // Validate the result contains the GraphQL authorization error code. + Console.WriteLine(response.ToString()); + if (string.IsNullOrEmpty(expectedErrorMessage)) + { + Assert.AreEqual(id, response.GetProperty("id").GetString()); + } + else + { + // Validate the result contains the GraphQL authorization error code. + string errorMessage = response.ToString(); + Assert.IsTrue(errorMessage.Contains(expectedErrorMessage)); + } } /// - /// Mutation performed on the unauthorized fields throws permission denied error because the - /// field `name` is an excluded field for the create operation on the anonymous role defined - /// for entity 'earth' + /// Update Mutation performed on the fields with different auth permissions + /// It throws permission denied error if role doesn't have permission to perform the operation /// [TestMethod] - public async Task CreateItemWithUnauthorizedFieldsReturnsError() + [DataRow("field-mutation-with-read-permission", DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE, DisplayName = "AuthZ failure for update mutation because of reference to excluded/disallowed fields.")] + [DataRow("authenticated", NO_ERROR_MESSAGE, DisplayName = "AuthZ success when role has no update/read operation restrictions.")] + [DataRow("only-update-role", "The mutation operation updateEarth was successful " + + "but the current user is unauthorized to view the response due to lack of read permissions", DisplayName = "AuthZ failure but sucessful operation where role has ONLY update permission and NO read permission.")] + [DataRow("wildcard-exclude-fields-role", DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE, DisplayName = "AuthZ failure for update mutation because of reference to excluded/disallowed field using wildcard.")] + [DataRow("only-create-role", MutationTests.USER_NOT_AUTHORIZED, DisplayName = "AuthZ failure when update permission is NOT there.")] + public async Task UpdateItemWithAuthPermissions(string roleName, string expectedErrorMessage) { - // Run mutation Add Earth; + // Create an item with "Authenticated" role string id = Guid.NewGuid().ToString(); const string name = "test_name"; - string mutation = $@" + string createMutation = $@" mutation {{ createEarth (item: {{ id: ""{id}"", name: ""{name}"" }}) {{ id name }} }}"; - JsonElement response = await ExecuteGraphQLRequestAsync("createEarth", mutation, variables: new()); - // Validate the result contains the GraphQL authorization error code. - string errorMessage = response.ToString(); - Assert.IsTrue(errorMessage.Contains(DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE)); - } + JsonElement createResponse = await ExecuteGraphQLRequestAsync("createEarth", createMutation, + variables: new(), + authToken: AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: AuthorizationType.Authenticated.ToString()), + clientRoleHeader: AuthorizationType.Authenticated.ToString()); + + // Making sure item is created successfully + Assert.AreEqual(id, createResponse.GetProperty("id").GetString()); - /// - /// Mutation performed on the unauthorized fields throws permission denied error because the - /// wildcard is used in the excluded field for the update operation on the anonymous role defined - /// for entity 'earth' - /// - [TestMethod] - public async Task UpdateItemWithUnauthorizedWildCardReturnsError() - { // Run mutation Update Earth; - string id = Guid.NewGuid().ToString(); string mutation = @" mutation ($id: ID!, $partitionKeyValue: String!, $item: UpdateEarthInput!) { updateEarth (id: $id, _partitionKeyValue: $partitionKeyValue, item: $item) { @@ -321,11 +340,87 @@ public async Task UpdateItemWithUnauthorizedWildCardReturnsError() name = "new_name" }; - JsonElement response = await ExecuteGraphQLRequestAsync("updateEarth", mutation, variables: new() { { "id", id }, { "partitionKeyValue", id }, { "item", update } }); + string authtoken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: roleName); + JsonElement response = await ExecuteGraphQLRequestAsync( + queryName: "updateEarth", + query: mutation, + variables: new() { { "id", id }, { "partitionKeyValue", id }, { "item", update } }, + authToken: authtoken, + clientRoleHeader: roleName); - // Validate the result contains the GraphQL authorization error code. - string errorMessage = response.ToString(); - Assert.IsTrue(errorMessage.Contains(DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE)); + Console.WriteLine(response.ToString()); + if (string.IsNullOrEmpty(expectedErrorMessage)) + { + Assert.AreEqual(id, response.GetProperty("id").GetString()); + } + else + { + // Validate the result contains the GraphQL authorization error code. + string errorMessage = response.ToString(); + Assert.IsTrue(errorMessage.Contains(expectedErrorMessage)); + } + } + + /// + /// Delete Mutation performed on the fields with different auth permissions + /// It throws permission denied error if role doesn't have permission to perform the operation + /// + [TestMethod] + [DataRow("field-mutation-with-read-permission", MutationTests.NO_ERROR_MESSAGE, DisplayName = "AuthZ success and blank response for delete mutation because of reference to excluded/disallowed fields.")] + [DataRow("authenticated", MutationTests.NO_ERROR_MESSAGE, DisplayName = "AuthZ success and blank response when role has no delete operation restrictions.")] + [DataRow("only-delete-role", "The mutation operation deleteEarth was successful " + + "but the current user is unauthorized to view the response due to lack of read permissions", DisplayName = "AuthZ failure but sucessful operation where role has ONLY delete permission and NO read permission.")] + [DataRow("wildcard-exclude-fields-role", MutationTests.NO_ERROR_MESSAGE, DisplayName = "AuthZ success and blank response for delete mutation because of reference to excluded/disallowed fields using wildcard")] + [DataRow("only-create-role", MutationTests.USER_NOT_AUTHORIZED, DisplayName = "AuthZ failure when delete permission is NOT there.")] + public async Task DeleteItemWithAuthPermissions(string roleName, string expectedErrorMessage) + { + // Create an item with "Authenticated" role + string id = Guid.NewGuid().ToString(); + const string name = "test_name"; + string createMutation = $@" +mutation {{ + createEarth (item: {{ id: ""{id}"", name: ""{name}"" }}) {{ + id + name + }} +}}"; + + JsonElement createResponse = await ExecuteGraphQLRequestAsync("createEarth", createMutation, + variables: new(), + authToken: AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: AuthorizationType.Authenticated.ToString()), + clientRoleHeader: AuthorizationType.Authenticated.ToString()); + + // Making sure item is created successfully + Assert.AreEqual(id, createResponse.GetProperty("id").GetString()); + + // Run mutation Update Earth; + string mutation = @" +mutation ($id: ID!, $partitionKeyValue: String!) { + deleteEarth (id: $id, _partitionKeyValue: $partitionKeyValue) { + id + name + } +}"; + string authtoken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: roleName); + JsonElement response = await ExecuteGraphQLRequestAsync( + queryName: "deleteEarth", + query: mutation, + variables: new() { { "id", id }, { "partitionKeyValue", id } }, + authToken: authtoken, + clientRoleHeader: roleName); + + Console.WriteLine(response.ToString()); + + if (string.IsNullOrEmpty(expectedErrorMessage)) + { + Assert.IsTrue(string.IsNullOrEmpty(response.ToString())); + } + else + { + // Validate the result contains the GraphQL authorization error code. + string errorMessage = response.ToString(); + Assert.IsTrue(errorMessage.Contains(expectedErrorMessage)); + } } /// diff --git a/src/Service.Tests/CosmosTests/QueryFilterTests.cs b/src/Service.Tests/CosmosTests/QueryFilterTests.cs index c3d2cf65ca..e5a247a58d 100644 --- a/src/Service.Tests/CosmosTests/QueryFilterTests.cs +++ b/src/Service.Tests/CosmosTests/QueryFilterTests.cs @@ -264,7 +264,8 @@ public async Task TestStringMultiFiltersOnArrayTypeWithOrCondition() private async Task ExecuteAndValidateResult(string graphQLQueryName, string gqlQuery, string dbQuery) { - JsonElement actual = await ExecuteGraphQLRequestAsync(graphQLQueryName, query: gqlQuery); + string authToken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: AuthorizationType.Authenticated.ToString()); + JsonElement actual = await ExecuteGraphQLRequestAsync(graphQLQueryName, query: gqlQuery, authToken: authToken); JsonDocument expected = await ExecuteCosmosRequestAsync(dbQuery, _pageSize, null, _containerName); ValidateResults(actual.GetProperty("items"), expected.RootElement); } @@ -898,7 +899,7 @@ public async Task TestQueryFilterFieldAuth_AuthorizedField() /// /// Tests that the field level query filter fails authorization when filter fields are /// unauthorized because the field 'name' on object type 'earth' is an excluded field of the read - /// operation permissions defined for the anonymous role. + /// operation permissions defined for a role. /// [TestMethod] public async Task TestQueryFilterFieldAuth_UnauthorizedField() @@ -912,7 +913,7 @@ public async Task TestQueryFilterFieldAuth_UnauthorizedField() } } }"; - string clientRoleHeader = AuthorizationType.Anonymous.ToString(); + string clientRoleHeader = "limited-read-role"; JsonElement response = await ExecuteGraphQLRequestAsync( queryName: "earths", query: gqlQuery, @@ -970,7 +971,8 @@ public async Task TestQueryFilterNestedFieldAuth_AuthorizedNestedField() } }"; - JsonElement actual = await ExecuteGraphQLRequestAsync(_graphQLQueryName, query: gqlQuery); + string authToken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: AuthorizationType.Authenticated.ToString()); + JsonElement actual = await ExecuteGraphQLRequestAsync(_graphQLQueryName, query: gqlQuery, authToken: authToken); Assert.AreEqual(actual.GetProperty("items")[0].GetProperty("earth").GetProperty("id").ToString(), _idList[0]); } @@ -996,7 +998,7 @@ public async Task TestQueryFilterNestedFieldAuth_UnauthorizedNestedField() } }"; - string clientRoleHeader = AuthorizationType.Anonymous.ToString(); + string clientRoleHeader = "limited-read-role"; JsonElement response = await ExecuteGraphQLRequestAsync( queryName: _graphQLQueryName, query: gqlQuery, @@ -1009,6 +1011,37 @@ public async Task TestQueryFilterNestedFieldAuth_UnauthorizedNestedField() Assert.IsTrue(errorMessage.Contains(DataApiBuilderException.GRAPHQL_FILTER_FIELD_AUTHZ_FAILURE)); } + /// + /// Tests that the nested field level query filter fails authorization when nested object is + /// unauthorized. Here, Nested array type 'moreAttributes' is avaliable for 'Authenticated' role only and + /// we are trying to access it with 'anonymous' role. + /// + [TestMethod] + public async Task TestQueryFilterNestedArrayFieldAuth_UnauthorizedNestedField() + { + // Run query + string gqlQuery = @"{ + planets(first: 10, " + QueryBuilder.FILTER_FIELD_NAME + + @" : {moons: {moonAdditionalAttributes: {moreAttributes: {name: {eq: ""moonattr0""}}}}}) + { + items { + name + } + } + }"; + + string clientRoleHeader = AuthorizationType.Anonymous.ToString(); + JsonElement response = await ExecuteGraphQLRequestAsync( + queryName: _graphQLQueryName, + query: gqlQuery, + authToken: AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: clientRoleHeader), + clientRoleHeader: clientRoleHeader); + + // Validate the result contains the GraphQL authorization error code. + string errorMessage = response.ToString(); + Assert.IsTrue(errorMessage.Contains(DataApiBuilderException.GRAPHQL_FILTER_FIELD_AUTHZ_FAILURE)); + } + /// /// This is for testing the scenario when the filter field is authorized, but the query field is unauthorized. /// For "type" field in "Earth" GraphQL type, it has @authorize(policy: "authenticated") directive in the test schema, diff --git a/src/Service.Tests/CosmosTests/TestBase.cs b/src/Service.Tests/CosmosTests/TestBase.cs index 06c4af0b5d..5d92acd5be 100644 --- a/src/Service.Tests/CosmosTests/TestBase.cs +++ b/src/Service.Tests/CosmosTests/TestBase.cs @@ -97,7 +97,8 @@ type MoonAdditionalAttribute @model(name:""MoonAdditionalAttribute"") { type MoreAttribute @model(name:""MoreAttrAlias"") { id : ID, - name : String + name : String, + type: String @authorize(roles: [""authenticated""]) }"; private static string[] _planets = { "Earth", "Mars", "Jupiter", "Tatooine", "Endor", "Dagobah", "Hoth", "Bespin", "Spec%ial" }; diff --git a/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForCosmos.verified.txt b/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForCosmos.verified.txt index 989b0a5310..b77019e6c8 100644 --- a/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForCosmos.verified.txt +++ b/src/Service.Tests/Snapshots/ConfigurationTests.TestReadingRuntimeConfigForCosmos.verified.txt @@ -271,18 +271,22 @@ }, Permissions: [ { - Role: anonymous, + Role: field-mutation-with-read-permission, Actions: [ { Action: Update, Fields: { Exclude: [ - * + name + ], + Include: [ + id, + type ] } }, { - Action: Read, + Action: Delete, Fields: { Exclude: [ name @@ -305,7 +309,7 @@ } }, { - Action: Delete + Action: Read } ] }, @@ -325,6 +329,84 @@ Action: Delete } ] + }, + { + Role: limited-read-role, + Actions: [ + { + Action: Read, + Fields: { + Exclude: [ + name + ], + Include: [ + id, + type + ] + } + } + ] + }, + { + Role: wildcard-exclude-fields-role, + Actions: [ + { + Action: Read, + Fields: { + Exclude: [ + * + ] + } + }, + { + Action: Delete, + Fields: { + Exclude: [ + * + ] + } + }, + { + Action: Update, + Fields: { + Exclude: [ + * + ] + } + }, + { + Action: Create, + Fields: { + Exclude: [ + * + ] + } + } + ] + }, + { + Role: only-create-role, + Actions: [ + { + Action: Create + } + ] + }, + { + Role: only-update-role, + Actions: [ + { + Action: Update + } + ] + }, + { + Role: only-delete-role, + Actions: [ + { + Action: Delete + } + ] } ] } @@ -439,7 +521,54 @@ Role: anonymous, Actions: [ { - Action: * + Action: Update, + Fields: { + Exclude: [ + * + ] + } + }, + { + Action: Read, + Fields: { + Exclude: [ + name + ], + Include: [ + id + ] + } + }, + { + Action: Create, + Fields: { + Exclude: [ + name + ], + Include: [ + id + ] + } + }, + { + Action: Delete + } + ] + }, + { + Role: authenticated, + Actions: [ + { + Action: Create + }, + { + Action: Read + }, + { + Action: Update + }, + { + Action: Delete } ] } diff --git a/src/Service.Tests/dab-config.CosmosDb_NoSql.json b/src/Service.Tests/dab-config.CosmosDb_NoSql.json index c00081b626..d079cb6bbc 100644 --- a/src/Service.Tests/dab-config.CosmosDb_NoSql.json +++ b/src/Service.Tests/dab-config.CosmosDb_NoSql.json @@ -277,18 +277,22 @@ }, "permissions": [ { - "role": "anonymous", + "role": "field-mutation-with-read-permission", "actions": [ { "action": "update", "fields": { "exclude": [ - "*" + "name" + ], + "include": [ + "id", + "type" ] } }, { - "action": "read", + "action": "delete", "fields": { "exclude": [ "name" @@ -311,7 +315,7 @@ } }, { - "action": "delete" + "action": "read" } ] }, @@ -331,6 +335,84 @@ "action": "delete" } ] + }, + { + "role": "limited-read-role", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "name" + ], + "include": [ + "id", + "type" + ] + } + } + ] + }, + { + "role": "wildcard-exclude-fields-role", + "actions": [ + { + "action": "read", + "fields": { + "exclude": [ + "*" + ] + } + }, + { + "action": "delete", + "fields": { + "exclude": [ + "*" + ] + } + }, + { + "action": "update", + "fields": { + "exclude": [ + "*" + ] + } + }, + { + "action": "create", + "fields": { + "exclude": [ + "*" + ] + } + } + ] + }, + { + "role": "only-create-role", + "actions": [ + { + "action": "create" + } + ] + }, + { + "role": "only-update-role", + "actions": [ + { + "action": "update" + } + ] + }, + { + "role": "only-delete-role", + "actions": [ + { + "action": "delete" + } + ] } ] }, @@ -445,7 +527,54 @@ "role": "anonymous", "actions": [ { - "action": "*" + "action": "update", + "fields": { + "exclude": [ + "*" + ] + } + }, + { + "action": "read", + "fields": { + "exclude": [ + "name" + ], + "include": [ + "id" + ] + } + }, + { + "action": "create", + "fields": { + "exclude": [ + "name" + ], + "include": [ + "id" + ] + } + }, + { + "action": "delete" + } + ] + }, + { + "role": "authenticated", + "actions": [ + { + "action": "create" + }, + { + "action": "read" + }, + { + "action": "update" + }, + { + "action": "delete" } ] }