0
votes

I have a problem to limit my graphql endpoint to only serve data the requesting user is allowed to request

I'm using

apollo-server 2.1.0
express 4.16.3
graphql 0.13.2
graphql-tools 4.0.0
neo4j-graphql-js 0.2.1

The type Tag has a field elements which should only contain the elements the current user owns.

type Tag {
  name: String!
  elements(username:String): [Element] @cypher(statement: "MATCH (this)-[:TAGGED]-(e:Element)-[:OWNER]-(u:User) WHERE u.name=$username RETURN e")
}

type Element {
  uuid: String!
  name: String
  users: [User] @relation(name:"OWNER", direction:"IN")
  tags: [Tag] @relation(name:"TAGGED", direction:"IN")
  responses: [Element] @relation(name:"RESPONSE", direction:"OUT")
}

When my query looks like:

{
Tag{
    name,
    elements(username:"crmue"){
      name
    }
  }
}

The result looks like expected. But I want to check and set the username argument within the resolver based on the context attached user.

But when I add the following line to the Tag root resolver before the query gets executed, my response is empty.

params['username'] = ctx.user.name;

In this case the generated cypher statement places the username agrument to root Tag section and not to child Element (@cypher statement) section. But I have no idea how to set the username argument for the Tag field elements within the resolver, before the data are getting fetched.

So I hope someone has maybe an idea how to solve my problem or has a better idea than my solution here with the @cypher statement.

Thanks!

UPDATE

My current basic resolvers are:

export const resolvers = {

  Tag : {
    elements : (object, params, ctx, resolveInfo) => {
      params["username"] = ctx.user.name;

    }
  },

  Query: {
    User(object, params, ctx, resolveInfo) {
      return neo4jgraphql(object, params, ctx, resolveInfo);
    },
    Element(object, params, ctx, resolveInfo) {
      return neo4jgraphql(object, params, ctx, resolveInfo);
    },

    Tag(object, params, ctx, resolveInfo) {
      if(!ctx.user){
       throw Error("Wrong request");
      }
      params["username"] = ctx.user.name;
      return neo4jgraphql(object, params, ctx, resolveInfo); 
    },

  }
};

Adding the param within a 'elements' field resolver has no effect, since the field resolvers are called when the data are already fetched.

1
use ctx.user.name directly in elements resolver?xadm
I tried that but the the field resolvers are called when the data are already fetched. I can use the element resolver to filter the fetched data afterafterwards.crmue

1 Answers

0
votes

Usually root resolver doesn't return the whole object, only 'own fields' leaving related fields to be processed by fields resolvers. In this case it looks like neo4jgraphql (I'm guessing, I didn't use it) is smart enough to process it entirely at the root level.

If params["username"] = ctx.user.name; in Tag doesn't work then it looks like neo4jgraphql doesn't care about params (IMHO it should - issue?) and works directly on resolver info argument (already existing variables).

Try to add username into variableValues array. Explanations Field resolver shouldn't be required in this case.

Second option: remove elements from fieldNodes (in Tag resolver) and use field resolver (params/variableValues).

If still in trouble check/log info state/values.