Skip to content

Commit

Permalink
fix(api): wildcard permissions failure (#75)
Browse files Browse the repository at this point in the history
We fix the wild card permission failure, which resulted in forbidden permission when resource allowed were wild cards.

Closes #74
  • Loading branch information
mawandm authored May 9, 2024
1 parent b6029eb commit d2aaabf
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 81 deletions.
8 changes: 4 additions & 4 deletions nesis/api/core/controllers/datasources.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ def operate_datasources():
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
Expand Down Expand Up @@ -85,8 +85,8 @@ def operate_datasource(datasource_id):
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
28 changes: 14 additions & 14 deletions nesis/api/core/controllers/management.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ def operate_users():
return jsonify(error_message(str(se))), 409
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
Expand Down Expand Up @@ -65,8 +65,8 @@ def operate_user(user_id):
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
Expand All @@ -90,8 +90,8 @@ def operate_user_roles(user_id):
return jsonify(error_message(str(se))), 409
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
Expand All @@ -107,8 +107,8 @@ def operate_user_role(user_id, role_id):
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
Expand All @@ -132,8 +132,8 @@ def operate_roles():
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
Expand Down Expand Up @@ -176,8 +176,8 @@ def operate_role(role_id):
return jsonify(error_message(str(se))), 409
except util.ServiceException as se:
return jsonify(error_message(str(se))), 400
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401

Expand All @@ -196,8 +196,8 @@ def operate_sessions():
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error operating session")
return jsonify(error_message("Server error")), 500
4 changes: 2 additions & 2 deletions nesis/api/core/controllers/predictions.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ def operate_module_predictions(module):
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
8 changes: 4 additions & 4 deletions nesis/api/core/controllers/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ def operate_settings(module):
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
Expand Down Expand Up @@ -65,8 +65,8 @@ def operate_setting(module, setting_id):
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
8 changes: 4 additions & 4 deletions nesis/api/core/controllers/tasks_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def operate_tasks():
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except util.ConflictException as ce:
return jsonify(error_message(str(ce))), 409
except:
Expand Down Expand Up @@ -72,8 +72,8 @@ def operate_task(task_id):
return jsonify(error_message(str(se))), 400
except util.UnauthorizedAccess:
return jsonify(error_message("Unauthorized access")), 401
except util.PermissionException:
return jsonify(error_message("Forbidden action on resource")), 403
except util.PermissionException as ex:
return jsonify(error_message(str(ex))), 403
except:
_LOG.exception("Error getting user")
return jsonify(error_message("Server error")), 500
9 changes: 7 additions & 2 deletions nesis/api/core/services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,16 @@ def authorized(
)

if resource:
query = query.filter(RoleAction.resource == resource)
query = query.filter(RoleAction.resource.in_([resource, "*"]))

user_role_actions = query.all()
if len(user_role_actions) == 0:
raise PermissionException(f"Not authorized to perform this action")
message = (
f"Not authorized to perform {action.name} on {resource}"
if resource
else f"Not authorized to perform {action.name} on {resource_type.name}"
)
raise PermissionException(message)

return session_user

Expand Down
74 changes: 24 additions & 50 deletions nesis/api/core/services/management.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import os
from typing import Optional
from typing import Optional, List

import bcrypt
import memcache
Expand Down Expand Up @@ -400,23 +400,27 @@ def create(self, **kwargs) -> Role:

for action in role_actions:
action_resource: Optional[str] = action.get("resource")
action_resources: Optional[List[str]] = action.get("resources") or []
if action_resource:
action_resources.append(action_resource)
action_action: Optional[str] = action.get("action")

if not any([action_resource, action_action]):
if action_action is None or len(action_resources) == 0:
raise ServiceException("resource or resources must be supplied")

action_resource_parts = action_resource.split("/")
resource_type = action_resource_parts[0]
resource_item = None
if len(action_resource_parts) > 1:
resource_item = action_resource_parts[1]
role_action = RoleAction(
action=Action[action_action.upper()],
role=None,
resource=resource_item,
resource_type=ResourceType[resource_type.upper()],
)
role_action_list.append(role_action)
for action_resource in action_resources:
action_resource_parts = action_resource.split("/")
resource_type = action_resource_parts[0]
resource_item = None
if len(action_resource_parts) > 1:
resource_item = action_resource_parts[1]
role_action = RoleAction(
action=Action[action_action.upper()],
role=None,
resource=resource_item,
resource_type=ResourceType[resource_type.upper()],
)
role_action_list.append(role_action)

if len(role_action_list) == 0:
raise ServiceException("Invalid role. Policy not supplied")
Expand Down Expand Up @@ -603,7 +607,9 @@ def update(self, **kwargs) -> Role:

class UserRoleService(ServiceOperation):
"""
Manage user roles
Manage user roles. This is a function of the user service. Permissions are part of the user function.
Whatever a user is permitted to do on a user, they are permitted to do on the user role.
For this reason, we don't check/test permissions in the user role service as it is called only in the user service.
"""

def __init__(self, config: dict, session_service: UserSessionService):
Expand All @@ -614,22 +620,14 @@ def __init__(self, config: dict, session_service: UserSessionService):

self.__LOG.info("Initializing service...")

def create(self, **kwargs) -> Role:
def create(self, **kwargs) -> UserRole:
user_id: str = kwargs["user_id"]
user_role: dict = kwargs["role"]

session = DBSession()
try:
session.expire_on_commit = False

services.authorized(
session_service=self.__session_service,
session=session,
token=kwargs.get("token"),
action=Action.CREATE,
resource_type=self.__resource_type,
)

role: Role = (
session.query(Role).filter(Role.uuid == user_role["id"]).first()
)
Expand Down Expand Up @@ -662,20 +660,12 @@ def create(self, **kwargs) -> Role:
if session:
session.close()

def get(self, **kwargs) -> list[Role]:
def get(self, **kwargs) -> list[UserRole]:
user_id = kwargs.get("user_id")
session = DBSession()
try:
session.expire_on_commit = False

services.authorized(
session_service=self.__session_service,
session=session,
token=kwargs.get("token"),
action=Action.READ,
resource_type=self.__resource_type,
)

return (
session.query(Role)
.filter(Role.id == UserRole.role)
Expand All @@ -697,14 +687,6 @@ def delete(self, **kwargs):
try:
session.expire_on_commit = False

services.authorized(
session_service=self.__session_service,
session=session,
token=kwargs.get("token"),
action=Action.DELETE,
resource_type=self.__resource_type,
)

if uuid is None:
query = (
session.query(UserRole)
Expand All @@ -729,22 +711,14 @@ def delete(self, **kwargs):
if session:
session.close()

def update(self, **kwargs) -> Role:
def update(self, **kwargs) -> UserRole:
role_uuid = kwargs["id"]
role: dict = kwargs["role"]

session = DBSession()
try:
session.expire_on_commit = False

services.authorized(
session_service=self.__session_service,
session=session,
token=kwargs.get("token"),
action=Action.UPDATE,
resource_type=self.__resource_type,
)

role_record = session.query(Role).filter(Role.uuid == role_uuid)
session.query(UserRole).filter(Role.uuid == role_uuid).filter(
UserRole.role == Role.id
Expand Down
Loading

0 comments on commit d2aaabf

Please sign in to comment.