ParticipioLabs / realities

A tool for decentralised organisations.
https://realities.platoproject.org/
GNU Affero General Public License v3.0
35 stars 9 forks source link

Research the best way to enable multi-tenancy #117

Closed Powersource closed 3 years ago

Powersource commented 4 years ago

Thinking about stuff like, how do we keep track of which neo4j nodes belong to which tenant. In a call we just had we had 3 ideas:

  1. A label on all nodes, something like :TenantBorderland, or :Tenant123. Is it intended usage of neo4j to create labels which have this dynamic names?
  2. Hugi had an idea that maybe it's possible to just maybe have 1 extra node per tenant that points at 1 node part of the tenant's graph, and from that be able to recursively discover the entire tenant's graph.
  3. A property on all nodes, something like tenantId=123. Need to research if it's possible for neo4j to index by this, which would be needed.
Powersource commented 4 years ago

So you seem to be able to create indexes for Label+Property, https://neo4j.com/docs/getting-started/current/cypher-intro/schema/#cypher-intro-indexes

To note is

The main reason for using indexes in a graph database is to find the starting point of a graph traversal. Once that starting point is found, the traversal relies on in-graph structures to achieve high performance.

so it only helps if we e.g. get all the Needs for a tenant (and if we have a Need+tenantId index), which makes sense I guess.

Powersource commented 4 years ago

There seem to be a few things to enable multi-tenancy in neo4j, like Fabric, but they seem to be mostly Enterprise edition features and also pretty heavyweight, e.g. having a whole separate db per tenant. ( edit: the most promising one i found was being able to switch between dbs with :use but creating new dbs to use with that is enterprise)

Powersource commented 4 years ago

Talked about this in a meeting. Realized that all the checking we'd have to do (that users only touch stuff within their tenant (correct value on the tenantId property on nodes)) is pretty similar to possible future checks we'd want to do if we add permission stuff like "this user can only edit these 3 nodes". So maybe what we need to do either way is something like add a permission check at the start of the functions in api/src/graphql/connectors/index.js, where we pass in the nodeIds we are about to operate on and only actually run the rest of the function if the permission check says it's fine (the nodes are in the right tenant and maybe in the future, the current user has permission to edit those specific nodes).

erikfrisk commented 4 years ago

Great info here!

I don't have any experience with multitenancy in neo4j, but a property or label on every node sounds reasonable to me. We could add each user's tenant ID to to their Auth0 user and pass it via the JWT to the Apollo context in the backend, or even fetch the user from the database at the start of handling each request (when formatting the user object in /api/src/index.js for example) if that's easier.

The resolvers can then get the tenant ID from the Apollo context and pass them as arguments to the connectors, where we could either run a check, like you said, or just add the tenant id to the query's match clause so nothing happens if the node is on the wrong tenant.

erikfrisk commented 4 years ago

PS. Maybe the check(s) can also be done in more custom authorization functions like the ones in /api/src/graphql/authorization/. Those functions can be stacked, so in the resolvers file it might look something like this...

updateNeed: combineResolvers(
  isAuthenticated,
  canUpdateNode,
  async (obj, args, { driver, user }) => {
    ...
  },
),
aerugo commented 4 years ago

There seem to be a few things to enable multi-tenancy in neo4j, like Fabric, but they seem to be mostly Enterprise edition features and also pretty heavyweight, e.g. having a whole separate db per tenant. ( edit: the most promising one i found was being able to switch between dbs with :use but creating new dbs to use with that is enterprise)

Just for reference, it's possible to run multiple neo4j instances on different ports with ineo. This is good to know in case we would need to run a completely separate white-label realities for a client in the future.