-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ODS-5764] Profile usage is not enforced (v5.2) (#675)
* [ODS-5764] Profile usage is not enforced (v5.1) (#672) * Initial commit of all perceived changes needed for Profiles enforcement. * Fixed bug with GetById action method not returning the application/vnd.ed-fi. content types for Profile-based requests. * Updated profile enforcement filter to match the needs of the v5.1.0 architecture (sans Dynamic Profiles), also adding some needed checks that are implemented as part of the v7.0 mapping contract logic. * Added lazy loading to the newly added GetByApiCollectionName method to ensure that the source dictionary has been fully initialized before the URI-based lookup dictionary is prepared. * using statement usage update for older version of C# language, and associated whitespace changes. * Remove commented out code, and fix whitespace/indentation issues. * Modified status and error message associated with GET requests using a writable content type (and vice-versa) to match behavior of pre-5.1.0 behavior. * Changes for alignment with v5.1.1 Postman Profiles integration tests. * Profiles boilerplate removal due to Postman export format update. * Remove all access token usage from tests that don't cover assigned profile functionality. * Fixed bad URLs in requests (removing extra slash). * Alignment of test expectations to actual behavior with Profile enforcement fixes. * Remove redundant Npgsql package reference. * Remove redundant NUnit package reference. * Removed unused access token for non-existing API client. * Changed conditional check for Profiles feature to use literal true rather then string-value of "true". * Provide a fix for the missing dependency for the EnforceAssignedProfileUsageFilter class when the Profiles feature is not enabled. * Updated Postman test failing based on case sensitive string comparison to use RegExp class for case-insensitive comparison. * Fixing Build Error on OdsStartupBase --------- Co-authored-by: Geoff McElhanon <[email protected]>
- Loading branch information
1 parent
56330e0
commit cd7ca9a
Showing
27 changed files
with
1,071 additions
and
908 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
Application/EdFi.Ods.Api/Filters/DataManagementRequestContextFilter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Licensed to the Ed-Fi Alliance under one or more agreements. | ||
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0. | ||
// See the LICENSE and NOTICES files in the project root for more information. | ||
|
||
using System; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using EdFi.Common.Configuration; | ||
using EdFi.Ods.Api.Constants; | ||
using EdFi.Ods.Common.Configuration; | ||
using EdFi.Ods.Common.Context; | ||
using EdFi.Ods.Common.Extensions; | ||
using EdFi.Ods.Common.Models; | ||
using EdFi.Ods.Common.Models.Resource; | ||
using EdFi.Ods.Common.Security.Claims; | ||
using log4net; | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.Extensions.Primitives; | ||
|
||
namespace EdFi.Ods.Api.Filters | ||
{ | ||
/// <summary> | ||
/// A resource filter that inspects the action descriptor's AttributeRouteInfo to locate | ||
/// the <see cref="Resource" /> associated with the current data management API request. | ||
/// </summary> | ||
public class DataManagementRequestContextFilter : IAsyncResourceFilter | ||
{ | ||
private readonly IContextProvider<DataManagementResourceContext> _contextProvider; | ||
private readonly ApiSettings _apiSettings; | ||
|
||
private readonly ILog _logger = LogManager.GetLogger(typeof(DataManagementRequestContextFilter)); | ||
private readonly IResourceModelProvider _resourceModelProvider; | ||
|
||
private readonly Lazy<string> _templatePrefix; | ||
private readonly Lazy<string[]> _knownSchemaUriSegments; | ||
|
||
public DataManagementRequestContextFilter( | ||
IResourceModelProvider resourceModelProvider, | ||
IContextProvider<DataManagementResourceContext> contextProvider, | ||
ApiSettings apiSettings) | ||
{ | ||
_resourceModelProvider = resourceModelProvider; | ||
_contextProvider = contextProvider; | ||
|
||
_knownSchemaUriSegments = new Lazy<string[]>( | ||
() => _resourceModelProvider.GetResourceModel() | ||
.SchemaNameMapProvider.GetSchemaNameMaps() | ||
.Select(m => m.UriSegment) | ||
.ToArray()); | ||
|
||
_apiSettings = apiSettings; | ||
_templatePrefix = new Lazy<string>(GetTemplatePrefix); | ||
} | ||
|
||
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) | ||
{ | ||
var attributeRouteInfo = context.ActionDescriptor.AttributeRouteInfo; | ||
|
||
if (attributeRouteInfo != null) | ||
{ | ||
string template = attributeRouteInfo.Template; | ||
|
||
// e.g. data/v3/ed-fi/gradebookEntries | ||
|
||
// Is this a data management route? | ||
if (template?.StartsWith(_templatePrefix.Value) ?? false) | ||
{ | ||
var templateSegment = new StringSegment(template); | ||
|
||
var parts = templateSegment.Subsegment(_templatePrefix.Value.Length).Split(new[]{'/'}); | ||
using var partsEnumerator = parts.GetEnumerator(); | ||
partsEnumerator.MoveNext(); | ||
|
||
string schema, resourceCollection; | ||
|
||
// If the schema segment is a templated route value... | ||
if (partsEnumerator.Current == "{schema}") | ||
{ | ||
if (!context.RouteData.Values.TryGetValue("schema", out object schemaAsObject) | ||
|| !context.RouteData.Values.TryGetValue("resource", out object resourceAsObject)) | ||
{ | ||
await next(); | ||
|
||
return; | ||
} | ||
|
||
schema = (string) schemaAsObject; | ||
resourceCollection = (string) resourceAsObject; | ||
} | ||
else | ||
{ | ||
// If this is NOT a known schema URI segment... | ||
if (!_knownSchemaUriSegments.Value.Any(s => partsEnumerator.Current.Equals(s))) | ||
{ | ||
await next(); | ||
|
||
return; | ||
} | ||
|
||
schema = partsEnumerator.Current.Value; | ||
|
||
partsEnumerator.MoveNext(); | ||
resourceCollection = partsEnumerator.Current.Value; | ||
} | ||
|
||
// Find and capture the associated resource to context | ||
try | ||
{ | ||
var resource = _resourceModelProvider.GetResourceModel() | ||
.GetResourceByApiCollectionName(schema, resourceCollection); | ||
|
||
_contextProvider.Set(new DataManagementResourceContext(resource)); | ||
} | ||
catch (Exception) | ||
{ | ||
_logger.Debug( | ||
$"Unable to find resource based on route template value '{template.Substring(RouteConstants.DataManagementRoutePrefix.Length + 1)}'..."); | ||
} | ||
} | ||
} | ||
|
||
await next(); | ||
} | ||
|
||
public void OnActionExecuted(ActionExecutedContext context) { } | ||
|
||
private string GetTemplatePrefix() | ||
{ | ||
string template = $"{RouteConstants.DataManagementRoutePrefix}/"; | ||
|
||
if (_apiSettings.GetApiMode() == ApiMode.YearSpecific) | ||
{ | ||
template += RouteConstants.SchoolYearFromRoute; | ||
} | ||
|
||
if (_apiSettings.GetApiMode() == ApiMode.InstanceYearSpecific) | ||
{ | ||
template += RouteConstants.InstanceIdFromRouteForFilter; | ||
template += RouteConstants.SchoolYearFromRoute; | ||
} | ||
|
||
return template; | ||
} | ||
} | ||
} |
Oops, something went wrong.