InvenTree icon indicating copy to clipboard operation
InvenTree copied to clipboard

Permissions Refactor - in Refinement

Open matmair opened this issue 1 year ago • 14 comments

The permission system currently uses a mixture of stock Django permissions, a self-written role-mapping engine and a ownership model for stock. This is not well documented and the behaviour is not consistent - making it harder to understand/predict.

There are a few issues regarding permissions, some quite old

Related issues

  • [ ] https://github.com/inventree/InvenTree/issues/7446
  • [ ] https://github.com/inventree/InvenTree/issues/7003
  • [ ] https://github.com/inventree/InvenTree/issues/5755
  • [ ] https://github.com/inventree/InvenTree/issues/4022

Requirements

Requirements for the overhaul:

  1. Interoperable (additional to) with Djangos default system
  2. Using existing fine-grained control patterns (Tree per Location -> Part -> Stock items)
  3. API-enforced and auto-documented
  4. Generic / pluggable so plugins can use the same systems (maybe with a permission register?)
  5. Extendable with per-model actions (ie. allocate stock, count stock, create revision, ship order but not change it)
  6. Integrate well with (LDAP/SSO synced) groups and be transparent to users

User stories

TBD

Feel free to submit your user stories / requirements / issues here - I will update / remove points as consensus is reached on them.

matmair avatar Jun 17 '24 22:06 matmair

I think it would be pretty helpful, if we could assign some users only permissions to:

  • CRUD parts, categories (including SP, MP, ...) from a specific category (and their nested children categories)
  • CRUD locations (including stock items) only from a specific location (and their nested children locations)
  • CRUD only specific companies, BOMs ... maybe here it would be helpful to create different "profiles" which can be assigned to a user, and to some models like BOMs, Companies, ...

This would be helpful to my personal inventree instance which I use for my electronics hobby, to add a separate profile for my family so we can manage our cellar, garage, ... too, without them having appearing my electronics inventory when they search for something they have in their garage. I could just run two inventree instances, but 1. this costs double RAM, CPU, ... and 2. I have to use two different logins.

As well, this could also be useful for business who have different departments: manufacturing, selling, .. different categories of products. Where the employees should not be able to mess with the parts, locations in other departments.

wolflu05 avatar Jun 18 '24 12:06 wolflu05

I think it would also be nice be bind this somehow to projects.

  • Assign users to projects
  • Assign parts/stock whatever to projects

Everyone in the project gets access to every item in the project. User groups already exist and can be used.

SergeoLacruz avatar Jun 19 '24 18:06 SergeoLacruz

Additional consideration: with the upcoming "lock part" feature, it would be a good idea to control who can lock / unlock a part. Maybe part "ownership" (either of individual parts or part categories) could come into play here.

SchrodingersGat avatar Jun 27 '24 01:06 SchrodingersGat

Coming from #7718, here are my user stories from working in a university with different research groups/projects who would like to share a common Inventree instance:

  • As an admin:
    • I want to assign one or multiple groups/projects to users so that different kind of stocks can be represented (e.g. common stock, group stock, per-project stock).
    • I want to select whether group/project items will be visible to other groups/projects to reflect different levels of sharing/not sharing Stock.
  • As a user:
    • I want to be able to assign a group/project (that I belong to) to every item of every level (Parts, StockItems, BuildOrders, PurchaseOrders, ..) so that different ways of working together can be represented
    • I want to set default groups/projects for newly created items per level so that accidentally forgetting group/project assignment and general amount of work is minimized.

wieselukas avatar Jul 24 '24 16:07 wieselukas

@wieselukas would you use case-required organisations (similar to GitHub/Gitlab with restricted visibility teams/groups below) or would globally visible groups be enough?

I am unsure if project codes are the right device to control Inventree-wide permissions as they represent simple 1:many FK relations (you basically would have to assign every stockitem, part, BO, PO, SO on it's own to the projectcode)

matmair avatar Jul 24 '24 19:07 matmair

I don't have much experience with github/lab groups but globally visible groups would be totally fine for me.

I like the idea of assigning it per stockitem, part, BO, PO, SO individually as it would allow for different use-cases. E.g. the current stock ownership feature could still be reflected when only assigning projects/groups to stock items. To not make this a manual effort this could either be done through per-user/per-type defaults (type being: stockitem, part, BO, PO, SO) and the possibility to assign project groups to a selection of items. Another, and maybe the better, option would be to link it to a category for parts and stock location for stockitems, while automatically assigning the same project/group to subcategories/locations. To do it manually for BO, PO and SO would be fine for me. Another case for "project codes" would be that for an admin moving stockitems, parts, BOs, POs, SOs between projects/group would just be a matter of changing the project codes for these items.

wieselukas avatar Jul 25 '24 09:07 wieselukas

@SergeoLacruz @wieselukas I would like to scope this in the next few months to get an actionable list of tasks assigned to epic. Would you / a college be willing to jump on a call to discuss ideas? This is not going to happen fast but I would like to write down a possible plan for after 1.0 so we know what parts might change in the mid-term. If you are interested feel free to drop me an email.

matmair avatar Nov 11 '24 23:11 matmair

If if is not around midnight I would like discuss this and add me ideas.

SergeoLacruz avatar Nov 16 '24 10:11 SergeoLacruz

Sorry for the late reply. I would also be available for a call. During the week 9-10am or 5-9pm UTC would mostly work I guess

wieselukas avatar Dec 13 '24 11:12 wieselukas

See also https://github.com/dimagi/django-prbac and the new release of guardian

matmair avatar May 08 '25 07:05 matmair

Starting to work on a prototype for this using a generic tree-supporting pluggable profile/roles based approach

matmair avatar Oct 16 '25 22:10 matmair

Here is a rough outline of my plans; this will probably be delivered in a number of PRs, feature flagged till all components are ready. I would appreciate feedback - for now I have not started major work, only touching some deges that might be affeted.@ @SchrodingersGat @wolflu05 @SergeoLacruz @wieselukas

I am considering moving this comment to a file in the project-adrs(currently in beta) as that would allow commenting on sections.

General Overview

To allow precise segmentation of and fine-grained permission on all things (as requested multiple times, in #7718 for example) 2 new concepts are introduced:

  • Workspaces
  • Profiles

These can be seen as extensions of the existing concepts of Project Codes and Groups (in their usage for permission scoping).

New Concepts

Workspaces

Workspaces can be thought of similar to organizations in GitHub, Groups in GitLab or Organizational Units in Active Directory. They borrow some names/ideas from these concepts, but are tailored to the needs of InvenTree and are not a superset.

Business Rules

  1. Workspaces support tree-like nesting, similar to part categories
  2. Workspaces have attributes to make navigating and organisation for the user easier. Each must have a name and slug and can have a short name, description, icon and color, an owner (user or group) and a responsible (user or group). The later two might be used for targeting notifications
  3. There is the default workspace "Default" (always pk 1, can not be deleted), which will be the default workspace for all models supporting workspaces
  4. Each object supporting workspaces is assigned to exactly one workspace
  5. Users can be a member of multiple workspaces
  6. A user can only work in one workspace at a time / API call and can only create interactions between objects in that workspace or global objects (not assignable to any workspace)
  7. Plugins can ship models that support workspaces or chose to stay global (available in all workspaces) - which is the default
  8. API paths for all models/objects/actions that support workspaces will be optionally extended by a workspace identifier, so that all queries are scoped to the required workspace. If no workspace is provided for a workspace-scoped endpoint, the "Default" workspace is assumed.
  9. Usage of the workspace feature can be enabled in a global system setting; disabling it will hide all UI features related to workspaces. Internally, workspaces will still be assigned to all new/manipulated objects with the "Default" workspace. Existing workspace assignments will be preserved, but ignored.
  10. Disabling the workspace feature after it has been used would hide all objects not assigned to the "Default" workspace - therefore, I am considering adding a wizard to the Admin Center that would allow re-assigning all objects to the "Default" workspace before disabling the feature.

Workspaces would be implemented as a single workspace model and by adding a generic foreign key to all models that support workspaces.

Usage

Workspaces might be organized like this:

- Default (default : 1)
- My Space Adventure (msa : 2)
    - Suits (msa/suit : 3)
        - First Eval Generation ( msa/suit/first : 4)
        - Andromda Generation (msa/suit/andromeda : 5)
        - Mars and Beyond Generation (msa/suit/mars : 6)
    - Rockets ( msa/rocket : 7)
    - Habitats ( msa/habitat : 8)
- Special Project X (spx : 9)

Being assigned access to "My Space Adventure" would give access to workspaces 2,3,4,5,6,7,8 Working in workspace 5 "msa/suit/andromeda" would only show objects to workspace 5 Working in workspace 2 "msa" would only show objects assigned to workspaces 2

Profiles

Profiles are a way to represent a certain configuration area of InvenTree, there can be a number of different profiles types, but every object is only assigned to one profile per profile type at a time.

Business Rules

  1. Profile types are defined globally
  2. Plugins can define new profile types
  3. Profiles are instances of a single profile type
  4. Profiles can have attributes, depending on their profile type
  5. Each object can only be assigned to one profile per profile type
  6. Default Profiles can be inherited (details to be defined) - so behavior can be defined at a higher level (e.g. part category) and inherited by all child objects unless overridden
  7. Profiles can be "owned" by a user or group to allow controlling configuration of certain profile types

Model structure:

  • ProfileType
    • name
    • description
    • source (core, plugin, unknown)
    • plugin (nullable FK to Plugin model)
  • Profile
    • profile_type (FK to ProfileType)
    • name
    • description
    • settings (JSONField for profile specific settings)
    • owner (nullable FK to User or Group)
  • ProfileAssignment
    • profile (FK to Profile)
    • content_type (Generic FK to any model supporting profiles)
    • object_id (Generic FK to any model supporting profiles)
    • inherited (bool, if the assignment is inherited from a parent object, e.g. part category)
    • inheritance_source (nullable Generic FK to the object the profile is inherited from)

Usage

Profiles might be used for:

  • Setting behavioral options for certain models (e.g. Part behavior profile, Supplier behavior profile)
  • Access control (e.g. defining which actions are allowed on a model for users assigned to a certain profile)
  • UI configuration (e.g. defining which fields are visible/editable for a model for users)
  • Required parameters

In the first iteration, I plan to use ProfileAssigments as a lookup target for permission checks, making a gradual transition from classic Django permissions to Profile based permission scoping possible.

Changes current things

Existing Roles

The role system would be preserved as is for reverse compatibility, but definitions of roles would move to the individual models / apps where possible to remove the coupling between users / and the apps (parts, stock, etc) as much as possible.

New Roles model?

I think it could make sense to have a new Roles model that defines roles as a model and that would make it usable by plugins as well.

Expand permission information in the API schema

The API schema would be expanded to include information about which permissions are required for each endpoint. I did a small prototype of this in #10628.

Extending docs / adding a best practices guide

The documentation should be extended to include information about how the permission system works and how to use it effectively. A best practices guide could be added to help users understand how to set up permissions in a way that is secure and is intended by the developers.

Things I want to avoid / think might cause a problem

  • Moving project codes into workspaces - project codes were introduces with another stated purpose and I want to avoid confusion
  • Using project codes as a way to segment permissions - projects codes are very simple objects and would need far reaching changes to be used for permission scoping, bluring the line to workspaces
  • Sharing stock items between workspaces - this would make the API more complex
  • Using any dynamic scoping that is not pre-defined - I want to avoid having to calculate permissions on the fly as much as possible for performance and audit logging (#9996) reasons
  • The ability for users to easily move objects between workspaces - this should be a deliberate action that requires admin access and is not done lightly (also because it is probably api-expensive)

Defintions

Global

Something system wide, there is only one value / setting / instance for or of it. Can not be segmented any further. Example: System Settings, Users, Groups

User

A human actor interacting with the InvenTree system, represented by a User object, typically using the frontend

Actor

An entity that interacts with the system. This can be a user, automated system, workarea access station

Model

A Django model

Object

An instance of a Django model

Action

An operation that can be performed via the API. Either on an object, a collection of objects, a model or against the global system

matmair avatar Oct 25 '25 23:10 matmair

Thanks for the starting point. I need to think about it... Will take some days.

SergeoLacruz avatar Oct 26 '25 11:10 SergeoLacruz

As this is an Epic, lest add some user stories.

Marcus is a libarian. He can create and modify components. But he cannot delete them. This is up to an administrator. He also cannot add supplierparts and prices. This is op to Harold Harold is working gin the purchasing department. He adds suppliers and their prices to the parts but he cannot modify the parts or the parameters. He can also create and edit purchase orders. Monika is a designer. She can view all parts, suppliers and prices because her job is also the create cost efficient designs but she has no edit rights at all. Barbara is a student worker supporting Monica. She can also see all the components but not the prices because this might leak too much data. Max is a tester working on the Astro project. He can add and modify test results to all parts related to the Astro project. He can also see the results from the Moonshot project for comparison but he cannot edit them. When Max goes on vacation for two weeks he introduces Oliver as his deputy who usually works on Moonshot. For the time of Max vacation Oliver can edit Moonshot and Astro parts. Bruce is working in the warehouse. He can shuffle around stock items and boxes between locations but he cannot create new locations. This is up to Marvin who makes the floor plan of the warehouse. Mike works in the factory. He can create parts that are manufactured, add serial numbers, and other data. But he cannot add or modify parts for design as Marcus can. Morgan is the administrator. He can do everything.

Of course this is far from complete and leaves a lot of room for discussion. Can this help? https://openfga.dev/

SergeoLacruz avatar Nov 01 '25 09:11 SergeoLacruz