Is it possible to have an "array division" in an @auth rule?

Consider an array in the user claim

{
  ...
  arr: ["one", "two", "three"],
  ...
}

and a schema

type Check {
  id: ID!
  test: [String!]!
}

where Check.test can only contain elements from arr but any number and any permutation (eg. ["two"], ["one", "three"], etc.)

I’d be interested if ALL elements of Check.test are IN arr. Is that possible?

I’m fairly confident this is not possible. The IN input argument is only one directional, and there is no ALL, EVERY, or SOME argument.

This would be a good feature request IMO.

2 Likes

I thought so. But thanks! :raised_hands:

By the way that’d be an example for having an option for custom auth middleware :stuck_out_tongue_winking_eye: @jdgamble555

1 Like

Yes, this is possible. You have to use “in” instead of eq.

e.g

{ rule:  "{$arr: { in: [\"one\"] } }" }

So it will check if there is any “one” in the array.

1 Like

@MichelDiz unfortunately this does not work since I do not know the array elements of Check.test beforehand. Thus I have to use a query rule with @filter. The only thing I could do would be

{ rule: """queryCheck(filter: { test: { in: $arr } }) { id }""" }

and this would result in true even if only one of the elements in arr matches what is in test.

  • arr = ["one", "two", "three"]; test = ["one", "three"] → results in true :white_check_mark:
  • arr = ["one", "two"]; test = ["one", "three"] → results in true :x:
2 Likes

I don’t get it.

If you need that all claims needs to be included. You can use AND, OR Operators.

For example { and: [

Here another examples:

@auth(
    query: { or: [
        {rule: "{$USER: { eq: {\"a\": \"b\"} } }"}, # this will be used to test eq with object
        {rule: "{$USER: { eq: 123.12 } }"}, # this will be used to test eq with float
        {rule: "{$USER: { eq: 1237890123456 } }"}, # this will be used to test eq with int64
        {rule: "{$USER: { eq: 1234 } }"}, # this will be used to test eq with int and array too
        {rule: "{$USER: { eq: true } }"}, # this will be used to test eq with boolean

        {rule: "{$USER: { in: [{\"c\": \"d\"}, {\"e\":\"f\"}] } }"}, # this will be used to test in with object
        {rule: "{$USER: { in: [456.23, 312.124] } }"}, # this will be used to test in with float
        {rule: "{$USER: { in: [9876543219876543, 1246879976444232435] } }"}, # this will be used to test in with int64
        {rule: "{$USER: { in: [5678, 6872] } }"}, # this will be used to test in with int and array too

        {rule: "{$USER: { regexp: \"^(.*)@dgraph.io$\" } }"}
    ]}

Pay attention that this is not DQL or GraphQL. It is a special check we do in the claims.

Thanks for the update! :raised_hands:

Maybe it’s just me who doesn’t get it, so let’s try to add a bit more context here.

Problem description

We have a permission based authorisation. All users permissions are stored in the user claim in a permissions array. The underlying schema would be

enum Permission {
  PERM_1
  PERM_2
  PERM_3
  PERM_4
}

interface CheckAccess {
  id: ID!
  requiredPermissions: [Permission!]! @search
}

type ProtectedNode implements CheckAccess {
  id: ID!
  title: String
 
  # from interface
  # requiredPermissions: [Permission!]! @search
}

type Context1 {
  id: ID!
  protectedField: ProtectedNode
}

type Context2 {
  id: ID!
  protectedField: ProtectedNode
}

Let’s assume two users with permissions

user1 = ["PERM_1", "PERM_3", "PERM_4"]
user2 = ["PERM_2", "PERM_3", "PERM_4"]

Let’s further assume that ProtectedNode needs context awareness and thus it needs to know if it belongs to either Context1 or Context2. Each of the ProtectedNodes require a certain set of permissions to be queryable by the user. Let’s say

// Context 1
{
  id: "0x1",
  protectedField: {
    id: "0x2",
    title: "Only users with PERM_1 and PERM_3 can query",
    requiredPermissions: [
      PERM_1,
      PERM_3
    ]
  }
}

and

// Context 2
{
  id: "0x3",
  protectedField: {
    id: "0x4",
    title: "Only users with PERM_2 and PERM_4 can query",
    requiredPermissions: [
      PERM_2,
      PERM_4
    ]
  }
}

I now want to query ProtectedNode but I need to check wether the user has sufficient rights. Thus the only protection I could think of would be

interface CheckAccess 
@auth(
  query: { rule: """{ queryCheckAccess(filter: { requiredPermissions: { in: $permissions } }) { id } }""" }
) {
  id: ID!
  requiredPermissions: [Permission!]! @search
} 

I don’t want to expose 0x2 to user2 since he is missing PERM_1 and vice versa for user1 and 0x4. Still, both users would be able to query both nodes!

The only solution I could think of, is that I add context aware permissions which combine all sorts of possible permission combinations and check for only one single value.

Just to clarify:

  • reverse edges are not a possibility
1 Like

I misunderstood. My focus was on the question ~> “array division” in an @auth rule?

In this case, it is possible to extract values from an array that comes from a JWT token claim. And apply logic to it. However, I never tested it using GraphQL in the logical body of the Auth rule. As the Auth rule accepts either GraphQL or a custom rule query. I thought the case was about the JWT claim and the rule, not something more deep related to your data. Which you should check with GraphQL.

I’ll take a look at it and think about this.

Cheers.

1 Like