neo4j-graphql / neo4j-graphql-js

NOTE: This project is no longer actively maintained. Please consider using the official Neo4j GraphQL Library (linked in README).
Other
609 stars 147 forks source link

Request: neo4j empowered authorizations through directives #203

Open emregency opened 5 years ago

emregency commented 5 years ago

Hi all, I have decided to use neo4j extensively for fine-grained authorization rules. I would like to hear from you guys if this sounds correct.

I have the following typeDefs:

type User {
    id: ID!
    username: String
    memberOf: [Group] @relation(name: "memberOf", direction: OUT)
}

type Group {
    id: ID!
    title: String!
}

And I am constantly checking if the user is memberOf the group for mutations.

I think, it is similar to a @hasScope but in this case, the scope is coming from the dB.

Can you guys provide some insights if this makes sense? Is there any way to merge this check in my mutations' resolver cypherusing some directives?

Thanks!

imkleats commented 5 years ago

I'm starting from a similar use-case (but with Discretionary Access Control features). I have some initial work to achieving this on my own fork. It's still very much in early stages of conception, but you're welcome to check it out.

The general approach I am taking is to inject a generator function (or simple parameters for simple implementations) into the context object that can create appropriate leading MATCH clauses, a "header" to the main MATCH clause, and any number of relational WHERE clauses.

The main reason I would advocate this approach over a custom directive is the ability to inject & pull in other Authorization information from the user through the context object; custom generator functions simply give more flexibility on what to include or not.

emregency commented 5 years ago

Thanks @imkleats I did have a look to your fork. It makes sense to "compose" with MATCH and WHERE clauses some checks using different parameters passed through the context and enhancing the business logic query. On one hand, incorporating ACL straight to the business logic and having this level of flexibility is great.

On the other hand, I have two questions about your implementation:

  1. How do you distinguish throw new Authorization error from null in your return ?
  2. How do you make your access control functions visible at your typeDefs ?

Cheers,

imkleats commented 5 years ago

1) That's part of the trade-off involved with achieving a single round trip for authorization&data. It does not seem impossible to build in an additional background field (Boolean) into the RETURN statement that matches your ACL criteria (i.e. isAuthed) that could be used to throw the Apollo error. [Edit: If you were to structure to it as an unmodified primary MATCH clause for the type you're querying along with an OPTIONAL MATCH clause with the ACL path connected to that primary type, you could verify whether 1) a node exists; and 2) whether the OPTIONAL MATCH is null (i.e. no permissions on that node). Then, when RETURN results stemming from that OPTIONAL MATCH are null, you could throw an AuthorizationError.

Most of my work thus far has been how to augment the automatically generated Cypher query (in the Translate library). This approach would also need some sort of validation call within the neo4jgraphql() function prior to when extractQueryResults is called. At first look, this doesn't seem too difficult to implement. Thanks for the ideas!]

2) How opaque/transparent the IDL should be with respect to business logic seems like a matter of preference. I would imagine that someone could decorate their TypeDefs with directives that are purely descriptive annotations if they wanted to. There might be room to be more verbose on the TypeDef that improve functionality.

emregency commented 5 years ago

@imkleats so much to the point. This will be a huge huge advantage! I am following closely :) thanks a lot for the detailed explanation, it makes sense and seems implementable. Cheers!

AdrienLemaire commented 4 years ago

Any progress on this issue? I asked a related question on neo4j forums: https://community.neo4j.com/t/saving-auth-roles-scopes-in-neo4j/19228

michaeldgraham commented 3 years ago

https://github.com/neo4j-graphql/neo4j-graphql-js/issues/608