Skip to content

Commit

Permalink
Merge pull request #581 from coderbydesign/add-tenant-id-constraints
Browse files Browse the repository at this point in the history
Add `tenant_id` db constraints (#1)
  • Loading branch information
coderbydesign authored Dec 9, 2021
2 parents fd8e0e5 + 0e9cb01 commit 51edf0a
Show file tree
Hide file tree
Showing 20 changed files with 270 additions and 193 deletions.
47 changes: 47 additions & 0 deletions rbac/management/migrations/0036_auto_20211118_1956.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Generated by Django 2.2.24 on 2021-11-18 19:56

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [("management", "0035_auto_20211014_1736")]

operations = [
migrations.AlterField(
model_name="access",
name="tenant",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="api.Tenant"),
),
migrations.AlterField(
model_name="group",
name="tenant",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="api.Tenant"),
),
migrations.AlterField(
model_name="permission",
name="tenant",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="api.Tenant"),
),
migrations.AlterField(
model_name="policy",
name="tenant",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="api.Tenant"),
),
migrations.AlterField(
model_name="principal",
name="tenant",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="api.Tenant"),
),
migrations.AlterField(
model_name="resourcedefinition",
name="tenant",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="api.Tenant"),
),
migrations.AlterField(
model_name="role",
name="tenant",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="api.Tenant"),
),
]
4 changes: 3 additions & 1 deletion tests/api/cross_access/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from django.test import TestCase
from django.utils import timezone
from management.models import Role
from api.models import Tenant
from rest_framework.serializers import ValidationError
from tenant_schemas.utils import tenant_context

Expand All @@ -33,6 +34,7 @@ class CrossAccountRequestModelTests(TestCase):
def setUp(self):
"""Set up the cross account request model tests."""
super().setUp()
self.tenant = Tenant.objects.create(schema_name="foo")

self.ref_time = timezone.now()
self.request = CrossAccountRequest.objects.create(
Expand Down Expand Up @@ -115,7 +117,7 @@ def test_request_with_same_start_and_end_date(self):

def test_the_request_could_be_associated_with_role(self):
ROLE_NAME = "Test Role"
role = Role.objects.create(name=ROLE_NAME)
role = Role.objects.create(name=ROLE_NAME, tenant=self.tenant)
self.assertEqual(self.request.roles.count(), 0)
self.assertEqual(role.cross_account_requests.count(), 0)

Expand Down
8 changes: 4 additions & 4 deletions tests/api/cross_access/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ def setUp(self):
t.create_schema()
t.ready = True
t.save()
self.role_1 = Role.objects.create(name="role_1", system=True)
self.role_2 = Role.objects.create(name="role_2", system=True)
self.role_9 = Role.objects.create(name="role_9", system=True)
self.role_8 = Role.objects.create(name="role_8", system=True)
self.role_1 = Role.objects.create(name="role_1", system=True, tenant=t)
self.role_2 = Role.objects.create(name="role_2", system=True, tenant=t)
self.role_9 = Role.objects.create(name="role_9", system=True, tenant=t)
self.role_8 = Role.objects.create(name="role_8", system=True, tenant=t)

self.request_1 = CrossAccountRequest.objects.create(
target_account=self.account,
Expand Down
25 changes: 14 additions & 11 deletions tests/internal/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ def setUp(self):
self.request.user = user

with tenant_context(self.tenant):
self.group = Group(name="System Group", system=True)
self.group = Group(name="System Group", system=True, tenant=self.tenant)
self.group.save()
self.role = Role.objects.create(name="System Role", description="A role for a group.", system=True)
self.policy = Policy.objects.create(name="System Policy", group=self.group)
self.role = Role.objects.create(
name="System Role", description="A role for a group.", system=True, tenant=self.tenant
)
self.policy = Policy.objects.create(name="System Policy", group=self.group, tenant=self.tenant)
self.policy.roles.add(self.role)
self.policy.save()
self.group.policies.add(self.policy)
Expand Down Expand Up @@ -97,8 +99,9 @@ def test_delete_tenant_allowed_and_unmodified(self, mock):
@patch.object(Tenant, "delete")
def test_delete_tenant_no_schema(self, mock):
"""Test that we can delete a tenant when allowed and unmodified."""
with tenant_context(Tenant.objects.get(schema_name="public")):
Group.objects.create(name="Custom Group")
public_tenant = Tenant.objects.get(schema_name="public")
with tenant_context(public_tenant):
Group.objects.create(name="Custom Group", tenant=public_tenant)

tenant_no_schema = Tenant.objects.create(schema_name="no_schema")
response = self.client.delete(f"/_private/api/tenant/{tenant_no_schema.schema_name}/", **self.request.META)
Expand All @@ -108,7 +111,7 @@ def test_delete_tenant_no_schema(self, mock):
def test_delete_tenant_allowed_but_multiple_groups(self):
"""Test that we cannot delete a tenant when allowed but modified."""
with tenant_context(self.tenant):
Group.objects.create(name="Custom Group")
Group.objects.create(name="Custom Group", tenant=self.tenant)

response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Expand Down Expand Up @@ -140,7 +143,7 @@ def test_delete_tenant_allowed_but_role_is_not_system(self):
def test_delete_tenant_allowed_but_custom_one_role_is_not_system(self):
"""Test that we cannot delete a tenant when allowed but modified."""
with tenant_context(self.tenant):
Role.objects.create(name="Custom Role")
Role.objects.create(name="Custom Role", tenant=self.tenant)

response = self.client.delete(f"/_private/api/tenant/{self.tenant.schema_name}/", **self.request.META)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
Expand Down Expand Up @@ -170,14 +173,14 @@ def test_list_unmodified_tenants(self):
t.save()

with tenant_context(modified_tenant_groups):
Group.objects.create(name="Custom Group")
Group.objects.create(name="Custom Group", tenant=modified_tenant_groups)

with tenant_context(modified_tenant_roles):
Role.objects.create(name="Custom Role")
Role.objects.create(name="Custom Role", tenant=modified_tenant_roles)

with tenant_context(unmodified_tenant_2):
Group.objects.create(name="System Group", system=True)
Role.objects.create(name="System Role", system=True)
Group.objects.create(name="System Group", system=True, tenant=unmodified_tenant_2)
Role.objects.create(name="System Role", system=True, tenant=unmodified_tenant_2)

response = self.client.get(f"/_private/api/tenant/unmodified/", **self.request.META)
response_data = json.loads(response.content)
Expand Down
4 changes: 2 additions & 2 deletions tests/management/access/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def setUp(self):
super().setUp()

with tenant_context(self.tenant):
self.permission = Permission.objects.create(permission="app:*:*")
self.access = Access.objects.create(permission=self.permission)
self.permission = Permission.objects.create(permission="app:*:*", tenant=self.tenant)
self.access = Access.objects.create(permission=self.permission, tenant=self.tenant)

def tearDown(self):
"""Tear down access model tests."""
Expand Down
48 changes: 28 additions & 20 deletions tests/management/access/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,27 @@ def setUp(self):
user.username = self.user_data["username"]
user.account = self.customer_data["account_id"]
request.user = user
public_tenant = Tenant.objects.get(schema_name="public")

self.access_data = {
"permission": "app:*:*",
"resourceDefinitions": [{"attributeFilter": {"key": "key1", "operation": "equal", "value": "value1"}}],
}
with tenant_context(self.tenant):
self.principal = Principal(username=self.user_data["username"])
self.principal = Principal(username=self.user_data["username"], tenant=self.tenant)
self.principal.save()
self.admin_principal = Principal(username="user_admin")
self.admin_principal = Principal(username="user_admin", tenant=self.tenant)
self.admin_principal.save()
self.group = Group(name="groupA")
self.group = Group(name="groupA", tenant=self.tenant)
self.group.save()
self.group.principals.add(self.principal)
self.group.save()
self.permission = Permission.objects.create(permission="app:*:*")
Permission.objects.create(permission="app:foo:bar")
with tenant_context(Tenant.objects.get(schema_name="public")):
Permission.objects.create(permission="app:foo:bar")
Permission.objects.create(permission="app:*:*")
self.permission = Permission.objects.create(permission="app:*:*", tenant=self.tenant)
Permission.objects.create(permission="app:foo:bar", tenant=self.tenant)

with tenant_context(public_tenant):
Permission.objects.create(permission="app:foo:bar", tenant=public_tenant)
Permission.objects.create(permission="app:*:*", tenant=public_tenant)

def tearDown(self):
"""Tear down access view tests."""
Expand Down Expand Up @@ -102,18 +104,24 @@ def create_policy(self, policy_name, group, roles, status=status.HTTP_201_CREATE
def create_platform_default_resource(self):
"""Setup default group and role."""
with tenant_context(self.tenant):
default_permission = Permission.objects.create(permission="default:*:*")
default_role = Role.objects.create(name="default role", platform_default=True, system=True)
default_access = Access.objects.create(permission=default_permission, role=default_role)
default_policy = Policy.objects.create(name="default policy", system=True)
default_permission = Permission.objects.create(permission="default:*:*", tenant=self.tenant)
default_role = Role.objects.create(
name="default role", platform_default=True, system=True, tenant=self.tenant
)
default_access = Access.objects.create(
permission=default_permission, role=default_role, tenant=self.tenant
)
default_policy = Policy.objects.create(name="default policy", system=True, tenant=self.tenant)
default_policy.roles.add(default_role)
default_group = Group.objects.create(name="default group", system=True, platform_default=True)
default_group = Group.objects.create(
name="default group", system=True, platform_default=True, tenant=self.tenant
)
default_group.policies.add(default_policy)

def create_role_and_permission(self, role_name, permission):
role = Role.objects.create(name=role_name)
assigned_permission = Permission.objects.create(permission=permission)
access = Access.objects.create(role=role, permission=assigned_permission)
role = Role.objects.create(name=role_name, tenant=self.tenant)
assigned_permission = Permission.objects.create(permission=permission, tenant=self.tenant)
access = Access.objects.create(role=role, permission=assigned_permission, tenant=self.tenant)
return role

def test_get_access_success(self):
Expand All @@ -123,7 +131,7 @@ def test_get_access_success(self):
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
role_uuid = response.data.get("uuid")
role = Role.objects.get(uuid=role_uuid)
access = Access.objects.create(role=role, permission=self.permission)
access = Access.objects.create(role=role, permission=self.permission, tenant=self.tenant)
policy_name = "policyA"
response = self.create_policy(policy_name, self.group.uuid, [role_uuid])
# Create platform default group, and add roles to it.
Expand Down Expand Up @@ -176,7 +184,7 @@ def test_access_for_cross_account_principal_return_permissions_based_on_assigned
headers = request.META

with tenant_context(self.tenant):
Principal.objects.create(username=user_name, cross_account=True)
Principal.objects.create(username=user_name, cross_account=True, tenant=self.tenant)
self.create_role_and_permission("Test Role one", "test:assigned:permission1")
self.create_role_and_permission("Test Role two", "test:assigned:permission2")
response = client.get(url, **headers)
Expand All @@ -198,7 +206,7 @@ def test_get_access_no_app_supplied(self):
response = self.create_role(role_name, access_data)
role_uuid = response.data.get("uuid")
role = Role.objects.get(uuid=role_uuid)
access = Access.objects.create(role=role, permission=self.permission)
access = Access.objects.create(role=role, permission=self.permission, tenant=self.tenant)
self.create_policy(policy_name, self.group.uuid, [role_uuid])

url = "{}?application=&username={}".format(reverse("access"), self.principal.username)
Expand All @@ -221,7 +229,7 @@ def test_get_access_multiple_apps_supplied(self):
response = self.create_role(role_name, access_data)
role_uuid = response.data.get("uuid")
role = Role.objects.get(uuid=role_uuid)
access = Access.objects.create(role=role, permission=self.permission)
access = Access.objects.create(role=role, permission=self.permission, tenant=self.tenant)
self.create_policy(policy_name, self.group.uuid, [role_uuid])

url = "{}?application={}&username={}".format(reverse("access"), "app,app2", self.principal.username)
Expand Down
8 changes: 4 additions & 4 deletions tests/management/group/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ def setUp(self):
super().setUp()

with tenant_context(self.tenant):
self.group = Group.objects.create(name="groupA")
self.roleA = Role.objects.create(name="roleA")
self.roleB = Role.objects.create(name="roleB")
self.policy = Policy(name="policyA", group=self.group)
self.group = Group.objects.create(name="groupA", tenant=self.tenant)
self.roleA = Role.objects.create(name="roleA", tenant=self.tenant)
self.roleB = Role.objects.create(name="roleB", tenant=self.tenant)
self.policy = Policy(name="policyA", group=self.group, tenant=self.tenant)
self.policy.save()
self.policy.roles.add(self.roleA)
self.policy.save()
Expand Down
Loading

0 comments on commit 51edf0a

Please sign in to comment.