diff --git a/src/Gemstone.Web/APIController/AuthorizationInfoControllerBase.cs b/src/Gemstone.Web/APIController/AuthorizationInfoControllerBase.cs index 49507353..f4fc1892 100644 --- a/src/Gemstone.Web/APIController/AuthorizationInfoControllerBase.cs +++ b/src/Gemstone.Web/APIController/AuthorizationInfoControllerBase.cs @@ -190,6 +190,53 @@ bool isSupported(string claimType) => claimsProvider /// A list of resources within the application. [HttpGet, Route("resources")] public virtual async Task GetResources(IAuthorizationPolicyProvider policyProvider, EndpointDataSource endpointDataSource) + { + Dictionary> resourceAccessLookup = await ResourceAccessLookup(policyProvider, endpointDataSource); + + IEnumerable resources = resourceAccessLookup + .OrderBy(kvp => kvp.Key) + .Select(kvp => new AuthorizationResource + { + Type = "Controller", + Name = kvp.Key, + AccessTypes = kvp.Value.OrderBy(type => type) + }); + + return Ok(resources); + + } + + /// + /// Gets a list of API resources available for which permissions can be granted within the application. + /// + /// Provides authorization policies defined within the application + /// Source for endpoint data used to look up controller and action metadata + /// A list of resources within the application. + [HttpGet, Route("APIresources")] + public virtual async Task GetAPIResources(IAuthorizationPolicyProvider policyProvider, EndpointDataSource endpointDataSource) + { + Dictionary> resourceAccessLookup = await ResourceAccessLookup(policyProvider, endpointDataSource); + + IEnumerable resources = resourceAccessLookup + .OrderBy(kvp => kvp.Key) + .Select(kvp => new AuthorizationResource + { + Type = "API", + Name = kvp.Key, + AccessTypes = kvp.Value.OrderBy(type => type) + }); + + return Ok(resources); + + } + + /// + /// Gets a list of resources available with the provided . + /// + /// Provides authorization policies defined within the application + /// Source for endpoint data used to look up controller and action metadata + /// A list of resources within the application. + private async Task>> ResourceAccessLookup(IAuthorizationPolicyProvider policyProvider, EndpointDataSource endpointDataSource) where T : IAuthorizationRequirement { Dictionary> resourceAccessLookup = []; @@ -206,12 +253,12 @@ public virtual async Task GetResources(IAuthorizationPolicyProvid IReadOnlyList requirementData = endpoint.Metadata.GetOrderedMetadata() ?? []; AuthorizationPolicy? policy = await AuthorizationPolicy.CombineAsync(policyProvider, authorizeData, policies); - bool hasControllerAccessRequirement = requirementData + bool hasAccessRequirement = requirementData .SelectMany(datum => datum.GetRequirements()) .Concat(policy?.Requirements ?? []) - .Any(requirement => requirement is ControllerAccessRequirement); + .Any(requirement => requirement is T); - if (!hasControllerAccessRequirement) + if (!hasAccessRequirement) continue; IReadOnlyList accessAttributes = endpoint.Metadata @@ -222,38 +269,7 @@ public virtual async Task GetResources(IAuthorizationPolicyProvid HashSet access = resourceAccessLookup.GetOrAdd(resourceName, _ => []); access.UnionWith(accessTypes); } - - IEnumerable resources = resourceAccessLookup - .OrderBy(kvp => kvp.Key) - .Select(kvp => new AuthorizationResource - { - Type = "Controller", - Name = kvp.Key, - AccessTypes = kvp.Value.OrderBy(type => type) - }); - - return Ok(resources); - - static IEnumerable ToAccessTypes(Endpoint endpoint, IEnumerable accessAttributes) - { - ResourceAccessType accessType = accessAttributes.GetAccessType(); - - if (accessType == ResourceAccessType.None) - return []; - - if (accessType != ResourceAccessType.Default) - return [accessType]; - - HttpMethodMetadata? httpMethodMetadata = endpoint.Metadata - .GetMetadata(); - - IReadOnlyList httpMethods = httpMethodMetadata?.HttpMethods - ?? []; - - return httpMethods - .Select(accessAttributes.GetAccessType) - .Where(type => type != ResourceAccessType.None); - } + return resourceAccessLookup; } /// @@ -273,6 +289,27 @@ public virtual IEnumerable CheckAccess([FromBody] ResourceAccessEntry[] ac // Static Methods + private static IEnumerable ToAccessTypes(Endpoint endpoint, IEnumerable accessAttributes) + { + ResourceAccessType accessType = accessAttributes.GetAccessType(); + + if (accessType == ResourceAccessType.None) + return []; + + if (accessType != ResourceAccessType.Default) + return [accessType]; + + HttpMethodMetadata? httpMethodMetadata = endpoint.Metadata + .GetMetadata(); + + IReadOnlyList httpMethods = httpMethodMetadata?.HttpMethods + ?? []; + + return httpMethods + .Select(accessAttributes.GetAccessType) + .Where(type => type != ResourceAccessType.None); + } + private static Regex? ToSearchPattern(string? searchText) { if (searchText is null) diff --git a/src/Gemstone.Web/APIController/ReadOnlyModelController.cs b/src/Gemstone.Web/APIController/ReadOnlyModelController.cs index f681826e..b2d9e113 100644 --- a/src/Gemstone.Web/APIController/ReadOnlyModelController.cs +++ b/src/Gemstone.Web/APIController/ReadOnlyModelController.cs @@ -337,12 +337,12 @@ public virtual async Task Search([FromBody] SearchPost postDat if (ParentKey != string.Empty && parentID is not null) { - filters.Append(new RecordFilter() + filters = filters.Append(new RecordFilter() { FieldName = ParentKey, Operator = "=", SearchParameter = parentID - }); + }).ToArray(); } IAsyncEnumerable result = tableOperations.QueryRecordsAsync(HttpContext.User, postData.OrderBy, postData.Ascending, page, PageSize, cancellationToken, filters); @@ -367,12 +367,12 @@ public virtual async Task GetPageInfo([FromBody] SearchPost po if (ParentKey != string.Empty && parentID is not null) { - filters.Append(new RecordFilter() + filters = filters.Append(new RecordFilter() { FieldName = ParentKey, Operator = "=", SearchParameter = parentID - }); + }).ToArray(); } int recordCount = await tableOperations.QueryRecordCountAsync(HttpContext.User, cancellationToken, filters).ConfigureAwait(false); @@ -401,12 +401,12 @@ public virtual async Task GetPageInfo(string? parentID, Cancellat if (ParentKey != string.Empty && parentID is not null) { - filters.Append(new RecordFilter() + filters = filters.Append(new RecordFilter() { FieldName = ParentKey, Operator = "=", SearchParameter = parentID - }); + }).ToArray(); } int recordCount = await tableOperations.QueryRecordCountAsync(HttpContext.User, cancellationToken, filters).ConfigureAwait(false);