diff --git a/docs/apps/rbac/for_app_developers.md b/docs/apps/rbac/for_app_developers.md index 8ae79cabc..ae156d933 100644 --- a/docs/apps/rbac/for_app_developers.md +++ b/docs/apps/rbac/for_app_developers.md @@ -2,11 +2,35 @@ These instructions are intended for someone applying this system to an existing Django app. Start with `docs/Installation.md` for the core ansible_base setup. -The app name is dab_rbac, INSTALLED_APPS path is "ansible_base.rbac". -You can choose to use this entirely at the Django model level - - you use roles to delegate permissions to users and teams - - this system will efficiently filter querysets to a certain permission level for a certain user +The 2 main things to enable DAB RBAC are: +1. Add to INSTALLED_APPS in settings, path is "ansible_base.rbac" +2. Register your models with the DAB RBAC `permission_registry` + +### DAB Models vs Django Models + +DAB RBAC uses specialized models that mirror Django's built-in auth models but are purpose-built for the RBAC system: + +- **`DABPermission`** - Mirrors Django's `Permission` model but only tracks permissions for RBAC-registered models and supports remote models +- **`DABContentType`** - Mirrors Django's `ContentType` but with enhanced caching and support for remote models +- **User/Team/Organization Models** - Configurable through settings, defaults to Django or DAB default models + +The custom permission and content type models provide: +- Better performance through aggressive caching +- Support for tracking permissions to remote services +- Clean separation from Django's built-in auth system, avoiding conflicts with other apps + +### Terminology for Developers + +When working with DAB RBAC code, use precise terminology: + +- **Role Definition** - Always use "role definition", never just "role" (which could refer to object roles or other concepts) +- **Object Role** - The instantiation of a role definition for a specific object +- **Role Assignment** - The record linking a user/team to a role definition for an object or globally +- **Permission** - An action on a model type (e.g., "change_inventory") +- **Access** - Avoid this term in code; used for AWX `awx/main/access.py` module, overlay logic on top of RBAC evaluations + +User-facing interfaces may simplify "role definition" to "role" for usability, but internal code should maintain precision. ### Migrations diff --git a/docs/apps/rbac/for_clients.md b/docs/apps/rbac/for_clients.md index c384634e9..ee71ff870 100644 --- a/docs/apps/rbac/for_clients.md +++ b/docs/apps/rbac/for_clients.md @@ -1,47 +1,83 @@ ## Using DAB RBAC as an API Client -This section tells how to use the API endpoints as a client; -what requests to make and how to build request data. +This section explains how to use the RBAC API endpoints to manage permissions. -You need a server running a Django project that uses this system. -Use test_app in this repo for a demo, see `test_app/README.md` for bootstrap. -The server runs at http://127.0.0.1:8000, and links within that will be referenced here. -Default password for admin user is "admin". +### Prerequisites -### Create Custom Role (Definition) +You need a server running a Django project that uses DAB RBAC. +Use test_app in this repo for a demo (see `test_app/README.md` for setup). +The server runs at http://127.0.0.1:8000, and examples reference this base URL. +Default admin password is "admin". -After logging in to test_app/, you can visit this endpoint to get the role definition API. +### API Workflow Overview -http://127.0.0.1:8000/api/v1/role_definitions/ +The RBAC API follows standard REST practices where models have relational dependencies. The typical order for establishing permissions: -Perform an OPTIONS request, and you will find this gives choices for `content_type`. -Out of the choices a single `content_type` needs to be chosen for a role definition. +1. **Types** (`/api/v1/role_metadata/`) - Read-only, managed by app developers +2. **Permissions** - Read-only, created when models are registered +3. **Role Definitions** (`/api/v1/role_definitions/`) - Managed and custom roles +4. **Role Assignments** - User assignments (`/api/v1/role_user_assignments/`) and team assignments (`/api/v1/role_team_assignments/`) -Multiple permissions can be selected, and are accepted in the form of a list. -To find out what permissions are valid for a role definition for a given `content_type` -make a GET to `/api/v1/role_metadata/` and look up the type under "allowed_permissions". +Users interact primarily with steps 3 and 4, while steps 1 and 2 are controlled by the application configuration. -A POST to this endpoint will create a new role definition, example data: +## Step 1: Understanding Available Types and Permissions + +### View Available Content Types + +Get the available content types and their permissions: + +``` +GET /api/v1/role_metadata/ +``` + +This returns read-only information configured by app developers: +- Available content types (e.g., "aap.inventory", "shared.organization") +- Permissions allowed for each content type +- No user interaction required with this data + +## Step 2: Creating Role Definitions + +### Create a Custom Role Definition + +``` +POST /api/v1/role_definitions/ +``` + +Example request body: ```json { "permissions": ["view_inventory"], "content_type": "aap.inventory", "name": "View a single inventory", - "description": "custom role" + "description": "Custom role for inventory viewing" } ``` -Name can be any string that's not blank. Description can be any string. +Required fields: +- `permissions`: List of permission codenames (from step 1) +- `content_type`: Content type string (from step 1) +- `name`: Display name for the role definition + +Optional fields: +- `description`: Additional context about the role definition + +### Managed vs Custom Role Definitions + +- **Managed roles**: Created by app developers, cannot be modified via API +- **Custom roles**: Created by users, fully manageable via API -### Assigning a User a Role to an Object +## Step 3: User Role Assignments -Select a role definition from `/api/v1/role_definitions/`, use the id as `role_definition` -and a user from `/api/v1/users/` and use the id as `user`. -Given the type of the role definition, check the available objects of that type, -in this case `/api/v1/inventories/` and obtain the desired id, this will become `object_id`. +### Assign Role Definition to User for Object -With all 3 ids ready, POST to http://127.0.0.1:8000/api/v1/role_user_assignments/ +Once you have a role definition, assign it to a user for a specific object: + +``` +POST /api/v1/role_user_assignments/ +``` + +Example request body: ```json { @@ -51,26 +87,43 @@ With all 3 ids ready, POST to http://127.0.0.1:8000/api/v1/role_user_assignments } ``` -This will give user id=3 view permission to a single inventory id=3, assuming the role definition -referenced is what was created in the last section. +Required fields: +- `role_definition`: ID from `/api/v1/role_definitions/` +- `user`: ID from `/api/v1/users/` +- `object_id`: ID of the target object (e.g., from `/api/v1/inventories/`) + +This grants the user the role definition's permissions for only the specified object. + +### Assign Role Definition to User Globally + +For system-wide permissions, omit the `object_id`: + +```json +{ + "role_definition": 5, + "user": 3 +} +``` + +The role definition must have `content_type: null` for global assignments. -### Assigning a User as a Member of a Team +## Step 4: Team Role Assignments -While this is possible with the RBAC API, it is not covered here, -because it may come from an external source. +### Team Membership -The "member_team" permission may later be prohibited from use in custom role definitions. +Teams are used to bulk assign permissions to multiple users. -### Assigning a Team a Role to an Object +You give permissions to a team by assigning the team a role definition, usually for a specific object. A single team can be assigned many roles, to many different objects. Teams can in theory be given global roles, but this may be disabled by the application settings. -If you used the test_app bootstrap script, then you will find the user "angry_spud" -is a member of the "awx_devs" team. +If a user has the "member_team" permission to a team, that user automatically inherits all permissions assigned to the team. -Assuming the team id is 2, POST to +### Assign Role Definition to Team -http://127.0.0.1:8000/api/v1/role_team_assignments/ +``` +POST /api/v1/role_team_assignments/ +``` -with data +Example request body: ```json { @@ -80,36 +133,60 @@ with data } ``` -This has a similar effect to user assignments, but in this case will give -permissions to all users of a team +This grants the role definition's permissions to all members of the team for the specified object. + +## Management Operations + +### View Existing Assignments + +List assignments for a specific object: + +``` +GET /api/v1/role_user_assignments/?object_id=3&content_type__model=inventory +GET /api/v1/role_team_assignments/?object_id=3&content_type__model=inventory +``` + +### Revoke an Assignment -### Viewing Assignments +Delete a specific assignment by ID: -For the single inventory mentioned above, it is possible to view the existing permission -assignments directly to that object. +``` +DELETE /api/v1/role_user_assignments/1/ +``` -GET +This removes the assignment and all permissions it granted. -http://127.0.0.1:8000/api/v1/role_team_assignments/?object_id=3&content_type__model=inventory +If you remove an assignment that a team has, all members to that team will lose that permission. -http://127.0.0.1:8000/api/v1/role_user_assignments/?object_id=3&content_type__model=inventory +## Organization-Level Permissions -### Revoking an Assignment +### Assigning Organization-Wide Permissions -From any of the assignment lists, the user can select an assignment to revoke. -Follow the "url" in the serializer from either user or team assignment lists. +To grant permissions to all objects within an organization: -DELETE http://127.0.0.1:8000/api/v1/role_user_assignments/1/ +1. **Create an organization-level role definition:** + ```json + { + "permissions": ["view_inventory", "change_inventory"], + "content_type": "shared.organization", + "name": "Organization Inventory Manager" + } + ``` -Will undo everything related to that assignment. -The user or team's users will lose permission that was granted by the object-role-assignment. +2. **Assign to user/team using organization ID:** + ```json + { + "role_definition": 4, + "object_id": 1, // organization ID + "user": 3 + } + ``` -### Assigning Organization Permission +This grants the specified permissions to all inventories within organization ID 1. -In the case of inventory, its parent object is its organization. -Instead of giving permission to a single inventory, you can use roles to give -permission to all inventories inside of an organization. +## Error Handling -The difference in the above steps are that -- when creating a custom role definition the `content_type` would be "shared.organization" -- when creating the assignment, the `object_id` would be the id of an organization +Common API errors: +- **400 Bad Request**: Invalid role definition/object/user combination +- **403 Forbidden**: Insufficient permissions to create assignment (you need "change" permission to the object to create role assignments) +- **404 Not Found**: Referenced object does not exist diff --git a/docs/apps/rbac/for_dab_developers.md b/docs/apps/rbac/for_dab_developers.md index c3995e193..67dafa31c 100644 --- a/docs/apps/rbac/for_dab_developers.md +++ b/docs/apps/rbac/for_dab_developers.md @@ -1,116 +1,89 @@ ## DAB RBAC System Design Principles -This is derived from the RBAC system in AWX which was implemented roughly -in the year 2015, and this remained stable until an overhaul, with early work -proceeding in the year 2023. - -The 2015 implementation had the following key distinguishing features: - - object roles were auto-created when a resource was created - - roles formed an acyclic (or cyclic) graph between each other via their parents and children - - object roles were defined by the `ImplicitRoleField` declared on each model - - teams gain permission by adding their `member_role` to parents of another role - -The key differences of the 2023 system are: - - object roles are not auto-created, but only created as needed to perform assignments - - resources are organized in a strict tree, mostly with organizations being the parents - - role definitions list canonical Django Permission objects - - teams are listed in a `role.teams.all()` relationship directly, similar to users - -The main _commonality_ between the two systems is that Django signals are used to cache -information that includes 3 bits of information (content_object, permission, object-role), -and then this information is used to produce querysets of objects that a certain user -has a certain permission for. This is done by matching object-roles to the object-roles -the user has been given. - -Cached information allows for scaling a deep, rich, permission assigning system -without performance death-spiral of querysets. - -### What Constitutes a Graph? - -The 2015 system, by auto-creating roles, was able to map roles directly to other roles -to define parents and children. This also allowed highly specific inheritance paths -along the lines of specific permissions... imagine an "inventory_admin" role -giving read permissions to all the job templates that used that inventory. - -Through the years when this system was in use, the inheritance rarely mapped -from one type of permission to a different permission like the example. - -Because of this, `ObjectRole`s in the 2023 system don't have the same parent/child -link to other roles. But there are still two types of graphs at work: - - Resources have parent resources, and could be drawn out as a tree structure - - Teams can have member permissions to other teams - -### System-Wide Roles - -The 2015 system treated the system admin and system auditor as system roles. -However, because the role ancestors are cached for each role, this meant that -every role had a link to the system admin role. To some extent, this threw cold -water on adding more system roles. The storage and additional caching overhead -for system roles did not encourage use of more system roles. - -Ultimately, system roles do not need caching like object roles do. -The querysets do not get out-of-control for the task of returning -the permissions a user has. Nesting inside of more complex queries still can. -Because of that, a method for handling system roles with an _entirely separate_ -system is offered here that hooks into the same bound methods as the object-role system. +The DAB RBAC features and goals: + - Adheres to patterns created by django.contrib.auth, specifically its permission model + - Adds roles, containers of multiple permissions + - Adds teams, allowing bulk-assignment of permissions to a group of users + - Allows managing multiple "levels" of permissions + - object-level permission + - inheritance from an objects parent object, main organization + - system-wide permissions + - Be as lazy as possible -## Models +This is a combination of former galaxy_ng/pulp and AWX systems. +The galaxy_ng/pulp RBAC system had everything above except for inheritance. +The AWX system did not enumerate permissions at all, and structured roles in a graph-based design. -These models represent the underlying RBAC implementation and generally will be abstracted away from your daily development tasks by signals connected by the permission registry. +### Internal Terminology -You should also prefer to use the attached methods when possible. -Those have some additional syntax aids, validation, and can take the user flags -and the global roles system into account. +For DAB developers working on the RBAC system itself: -### `ObjectRole` +- **Role Definition** - Always use this term; never "role" which is ambiguous +- **Object Role** - Instantiation of a role definition for a specific object +- **Role Assignment** - Record of user/team having a role definition (user assignment or team assignment) +- **Permission** - Django Permission object representing an action on a model type +- **Access** - Discouraged term; use specific permission checks instead +- **Content Type** - Use DABContentType, not Django's ContentType -`ObjectRole` is an instantiation of a role definition for a particular object. -The `give_permission` method creates an object role if one does not exist for that (object, role definition) +### Evolution from Role Graphs to Resource Trees -#### `descendent_roles()` +**Previous (2015) AWX System:** +The older system created a complex graph where roles had parent-child relationships with other roles. Each object auto-created its own roles, and permissions flowed through role inheritance chains. This means you could have "admin_role" to a job template which would give CRUD permissions plus the ability to run the job template, or "execute_role" which would give ability to run but not the ability to edit. Inheritance worked by "admin_role" to an organization being a parent of the roles of all objects within the organization. -For a given object role, if that role offers a "member_team" permission, this gives all -the roles that are implied by ownership of this role. +**Current (2023+) System:** +The current system abandons role-to-role inheritance in favor of: +- **Resource Tree Structure**: Resources are organized in a strict hierarchical tree (typically with organizations as parents) +- **Named Permissions**: Instead of role inheritance, we use explicit Django Permission objects +- **On-Demand Object Roles**: Object roles are only created when assignments are made, not automatically +- **Direct Relationships**: Teams and users have direct relationships to role definitions -For object roles that do not offer that permission, or do not apply to a team -or a team's parent objects, this should return an empty set. +### Key Architectural Components -#### `needed_cache_updates()` +#### Resource Hierarchy (Not Role Hierarchy) +Resources form a tree where parent-child relationships are defined by the models themselves (e.g., inventories belong to organizations). Permission inheritance flows down this resource tree, not through a separate role graph. -This shows the additions and removals needed to make the `RoleEvaluation` correct -for the particular `ObjectRole` in question. -This is used as a part of the re-computation logic to cache role-object-permission evaluations. +#### Named Permissions Replace Role Inheritance +Instead of roles inheriting from other roles, we explicitly list Django Permission objects in role definitions. This makes permission grants more transparent and predictable. -### `RoleEvaluation` +#### Team Membership as Permission Multiplication +Teams can have member permissions to other teams, but this is the only remaining "graph-like" structure. This is intentionally limited to team membership to keep complexity manageable. + +### Performance Through Caching + +Both the old and current systems use Django signals to cache permission evaluations. The `RoleEvaluation` table caches which users have which permissions to which objects, enabling efficient queryset filtering without performance degradation. -`RoleEvaluation` gives cached permission evaluations for a role. -Each entry tells you that ownership in the linked `role` field confers the -permission listed in the `codename` field to the object defined by the -fields `object_id` and `content_type_id`. +#### System-Wide vs Object-Specific Roles +System-wide roles are handled through a separate, lighter-weight system that doesn't require the same caching overhead as object-specific roles. This allows for more flexible global permission management. -This is used for generating querysets and making role evaluations. +## Models + +These models represent the underlying RBAC implementation and are generally abstracted away from daily development tasks by signals connected through the permission registry. -This table is _not_ the source of truth for information in any way. -You can delete the entire table, and you should be able to re-populate it -by calling the `compute_object_role_permissions()` method. +### `ObjectRole` -Because its function is querysets and permission evaluations, it has -class methods that serve these functions. -Importantly, these consider _indirect_ permissions given by parent objects, -teams, or both. +`ObjectRole` represents an instantiation of a role definition for a particular object. Object roles are created on-demand when assignments are made, rather than being auto-created for every resource. -#### `accessible_ids(cls, user, codename)` +Key characteristics: +- Links a role definition to a specific object +- Created by `give_permission` methods when assignments are made +- Handles team membership inheritance through `descendent_roles()` +- Manages cache updates for efficient permission evaluation + +### `RoleEvaluation` -Returns a queryset which is a values list of ids for objects of `cls` type -that `user` has the permission to, where that permission is given in `codename`. +`RoleEvaluation` provides cached permission evaluations for efficient querying. This is a performance optimization table that can be completely rebuilt from the source data. -This is lighter weight and more efficient than using `accessible_objects` when it is needed -as a subquery as a part of a larger query. +Key characteristics: +- Caches which users/teams have which permissions to which objects +- Not the source of truth - can be deleted and regenerated +- Enables efficient queryset filtering through class methods +- Handles indirect permissions (parent objects, team inheritance) -#### `accessible_objects(cls, user, codename)` +## Integration with App Models -Return a queryset from `cls` model that `user` has the `codename` permission to. +For application developers using DAB RBAC, the system attaches methods directly to your registered models. These methods provide the primary interface for permission evaluation: -#### `get_permissions(user, obj)` +- `MyModel.access_qs(user, permission)` - Filter querysets by permission +- `user.has_obj_perm(obj, permission)` - Check specific object permissions -Returns all permissions that `user` has to `obj`. +For detailed documentation on these methods and their usage patterns, see the [App Developer Integration Guide](for_app_developers.md#evaluating-permissions). diff --git a/docs/apps/rbac/for_users.md b/docs/apps/rbac/for_users.md index afb70b590..476cc3d32 100644 --- a/docs/apps/rbac/for_users.md +++ b/docs/apps/rbac/for_users.md @@ -1,126 +1,93 @@ # Using DAB Role-Based Access Control Access control allows or denies requests from a user based on some permission specification. -Roles are an implementation detail of some access control systems, such as this one. +This system uses role definitions to organize and assign permissions efficiently. -## Model Permissions +## Terminology -Permissions are defined on a per-model basis, like **permission to change inventory**, -which represents the permission to modify an inventory, but _which_ inventory -is still unclear when looking at the permission itself. +For clarity, this documentation uses precise terminology: -Permissions combine two pieces of information +- **Permission**: An action for a specific model type (e.g., "change inventory", "view project") +- **Role Definition**: A collection of permissions that can be assigned. In user-facing interfaces, these are often simply called "roles" +- **Role Assignment**: A record linking a user or team to a role definition, either for a specific object or globally +- **Content Type**: The model type that permissions apply to (e.g., Inventory, Project, Organization) - - The **action** being taken - - The **content type** the action applies to +## Basic Concepts -## Role Definitions +### 1. Permissions -The DAB RBAC system may use the word "role" or "role definition" interchangeably. -The "role definition" wording is help clarify that it is abstract, -meaning that it does not have an object association. +Permissions are the foundation of the access control system. Each permission combines: -Roles contain two functional pieces of information (excluding things like its `name`) + - The **action** being taken (view, change, delete, execute, etc.) + - The **content type** the action applies to (inventory, project, organization, etc.) - - A list of **permissions** the role gives to all asignees - - A **content type** restriction +For example, "change inventory" means the permission to modify inventory objects, but doesn't specify _which_ inventory until assigned. -## Role User Assignments +### 2. Role Definitions -When you give a user some permissions, 3 pieces of information are involved +Role definitions group related permissions together for easy assignment. Each role definition contains: - - The **role** - - The **user** getting the permissions listed in that role - - The **object** this assignment is applied to + - A list of **permissions** granted to anyone assigned this role + - A **content type** that determines what objects this role can be assigned to -This is illustrated in the image below. 1 user gets 1 or more permissions to the object. +Role definitions are templates - they become useful when assigned to users for specific objects. -![User getting permission to an object](images/user_obj.svg) +## Permission Assignment Levels -## Role Team Assignments +The RBAC system allows assigning permissions at three different levels, each serving different use cases: -Teams are treated like other objects in the system by DAB RBAC, -with the exception that its **member** permission acts as a multiplier. -By receiving a team's member permission, you automatically receive all -permissions that the team has. +### 1. Object-Level Assignments -Teams permissions tracked separately from users in the database, -which are called role-team-assignments. -You can think of a team as a grouping of users who are members of that team. -Thus, giving permissions to a team is a bulk assignment of all the users -in the team. This is illustrated in the below image. +Give permissions to specific objects. When assigning a role definition to a user for an object, you specify: -![Team getting permission to an object](images/team_obj.svg) + - The **role definition** (which permissions to grant) + - The **user** receiving the permissions + - The **object** the assignment applies to -Abstractly, teams can also get the member permission **to another team** -but this may or may not be enabled by the app using DAB RBAC -based on usability concerns. +This grants the user only the specified permissions for only that specific object. -## Organizations +![User getting permission to an object](images/user_obj.svg) -Similar to how teams are a grouping of users, organizations are a grouping -of objects. -Most objects tend to have an organization field which is filled in when -creating the object, which may be required. +### 2. Organization-Level Assignments -A role with the organization **content_type** can include **permissions** -for any **objects** inside of that organization. -When a user or team is assigned a role listing those permissions, -for a particular organization, they receive those permissions for -**all** objects in that organization. -This is illustrated below. +Organizations group objects together. When you assign a role definition to a user for an organization, they receive those permissions for **all** objects within that organization. ![User getting an organization role](images/user_org.svg) -### Resource Tree +This is powerful for managing permissions at scale - one assignment can grant access to many related objects. -This concept is mainly intended for organizations, but it generalized -in DAB RBAC, so that any model can have child models if they have -a relational link between them. +#### Resource Hierarchy -So if you consider the above illustration of a user gaining permission -to an organization, the grouping of objects could have nested groupings. +The organization concept is part of a broader resource hierarchy. Objects can have parent-child relationships, creating a tree structure where permissions granted at a parent level apply to all children. -## Teams and Organizations +### 3. System-Wide Assignments -Teams can also be given organization-level roles. -This means that _a single role assignment_ can give permission -to multiple objects to multiple users. +System-wide role definitions have no content type restriction and provide **global** permissions. When assigned, users receive the listed permissions for **all** objects of the relevant types in the entire system. -![Team getting an organization role](images/team_org.svg) +![User getting a system-wide role](images/user_system.svg) -## System-wide Roles +System-wide assignments are powerful but require careful consideration to avoid confusing user experiences. For example, granting "change inventory" globally while not granting "view organization" could allow users to edit inventories in organizations they cannot see. -DAB RBAC allows creating **system-wide role definitions**. -System-wide role definitions are idenified by a **null content_type**. -Any assignments given for this role will, correspondingly, have a **null object**. +## Team-Based Permission Management -These roles will give their listed permissions **globaly**, -in other words, for the entire system. -In most cases, this means that users who are assigned these roles have -the listed permissions to all objects of that type. +Teams provide a way to bulk-assign permissions to multiple users efficiently. -If a global role gave **permission to change inventory**, for example, -that would allow a user with that role to change **all inventories** in the system. +### Team Membership -System-wide roles give listed permission to objects even if they are in -an organization that the user has no permission to. -Because of this, they can be said to give "super" permissions, like how -the superuser of the system has all permissions. -System-wide roles also give permission to objects that are in no organization. -This is illustrated below. +Teams have a special **member** permission that acts as a multiplier. Users with team membership automatically inherit all permissions that have been assigned to the team. -![User getting a system-wide role](images/user_system.svg) +### Direct Team Assignments + +You can assign role definitions directly to teams. This grants the specified permissions to all team members. + +![Team getting permission to an object](images/team_obj.svg) + +### Combined Team and Organization Assignments + +Teams can receive organization-level assignments, meaning a single role assignment can grant permissions to multiple objects for multiple users simultaneously. + +![Team getting an organization role](images/team_org.svg) + +### Nested Team Membership -You can think of the system as grouping of objects that includes all objects -in the system. Even as some objects are a part of lower-level groupings, -like an organization, they are still a part of the system grouping. - -Extra care is needed to make sure that system-wide roles do not create -a disjointed user experience. -For example, permission to view and edit all inventories in the system -can be given to a user while still not giving that user to view all -organizations. That would give the user permission to edit inventories -which are in _organizations_ the user can not view. -This example could be remedied by adding **permission to view organizations** -to the role. +Teams can be given member permission to other teams, creating nested hierarchies (if enabled by the application).