Repository: OctoPrint/OctoPrint

Issue:
[1.4.0rc3] Permission issue, can start print from Cura without such permission
### Problem

> @foosel 
> 
> > Could you please check what appkeys exist in your system and for which users, and that the key in Cura is actually for the user you expect it to be? You can do so via Settings > Application Keys.
> 
> I just tested again, making sure to be logged in as the api_user to get the API key (that has > limited access) and although I can not move or preheat the printer within Cura, slicing and clicking "Print with OctoPrint" does in fact upload the file (allowed) and start the print (shouldn't be allowed).

_Originally posted by @gcurtis79 in https://github.com/foosel/OctoPrint/issues/3389#issuecomment-566840541_

### Solution

Make sure `PRINT` permission gets checked on evaluation of `select` and `print` request parameters on upload API, probably not the case right now, causing this issue.
[1.4.0rc3] Permission issue, can start print from Cura without such permission
### Problem

> @foosel 
> 
> > Could you please check what appkeys exist in your system and for which users, and that the key in Cura is actually for the user you expect it to be? You can do so via Settings > Application Keys.
> 
> I just tested again, making sure to be logged in as the api_user to get the API key (that has > limited access) and although I can not move or preheat the printer within Cura, slicing and clicking "Print with OctoPrint" does in fact upload the file (allowed) and start the print (shouldn't be allowed).

_Originally posted by @gcurtis79 in https://github.com/foosel/OctoPrint/issues/3389#issuecomment-566840541_

### Solution

Make sure `PRINT` permission gets checked on evaluation of `select` and `print` request parameters on upload API, probably not the case right now, causing this issue.


Discussion:
Is this something you plan to fix today (this year) still? If not this sounds like something I could make a PR for, for you to check out next year.
Not today, so sure, go ahead :)
It looks like the `PRINT` permission is properly checked on evaluation of `select` and `print` request parameters on upload API, however the `PRINT` permission seems broken. 

All permissions which specify additional needs (`FILES_DOWNLOAD`, `FILES_DELETE`, `FILES_SELECT`, `PRINT`, `GCODE_VIEWER` and `TIMELAPSE_ADMIN`) seem to always be available. This can also be seen in the UI by revoking the `File List` permission; the file list should disappear but it doesn't. Same with removing the `File Delete` permission, which should remove the trash icon from the file list but doesn't. 

Removing the `FILE_LIST` need from the definition of these permissions fixes this. Removing the `FILE_SELECT` from the `PRINT` permission fixes the issue reported by @gcurtis79.

I've been looking why multiple needs are not working and will continue to do so.
~~My previous assessment seems incorrect. The problem is not so much multiple needs, but the FILES_LIST permission seems suspect.~~

See below
My original assessment was correct. I understand the Needs and Permissions a bit better now.

When an OctoPrintPermission has multiple Needs, Permission.allows() checks if there's an intersection between the needs of the Permission and the provides of the Identity. Because the length of the intersection is not checked, this is true if one or more needs overlap. So because the `PRINT` permission also has the `FILES_SELECT` permission, Permission.PRINT.can() returns true if the user does not provide a `print` Needs but has a `files_select` Needs. 

The quickest fix is to remove the multiple Needs in the OctoPrintPermissions definitions. A better fix is to check the length of the intersection between the Identity provides and Permission needs to be the same as the Permission needs in Permission.allows, but that's an upstream fix.
Is this something you plan to fix today (this year) still? If not this sounds like something I could make a PR for, for you to check out next year.
Not today, so sure, go ahead :)
It looks like the `PRINT` permission is properly checked on evaluation of `select` and `print` request parameters on upload API, however the `PRINT` permission seems broken. 

All permissions which specify additional needs (`FILES_DOWNLOAD`, `FILES_DELETE`, `FILES_SELECT`, `PRINT`, `GCODE_VIEWER` and `TIMELAPSE_ADMIN`) seem to always be available. This can also be seen in the UI by revoking the `File List` permission; the file list should disappear but it doesn't. Same with removing the `File Delete` permission, which should remove the trash icon from the file list but doesn't. 

Removing the `FILE_LIST` need from the definition of these permissions fixes this. Removing the `FILE_SELECT` from the `PRINT` permission fixes the issue reported by @gcurtis79.

I've been looking why multiple needs are not working and will continue to do so.
~~My previous assessment seems incorrect. The problem is not so much multiple needs, but the FILES_LIST permission seems suspect.~~

See below
My original assessment was correct. I understand the Needs and Permissions a bit better now.

When an OctoPrintPermission has multiple Needs, Permission.allows() checks if there's an intersection between the needs of the Permission and the provides of the Identity. Because the length of the intersection is not checked, this is true if one or more needs overlap. So because the `PRINT` permission also has the `FILES_SELECT` permission, Permission.PRINT.can() returns true if the user does not provide a `print` Needs but has a `files_select` Needs. 

The quickest fix is to remove the multiple Needs in the OctoPrintPermissions definitions. A better fix is to check the length of the intersection between the Identity provides and Permission needs to be the same as the Permission needs in Permission.allows, but that's an upstream fix.

Resolving patch:
diff --git a/src/octoprint/access/permissions.py b/src/octoprint/access/permissions.py
--- a/src/octoprint/access/permissions.py
+++ b/src/octoprint/access/permissions.py
@@ -79,6 +79,22 @@ def get_name(self):
 	def get_description(self):
 		return self._description
 
+	def allows(self, identity):
+		"""Whether the identity can access this permission.
+		Overridden from Permission.allows to make sure the Identity provides ALL
+		required needs instead of ANY required need.
+
+		:param identity: The identity
+		"""
+		if self.needs and len(self.needs.intersection(identity.provides)) != len(self.needs):
+			return False
+
+		if self.excludes and self.excludes.intersection(identity.provides):
+			return False
+
+		return True
+
+
 	def union(self, other):
 		"""Create a new OctoPrintPermission with the requirements of the union of this
 		and other.


Test patch: