ChilliCream / graphql-platform

Welcome to the home of the Hot Chocolate GraphQL server for .NET, the Strawberry Shake GraphQL client for .NET and Banana Cake Pop the awesome Monaco based GraphQL IDE.
https://chillicream.com
MIT License
5.23k stars 744 forks source link

Getting `AUTH_NOT_AUTHORIZED ` in version 13.0.0 and later #5818

Closed marcel-rudolph closed 1 year ago

marcel-rudolph commented 1 year ago

Is there an existing issue for this?

Product

Hot Chocolate

Describe the bug

Starting with version 13.0.0-rc8/13.0.0 all type fields with a [Authorize(Policy = "SomePolicy")] annotation are now always returning an AUTH_NOT_AUTHORIZED error:

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

Until version 13.0.0.-rc7 and without code changes everything works as expected.

Our implementation is very closed on what is described on the HC documentation.

I've checked both the release notes and migration guide on the website, but couldn't find an clue.

I would be very thankful for any hint. At the moment we have to stick at version 13.0.0-rc7.

Steps to reproduce

I've prepared two demo projects for both version 13.0.0-rc7 and 13.0.1 with instructions about how to reproduce the issue. https://github.com/marcel-rudolph/hc13-issue-demo

Relevant log output

There are no further exceptions or log messages beside the above posted response example.

Additional Context?

No response

Version

13.0.1

WalissonPires commented 1 year ago

I'm having the same problem. I also have a nice sample project created based on the documentation: https://github.com/WalissonPires/HCAuthTest

michaelstaib commented 1 year ago

@WalissonPires what is you issue exactly. I cloned the repro and works fine.

michaelstaib commented 1 year ago

I think I know where you are stuck and its not a bug. I will have a YouTube episode next week on authorization where I will explain the new system.

WalissonPires commented 1 year ago

@michaelstaib I need the HandleRequirementAsync method to be invoked, to access the IResolverContext. In no time he is called. Watch the video: https://youtu.be/MH40NTQnFks

david-brink-talogy commented 1 year ago

@michaelstaib, I'm seeing this same issue. Can you share some of the context about the new system prior to the youtube video? Is it still possible to have a custom AuthorizationHandler that has access to the IResolverContext?

If there have been API changes, shouldn't this issue be re-opened to at least address the documentation? https://chillicream.com/docs/hotchocolate/v13/security/authorization#iresolvercontext-within-an-authorizationhandler

PascalSenn commented 1 year ago

@WalissonPires I believe this is because the policy now by default runs on validation. So there will not be a resolver context and this is also why you get a HttpContext.

If you want to run it not on validation but BEFORE_RESOLVER then you have to specify it:

[Authorize(Policy = "SomePolicy", Apply=ApplyPolicy.BEFORE_RESOLVER)]

@psiservices-dbrink i agree this should go in the docs

michaelstaib commented 1 year ago

Actually ... we have now by default the AuthorizationContext which is available on validation.

david-brink-talogy commented 1 year ago

For us, the query in in question has a tenant argument which is checked via custom authorization handler to see if the user has permission to that tenant. It doesn't look like AuthorizationContext has the query deserialized in a such a way as to provide argument access. Adding ApplyPolicy.BeforeResolver did the trick.

Edit: I was wrong, when using ApplyPolicy.BeforeResolver or ApplyPolicy.AfterResolver my query is now executed, but the requirement is never enforced, the policy is bypassed, and HandleRequirementAsync is never invoked.

Task HandleRequirementAsync(AuthorizationHandlerContext context, TenantRequirement requirement, IResolverContext resolverContext) {
  if (!HasPermission(context, resolverContext.ArgumentValue<string>("tenant")) {
    context.Fail();
  }
  else {
    context.Succeed(requirement);
  }
}
WalissonPires commented 1 year ago

@PascalSenn It was exactly what he needed. Thanks

david-brink-talogy commented 1 year ago

Edit: I was wrong, when using ApplyPolicy.BeforeResolver or ApplyPolicy.AfterResolver my query is now executed, but the requirement is never enforced, the policy is bypassed, and HandleRequirementAsync is never invoked.

I believe I've figured out my problem. Previously our outermost query class was decorated with the AuthorizeAttribute; this no longer invokes the AuthorizationHandler. After moving the attribute to the query method it works as expected.


// v12
[Authorize(Policy="Stuff")]
public class Query {
  public Stuff GetStuff() => new();
}

// v13
[Authorize]
public class Query {
  [Authorize(Policy="Stuff", Apply = ApplyPolicy.BeforeResolver)]
  public Stuff GetStuff() => new();
}
michaelstaib commented 1 year ago

yes and no :)

YouTube episode is coming tomorrow.

youtube.chillicream.com

twirlse commented 1 year ago

Thank you for you work! However... A YouTube video is not a great way to document code. It is impossible to search, it is missing samples and code that one can copy, it is impossible to compare to previous versions. Documentation is boring (at least for me) but a must-have for a good and reliable project. And security documentation even more so.