diff --git a/CHANGELOG.md b/CHANGELOG.md index ac6634d..fd90c6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to ### Changed - ♻️(plugins) rewrite plugin system as django app #844 +- 🔒️(users) restrict listable users to same organization #846 ### Fixed diff --git a/docker/auth/realm.json b/docker/auth/realm.json index 5966420..03fbbb9 100644 --- a/docker/auth/realm.json +++ b/docker/auth/realm.json @@ -50,6 +50,9 @@ "firstName": "John", "lastName": "Doe", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -81,6 +84,9 @@ "firstName": "E2E", "lastName": "Chromium", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -95,6 +101,9 @@ "firstName": "E2E", "lastName": "Webkit", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -109,6 +118,9 @@ "firstName": "E2E", "lastName": "Firefox", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -123,6 +135,9 @@ "firstName": "E2E", "lastName": "Group Member", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -137,6 +152,9 @@ "firstName": "E2E", "lastName": "Group Administrator", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -151,6 +169,9 @@ "firstName": "E2E", "lastName": "Group Owner", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -165,6 +186,9 @@ "firstName": "E2E", "lastName": "Mailbox Member", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -179,6 +203,9 @@ "firstName": "E2E", "lastName": "Mailbox Administrator", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -193,6 +220,9 @@ "firstName": "E2E", "lastName": "Mailbox Owner", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -207,6 +237,9 @@ "firstName": "E2E", "lastName": "Group Member Mailbox Member", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -221,6 +254,9 @@ "firstName": "E2E", "lastName": "Group Member Mailbox Administrator", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -235,6 +271,9 @@ "firstName": "E2E", "lastName": "Group Member Mailbox Owner", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -249,6 +288,9 @@ "firstName": "E2E", "lastName": "Group Administrator Mailbox Member", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -263,6 +305,9 @@ "firstName": "E2E", "lastName": "Group Administrator Mailbox Administrator", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -277,6 +322,9 @@ "firstName": "E2E", "lastName": "Group Administrator Mailbox Owner", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -291,6 +339,9 @@ "firstName": "E2E", "lastName": "Group Owner Mailbox Member", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -305,6 +356,9 @@ "firstName": "E2E", "lastName": "Group Owner Mailbox Administrator", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", @@ -319,6 +373,9 @@ "firstName": "E2E", "lastName": "Mailbox Owner", "enabled": true, + "attributes": { + "siret": "13002526500013" + }, "credentials": [ { "type": "password", diff --git a/src/backend/core/api/client/viewsets.py b/src/backend/core/api/client/viewsets.py index dd0971c..7ab6b2b 100644 --- a/src/backend/core/api/client/viewsets.py +++ b/src/backend/core/api/client/viewsets.py @@ -263,9 +263,10 @@ class UserViewSet( queryset = self.queryset if self.action == "list": - # Exclude inactive contacts + # Filter active users + # and users from same organization queryset = queryset.filter( - is_active=True, + is_active=True, organization_id=self.request.user.organization_id ) # Exclude all users already in the given team diff --git a/src/backend/core/tests/users/test_api_users_list.py b/src/backend/core/tests/users/test_api_users_list.py index 023bae5..9c1baa6 100644 --- a/src/backend/core/tests/users/test_api_users_list.py +++ b/src/backend/core/tests/users/test_api_users_list.py @@ -31,26 +31,29 @@ def test_api_users_list_anonymous(): def test_api_users_list_authenticated(): """ - Authenticated users should be able to list all users. + Authenticated users should be able to list users from their organization. """ - user = factories.UserFactory() + organization = factories.OrganizationFactory(with_registration_id=True) + user = factories.UserFactory(organization=organization) client = APIClient() client.force_login(user) - factories.UserFactory.create_batch(2) + factories.UserFactory(organization=organization) + factories.UserFactory.create_batch(2) # 2 users outside organization response = client.get( "/api/v1.0/users/", ) assert response.status_code == HTTP_200_OK - assert len(response.json()["results"]) == 3 + assert len(response.json()["results"]) == 2 def test_api_users_list_authenticated_response_content( client, django_assert_num_queries ): """ - Authenticated users should be able to list all users with the expected output. + Authenticated users should be able to list all users from their organization + with the expected output. """ user_organization = factories.OrganizationFactory( with_registration_id=True, name="HAL 9000" @@ -67,7 +70,7 @@ def test_api_users_list_authenticated_response_content( other_user_organization = factories.OrganizationFactory( with_registration_id=True, name="Corp. Inc." ) - other_user = factories.UserFactory( + factories.UserFactory( organization=other_user_organization, email="sara83@example.com", name="Christopher Thompson", @@ -85,23 +88,10 @@ def test_api_users_list_authenticated_response_content( .first() ) assert edited_json == { - "count": 2, + "count": 1, "next": None, "previous": None, "results": [ - { - "email": "sara83@example.com", - "id": str(other_user.pk), - "is_device": False, - "is_staff": False, - "language": "fr-fr", - "name": "Christopher Thompson", - "organization": { - "id": str(other_user.organization.pk), - "name": "Corp. Inc.", - }, - "timezone": "UTC", - }, { "email": "kylefields@example.net", "id": str(user.pk), @@ -124,13 +114,17 @@ def test_api_users_authenticated_list_by_email(): Authenticated users should be able to search users with a case-insensitive and partial query on the email. """ - user = factories.UserFactory(email="tester@ministry.fr", name="john doe") - dave = factories.UserFactory(email="david.bowman@work.com", name=None) + user = factories.UserFactory( + email="tester@ministry.fr", name="john doe", with_organization=True + ) + dave = factories.UserFactory( + email="david.bowman@work.com", name=None, organization=user.organization + ) nicole = factories.UserFactory( - email="nicole_foole@work.com", name=None, with_organization=True + email="nicole_foole@work.com", name=None, organization=user.organization ) frank = factories.UserFactory( - email="frank_poole@work.com", name=None, with_organization=True + email="frank_poole@work.com", name=None, organization=user.organization ) factories.UserFactory(email="heywood_floyd@work.com", name=None) @@ -203,13 +197,17 @@ def test_api_users_authenticated_list_by_name(): Authenticated users should be able to search users with a case-insensitive and partial query on the name. """ - user = factories.UserFactory(email="tester@ministry.fr", name="john doe") - dave = factories.UserFactory(name="Dave bowman", email=None) + user = factories.UserFactory( + email="tester@ministry.fr", name="john doe", with_organization=True + ) + dave = factories.UserFactory( + name="Dave bowman", email=None, organization=user.organization + ) nicole = factories.UserFactory( - name="nicole foole", email=None, with_organization=True + name="nicole foole", email=None, organization=user.organization ) frank = factories.UserFactory( - name="frank poolé", email=None, with_organization=True + name="frank poolé", email=None, organization=user.organization ) factories.UserFactory(name="heywood floyd", email=None) diff --git a/src/backend/demo/management/commands/create_demo.py b/src/backend/demo/management/commands/create_demo.py index 73052de..7973e73 100755 --- a/src/backend/demo/management/commands/create_demo.py +++ b/src/backend/demo/management/commands/create_demo.py @@ -201,6 +201,10 @@ def create_demo(stdout): # pylint: disable=too-many-locals ) # this is a quick fix to fix e2e tests # tests needs some no random data + organization, _created = models.Organization.objects.get_or_create( + name="13002526500013", + registration_id_list=["13002526500013"], + ) queue.push( models.User( sub=uuid4(), @@ -210,6 +214,7 @@ def create_demo(stdout): # pylint: disable=too-many-locals is_superuser=False, is_active=True, is_staff=False, + organization=organization, language=random.choice(settings.LANGUAGES)[0], ) ) @@ -222,6 +227,7 @@ def create_demo(stdout): # pylint: disable=too-many-locals is_superuser=False, is_active=True, is_staff=False, + organization=organization, language=random.choice(settings.LANGUAGES)[0], ) )