diff --git a/backend/src/zango/api/platform/permissions/v1/views.py b/backend/src/zango/api/platform/permissions/v1/views.py index 5a9b38423..cad947f80 100644 --- a/backend/src/zango/api/platform/permissions/v1/views.py +++ b/backend/src/zango/api/platform/permissions/v1/views.py @@ -137,12 +137,20 @@ def get(self, request, *args, **kwargs): return get_api_response(success, response, status) - def put(self, request, *args, **kwargs): + def put(self, request, app_uuid, *args, **kwargs): try: obj = self.get_obj(**kwargs) serializer = PolicySerializer(instance=obj, data=request.data, partial=True) if serializer.is_valid(): serializer.save(**{"roles": request.data.getlist("roles", [])}) + + tenant = TenantModel.objects.get(uuid=app_uuid) + connection.set_tenant(tenant) + with connection.cursor() as c: + ws = Workspace(connection.tenant, request=None, as_systemuser=True) + ws.ready() + ws.sync_role_policies() + success = True status_code = 200 result = { diff --git a/backend/src/zango/api/platform/tenancy/v1/views.py b/backend/src/zango/api/platform/tenancy/v1/views.py index bef45dee2..911237e6e 100644 --- a/backend/src/zango/api/platform/tenancy/v1/views.py +++ b/backend/src/zango/api/platform/tenancy/v1/views.py @@ -323,7 +323,7 @@ def post(self, request, *args, **kwargs): connection.set_tenant(tenant) with connection.cursor() as c: ws = Workspace(connection.tenant, request=None, as_systemuser=True) - ws.sync_role_with_policies() + ws.sync_role_policies() else: success = False status_code = 400 @@ -383,7 +383,7 @@ def put(self, request, *args, **kwargs): connection.set_tenant(tenant) with connection.cursor() as c: ws = Workspace(connection.tenant, request=None, as_systemuser=True) - ws.sync_role_with_policies() + ws.sync_role_policies() else: success = False status_code = 400 @@ -397,6 +397,10 @@ def put(self, request, *args, **kwargs): result = {"message": error_message} except Exception as e: + import traceback + + traceback.print_exc() + success = False result = {"message": str(e)} status_code = 500 diff --git a/backend/src/zango/apps/dynamic_models/workspace/base.py b/backend/src/zango/apps/dynamic_models/workspace/base.py index e71fdb68b..5766e3d66 100644 --- a/backend/src/zango/apps/dynamic_models/workspace/base.py +++ b/backend/src/zango/apps/dynamic_models/workspace/base.py @@ -5,8 +5,9 @@ import os import re +from collections import defaultdict + from django.conf import settings -from django.contrib.postgres.aggregates import ArrayAgg from django.db import connection from zango.apps.appauth.models import UserRoleModel @@ -433,7 +434,7 @@ def sync_policies(self): existing_policies = list( PolicyModel.objects.filter(type="user").values_list("id", flat=True) ) - role_with_policies = {} + policy_roles = defaultdict(list) modules = self.get_all_module_paths() for module in modules: policy_file = f"{module}/policies.json" @@ -451,10 +452,6 @@ def sync_policies(self): policy = json.load(f) except json.decoder.JSONDecodeError as e: raise Exception(f"Error parsing {policy_file}: {e}") - for policy_dict in policy["policies"]: - roles = policy_dict.get("roles", []) - for role in roles: - role_with_policies[role] = [] for policy_details in policy["policies"]: if not isinstance(policy_details["statement"], dict): raise Exception( @@ -477,8 +474,7 @@ def sync_policies(self): raise Exception("Policy name already exists") existing_policies.remove(policy.id) roles = policy_details.get("roles", []) - for role in roles: - role_with_policies[role].append(policy.id) + policy_roles[policy.id].extend(roles) except Exception as e: raise Exception( f"Error creating policy {policy_details['name']} in {policy_path}: {e}" @@ -486,42 +482,33 @@ def sync_policies(self): for policy_id in existing_policies: PolicyModel.objects.get(id=policy_id).delete() - self.sync_policies_with_roles(role_with_policies) + self.sync_policies_with_roles(policy_roles) - def sync_policies_with_roles(self, role_with_policies): + def sync_policies_with_roles(self, policy_roles): """ mapping roles from policies.json to UserRoleModel """ - for role, policies in role_with_policies.items(): - user_role = UserRoleModel.objects.filter( - name=role, - ).first() - if user_role: - user_role.policies.set(policies) - - def sync_role_with_policies(self): - """ - mapping roles from UserRoleModel to policies.json - """ - all_policies = {} - policies_without_roles = list( - PolicyModel.objects.filter(type="user", role_policies__isnull=True).values( - "name", "description", "statement" - ) - ) - policies_with_roles = list( - PolicyModel.objects.filter(type="user", role_policies__isnull=False) - .values("name", "description", "statement") - .annotate(roles=ArrayAgg("role_policies__name", distinct=True)) - ) - all_policies["policies"] = policies_without_roles + policies_with_roles - modules = self.get_all_module_paths() - for module in modules: - policy_file = f"{module}/policies.json" - if os.path.isfile(policy_file): - model_module = ( - module.replace(str(settings.BASE_DIR) + "/", "") + "/policies" - ) - model_module = model_module.lstrip("/").replace("/", ".") - with open(policy_file, "w") as f: - f.write(json.dumps(all_policies, indent=4)) + for policy_id, roles in policy_roles.items(): + try: + policy = PolicyModel.objects.get(id=policy_id) + role_ids = [UserRoleModel.objects.get(name=role).id for role in roles] + policy.role_policies.set(role_ids) + except Exception as e: + raise Exception(f"Error adding roles to policy {policy.name}: {e}") + except UserRoleModel.DoesNotExist: + raise Exception("Role does not exist") + + def sync_role_policies(self): + for policy in PolicyModel.objects.all(): + if not policy.path: + continue + if policy.path and "packages" in policy.path: + continue + roles = policy.role_policies.all() + with open(f"{self.path}/{policy.path}/policies.json", "r") as f: + policies = json.load(f) + for policy_details in policies["policies"]: + if policy_details["name"] == policy.name: + policy_details["roles"] = [role.name for role in roles] + with open(f"{self.path}/{policy.path}/policies.json", "w") as f: + json.dump(policies, f, indent=4) diff --git a/backend/src/zango/tests/apps/permissions/policy_framework/test_policy_ip_permission/tests.py b/backend/src/zango/tests/apps/permissions/policy_framework/test_policy_ip_permission/tests.py index f48a2889a..6130bd420 100644 --- a/backend/src/zango/tests/apps/permissions/policy_framework/test_policy_ip_permission/tests.py +++ b/backend/src/zango/tests/apps/permissions/policy_framework/test_policy_ip_permission/tests.py @@ -25,23 +25,22 @@ def sync_policies(self): ws = Workspace(self.tenant, as_systemuser=True) ws.ready() ws.sync_policies() - + def test_role_ip_permissions(self): self.sync_policies() # delete the all ip view policy as we have to check for specific IPs. PolicyModel.objects.get(name="AllIPGetViewAccess").delete() + PolicyModel.objects.get(name="AllowFromAnywhere").delete() self.client = ZangoClient(self.tenant) - res = self.client.get("/customers/customer/",**{ - 'REMOTE_ADDR': '1.2.3.4' - }) - self.assertHTMLEqual(res.content.decode(), "