diff --git a/src/Service.Tests/Authorization/REST/RestAuthorizationHandlerUnitTests.cs b/src/Service.Tests/Authorization/REST/RestAuthorizationHandlerUnitTests.cs index d8bfea1d18..4b298f78c5 100644 --- a/src/Service.Tests/Authorization/REST/RestAuthorizationHandlerUnitTests.cs +++ b/src/Service.Tests/Authorization/REST/RestAuthorizationHandlerUnitTests.cs @@ -234,16 +234,23 @@ public async Task EntityRoleOperationResourceTest() // Negative tests where authorization fails for Find requests with no $f filter query string parameter [DataRow(new string[] { "col1", "col2", "col3", "col4", "col5" }, DisplayName = "Find - Request all allowed + 1 disallowed column(s)")] [DataRow(new string[] { "col1", "col5", "col6", "col7", "col9" }, DisplayName = "Find - Request 1 allowed + > 1 disallowed column(s)")] + [DataRow(new string[] { }, false, false, DisplayName = "Find - Request on entity with no included columns. The request url contains no key,select,orderby,filter.")] #pragma warning restore format [TestMethod] - public async Task FindColumnPermissionsTests(string[] columnsRequestedInput) + public async Task FindColumnPermissionsTests(string[] columnsRequestedInput, + bool areAllowedExposedColumns = true, + bool expectedAuthorizationResult = true) { IEnumerable columnsRequested = new List( columnsRequestedInput); - IEnumerable allowedColumns = new List( - new string[] { "col1", "col2", "col3", "col4" }); + IEnumerable allowedColumns = new List(); + + if (areAllowedExposedColumns) + { + allowedColumns = new List(new string[] { "col1", "col2", "col3", "col4" }); + } + bool areColumnsAllowed = true; - bool expectedAuthorizationResult = true; // Creates Mock AuthorizationResolver to return a preset result based on [TestMethod] input. Mock authorizationResolver = new(); diff --git a/src/Service/Authorization/RestAuthorizationHandler.cs b/src/Service/Authorization/RestAuthorizationHandler.cs index dd4db530fb..0a83055350 100644 --- a/src/Service/Authorization/RestAuthorizationHandler.cs +++ b/src/Service/Authorization/RestAuthorizationHandler.cs @@ -190,6 +190,12 @@ public Task HandleAsync(AuthorizationHandlerContext context) // - For other operation types, columnsToCheck is a result of identifying // any reference to a column in all parts of a request (body, URL, querystring) IEnumerable fieldsReturnedForFind = _authorizationResolver.GetAllowedExposedColumns(entityName, roleName, operation); + if (fieldsReturnedForFind.Count() == 0) + { + // READ operations with no accessible fields fail authorization. + context.Fail(); + } + restContext.UpdateReturnFields(fieldsReturnedForFind); } else diff --git a/src/Service/Resolvers/Sql Query Structures/SqlQueryStructure.cs b/src/Service/Resolvers/Sql Query Structures/SqlQueryStructure.cs index 9b46bc5ed3..b1db72228a 100644 --- a/src/Service/Resolvers/Sql Query Structures/SqlQueryStructure.cs +++ b/src/Service/Resolvers/Sql Query Structures/SqlQueryStructure.cs @@ -146,19 +146,6 @@ public SqlQueryStructure( IsListQuery = context.IsMany; TableAlias = $"{DatabaseObject.SchemaName}_{DatabaseObject.Name}"; AddFields(context, sqlMetadataProvider); - if (Columns.Count == 0) - { - SourceDefinition sourceDefinition = GetUnderlyingSourceDefinition(); - foreach (KeyValuePair column in sourceDefinition.Columns) - { - // We only include columns that are exposed for use in requests - if (sqlMetadataProvider.TryGetExposedColumnName(EntityName, column.Key, out string? name)) - { - AddColumn(column.Key, name!); - } - } - } - foreach (KeyValuePair predicate in context.PrimaryKeyValuePairs) { sqlMetadataProvider.TryGetBackingColumn(EntityName, predicate.Key, out string? backingColumn);