Skip to content

Commit

Permalink
Fixed that field authorization at the validation level was skipped (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Feb 4, 2023
1 parent 981104d commit f90438c
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 6 deletions.
Expand Up @@ -84,6 +84,12 @@ public override void OnBeforeCompleteTypes()
// will use to transform the schema authorization.
var state = _state = CreateState();

// copy temporary state to schema state.
if (_context.ContextData.TryGetValue(AuthorizationRequestPolicy, out var value))
{
_schemaContextData[AuthorizationRequestPolicy] = value;
}

// before we can apply schema transformations we will inspect the object types
// to identify the ones that are protected with authorization directives.
InspectObjectTypesForAuthDirective(state);
Expand Down
12 changes: 6 additions & 6 deletions src/HotChocolate/Core/src/Validation/DocumentValidator.cs
Expand Up @@ -18,7 +18,7 @@ public sealed class DocumentValidator : IDocumentValidator
{
private readonly DocumentValidatorContextPool _contextPool;
private readonly IDocumentValidatorRule[] _allRules;
private readonly IDocumentValidatorRule[] _nonCashableRules;
private readonly IDocumentValidatorRule[] _nonCachableRules;
private readonly IValidationResultAggregator[] _aggregators;
private readonly int _maxAllowedErrors;

Expand Down Expand Up @@ -55,21 +55,21 @@ public sealed class DocumentValidator : IDocumentValidator

_contextPool = contextPool ?? throw new ArgumentNullException(nameof(contextPool));
_allRules = rules.ToArray();
_nonCashableRules = _allRules.Where(t => !t.IsCacheable).ToArray();
_nonCachableRules = _allRules.Where(t => !t.IsCacheable).ToArray();
_aggregators = resultAggregators.ToArray();
_maxAllowedErrors = errorOptions.MaxAllowedErrors;
}

/// <inheritdoc />
public bool HasDynamicRules => _nonCashableRules.Length > 0 || _aggregators.Length > 0;
public bool HasDynamicRules => _nonCachableRules.Length > 0 || _aggregators.Length > 0;

/// <inheritdoc />
public ValueTask<DocumentValidatorResult> ValidateAsync(
ISchema schema,
DocumentNode document,
string documentId,
IDictionary<string, object?> contextData,
bool onlyNonCashable,
bool onlyNonCachable,
CancellationToken cancellationToken = default)
{
if (schema is null)
Expand All @@ -87,13 +87,13 @@ public sealed class DocumentValidator : IDocumentValidator
throw new ArgumentNullException(nameof(documentId));
}

if (onlyNonCashable && _nonCashableRules.Length == 0 && _aggregators.Length == 0)
if (onlyNonCachable && _nonCachableRules.Length == 0 && _aggregators.Length == 0)
{
return new(DocumentValidatorResult.Ok);
}

var context = _contextPool.Get();
var rules = onlyNonCashable ? _nonCashableRules : _allRules;
var rules = onlyNonCachable ? _nonCachableRules : _allRules;
var handleCleanup = true;

try
Expand Down
Expand Up @@ -672,4 +672,54 @@ public sealed class FooDirectiveAttribute : ObjectTypeDescriptorAttribute
Type type)
=> descriptor.Directive(new FooDirective());
}

[Fact]
public async Task Ensure_Authorization_Works_On_Subscription()
{
var result =
await new ServiceCollection()
.AddGraphQLServer()
.AddQueryType(c => c.Field("n").Resolve("b"))
.AddSubscriptionType<Subscription>()
.AddInMemorySubscriptions()
.AddAuthorizationHandler<MockAuth>()
.ExecuteRequestAsync("subscription { onFoo }");

result.MatchInlineSnapshot(
"""
{
"errors": [
{
"message": "The current user is not authorized to access this resource.",
"extensions": {
"code": "AUTH_NOT_AUTHORIZED"
}
}
]
}
""");
}

public class Subscription
{
[Authorize(Apply = ApplyPolicy.Validation)]
[Subscribe]
[Topic("Foo")]
public string OnFoo([EventMessage] string message) => message;
}

public sealed class MockAuth : IAuthorizationHandler
{
public ValueTask<AuthorizeResult> AuthorizeAsync(
IMiddlewareContext context,
AuthorizeDirective directive,
CancellationToken cancellationToken = default)
=> new(AuthorizeResult.NotAllowed);

public ValueTask<AuthorizeResult> AuthorizeAsync(
AuthorizationContext context,
IReadOnlyList<AuthorizeDirective> directives,
CancellationToken cancellationToken = default)
=> new(AuthorizeResult.NotAllowed);
}
}

0 comments on commit f90438c

Please sign in to comment.