I’m currently trying to make Hye Ararat (web ui) hide options the user doesn’t have access to (e.g. not showing the edit button on projects if the user doesn’t have permission), however, I’ve noticed that while there are /access endpoints for Instances & Projects (which in scriptlet form have to be manually defined), there are other resources that don’t strictly inherit access from the project-level, that don’t have such endpoints defined (server and storage_volume on the authorization model schema).
Is this something that should be changed on the API-side of Incus, or should the panel attempt to communicate directly with the OpenFGA service & parse scriptlet logic?
It also seems that the /access endpoints that do exist only define a role, when entitlements can be fine-grained, such as can_access_files (I however have not gotten to testing the behavior of the endpoint yet so I could be completely wrong, going off the documentation here).
Off the top of my head I have a feeling it may be better to have more fine-grained level of access control on other resources as well, however, I haven’t really thought that element through thoroughly.
We’ll need to find the right balance there as we don’t want the UI to overwhelm the backend with permission check requests but we also want the UI to be able to adapt to the user’s permission level.
I suspect it would make sense to have a more central /1.0/metadata/access endpoint which can return an overall view of the user’s access on the server.
This would probably include:
Global “is_admin” flag to bypass everything else
Top-level server-wide permissions
Dictionary of projects to list of permissions (so you’d immediately get the allowable project list and an idea of the level of access within that project)
List of per-object permissions
Not all of it would be available on all backends as basically only OpenFGA really allows listing permissions rather than just checking on-demand during an API operation. The scriptlet supports a limited subset of listing and may be extended to provide more details too.
So we’d basically be differentiating null vs empty values where null means that the backend couldn’t provide the information and the frontend should therefore act as if unrestricted but with the knowledge that operations could still be declined.
… and only because I absolutely needed to implement those! I don’t see a good way to implement that for all the objects, and because the scriptlet doesn’t have access to most the information about them, we’d need to implement costly (not in dev time, but in DB lookups) helpers just to fetch said objects (or just their names). OpenFGA is its own source of truth, so lookup is inexpensive. I think what you’re describing can only ever apply reasonably to OpenFGA.
The endpoint would quickly get really expensive, which mandates for caching on the client side, but you really wouldn’t want your users to not be able to click a button after a permission change if they don’t clear their cache (reloading the page is fine, but that’s soooo y2k ).
Now of course we could add the concept of rights/roles to fit the « rough roles » aspect of OIDC and SAML, which the scriptlet could probably consume, but I think we have internalized that it won’t be happening anytime soon
As I’m not an OpenFGA cool kid, I’m sure your endpoint is great, but I’m also sure I won’t be seeing a lot of grayed-out buttons in my UI at my job!
OIDC claims would provide a similar level of prior knowledge of the user’s permissions that could then be included in the API above. I’m not familiar with SAML but so long as that works similarly, that is, the user gets granted some access at token issuance time, then it would fit fine with that API.
It’s really the scriptlet approach or the old OpenFGA approach (prior to them having a listing ability) where you end up with little more than a “user is admin” level of granularity.
Permissions changing after fetching the access metadata is indeed a bit of an issue. Incus could probably set the right caching/lifespan value, aligning it with the user’s session token’s expiry. But that won’t help with OpenFGA where accesses can be changed without any notification to Incus.
I don’t know that it’s necessarily that big a deal though. Someone not getting the accesses they need after they were granted will typically reach for that refresh button anyway.
My data fetching layer maintains essentially a structured data store in the browser, so I do have that taken care of! The UI also auto-updates with information from the events socket, so if there was a way to emit events on permissions-related changes, the reload aspect could be resolved (this may be fundamentally incompatible with the scriptlet/openfga system though). I think this isn’t a huge deal, worst case scenario they press a button and it displays some sort of permission denied message.
The scriptlet is very expensive to maintain, even on individual resource fetch in the current implementation, however, maybe it could be significantly cheapened if the values were pre-calculated and cached as much as possible on the server side (maybe upon a change to any of the dependents in the scriptlet, caching results for users when those dependents don’t change), or cached upon first request with awareness to when its invalid. Just some creative ways to try to lighten the load.
Global endpoint and per-resource both should behave fine with the interface implementation. A global endpoint increases the processing on the server, but decreases the amount of network traffic. However, I currently already query /1.0 on initial request to get the auth key to see if the user is validly authenticated, if this endpoint could replace that as well, it becomes even more valuable! The global endpoint also has the advantage of pre-populating my client side cache with a lot of resource names, which will increase general responsiveness of the UI.