Skip to content

Commit 165ba8a

Browse files
authored
Cosmos DB: Added Authorization related tests (#2034)
## Why make this change? No Code Change as of Now. ## What is this change? Added tests to cover scenarios related to auth in cosmos DB, with below config changes: a) Added different combinations of role for `Earth` entity b) Removed `Anonymous` role for `Earth` entity **NOTE:** Item level authorization tests are not covered here. ## How was this tested? - [x] Integration Tests - [ ] Unit Tests
1 parent f557b4d commit 165ba8a

File tree

6 files changed

+452
-53
lines changed

6 files changed

+452
-53
lines changed

config-generators/cosmosdb_nosql-commands.txt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,25 @@ update StarAlias --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.s
88
add TagAlias --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.tag" --permissions "anonymous:create,read,update,delete" --graphql "Tag:Tags"
99
add Moon --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moon" --permissions "anonymous:create,read,update,delete" --graphql true
1010
update Moon --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moon" --permissions "authenticated:create,read,update,delete"
11-
add Earth --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.earth" --permissions "anonymous:delete" --graphql "Earth:Earths"
12-
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:create" --fields.include "id" --fields.exclude "name"
13-
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:read" --fields.include "id,type" --fields.exclude "name"
14-
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:update" --fields.exclude "*"
11+
add Earth --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.earth" --permissions "field-mutation-with-read-permission:read" --graphql "Earth:Earths"
12+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "field-mutation-with-read-permission:create" --fields.include "id" --fields.exclude "name"
13+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "field-mutation-with-read-permission:delete" --fields.include "id,type" --fields.exclude "name"
14+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "field-mutation-with-read-permission:update" --fields.include "id,type" --fields.exclude "name"
1515
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "authenticated:create,read,update,delete"
16+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "limited-read-role:read" --fields.include "id,type" --fields.exclude "name"
17+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "wildcard-exclude-fields-role:create" --fields.exclude "*"
18+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "wildcard-exclude-fields-role:update" --fields.exclude "*"
19+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "wildcard-exclude-fields-role:delete" --fields.exclude "*"
20+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "wildcard-exclude-fields-role:read" --fields.exclude "*"
21+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "only-create-role:create"
22+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "only-update-role:update"
23+
update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "only-delete-role:delete"
1624
add Sun --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.sun" --permissions "anonymous:create,update,delete" --graphql true
1725
update Sun --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:read" --fields.include "*" --fields.exclude "name"
1826
add AdditionalAttribute --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.additionalAttribute" --permissions "anonymous:*" --graphql "AdditionalAttribute:AdditionalAttributes"
1927
add MoonAdditionalAttribute --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moonAdditionalAttributes" --permissions "anonymous:*" --graphql "MoonAdditionalAttribute:MoonAdditionalAttributes"
20-
add MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moreAttribute" --permissions "anonymous:*" --graphql "MoreAttribute:MoreAttributes"
28+
add MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.moreAttribute" --permissions "anonymous:delete" --graphql "MoreAttribute:MoreAttributes"
29+
update MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:create" --fields.include "id" --fields.exclude "name"
30+
update MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:read" --fields.include "id" --fields.exclude "name"
31+
update MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --permissions "anonymous:update" --fields.exclude "*"
32+
update MoreAttrAlias --config "dab-config.CosmosDb_NoSql.json" --permissions "authenticated:create,read,update,delete"

src/Service.Tests/CosmosTests/MutationTests.cs

Lines changed: 127 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,16 @@ public class MutationTests : TestBase
3131
name
3232
}
3333
}";
34+
3435
private static readonly string _deletePlanetMutation = @"
3536
mutation ($id: ID!, $partitionKeyValue: String!) {
3637
deletePlanet (id: $id, _partitionKeyValue: $partitionKeyValue) {
3738
id
3839
name
3940
}
4041
}";
42+
private const string USER_NOT_AUTHORIZED = "The current user is not authorized to access this resource";
43+
private const string NO_ERROR_MESSAGE = null;
4144

4245
/// <summary>
4346
/// Executes once for the test.
@@ -252,62 +255,78 @@ public async Task MutationMissingRequiredPartitionKeyValueReturnError()
252255
}
253256

254257
/// <summary>
255-
/// Mutation can be performed on the authorized fields because the
256-
/// field `id` is an included field for the create operation on the anonymous role defined
257-
/// for entity 'earth'
258+
/// Create Mutation performed on the fields with different auth permissions
259+
/// It throws permission denied error if role doesn't have permission to perform the operation
258260
/// </summary>
259261
[TestMethod]
260-
public async Task CanCreateItemWithAuthorizedFields()
262+
[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.")]
263+
[DataRow("authenticated", MutationTests.NO_ERROR_MESSAGE, DisplayName = "AuthZ success when role has no create/read operation restrictions.")]
264+
[DataRow("only-create-role", "The mutation operation createEarth was successful " +
265+
"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.")]
266+
[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.")]
267+
[DataRow("only-update-role", MutationTests.USER_NOT_AUTHORIZED, DisplayName = "AuthZ failure when create permission is NOT there.")]
268+
public async Task CreateItemWithAuthPermissions(string roleName, string expectedErrorMessage)
261269
{
262270
// Run mutation Add Earth;
263271
string id = Guid.NewGuid().ToString();
272+
const string name = "test_name";
264273
string mutation = $@"
265274
mutation {{
266-
createEarth (item: {{ id: ""{id}"" }}) {{
275+
createEarth (item: {{ id: ""{id}"", name: ""{name}"" }}) {{
267276
id
277+
name
268278
}}
269279
}}";
270-
JsonElement response = await ExecuteGraphQLRequestAsync("createEarth", mutation, variables: new());
280+
string authtoken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: roleName);
281+
JsonElement response = await ExecuteGraphQLRequestAsync("createEarth", mutation, variables: new(), authToken: authtoken, clientRoleHeader: roleName);
271282

272-
// Validate results
273-
Assert.AreEqual(id, response.GetProperty("id").GetString());
283+
// Validate the result contains the GraphQL authorization error code.
284+
Console.WriteLine(response.ToString());
285+
if (string.IsNullOrEmpty(expectedErrorMessage))
286+
{
287+
Assert.AreEqual(id, response.GetProperty("id").GetString());
288+
}
289+
else
290+
{
291+
// Validate the result contains the GraphQL authorization error code.
292+
string errorMessage = response.ToString();
293+
Assert.IsTrue(errorMessage.Contains(expectedErrorMessage));
294+
}
274295
}
275296

276297
/// <summary>
277-
/// Mutation performed on the unauthorized fields throws permission denied error because the
278-
/// field `name` is an excluded field for the create operation on the anonymous role defined
279-
/// for entity 'earth'
298+
/// Update Mutation performed on the fields with different auth permissions
299+
/// It throws permission denied error if role doesn't have permission to perform the operation
280300
/// </summary>
281301
[TestMethod]
282-
public async Task CreateItemWithUnauthorizedFieldsReturnsError()
302+
[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.")]
303+
[DataRow("authenticated", NO_ERROR_MESSAGE, DisplayName = "AuthZ success when role has no update/read operation restrictions.")]
304+
[DataRow("only-update-role", "The mutation operation updateEarth was successful " +
305+
"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.")]
306+
[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.")]
307+
[DataRow("only-create-role", MutationTests.USER_NOT_AUTHORIZED, DisplayName = "AuthZ failure when update permission is NOT there.")]
308+
public async Task UpdateItemWithAuthPermissions(string roleName, string expectedErrorMessage)
283309
{
284-
// Run mutation Add Earth;
310+
// Create an item with "Authenticated" role
285311
string id = Guid.NewGuid().ToString();
286312
const string name = "test_name";
287-
string mutation = $@"
313+
string createMutation = $@"
288314
mutation {{
289315
createEarth (item: {{ id: ""{id}"", name: ""{name}"" }}) {{
290316
id
291317
name
292318
}}
293319
}}";
294-
JsonElement response = await ExecuteGraphQLRequestAsync("createEarth", mutation, variables: new());
295320

296-
// Validate the result contains the GraphQL authorization error code.
297-
string errorMessage = response.ToString();
298-
Assert.IsTrue(errorMessage.Contains(DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE));
299-
}
321+
JsonElement createResponse = await ExecuteGraphQLRequestAsync("createEarth", createMutation,
322+
variables: new(),
323+
authToken: AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: AuthorizationType.Authenticated.ToString()),
324+
clientRoleHeader: AuthorizationType.Authenticated.ToString());
325+
326+
// Making sure item is created successfully
327+
Assert.AreEqual(id, createResponse.GetProperty("id").GetString());
300328

301-
/// <summary>
302-
/// Mutation performed on the unauthorized fields throws permission denied error because the
303-
/// wildcard is used in the excluded field for the update operation on the anonymous role defined
304-
/// for entity 'earth'
305-
/// </summary>
306-
[TestMethod]
307-
public async Task UpdateItemWithUnauthorizedWildCardReturnsError()
308-
{
309329
// Run mutation Update Earth;
310-
string id = Guid.NewGuid().ToString();
311330
string mutation = @"
312331
mutation ($id: ID!, $partitionKeyValue: String!, $item: UpdateEarthInput!) {
313332
updateEarth (id: $id, _partitionKeyValue: $partitionKeyValue, item: $item) {
@@ -321,11 +340,87 @@ public async Task UpdateItemWithUnauthorizedWildCardReturnsError()
321340
name = "new_name"
322341
};
323342

324-
JsonElement response = await ExecuteGraphQLRequestAsync("updateEarth", mutation, variables: new() { { "id", id }, { "partitionKeyValue", id }, { "item", update } });
343+
string authtoken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: roleName);
344+
JsonElement response = await ExecuteGraphQLRequestAsync(
345+
queryName: "updateEarth",
346+
query: mutation,
347+
variables: new() { { "id", id }, { "partitionKeyValue", id }, { "item", update } },
348+
authToken: authtoken,
349+
clientRoleHeader: roleName);
325350

326-
// Validate the result contains the GraphQL authorization error code.
327-
string errorMessage = response.ToString();
328-
Assert.IsTrue(errorMessage.Contains(DataApiBuilderException.GRAPHQL_MUTATION_FIELD_AUTHZ_FAILURE));
351+
Console.WriteLine(response.ToString());
352+
if (string.IsNullOrEmpty(expectedErrorMessage))
353+
{
354+
Assert.AreEqual(id, response.GetProperty("id").GetString());
355+
}
356+
else
357+
{
358+
// Validate the result contains the GraphQL authorization error code.
359+
string errorMessage = response.ToString();
360+
Assert.IsTrue(errorMessage.Contains(expectedErrorMessage));
361+
}
362+
}
363+
364+
/// <summary>
365+
/// Delete Mutation performed on the fields with different auth permissions
366+
/// It throws permission denied error if role doesn't have permission to perform the operation
367+
/// </summary>
368+
[TestMethod]
369+
[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.")]
370+
[DataRow("authenticated", MutationTests.NO_ERROR_MESSAGE, DisplayName = "AuthZ success and blank response when role has no delete operation restrictions.")]
371+
[DataRow("only-delete-role", "The mutation operation deleteEarth was successful " +
372+
"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.")]
373+
[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")]
374+
[DataRow("only-create-role", MutationTests.USER_NOT_AUTHORIZED, DisplayName = "AuthZ failure when delete permission is NOT there.")]
375+
public async Task DeleteItemWithAuthPermissions(string roleName, string expectedErrorMessage)
376+
{
377+
// Create an item with "Authenticated" role
378+
string id = Guid.NewGuid().ToString();
379+
const string name = "test_name";
380+
string createMutation = $@"
381+
mutation {{
382+
createEarth (item: {{ id: ""{id}"", name: ""{name}"" }}) {{
383+
id
384+
name
385+
}}
386+
}}";
387+
388+
JsonElement createResponse = await ExecuteGraphQLRequestAsync("createEarth", createMutation,
389+
variables: new(),
390+
authToken: AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: AuthorizationType.Authenticated.ToString()),
391+
clientRoleHeader: AuthorizationType.Authenticated.ToString());
392+
393+
// Making sure item is created successfully
394+
Assert.AreEqual(id, createResponse.GetProperty("id").GetString());
395+
396+
// Run mutation Update Earth;
397+
string mutation = @"
398+
mutation ($id: ID!, $partitionKeyValue: String!) {
399+
deleteEarth (id: $id, _partitionKeyValue: $partitionKeyValue) {
400+
id
401+
name
402+
}
403+
}";
404+
string authtoken = AuthTestHelper.CreateStaticWebAppsEasyAuthToken(specificRole: roleName);
405+
JsonElement response = await ExecuteGraphQLRequestAsync(
406+
queryName: "deleteEarth",
407+
query: mutation,
408+
variables: new() { { "id", id }, { "partitionKeyValue", id } },
409+
authToken: authtoken,
410+
clientRoleHeader: roleName);
411+
412+
Console.WriteLine(response.ToString());
413+
414+
if (string.IsNullOrEmpty(expectedErrorMessage))
415+
{
416+
Assert.IsTrue(string.IsNullOrEmpty(response.ToString()));
417+
}
418+
else
419+
{
420+
// Validate the result contains the GraphQL authorization error code.
421+
string errorMessage = response.ToString();
422+
Assert.IsTrue(errorMessage.Contains(expectedErrorMessage));
423+
}
329424
}
330425

331426
/// <summary>

0 commit comments

Comments
 (0)