diff --git a/config-generators/cosmosdb_nosql-commands.txt b/config-generators/cosmosdb_nosql-commands.txt index afd0a64ce4..584cbd21f9 100644 --- a/config-generators/cosmosdb_nosql-commands.txt +++ b/config-generators/cosmosdb_nosql-commands.txt @@ -12,4 +12,6 @@ add Earth --config "dab-config.CosmosDb_NoSql.json" --source "graphqldb.earth" - 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 "*" -update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "authenticated:create,read,update,delete" \ No newline at end of file +update Earth --config "dab-config.CosmosDb_NoSql.json" --permissions "authenticated:create,read,update,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" diff --git a/src/Config/RuntimeConfig.cs b/src/Config/RuntimeConfig.cs index c973eb37b0..a58bdc60cf 100644 --- a/src/Config/RuntimeConfig.cs +++ b/src/Config/RuntimeConfig.cs @@ -237,6 +237,7 @@ public void MapGraphQLSingularTypeToEntityName(ILogger? logger) if (entity.GraphQL is null || entity.GraphQL is true) { // Use entity name since GraphQL type unavailable + GraphQLSingularTypeToEntityNameMap.TryAdd(entityName, entityName); logger?.LogInformation($"GraphQL type for {entityName} is {entityName}"); } } diff --git a/src/Service.Tests/CosmosTests/QueryFilterTests.cs b/src/Service.Tests/CosmosTests/QueryFilterTests.cs index 6ecc99b2f3..29f764fc89 100644 --- a/src/Service.Tests/CosmosTests/QueryFilterTests.cs +++ b/src/Service.Tests/CosmosTests/QueryFilterTests.cs @@ -36,7 +36,7 @@ public static void TestFixtureSetup(TestContext context) OverrideEntityContainer("Planet", _containerName); OverrideEntityContainer("Earth", _containerName); OverrideEntityContainer("StarAlias", _containerName); - OverrideEntityContainer("TagAlias", _containerName); + OverrideEntityContainer("Sun", _containerName); } /// @@ -834,6 +834,61 @@ public async Task TestQueryFieldAuthConflictingWithFilterFieldAuth_Unauthorized( string errorMessage = response.ToString(); Assert.IsTrue(errorMessage.Contains("The current user is not authorized to access this resource.")); } + + /// + /// Tests that the field level query filter succeeds requests + /// when GraphQL is set to true without setting singular type in runtime config and + /// when include fields are WILDCARD, + /// all the columns are able to be retrieved for authorization validation. + /// + [TestMethod] + public async Task TestQueryFilterFieldAuthWithoutSingularType() + { + string gqlQuery = @"{ + suns(first: 1, " + QueryBuilder.FILTER_FIELD_NAME + @" : {id : {eq : """ + _idList[0] + @"""}}) + { + items { + id + name + } + } + }"; + + string dbQuery = $"SELECT top 1 c.id, c.name FROM c where c.id = \"{_idList[0]}\""; + await ExecuteAndValidateResult("suns", gqlQuery, dbQuery); + } + + /// + /// Tests that the field level query filter failed authorization validation + /// when include fields are WILDCARD and exclude fields specifies fields, + /// exclude fields takes precedence over include fields. + /// + [TestMethod] + public async Task TestQueryFilterFieldAuth_ExcludeTakesPredecence() + { + string gqlQuery = @"{ + suns(first: 1, " + QueryBuilder.FILTER_FIELD_NAME + @" : {name : {eq : ""test name""}}) + { + items { + id + name + } + } + }"; + + string clientRoleHeader = AuthorizationType.Anonymous.ToString(); + JsonElement response = await ExecuteGraphQLRequestAsync( + queryName: "suns", + query: gqlQuery, + variables: new() { { "name", "test name" } }, + 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)); + + } #endregion [ClassCleanup] diff --git a/src/Service.Tests/CosmosTests/TestBase.cs b/src/Service.Tests/CosmosTests/TestBase.cs index 49018c5a3c..8d35b339e8 100644 --- a/src/Service.Tests/CosmosTests/TestBase.cs +++ b/src/Service.Tests/CosmosTests/TestBase.cs @@ -72,6 +72,11 @@ type Earth @model(name:""Earth"") { id : ID, name : String, type: String @authorize(roles: [""authenticated""]) +} + +type Sun @model(name:""Sun"") { + id : ID, + name : String }"; private static string[] _planets = { "Earth", "Mars", "Jupiter", "Tatooine", "Endor", "Dagobah", "Hoth", "Bespin", "Spec%ial" }; diff --git a/src/Service.Tests/dab-config.CosmosDb_NoSql.json b/src/Service.Tests/dab-config.CosmosDb_NoSql.json index 41063efd9c..84156a1759 100644 --- a/src/Service.Tests/dab-config.CosmosDb_NoSql.json +++ b/src/Service.Tests/dab-config.CosmosDb_NoSql.json @@ -148,6 +148,31 @@ } } }, + "Sun": { + "source": "graphqldb.sun", + "permissions": [ + { + "role": "anonymous", + "actions": [ + "create", + { + "action": "read", + "fields": { + "include": [ + "*" + ], + "exclude": [ + "name" + ] + } + }, + "update", + "delete" + ] + } + ], + "graphql": true + }, "Moon": { "source": "graphqldb.moon", "permissions": [