diff --git a/Application/EdFi.Ods.Api/Controllers/DataManagementControllerBase.cs b/Application/EdFi.Ods.Api/Controllers/DataManagementControllerBase.cs index 458a4ef633..6b7d3f645e 100644 --- a/Application/EdFi.Ods.Api/Controllers/DataManagementControllerBase.cs +++ b/Application/EdFi.Ods.Api/Controllers/DataManagementControllerBase.cs @@ -152,9 +152,9 @@ public virtual async Task GetAll( //respond quickly to DOS style requests (should we catch these earlier? e.g. attribute filter?) // Store alternative auth approach decision into call context - if (additionalParameters?.TryGetValue("useCteAuth", out string useCteAuth) == true) + if (additionalParameters?.TryGetValue("useJoinAuth", out string useJoinAuth) == true) { - _contextStorage.SetValue("UseCteAuth", Convert.ToBoolean(useCteAuth)); + _contextStorage.SetValue("UseJoinAuth", Convert.ToBoolean(useJoinAuth)); } var queryParameters = new QueryParameters(urlQueryParametersRequest); diff --git a/Application/EdFi.Ods.Api/Controllers/Partitions/Controllers/PartitionsController.cs b/Application/EdFi.Ods.Api/Controllers/Partitions/Controllers/PartitionsController.cs index 27b84844be..fb135e7a14 100644 --- a/Application/EdFi.Ods.Api/Controllers/Partitions/Controllers/PartitionsController.cs +++ b/Application/EdFi.Ods.Api/Controllers/Partitions/Controllers/PartitionsController.cs @@ -70,9 +70,9 @@ public async Task Get( [FromQuery] Dictionary additionalParameters = default) { // Store alternative auth approach decision into call context - if (additionalParameters?.TryGetValue("useCteAuth", out string useCteAuth) == true) + if (additionalParameters?.TryGetValue("useJoinAuth", out string useJoinAuth) == true) { - _contextStorage.SetValue("UseCteAuth", Convert.ToBoolean(useCteAuth)); + _contextStorage.SetValue("UseJoinAuth", Convert.ToBoolean(useJoinAuth)); } if (number is < 1 or > 200) diff --git a/Application/EdFi.Ods.Api/Security/Authorization/Repositories/AggregateRootQueryBuilderProviderAuthorizationDecorator.cs b/Application/EdFi.Ods.Api/Security/Authorization/Repositories/AggregateRootQueryBuilderProviderAuthorizationDecorator.cs index 24b492f69c..0f6a0c50f0 100644 --- a/Application/EdFi.Ods.Api/Security/Authorization/Repositories/AggregateRootQueryBuilderProviderAuthorizationDecorator.cs +++ b/Application/EdFi.Ods.Api/Security/Authorization/Repositories/AggregateRootQueryBuilderProviderAuthorizationDecorator.cs @@ -56,11 +56,11 @@ public QueryBuilder GetQueryBuilder( queryParameters, additionalQueryParameters); - // Do not process if CTE auth has been indicated - bool shouldUseCteAuth = additionalQueryParameters?.TryGetValue("UseCteAuth", out string useCteAuth) == true - && Convert.ToBoolean(useCteAuth); + // Process if join-based auth has been indicated + bool shouldUseJoinAuth = additionalQueryParameters?.TryGetValue("UseJoinAuth", out string useJoinAuth) == true + && Convert.ToBoolean(useJoinAuth); - if (shouldUseCteAuth) + if (!shouldUseJoinAuth) { return queryBuilder; } diff --git a/Application/EdFi.Ods.Api/Security/Authorization/Repositories/AggregateRootQueryBuilderProviderCteAuthorizationDecorator.cs b/Application/EdFi.Ods.Api/Security/Authorization/Repositories/AggregateRootQueryBuilderProviderCteAuthorizationDecorator.cs index 7a0cfe5315..d103aec836 100644 --- a/Application/EdFi.Ods.Api/Security/Authorization/Repositories/AggregateRootQueryBuilderProviderCteAuthorizationDecorator.cs +++ b/Application/EdFi.Ods.Api/Security/Authorization/Repositories/AggregateRootQueryBuilderProviderCteAuthorizationDecorator.cs @@ -56,11 +56,11 @@ public QueryBuilder GetQueryBuilder( queryParameters, additionalQueryParameters); - // Only process if CTE auth has been indicated - bool shouldUseCteAuth = additionalQueryParameters?.TryGetValue("UseCteAuth", out string useCteAuth) == true - && Convert.ToBoolean(useCteAuth); + // Process unless join-based auth has been indicated + bool shouldUseJoinAuth = additionalQueryParameters?.TryGetValue("UseJoinAuth", out string useJoinAuth) == true + && Convert.ToBoolean(useJoinAuth); - if (!shouldUseCteAuth) + if (shouldUseJoinAuth) { return queryBuilder; } diff --git a/Application/EdFi.Ods.Api/Security/AuthorizationStrategies/Relationships/Filters/QueryBuilderExtensions.cs b/Application/EdFi.Ods.Api/Security/AuthorizationStrategies/Relationships/Filters/QueryBuilderExtensions.cs index 7b4b756956..c70692b1be 100644 --- a/Application/EdFi.Ods.Api/Security/AuthorizationStrategies/Relationships/Filters/QueryBuilderExtensions.cs +++ b/Application/EdFi.Ods.Api/Security/AuthorizationStrategies/Relationships/Filters/QueryBuilderExtensions.cs @@ -20,7 +20,7 @@ public static class QueryBuilderExtensions /// /// Applies a join-based filter to the criteria for the specified authorization view. /// - /// + /// The to which criteria should be applied. /// The named parameters to be used to satisfy additional filtering requirements. /// The name of the view to be filtered. /// The name of the property to be joined for the entity being queried. @@ -38,10 +38,10 @@ public static void ApplySingleColumnJoinFilter( JoinType joinType, string authViewAlias = null) { - // Temporary logic to opt-in to CTE-based authorization approach - if (_callContextStorage.GetValue("UseCteAuth")) + // Temporary logic to opt-in to join-based authorization approach + if (_callContextStorage.GetValue("UseJoinAuth")) { - ApplySingleColumnJoinFilterUsingCtes(queryBuilder, parameters, viewName, subjectEndpointName, viewSourceEndpointName, viewTargetEndpointName, joinType, authViewAlias); + ApplySingleColumnJoinFilterUsingJoins(queryBuilder, parameters, viewName, subjectEndpointName, viewSourceEndpointName, viewTargetEndpointName, joinType, authViewAlias); return; } @@ -53,53 +53,47 @@ public static void ApplySingleColumnJoinFilter( authViewAlias = string.IsNullOrWhiteSpace(authViewAlias) ? $"authView{viewName}" : $"authView{authViewAlias}"; - // Apply authorization join using ICriteria + // Create a CTE query for the authorization view + var cte = new QueryBuilder(queryBuilder.Dialect); + cte.From($"auth.{viewName} AS av"); + cte.Select($"av.{viewTargetEndpointName}"); + cte.Distinct(); + + // Apply claims to the CTE query + if (value is object[] arrayOfValues) + { + cte.WhereIn($"av.{viewSourceEndpointName}", arrayOfValues); + } + else + { + cte.Where($"av.{viewSourceEndpointName}", value); + } + + // Add the CTE to the main query, with alias + queryBuilder.With(authViewAlias, cte); + + // Apply join to the authorization CTE if (joinType == JoinType.InnerJoin) { queryBuilder.Join( - $"auth.{viewName} AS {authViewAlias}", + authViewAlias, j => j.On($"r.{subjectEndpointName}", $"{authViewAlias}.{viewTargetEndpointName}")); } else if (joinType == JoinType.LeftOuterJoin) { queryBuilder.LeftJoin( - $"auth.{viewName} AS {authViewAlias}", + authViewAlias, j => j.On($"r.{subjectEndpointName}", $"{authViewAlias}.{viewTargetEndpointName}")); + + queryBuilder.Where(qb => qb.WhereNotNull($"{authViewAlias}.{viewTargetEndpointName}")); } else { throw new NotSupportedException("Unsupported authorization view join type."); } - - if (value is object[] arrayOfValues) - { - if (joinType == JoinType.InnerJoin) - { - queryBuilder.WhereIn($"{authViewAlias}.{viewSourceEndpointName}", arrayOfValues); - } - else - { - queryBuilder.Where(qb => - qb.WhereIn($"{authViewAlias}.{viewSourceEndpointName}", arrayOfValues) - .WhereNotNull($"{authViewAlias}.{viewTargetEndpointName}")); - } - } - else - { - if (joinType == JoinType.InnerJoin) - { - queryBuilder.Where($"{authViewAlias}.{viewSourceEndpointName}", value); - } - else - { - queryBuilder.Where(qb => - qb.Where($"{authViewAlias}.{viewSourceEndpointName}", value) - .WhereNotNull($"{authViewAlias}.{viewTargetEndpointName}")); - } - } } - private static void ApplySingleColumnJoinFilterUsingCtes( + private static void ApplySingleColumnJoinFilterUsingJoins( this QueryBuilder queryBuilder, IDictionary parameters, string viewName, @@ -117,50 +111,56 @@ private static void ApplySingleColumnJoinFilterUsingCtes( authViewAlias = string.IsNullOrWhiteSpace(authViewAlias) ? $"authView{viewName}" : $"authView{authViewAlias}"; - // Create a CTE query for the authorization view - var cte = new QueryBuilder(queryBuilder.Dialect); - cte.From($"auth.{viewName} AS av"); - cte.Select($"av.{viewTargetEndpointName}"); - cte.Distinct(); - - // Apply claims to the CTE query - if (value is object[] arrayOfValues) - { - cte.WhereIn($"av.{viewSourceEndpointName}", arrayOfValues); - } - else - { - cte.Where($"av.{viewSourceEndpointName}", value); - } - - // Add the CTE to the main query, with alias - queryBuilder.With(authViewAlias, cte); - - // Apply join to the authorization CTE + // Apply authorization join using ICriteria if (joinType == JoinType.InnerJoin) { queryBuilder.Join( - authViewAlias, + $"auth.{viewName} AS {authViewAlias}", j => j.On($"r.{subjectEndpointName}", $"{authViewAlias}.{viewTargetEndpointName}")); } else if (joinType == JoinType.LeftOuterJoin) { queryBuilder.LeftJoin( - authViewAlias, + $"auth.{viewName} AS {authViewAlias}", j => j.On($"r.{subjectEndpointName}", $"{authViewAlias}.{viewTargetEndpointName}")); - - queryBuilder.Where(qb => qb.WhereNotNull($"{authViewAlias}.{viewTargetEndpointName}")); } else { throw new NotSupportedException("Unsupported authorization view join type."); } + + if (value is object[] arrayOfValues) + { + if (joinType == JoinType.InnerJoin) + { + queryBuilder.WhereIn($"{authViewAlias}.{viewSourceEndpointName}", arrayOfValues); + } + else + { + queryBuilder.Where(qb => + qb.WhereIn($"{authViewAlias}.{viewSourceEndpointName}", arrayOfValues) + .WhereNotNull($"{authViewAlias}.{viewTargetEndpointName}")); + } + } + else + { + if (joinType == JoinType.InnerJoin) + { + queryBuilder.Where($"{authViewAlias}.{viewSourceEndpointName}", value); + } + else + { + queryBuilder.Where(qb => + qb.Where($"{authViewAlias}.{viewSourceEndpointName}", value) + .WhereNotNull($"{authViewAlias}.{viewTargetEndpointName}")); + } + } } /// /// Applies a join-based filter to the criteria for the specified custom authorization view. /// - /// The criteria to which filters should be applied. + /// The to which criteria should be applied. /// The name of the view to be filtered. /// The name of the property to be joined for the entity being queried. /// The name of the property to be joined for the other property as authorization view.