Feature/add support permissions (#445)
* added support perm macro which removes secrets perms w/ burnettk * support perm macro inherits from basic now and updated docs on permissions to be more accurate w/ burnettk --------- Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
a9b6f05e14
commit
29620cb17f
|
@ -4,74 +4,52 @@ The permission URL, or target URI, refers to the specific endpoint or resource t
|
|||
|
||||
- **PG:** [process_group_identifier]: Applies to the specified process group, including all sub process groups and process models.
|
||||
- **PM:** [process_model_identifier]: Applies to the specified process model.
|
||||
- **BASIC:** Provides basic access to complete tasks and use the site.
|
||||
- **ELEVATED:** Enables operations that require elevated permissions.
|
||||
- **ALL:** Grants access to all API endpoints, providing admin-like permissions.
|
||||
- **BASIC:** Allows basic access to complete tasks and use the site.
|
||||
- **SUPPORT:** BASIC permissions and add significant administrative permissions.
|
||||
- **ELEVATED:** Includes SUPPORT permissions and adds the ability to view and modify secrets. Does not include the ability to view or modify process groups and process models.
|
||||
- **ALL:** Grants access to all API endpoints, with no limitations.
|
||||
|
||||
```{admonition} Note
|
||||
An asterisk (*) can be used as a wildcard to give access to everything within a specific category. For example, "/process-models/", allows access to all resources related to process models.
|
||||
An asterisk (*) can be used as a wildcard to give access to everything within a specific category. For example, `/process-models/*`, allows access to all resources related to process models.
|
||||
```
|
||||
|
||||
This functionality is implemented in [authorization service.py](https://github.com/sartography/spiff-arena/blob/main/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py).
|
||||
|
||||
(pg)=
|
||||
## PG
|
||||
|
||||
Process Groups permissions controls access rights granted to users or entities within that particular process model. By assigning permissions to process groups, you can determine what actions or operations users can perform within those groups.
|
||||
|
||||
[View GIT Repository - BASIC](https://github.com/sartography/spiff-arena/blob/main/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py#L557)
|
||||
|
||||
```python
|
||||
def set_process_model_permissions(cls, target: str, permission_set: str) -> list[PermissionToAssign]:
|
||||
```
|
||||
Process Groups permissions controls access rights granted to users or entities within the given process group.
|
||||
|
||||
(pm)=
|
||||
## PM
|
||||
|
||||
These permissions relates to process models. It defines the permissions and access rights assigned to users or entities specifically within a given process model.
|
||||
These permissions relate to process models, and assigns permissions and access rights to users or entities specifically within a given process model.
|
||||
|
||||
[View GIT Repository - BASIC](https://github.com/sartography/spiff-arena/blob/main/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py#L574)
|
||||
## BASIC
|
||||
|
||||
```python
|
||||
def set_process_group_permissions(cls, target: str, permission_set: str) -> list[PermissionToAssign]:
|
||||
```
|
||||
These permissions cover basic actions such as signing in to the site and completing tasks that are assigned to you.
|
||||
|
||||
## BASIC
|
||||
## SUPPORT
|
||||
|
||||
These permissions cover basic actions such as creating users and process instances, checking user existence, and reading various entities like process groups, models, and tasks.
|
||||
These permissions are significant, allowing support personnel to debug process instances and take corrective action when errors occur.
|
||||
In typical scenarios, a user with SUPPORT permissions would also be assigned access to view or modify process groups and models.
|
||||
See [PG](#pg) and [PM](#pm).
|
||||
|
||||
[View GIT Repository - BASIC](https://github.com/sartography/spiff-arena/blob/main/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py#L494)
|
||||
|
||||
```python
|
||||
def set_basic_permissions(cls) -> list[PermissionToAssign]:
|
||||
```
|
||||
|
||||
## ELEVATED
|
||||
|
||||
These permissions cover basic actions such as creating users and process instances, checking user existence, and reading various entities like process groups, models, and tasks.
|
||||
|
||||
[View GIT Repository - BASIC](https://github.com/sartography/spiff-arena/blob/main/spiffworkflow-backend/src/spiffworkflow_backend/services/authorization_service.py#L494)
|
||||
|
||||
```python
|
||||
def explode_permissions(cls, permission_set: str, target: str) -> list[PermissionToAssign]:
|
||||
```
|
||||
## ELEVATED
|
||||
|
||||
A user with elevated permissions can do anything on the site except interact with process models.
|
||||
In typical scenarios, a user with ELEVATED permissions would also be assigned access to view or modify process groups and models.
|
||||
|
||||
## ALL
|
||||
|
||||
The "ALL" permission grants unrestricted access to all API endpoints. It essentially provides administrator-like permissions, allowing the user to perform any action or operation available within the system.
|
||||
|
||||
```python
|
||||
elif target == "ALL":
|
||||
for permission in permissions:
|
||||
permissions_to_assign.append(PermissionToAssign(permission=permission, target_uri="/*"))
|
||||
elif target.startswith("/"):
|
||||
for permission in permissions:
|
||||
permissions_to_assign.append(PermissionToAssign(permission=permission, target_uri=target))
|
||||
```
|
||||
|
||||
|
||||
The "ALL" permission grants unrestricted access to all API endpoints.
|
||||
It provides administrator-level permissions, allowing the user to perform any action or operation available within the system.
|
||||
|
||||
### ALL URLs
|
||||
|
||||
```python
|
||||
/active-users/unregister/{last_visited_identifier}:
|
||||
% use bash syntax here to avoid syntax highlighting. otherwise it gets highlighted as if it's python
|
||||
```bash
|
||||
/active-users/unregister/{last_visited_identifier}:
|
||||
/active-users/updates/{last_visited_identifier}:
|
||||
/authentication_callback/{service}/{auth_method}:
|
||||
/authentications:
|
||||
|
|
|
@ -530,7 +530,20 @@ class AuthorizationService:
|
|||
|
||||
@classmethod
|
||||
def set_elevated_permissions(cls) -> list[PermissionToAssign]:
|
||||
permissions_to_assign: list[PermissionToAssign] = []
|
||||
"""This is basically /* without write access to Process Groups and Process Models.
|
||||
|
||||
Useful for admin-like permissions on readonly environments like a production environment.
|
||||
"""
|
||||
permissions_to_assign = cls.set_support_permissions()
|
||||
for permission in ["create", "read", "update", "delete"]:
|
||||
permissions_to_assign.append(PermissionToAssign(permission=permission, target_uri="/secrets/*"))
|
||||
|
||||
return permissions_to_assign
|
||||
|
||||
@classmethod
|
||||
def set_support_permissions(cls) -> list[PermissionToAssign]:
|
||||
"""Just like elevated permissions minus access to secrets."""
|
||||
permissions_to_assign = cls.set_basic_permissions()
|
||||
for process_instance_action in ["resume", "terminate", "suspend", "reset"]:
|
||||
permissions_to_assign.append(
|
||||
PermissionToAssign(permission="create", target_uri=f"/process-instance-{process_instance_action}/*")
|
||||
|
@ -562,7 +575,6 @@ class AuthorizationService:
|
|||
|
||||
for permission in ["create", "read", "update", "delete"]:
|
||||
permissions_to_assign.append(PermissionToAssign(permission=permission, target_uri="/process-instances/*"))
|
||||
permissions_to_assign.append(PermissionToAssign(permission=permission, target_uri="/secrets/*"))
|
||||
|
||||
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/data-stores/*"))
|
||||
return permissions_to_assign
|
||||
|
@ -614,6 +626,8 @@ class AuthorizationService:
|
|||
* Basic access to complete tasks and use the site
|
||||
ELEVATED
|
||||
* Operations that require elevated permissions
|
||||
SUPPORT
|
||||
* Like elevated minus access to secrets
|
||||
|
||||
Permission Macros:
|
||||
all
|
||||
|
@ -638,6 +652,8 @@ class AuthorizationService:
|
|||
permissions_to_assign += cls.set_basic_permissions()
|
||||
elif target.startswith("ELEVATED"):
|
||||
permissions_to_assign += cls.set_elevated_permissions()
|
||||
elif target.startswith("SUPPORT"):
|
||||
permissions_to_assign += cls.set_support_permissions()
|
||||
elif target == "ALL":
|
||||
for permission in permissions:
|
||||
permissions_to_assign.append(PermissionToAssign(permission=permission, target_uri="/*"))
|
||||
|
|
|
@ -275,77 +275,29 @@ class TestAuthorizationService(BaseTest):
|
|||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
expected_permissions = sorted(
|
||||
[
|
||||
("/active-users/*", "create"),
|
||||
("/connector-proxy/typeahead/*", "read"),
|
||||
("/debug/version-info", "read"),
|
||||
("/extensions", "read"),
|
||||
("/onboarding", "read"),
|
||||
("/process-groups", "read"),
|
||||
("/process-instances/find-by-id/*", "read"),
|
||||
("/process-instances/for-me", "create"),
|
||||
("/process-instances/report-metadata", "read"),
|
||||
("/process-instances/reports/*", "create"),
|
||||
("/process-instances/reports/*", "delete"),
|
||||
("/process-instances/reports/*", "read"),
|
||||
("/process-instances/reports/*", "update"),
|
||||
("/process-models", "read"),
|
||||
("/processes", "read"),
|
||||
("/processes/callers/*", "read"),
|
||||
("/service-tasks", "read"),
|
||||
("/tasks/*", "create"),
|
||||
("/tasks/*", "delete"),
|
||||
("/tasks/*", "read"),
|
||||
("/tasks/*", "update"),
|
||||
("/user-groups/for-current-user", "read"),
|
||||
("/users/exists/by-username", "create"),
|
||||
("/users/search", "read"),
|
||||
]
|
||||
)
|
||||
expected_permissions = self._expected_basic_permissions()
|
||||
permissions_to_assign = AuthorizationService.explode_permissions("all", "BASIC")
|
||||
permissions_to_assign_tuples = sorted([(p.target_uri, p.permission) for p in permissions_to_assign])
|
||||
assert permissions_to_assign_tuples == expected_permissions
|
||||
|
||||
def test_explode_permissions_support(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
expected_permissions = self._expected_support_permissions()
|
||||
permissions_to_assign = AuthorizationService.explode_permissions("all", "SUPPORT")
|
||||
permissions_to_assign_tuples = sorted([(p.target_uri, p.permission) for p in permissions_to_assign])
|
||||
assert permissions_to_assign_tuples == expected_permissions
|
||||
|
||||
def test_explode_permissions_elevated(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
expected_permissions = sorted(
|
||||
[
|
||||
("/authentications", "read"),
|
||||
("/can-run-privileged-script/*", "create"),
|
||||
("/data-stores/*", "read"),
|
||||
("/debug/*", "create"),
|
||||
("/event-error-details/*", "read"),
|
||||
("/extensions-get-data/*", "read"),
|
||||
("/extensions/*", "create"),
|
||||
("/logs/*", "read"),
|
||||
("/messages", "read"),
|
||||
("/messages/*", "create"),
|
||||
("/process-data-file-download/*", "read"),
|
||||
("/process-data/*", "read"),
|
||||
("/process-instance-reset/*", "create"),
|
||||
("/process-instance-resume/*", "create"),
|
||||
("/process-instance-suspend/*", "create"),
|
||||
("/process-instance-terminate/*", "create"),
|
||||
("/process-instances/*", "create"),
|
||||
("/process-instances/*", "delete"),
|
||||
("/process-instances/*", "read"),
|
||||
("/process-instances/*", "update"),
|
||||
("/secrets/*", "create"),
|
||||
("/secrets/*", "delete"),
|
||||
("/secrets/*", "read"),
|
||||
("/secrets/*", "update"),
|
||||
("/send-event/*", "create"),
|
||||
("/task-assign/*", "create"),
|
||||
("/task-complete/*", "create"),
|
||||
("/task-data/*", "update"),
|
||||
("/task-data/*", "read"),
|
||||
]
|
||||
)
|
||||
expected_permissions = self._expected_elevated_permissions()
|
||||
permissions_to_assign = AuthorizationService.explode_permissions("all", "ELEVATED")
|
||||
permissions_to_assign_tuples = sorted([(p.target_uri, p.permission) for p in permissions_to_assign])
|
||||
assert permissions_to_assign_tuples == expected_permissions
|
||||
|
@ -489,3 +441,76 @@ class TestAuthorizationService(BaseTest):
|
|||
self.assert_user_has_permission(user_two, "read", "/v1.0/process-groups/hey2")
|
||||
self.assert_user_has_permission(user_two, "read", "/v1.0/process-groups/hey2:yo")
|
||||
self.assert_user_has_permission(user_two, "create", "/v1.0/process-groups/hey2:yo")
|
||||
|
||||
def _expected_basic_permissions(self) -> list[tuple[str, str]]:
|
||||
return sorted(
|
||||
[
|
||||
("/active-users/*", "create"),
|
||||
("/connector-proxy/typeahead/*", "read"),
|
||||
("/debug/version-info", "read"),
|
||||
("/extensions", "read"),
|
||||
("/onboarding", "read"),
|
||||
("/process-groups", "read"),
|
||||
("/process-instances/find-by-id/*", "read"),
|
||||
("/process-instances/for-me", "create"),
|
||||
("/process-instances/report-metadata", "read"),
|
||||
("/process-instances/reports/*", "create"),
|
||||
("/process-instances/reports/*", "delete"),
|
||||
("/process-instances/reports/*", "read"),
|
||||
("/process-instances/reports/*", "update"),
|
||||
("/process-models", "read"),
|
||||
("/processes", "read"),
|
||||
("/processes/callers/*", "read"),
|
||||
("/service-tasks", "read"),
|
||||
("/tasks/*", "create"),
|
||||
("/tasks/*", "delete"),
|
||||
("/tasks/*", "read"),
|
||||
("/tasks/*", "update"),
|
||||
("/user-groups/for-current-user", "read"),
|
||||
("/users/exists/by-username", "create"),
|
||||
("/users/search", "read"),
|
||||
]
|
||||
)
|
||||
|
||||
def _expected_support_permissions(self) -> list[tuple[str, str]]:
|
||||
return sorted(
|
||||
self._expected_basic_permissions()
|
||||
+ [
|
||||
("/authentications", "read"),
|
||||
("/can-run-privileged-script/*", "create"),
|
||||
("/data-stores/*", "read"),
|
||||
("/debug/*", "create"),
|
||||
("/event-error-details/*", "read"),
|
||||
("/extensions-get-data/*", "read"),
|
||||
("/extensions/*", "create"),
|
||||
("/logs/*", "read"),
|
||||
("/messages", "read"),
|
||||
("/messages/*", "create"),
|
||||
("/process-data-file-download/*", "read"),
|
||||
("/process-data/*", "read"),
|
||||
("/process-instance-reset/*", "create"),
|
||||
("/process-instance-resume/*", "create"),
|
||||
("/process-instance-suspend/*", "create"),
|
||||
("/process-instance-terminate/*", "create"),
|
||||
("/process-instances/*", "create"),
|
||||
("/process-instances/*", "delete"),
|
||||
("/process-instances/*", "read"),
|
||||
("/process-instances/*", "update"),
|
||||
("/send-event/*", "create"),
|
||||
("/task-assign/*", "create"),
|
||||
("/task-complete/*", "create"),
|
||||
("/task-data/*", "update"),
|
||||
("/task-data/*", "read"),
|
||||
]
|
||||
)
|
||||
|
||||
def _expected_elevated_permissions(self) -> list[tuple[str, str]]:
|
||||
return sorted(
|
||||
self._expected_support_permissions()
|
||||
+ [
|
||||
("/secrets/*", "create"),
|
||||
("/secrets/*", "delete"),
|
||||
("/secrets/*", "read"),
|
||||
("/secrets/*", "update"),
|
||||
]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue