diff --git a/cSpell.json b/cSpell.json index 8fcd9db9a0b..7c41ef0e085 100644 --- a/cSpell.json +++ b/cSpell.json @@ -32,7 +32,11 @@ "Swashbuckle", "traversion", "Websockets", - "Newtonsoft" + "Newtonsoft", + "cachable", + "fricking", + "runtimes", + "NATS" ], "ignoreWords": [ "Specwise", @@ -53,6 +57,7 @@ "Staib", "shoooe", "Senn", + "Rafi", "Snapshooter", "relayjs", "Rgba", diff --git a/src/HotChocolate/Core/src/Authorization/AuthorizeValidationResultAggregator.cs b/src/HotChocolate/Core/src/Authorization/AuthorizeValidationResultAggregator.cs index 7ac7b026423..6157ba4e99d 100644 --- a/src/HotChocolate/Core/src/Authorization/AuthorizeValidationResultAggregator.cs +++ b/src/HotChocolate/Core/src/Authorization/AuthorizeValidationResultAggregator.cs @@ -52,7 +52,7 @@ public async ValueTask AggregateAsync( } } - private IError CreateError(AuthorizeResult result) + private static IError CreateError(AuthorizeResult result) { return result switch { diff --git a/src/HotChocolate/Core/src/Authorization/AuthorizeValidationRule.cs b/src/HotChocolate/Core/src/Authorization/AuthorizeValidationRule.cs index b8dc374ca63..cfe8bb0f4a5 100644 --- a/src/HotChocolate/Core/src/Authorization/AuthorizeValidationRule.cs +++ b/src/HotChocolate/Core/src/Authorization/AuthorizeValidationRule.cs @@ -16,7 +16,7 @@ public AuthorizeValidationRule(AuthorizationCache cache) _cache = cache ?? throw new ArgumentNullException(nameof(cache)); } - public bool IsCacheable => true; + public bool IsCacheable => false; public void Validate(IDocumentValidatorContext context, DocumentNode document) { diff --git a/src/HotChocolate/Core/test/Authorization.Tests/AnnotationBasedAuthorizationTests.cs b/src/HotChocolate/Core/test/Authorization.Tests/AnnotationBasedAuthorizationTests.cs index 07313d8aa8d..7bcbf4bc1b1 100644 --- a/src/HotChocolate/Core/test/Authorization.Tests/AnnotationBasedAuthorizationTests.cs +++ b/src/HotChocolate/Core/test/Authorization.Tests/AnnotationBasedAuthorizationTests.cs @@ -64,6 +64,56 @@ public async Task Authorize_Person_NoAccess() """); } + [Fact] + public async Task Authorize_Person_NoAccess_EnsureNotCached() + { + // arrange + var results = new Stack(); + results.Push(AuthorizeResult.NotAllowed); + results.Push(AuthorizeResult.Allowed); + + var handler = new AuthHandler2(results); + var services = CreateServices(handler); + var executor = await services.GetRequestExecutorAsync(); + + // act + await executor.ExecuteAsync( + """ + { + person(id: "UGVyc29uCmRhYmM=") { + name + } + } + """); + + var result = await executor.ExecuteAsync( + """ + { + person(id: "UGVyc29uCmRhYmM=") { + name + } + } + """); + + // assert + Snapshot + .Create() + .Add(result) + .MatchInline( + """ + { + "errors": [ + { + "message": "The current user is not authorized to access this resource.", + "extensions": { + "code": "AUTH_NOT_AUTHORIZED" + } + } + ] + } + """); + } + [Fact] public async Task Authorize_Query_NoAccess() { @@ -561,7 +611,7 @@ public async Task Skip_Authorize_On_Node_Field() } private static IServiceProvider CreateServices( - AuthHandler handler, + IAuthorizationHandler handler, Action? configure = null) => new ServiceCollection() .AddGraphQLServer() @@ -661,6 +711,27 @@ public ValueTask AuthorizeAsync( } } + private sealed class AuthHandler2 : IAuthorizationHandler + { + private readonly Stack _results; + public AuthHandler2(Stack results) + { + _results = results; + } + + public ValueTask AuthorizeAsync( + IMiddlewareContext context, + AuthorizeDirective directive, + CancellationToken cancellationToken = default) + => new(AuthorizeResult.Allowed); + + public ValueTask AuthorizeAsync( + AuthorizationContext context, + IReadOnlyList directives, + CancellationToken cancellationToken = default) + => new(_results.Pop()); + } + [DirectiveType(DirectiveLocation.Object)] public sealed class FooDirective { }