Skip to content

Commit f3bf743

Browse files
committed
add mutation auth tests
1 parent 59f51a4 commit f3bf743

File tree

2 files changed

+190
-48
lines changed

2 files changed

+190
-48
lines changed

src/Service.Tests/CosmosTests/MutationTests.cs

Lines changed: 119 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@
1313
using Azure.DataApiBuilder.Core.Configurations;
1414
using Azure.DataApiBuilder.Core.Resolvers;
1515
using Azure.DataApiBuilder.Service.Exceptions;
16-
using Azure.DataApiBuilder.Service.GraphQLBuilder.Queries;
1716
using Azure.DataApiBuilder.Service.Tests.Configuration;
1817
using Microsoft.AspNetCore.TestHost;
1918
using Microsoft.Azure.Cosmos;
2019
using Microsoft.Extensions.DependencyInjection;
21-
using Microsoft.OData.UriParser;
2220
using Microsoft.VisualStudio.TestTools.UnitTesting;
2321

2422
namespace Azure.DataApiBuilder.Service.Tests.CosmosTests
@@ -255,62 +253,76 @@ public async Task MutationMissingRequiredPartitionKeyValueReturnError()
255253
}
256254

257255
/// <summary>
258-
/// Mutation can be performed on the authorized fields because the
259-
/// field `id` is an included field for the create operation on the anonymous role defined
260-
/// for entity 'earth'
256+
/// Create Mutation performed on the fields with different auth permissions
257+
/// It throws permission denied error if role doesn't have permission to perform the operation
261258
/// </summary>
262259
[TestMethod]
263-
public async Task CanCreateItemWithAuthorizedFields()
260+
[DataRow("field-mutation-with-read-permission", DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE)] // exclude and include fields
261+
[DataRow("authenticated", null)] // full permission
262+
[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")] // if only create permission is there
263+
[DataRow("wildcard-exclude-fields-role", DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE)] // exclude wildcard
264+
[DataRow("only-update-role", "The current user is not authorized to access this resource" )] // if create permission is not there
265+
public async Task CreateItemWithAuthPermissions(string roleName, string expectedErrorMessage)
264266
{
265267
// Run mutation Add Earth;
266268
string id = Guid.NewGuid().ToString();
269+
const string name = "test_name";
267270
string mutation = $@"
268271
mutation {{
269-
createEarth (item: {{ id: ""{id}"" }}) {{
272+
createEarth (item: {{ id: ""{id}"", name: ""{name}"" }}) {{
270273
id
274+
name
271275
}}
272276
}}";
273-
JsonElement response = await ExecuteGraphQLRequestAsync("createEarth", mutation, variables: new());
277+
string authtoken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: roleName);
278+
JsonElement response = await ExecuteGraphQLRequestAsync("createEarth", mutation, variables: new(), authToken: authtoken, clientRoleHeader: roleName);
274279

275-
// Validate results
276-
Assert.AreEqual(id, response.GetProperty("id").GetString());
280+
// Validate the result contains the GraphQL authorization error code.
281+
Console.WriteLine(response.ToString());
282+
if (string.IsNullOrEmpty(expectedErrorMessage))
283+
{
284+
Assert.AreEqual(id, response.GetProperty("id").GetString());
285+
}
286+
else
287+
{
288+
// Validate the result contains the GraphQL authorization error code.
289+
string errorMessage = response.ToString();
290+
Assert.IsTrue(errorMessage.Contains(expectedErrorMessage));
291+
}
277292
}
278293

279294
/// <summary>
280-
/// Mutation performed on the unauthorized fields throws permission denied error because the
281-
/// field `name` is an excluded field for the create operation on the anonymous role defined
282-
/// for entity 'earth'
295+
/// Update Mutation performed on the fields with different auth permissions
296+
/// It throws permission denied error if role doesn't have permission to perform the operation
283297
/// </summary>
284298
[TestMethod]
285-
public async Task CreateItemWithUnauthorizedFieldsReturnsError()
299+
[DataRow("field-mutation-with-read-permission", DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE)] // exclude and include fields
300+
[DataRow("authenticated", null)] // full permission
301+
[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")] // if only update permission is there
302+
[DataRow("wildcard-exclude-fields-role", DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE)] // exclude wildcard
303+
[DataRow("only-create-role", "The current user is not authorized to access this resource")] // if update permission is not there
304+
public async Task UpdateItemWithAuthPermissions(string roleName, string expectedErrorMessage)
286305
{
287-
// Run mutation Add Earth;
306+
// Create an item with "Authenticated" role
288307
string id = Guid.NewGuid().ToString();
289308
const string name = "test_name";
290-
string mutation = $@"
309+
string createMutation = $@"
291310
mutation {{
292311
createEarth (item: {{ id: ""{id}"", name: ""{name}"" }}) {{
293312
id
294313
name
295314
}}
296315
}}";
297-
JsonElement response = await ExecuteGraphQLRequestAsync("createEarth", mutation, variables: new());
298316

299-
// Validate the result contains the GraphQL authorization error code.
300-
string errorMessage = response.ToString();
301-
Assert.IsTrue(errorMessage.Contains(DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE));
302-
}
317+
JsonElement createResponse = await ExecuteGraphQLRequestAsync("createEarth", createMutation,
318+
variables: new(),
319+
authToken: AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: AuthorizationType.Authenticated.ToString()),
320+
clientRoleHeader: AuthorizationType.Authenticated.ToString());
321+
322+
// Making sure item is created successfully
323+
Assert.AreEqual(id, createResponse.GetProperty("id").GetString());
303324

304-
/// <summary>
305-
/// Mutation performed on the unauthorized fields throws permission denied error because the
306-
/// wildcard is used in the excluded field for the update operation on the anonymous role defined
307-
/// for entity 'earth'
308-
/// </summary>
309-
[TestMethod]
310-
public async Task UpdateItemWithUnauthorizedWildCardReturnsError()
311-
{
312325
// Run mutation Update Earth;
313-
string id = Guid.NewGuid().ToString();
314326
string mutation = @"
315327
mutation ($id: ID!, $partitionKeyValue: String!, $item: UpdateEarthInput!) {
316328
updateEarth (id: $id, _partitionKeyValue: $partitionKeyValue, item: $item) {
@@ -324,11 +336,83 @@ public async Task UpdateItemWithUnauthorizedWildCardReturnsError()
324336
name = "new_name"
325337
};
326338

327-
JsonElement response = await ExecuteGraphQLRequestAsync("updateEarth", mutation, variables: new() { { "id", id }, { "partitionKeyValue", id }, { "item", update } });
339+
string authtoken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: roleName);
340+
JsonElement response = await ExecuteGraphQLRequestAsync(
341+
queryName: "updateEarth",
342+
query: mutation,
343+
variables: new() { { "id", id }, { "partitionKeyValue", id }, { "item", update } },
344+
authToken: authtoken,
345+
clientRoleHeader: roleName);
328346

329-
// Validate the result contains the GraphQL authorization error code.
330-
string errorMessage = response.ToString();
331-
Assert.IsTrue(errorMessage.Contains(DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE));
347+
if (string.IsNullOrEmpty(expectedErrorMessage))
348+
{
349+
Assert.AreEqual(id, response.GetProperty("id").GetString());
350+
}
351+
else
352+
{
353+
// Validate the result contains the GraphQL authorization error code.
354+
string errorMessage = response.ToString();
355+
Assert.IsTrue(errorMessage.Contains(expectedErrorMessage));
356+
}
357+
}
358+
359+
/// <summary>
360+
/// Delete Mutation performed on the fields with different auth permissions
361+
/// It throws permission denied error if role doesn't have permission to perform the operation
362+
/// </summary>
363+
[TestMethod]
364+
[DataRow("field-mutation-with-read-permission", null)] // exclude and include fields. Response is BLANK.
365+
[DataRow("authenticated", null)] // full permission. Response is BLANK
366+
[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")] // if only update permission is there
367+
[DataRow("wildcard-exclude-fields-role", "The mutation operation deleteEarth was successful but the current user is unauthorized to view the response due to lack of read permissions")] // exclude wildcard
368+
[DataRow("only-create-role", "The current user is not authorized to access this resource")] // if update permission is not there
369+
public async Task DeleteItemWithAuthPermissions(string roleName, string expectedErrorMessage)
370+
{
371+
// Create an item with "Authenticated" role
372+
string id = Guid.NewGuid().ToString();
373+
const string name = "test_name";
374+
string createMutation = $@"
375+
mutation {{
376+
createEarth (item: {{ id: ""{id}"", name: ""{name}"" }}) {{
377+
id
378+
name
379+
}}
380+
}}";
381+
382+
JsonElement createResponse = await ExecuteGraphQLRequestAsync("createEarth", createMutation,
383+
variables: new(),
384+
authToken: AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: AuthorizationType.Authenticated.ToString()),
385+
clientRoleHeader: AuthorizationType.Authenticated.ToString());
386+
387+
// Making sure item is created successfully
388+
Assert.AreEqual(id, createResponse.GetProperty("id").GetString());
389+
390+
// Run mutation Update Earth;
391+
string mutation = @"
392+
mutation ($id: ID!, $partitionKeyValue: String!) {
393+
deleteEarth (id: $id, _partitionKeyValue: $partitionKeyValue) {
394+
id
395+
name
396+
}
397+
}";
398+
string authtoken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: roleName);
399+
JsonElement response = await ExecuteGraphQLRequestAsync(
400+
queryName: "deleteEarth",
401+
query: mutation,
402+
variables: new() { { "id", id }, { "partitionKeyValue", id }},
403+
authToken: authtoken,
404+
clientRoleHeader: roleName);
405+
406+
if (string.IsNullOrEmpty(expectedErrorMessage))
407+
{
408+
Assert.IsTrue(string.IsNullOrEmpty(response.ToString()));
409+
}
410+
else
411+
{
412+
// Validate the result contains the GraphQL authorization error code.
413+
string errorMessage = response.ToString();
414+
Assert.IsTrue(errorMessage.Contains(expectedErrorMessage));
415+
}
332416
}
333417

334418
/// <summary>
@@ -649,7 +733,7 @@ public void TestFixtureTearDown()
649733
{
650734
CosmosClientProvider cosmosClientProvider = _application.Services.GetService<CosmosClientProvider>();
651735
CosmosClient cosmosClient = cosmosClientProvider.Clients[cosmosClientProvider.RuntimeConfigProvider.GetConfig().GetDefaultDataSourceName()];
652-
// cosmosClient.GetDatabase(DATABASE_NAME).GetContainer(_containerName).DeleteContainerAsync().Wait();
736+
cosmosClient.GetDatabase(DATABASE_NAME).GetContainer(_containerName).DeleteContainerAsync().Wait();
653737
}
654738
}
655739
}

src/Service.Tests/dab-config.CosmosDb_NoSql.json

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -277,18 +277,41 @@
277277
},
278278
"permissions": [
279279
{
280-
"role": "anonymous",
280+
"role": "authenticated",
281281
"actions": [
282282
{
283-
"action": "update",
283+
"action": "create"
284+
},
285+
{
286+
"action": "read"
287+
},
288+
{
289+
"action": "update"
290+
},
291+
{
292+
"action": "delete"
293+
}
294+
]
295+
},
296+
{
297+
"role": "field-mutation-with-read-permission",
298+
"actions": [
299+
{
300+
"action": "read"
301+
},
302+
{
303+
"action": "create",
284304
"fields": {
285305
"exclude": [
286-
"*"
306+
"name"
307+
],
308+
"include": [
309+
"id"
287310
]
288311
}
289312
},
290313
{
291-
"action": "read",
314+
"action": "update",
292315
"fields": {
293316
"exclude": [
294317
"name"
@@ -300,33 +323,68 @@
300323
}
301324
},
302325
{
303-
"action": "create",
326+
"action": "delete",
304327
"fields": {
305328
"exclude": [
306329
"name"
307330
],
308331
"include": [
309-
"id"
332+
"id",
333+
"type"
310334
]
311335
}
312-
},
313-
{
314-
"action": "delete"
315336
}
316337
]
317338
},
318339
{
319-
"role": "authenticated",
340+
"role": "wildcard-exclude-fields-role",
320341
"actions": [
321342
{
322-
"action": "create"
343+
"action": "update",
344+
"fields": {
345+
"exclude": [
346+
"*"
347+
]
348+
}
323349
},
324350
{
325-
"action": "read"
351+
"action": "create",
352+
"fields": {
353+
"exclude": [
354+
"*"
355+
]
356+
}
326357
},
358+
{
359+
"action": "delete",
360+
"fields": {
361+
"exclude": [
362+
"*"
363+
]
364+
}
365+
}
366+
367+
]
368+
},
369+
{
370+
"role": "only-create-role",
371+
"actions": [
372+
{
373+
"action": "create"
374+
}
375+
]
376+
},
377+
{
378+
"role": "only-update-role",
379+
"actions": [
327380
{
328381
"action": "update"
329-
},
382+
}
383+
]
384+
},
385+
{
386+
"role": "only-delete-role",
387+
"actions": [
330388
{
331389
"action": "delete"
332390
}

0 commit comments

Comments
 (0)