graphql-dotnet / server

ASP.NET Core GraphQL Server
MIT License
578 stars 163 forks source link

How to set default authorization policy for graphql types and override it for specific fields? #549

Closed alekbarszczewski closed 2 years ago

alekbarszczewski commented 3 years ago

My goal is to require authorization for all fields by default and allow public access only for few fields. Tried this:

.AddGraphTypes(typeof(RootSchema))
                .AddGraphQLAuthorization(x =>
                {
                    x.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
                    x.AddPolicy("Authorize", new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
                    x.AddPolicy("Public", configurePolicy =>
                    {
                        configurePolicy.RequireAssertion((authContext) => true);
                    });
                });

However it does not enforce DefaultPolicy for fields and it allows access to all fields unless "Authorize" policy is explicitly enforced:

public class GroupMutationType : ObjectGraphType
    {
        public GroupMutationType()
        {
            Name = "GroupMutation";

            this.AuthorizeWith("Authorized"); // this works (prevents access) but when commented out public access is allowed
           // ...
         }
}

What I want to make all fields authorized by default unless for example they use this.AuthorizeWith("Public"). Is it possible?

Shane32 commented 2 years ago

This is now generally possible with GraphQL.NET 7 and GraphQL.NET Server 7 (when released). Any fields marked with AllowAnonymous will cause the validation rule to ignore the type's authorization rule. In your example, you'd need to mark the Query type with an authorization rule, and then the specific field with AllowAnonymous. If the type is not a scalar, then type that the field returns would be considered to have anonymous access unless you also set that type with authorization rules, and specific fields with AllowAnonymous, and so on.

For example:

{                        # QueryType marked with Authorize()
  loginInfo {            # LoginInfo field marked with AllowAnonymous(), and LoginInfoType type marked with Authorize()
    isAuthenticated      # IsAuthenticated field marked with AllowAnonymous()
    # roles              # roles is not marked, so requires authentication because LoginInfoType is marked with Authorize()
  }
}

Does this meet your needs @alekbarszczewski ?

Shane32 commented 2 years ago

Note that introspection fields are implicitly marked with AllowAnonymous(); however it is not allowed to only request __typename on a type, like this:

# this query is refused
{                 # no requirements set here
  protected {     # ProtectedType marked with Authorize()
    __typename
  }
}
alekbarszczewski commented 2 years ago

Thanks @Shane32 I think this is what I need.

however it is not allowed to only request __typename on a type, like this:

I am still using graphl-net 4.5.0 and in this version you are actually allowed to query only __typename field - has anything changed regarding this in newer versions o grapqhl-net / server

Shane32 commented 2 years ago

I mean you are not allowed to on a type that has a failing authorization requirement. So in the example above, if ProtectedType requires authentication, but you are not authenticated, then the above query would fail.

alekbarszczewski commented 2 years ago

Ok got it, I misunderstood you. Thanks! For me you can close this as what you described is exactly what I needed.

Shane32 commented 2 years ago

Excellent. Look for v7 to be released within a week or so.