Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to many-to-many relationship field fails where user doesn't have update permission to both lists in relationship #2797

Closed
intmainvoid opened this issue Apr 22, 2020 · 3 comments

Comments

@intmainvoid
Copy link
Contributor

Bug report

Summary

Updates to a relationship field where that relationship is part of a many-to-many fails when the user does not have permission to both lists. Upon failure, records between the two joining tables are now inconsistent as one of them has been updated and the other has not.

To Reproduce

  • Setup a Keystone instance with the Knex Postgres adatper
  • Setup two lists: User and Interest. A user may have many different interest and each interest can relate to many users. ie. This is a many-to-many relationship.
  • Setup the permissions so a user can update their own user record but may not add to - or otherwise update - the list of interests.

My list definitions look like this:

User:

const UserSchema = {
	label: 'Users',
	fields: {
		firstName: { type: Text },
		lastName: { type: Text },
		email: { type: Text, isUnique: true },
		password: { type: Password },
		interests: { type: Relationship, ref: 'Interest.users', many: true },
	},

	access: {
		read: userIsAdminStaffOrOwner,
		update: userIsAdminStaffOrOwner,
		create: true,
		delete: userIsAdmin,
		auth: true
	},
};

Interest:

const InterestSchema = {
	label: 'Interests',
	labelField: 'description',
	fields: {
		description: { type: Text },
		users: { type: Relationship, ref: 'User.interests', many: true },
	},

	// Only Admins should be able to modify this
	access: {
		read: true, // Public read access
		update: userIsAdmin,
		create: userIsAdmin,
		delete: userIsAdmin,
	},
};

When I authenticate as the user I want to update, and then attempt to add some interests to the user via the following GraphQL...

mutation ADD_INTERESTS {
  updateUser(id:1, data: {
    interests: {
      connect: [
        { id: 2 },
        { id: 3 }
      ]
    }
  }) {
    id
  }
}

... I receive the following error:

{
  "errors": [
    {
      "message": "You do not have access to this resource",
      "name": "AccessDeniedError",
      "time_thrown": "2020-04-22T01:57:49.204Z",
      "data": {
        "type": "mutation",
        "target": "updateUser"
      },
      "path": [
        "updateUser"
      ],
      "uid": "ck9aotfzl0000Yus4grsyh5hr"
    }
  ],
  "data": {
    "updateUser": null
  }
}

In addition, looking at the database, there are two joining tables between User and Interest. These are: User_interests and Interest_users. When the above error is received, User_interests has been updated to include the connection of the two interests above, but Interest_users has NOT been updated. So now there is inconsistency in the data in the database.

Expected behaviour

The update should succeed providing the user has update permission to either list.

Specifically, when Keystone has a many-to-many relationship between two lists, and a user with the rights to update a record in one of the lists (but not the other) attempts to create a relationship between two records on each side of that relationship, that update should succeed. At the very least it should fail in an atomic way (ie. neither of the joining tables should be updated)

Screenshots

N/A

System information

  • OS: MacOS 10.15.3

Additional context

If I modify the Interest list to allow updates from everyone (ie. update: userIsAdmin --> update: true), the update succeeds as expected.

@molomby
Copy link
Member

molomby commented Apr 23, 2020

Hey bud 👋 The relationship integrity part of this is covered in #1925 and has only recently been fixed. What version of KS was this on? If you're on Keystone ^8.0.0 you should only get a single relationship table.

That doesn't address your main question around how access control effects editing relationships though. I suspect this is by design but will defer to @timleslie.

@intmainvoid
Copy link
Contributor Author

Hey @molomby. Thanks for the detail. This case was definitely on an older version. Keen to know more about how permissions work on joining tables though (removing or adding relationships between many-many or even one-many relationships)

@timleslie
Copy link
Contributor

This should indeed now work. An update operation on a relationship field takes its access control fields from the list being updated, so in your case you are doing an updateUser, so the permission to perform the connect operations would be determined from the User list. If you did an updateInterests and updated the users field, the access control would be determined from the Interests field. You need to be a little bit careful when setting up the access control on related fields, as the same piece of data (the join table in the DB) can have different access control rules depending on which list you attempt to access it from.

I'm going to close out this issue now, but if you can reproduce the error with the latest versions, or anything is still unclear then feel free to reopen this issue or create a new issue 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants