Skip to content

Commit

Permalink
Reversed support for authorization to make CTE-based authorization th…
Browse files Browse the repository at this point in the history
…e default, with inner join opt-in through the "useJoinAuth" query string parameter.
  • Loading branch information
gmcelhanon committed Oct 17, 2024
1 parent 84141f1 commit 8b57711
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ public virtual async Task<IActionResult> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ public async Task<IActionResult> Get(
[FromQuery] Dictionary<string, string> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static class QueryBuilderExtensions
/// <summary>
/// Applies a join-based filter to the criteria for the specified authorization view.
/// </summary>
/// <param name="queryBuilder"></param>
/// <param name="queryBuilder">The <see cref="QueryBuilder" /> to which criteria should be applied.</param>
/// <param name="parameters">The named parameters to be used to satisfy additional filtering requirements.</param>
/// <param name="viewName">The name of the view to be filtered.</param>
/// <param name="subjectEndpointName">The name of the property to be joined for the entity being queried.</param>
Expand All @@ -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<bool>("UseCteAuth"))
// Temporary logic to opt-in to join-based authorization approach
if (_callContextStorage.GetValue<bool>("UseJoinAuth"))
{
ApplySingleColumnJoinFilterUsingCtes(queryBuilder, parameters, viewName, subjectEndpointName, viewSourceEndpointName, viewTargetEndpointName, joinType, authViewAlias);
ApplySingleColumnJoinFilterUsingJoins(queryBuilder, parameters, viewName, subjectEndpointName, viewSourceEndpointName, viewTargetEndpointName, joinType, authViewAlias);
return;
}

Expand All @@ -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<string, object> parameters,
string viewName,
Expand All @@ -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}"));
}
}
}

/// <summary>
/// Applies a join-based filter to the criteria for the specified custom authorization view.
/// </summary>
/// <param name="criteria">The criteria to which filters should be applied.</param>
/// <param name="queryBuilder">The <see cref="QueryBuilder" /> to which criteria should be applied.</param>
/// <param name="viewName">The name of the view to be filtered.</param>
/// <param name="subjectEndpointNames">The name of the property to be joined for the entity being queried.</param>
/// <param name="viewTargetEndpointNames">The name of the property to be joined for the other property as authorization view.</param>
Expand Down

0 comments on commit 8b57711

Please sign in to comment.