Skip to content

Commit df124cb

Browse files
Shane32gao-artur
andauthored
Remove GetRecursivelyReferencedUsedFragments and SkipNode (#1143)
Co-authored-by: Artur Gordashnikov <[email protected]>
1 parent bf0cd69 commit df124cb

File tree

7 files changed

+10
-178
lines changed

7 files changed

+10
-178
lines changed

docs/migration/migration8.md

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
in the response prefer the same status code. For practical purposes, this means that the included
3535
errors triggered by the authorization validation rule will now return 401 or 403 when appropriate.
3636
- The `SelectResponseContentType` method now returns a `MediaTypeHeaderValue` instead of a string.
37+
- The `AuthorizationVisitorBase.GetRecursivelyReferencedUsedFragments` method has been removed as
38+
`ValidationContext` now provides an overload to `GetRecursivelyReferencedFragments` which will only
39+
return fragments in use by the specified operation.
40+
- The `AuthorizationVisitorBase.SkipNode` method has been removed as `ValidationContext` now provides
41+
a `ShouldIncludeNode` method.
3742

3843
## Other changes
3944

src/Transports.AspNetCore/AuthorizationVisitorBase.GetRecursivelyReferencedUsedFragments.cs

-102
This file was deleted.

src/Transports.AspNetCore/AuthorizationVisitorBase.cs

+2-68
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public AuthorizationVisitorBase(ValidationContext context)
88
{
99
if (context == null)
1010
throw new ArgumentNullException(nameof(context));
11-
_fragmentDefinitionsToCheck = GetRecursivelyReferencedUsedFragments(context);
11+
_fragmentDefinitionsToCheck = context.GetRecursivelyReferencedFragments(context.Operation, true);
1212
}
1313

1414
private bool _checkTree; // used to skip processing fragments or operations that do not apply
@@ -36,7 +36,7 @@ public virtual async ValueTask EnterAsync(ASTNode node, ValidationContext contex
3636
else if (_checkTree)
3737
{
3838
// if a directive indicates to skip this node, skip authorization checks until Leave() is called for this node
39-
if (SkipNode(node, context))
39+
if (!context.ShouldIncludeNode(node))
4040
{
4141
_checkTree = false;
4242
_checkUntil = node;
@@ -175,72 +175,6 @@ async ValueTask PopAndProcessAsync()
175175
}
176176
}
177177

178-
/// <summary>
179-
/// Indicates if the specified node should skip authentication processing.
180-
/// Default implementation looks at @skip and @include directives only.
181-
/// </summary>
182-
protected virtual bool SkipNode(ASTNode node, ValidationContext context)
183-
{
184-
// according to GraphQL spec, directives with the same name may be defined so long as they cannot be
185-
// placed on the same node types as other directives with the same name; so here we verify that the
186-
// node is a field, fragment spread, or inline fragment, the only nodes allowed by the built-in @skip
187-
// and @include directives
188-
if (node is not GraphQLField && node is not GraphQLFragmentSpread && node is not GraphQLInlineFragment)
189-
return false;
190-
191-
var directivesNode = (IHasDirectivesNode)node;
192-
193-
var skipDirective = directivesNode.Directives?.FirstOrDefault(x => x.Name == "skip");
194-
if (skipDirective != null)
195-
{
196-
var value = GetDirectiveValue(skipDirective, context, false);
197-
if (value)
198-
return true;
199-
}
200-
201-
var includeDirective = directivesNode.Directives?.FirstOrDefault(x => x.Name == "include");
202-
if (includeDirective != null)
203-
{
204-
var value = GetDirectiveValue(includeDirective, context, true);
205-
if (!value)
206-
return true;
207-
}
208-
209-
return false;
210-
211-
static bool GetDirectiveValue(GraphQLDirective directive, ValidationContext context, bool defaultValue)
212-
{
213-
var ifArg = directive.Arguments?.FirstOrDefault(x => x.Name == "if");
214-
if (ifArg != null)
215-
{
216-
if (ifArg.Value is GraphQLBooleanValue boolValue)
217-
{
218-
return boolValue.BoolValue;
219-
}
220-
else if (ifArg.Value is GraphQLVariable variable)
221-
{
222-
if (context.Operation.Variables != null)
223-
{
224-
var varDef = context.Operation.Variables.FirstOrDefault(x => x.Variable.Name == variable.Name);
225-
if (varDef != null && varDef.Type.Name() == "Boolean")
226-
{
227-
if (context.Variables.TryGetValue(variable.Name.StringValue, out var value))
228-
{
229-
if (value is bool boolValue2)
230-
return boolValue2;
231-
}
232-
if (varDef.DefaultValue is GraphQLBooleanValue boolValue3)
233-
{
234-
return boolValue3.BoolValue;
235-
}
236-
}
237-
}
238-
}
239-
}
240-
return defaultValue;
241-
}
242-
}
243-
244178
/// <summary>
245179
/// Runs when a fragment is added or updated; the fragment might not be waiting on any
246180
/// other fragments, or it still might be.

tests/ApiApprovalTests/net50+net60+net80/GraphQL.Server.Transports.AspNetCore.approved.txt

-2
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,11 @@ namespace GraphQL.Server.Transports.AspNetCore
3636
protected abstract System.Threading.Tasks.ValueTask<Microsoft.AspNetCore.Authorization.AuthorizationResult> AuthorizeAsync(string policy);
3737
public virtual System.Threading.Tasks.ValueTask EnterAsync(GraphQLParser.AST.ASTNode node, GraphQL.Validation.ValidationContext context) { }
3838
protected virtual string GenerateResourceDescription(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info) { }
39-
protected System.Collections.Generic.List<GraphQLParser.AST.GraphQLFragmentDefinition>? GetRecursivelyReferencedUsedFragments(GraphQL.Validation.ValidationContext validationContext) { }
4039
protected virtual void HandleNodeNotAuthorized(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info) { }
4140
protected virtual void HandleNodeNotInPolicy(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info, string policy, Microsoft.AspNetCore.Authorization.AuthorizationResult authorizationResult) { }
4241
protected virtual void HandleNodeNotInRoles(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info, System.Collections.Generic.List<string> roles) { }
4342
protected abstract bool IsInRole(string role);
4443
public virtual System.Threading.Tasks.ValueTask LeaveAsync(GraphQLParser.AST.ASTNode node, GraphQL.Validation.ValidationContext context) { }
45-
protected virtual bool SkipNode(GraphQLParser.AST.ASTNode node, GraphQL.Validation.ValidationContext context) { }
4644
protected virtual System.Threading.Tasks.ValueTask<bool> ValidateAsync(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info) { }
4745
public virtual System.Threading.Tasks.ValueTask<bool> ValidateSchemaAsync(GraphQL.Validation.ValidationContext context) { }
4846
public readonly struct ValidationInfo : System.IEquatable<GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo>

tests/ApiApprovalTests/netcoreapp21+netstandard20/GraphQL.Server.Transports.AspNetCore.approved.txt

-2
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,11 @@ namespace GraphQL.Server.Transports.AspNetCore
4343
protected abstract System.Threading.Tasks.ValueTask<Microsoft.AspNetCore.Authorization.AuthorizationResult> AuthorizeAsync(string policy);
4444
public virtual System.Threading.Tasks.ValueTask EnterAsync(GraphQLParser.AST.ASTNode node, GraphQL.Validation.ValidationContext context) { }
4545
protected virtual string GenerateResourceDescription(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info) { }
46-
protected System.Collections.Generic.List<GraphQLParser.AST.GraphQLFragmentDefinition>? GetRecursivelyReferencedUsedFragments(GraphQL.Validation.ValidationContext validationContext) { }
4746
protected virtual void HandleNodeNotAuthorized(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info) { }
4847
protected virtual void HandleNodeNotInPolicy(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info, string policy, Microsoft.AspNetCore.Authorization.AuthorizationResult authorizationResult) { }
4948
protected virtual void HandleNodeNotInRoles(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info, System.Collections.Generic.List<string> roles) { }
5049
protected abstract bool IsInRole(string role);
5150
public virtual System.Threading.Tasks.ValueTask LeaveAsync(GraphQLParser.AST.ASTNode node, GraphQL.Validation.ValidationContext context) { }
52-
protected virtual bool SkipNode(GraphQLParser.AST.ASTNode node, GraphQL.Validation.ValidationContext context) { }
5351
protected virtual System.Threading.Tasks.ValueTask<bool> ValidateAsync(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info) { }
5452
public virtual System.Threading.Tasks.ValueTask<bool> ValidateSchemaAsync(GraphQL.Validation.ValidationContext context) { }
5553
public readonly struct ValidationInfo : System.IEquatable<GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo>

tests/ApiApprovalTests/netcoreapp31/GraphQL.Server.Transports.AspNetCore.approved.txt

-2
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,11 @@ namespace GraphQL.Server.Transports.AspNetCore
3636
protected abstract System.Threading.Tasks.ValueTask<Microsoft.AspNetCore.Authorization.AuthorizationResult> AuthorizeAsync(string policy);
3737
public virtual System.Threading.Tasks.ValueTask EnterAsync(GraphQLParser.AST.ASTNode node, GraphQL.Validation.ValidationContext context) { }
3838
protected virtual string GenerateResourceDescription(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info) { }
39-
protected System.Collections.Generic.List<GraphQLParser.AST.GraphQLFragmentDefinition>? GetRecursivelyReferencedUsedFragments(GraphQL.Validation.ValidationContext validationContext) { }
4039
protected virtual void HandleNodeNotAuthorized(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info) { }
4140
protected virtual void HandleNodeNotInPolicy(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info, string policy, Microsoft.AspNetCore.Authorization.AuthorizationResult authorizationResult) { }
4241
protected virtual void HandleNodeNotInRoles(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info, System.Collections.Generic.List<string> roles) { }
4342
protected abstract bool IsInRole(string role);
4443
public virtual System.Threading.Tasks.ValueTask LeaveAsync(GraphQLParser.AST.ASTNode node, GraphQL.Validation.ValidationContext context) { }
45-
protected virtual bool SkipNode(GraphQLParser.AST.ASTNode node, GraphQL.Validation.ValidationContext context) { }
4644
protected virtual System.Threading.Tasks.ValueTask<bool> ValidateAsync(GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo info) { }
4745
public virtual System.Threading.Tasks.ValueTask<bool> ValidateSchemaAsync(GraphQL.Validation.ValidationContext context) { }
4846
public readonly struct ValidationInfo : System.IEquatable<GraphQL.Server.Transports.AspNetCore.AuthorizationVisitorBase.ValidationInfo>

tests/Transports.AspNetCore.Tests/AuthorizationTests.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,9 @@ private void Apply(IMetadataWriter obj, Mode mode)
545545
public void Constructors()
546546
{
547547
Should.Throw<ArgumentNullException>(() => new AuthorizationVisitor(null!, _principal, Mock.Of<IAuthorizationService>()));
548-
Should.Throw<ArgumentNullException>(() => new AuthorizationVisitor(new ValidationContext(), null!, Mock.Of<IAuthorizationService>()));
549-
Should.Throw<ArgumentNullException>(() => new AuthorizationVisitor(new ValidationContext(), _principal, null!));
548+
var context = new ValidationContext() { Operation = new(new([])), Document = new([]) };
549+
Should.Throw<ArgumentNullException>(() => new AuthorizationVisitor(context, null!, Mock.Of<IAuthorizationService>()));
550+
Should.Throw<ArgumentNullException>(() => new AuthorizationVisitor(context, _principal, null!));
550551
}
551552

552553
[Theory]

0 commit comments

Comments
 (0)