Skip to content
22 changes: 17 additions & 5 deletions config-generators/cosmosdb_nosql-commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
159 changes: 127 additions & 32 deletions src/Service.Tests/CosmosTests/MutationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,16 @@ public class MutationTests : TestBase
name
}
}";

private static readonly string _deletePlanetMutation = @"
mutation ($id: ID!, $partitionKeyValue: String!) {
deletePlanet (id: $id, _partitionKeyValue: $partitionKeyValue) {
id
name
}
}";
private const string USER_NOT_AUTHORIZED = "The current user is not authorized to access this resource";
private const string NO_ERROR_MESSAGE = null;

/// <summary>
/// Executes once for the test.
Expand Down Expand Up @@ -252,62 +255,78 @@ public async Task MutationMissingRequiredPartitionKeyValueReturnError()
}

/// <summary>
/// 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
/// </summary>
[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));
}
}

/// <summary>
/// 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
/// </summary>
[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());

/// <summary>
/// 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'
/// </summary>
[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) {
Expand All @@ -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));
}
}

/// <summary>
/// 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
/// </summary>
[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));
}
}

/// <summary>
Expand Down
Loading