PageRenderTime 60ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/sentry/api/endpoints/test_scim_user_index.py

https://github.com/getsentry/sentry
Python | 207 lines | 183 code | 23 blank | 1 comment | 1 complexity | e48ef016535e16643539f07cfd0fb801 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. from django.urls import reverse
  2. from sentry.models import OrganizationMember
  3. from sentry.models.auditlogentry import AuditLogEntry, AuditLogEntryEvent
  4. from sentry.scim.endpoints.utils import SCIMQueryParamSerializer
  5. from sentry.testutils import SCIMAzureTestCase, SCIMTestCase, TestCase
  6. CREATE_USER_POST_DATA = {
  7. "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  8. "userName": "test.user@okta.local",
  9. "name": {"givenName": "Test", "familyName": "User"},
  10. "emails": [{"primary": True, "value": "test.user@okta.local", "type": "work"}],
  11. "active": True,
  12. }
  13. class SCIMMemberIndexTests(SCIMTestCase):
  14. def test_get_users_index_empty(self):
  15. url = reverse("sentry-api-0-organization-scim-member-index", args=[self.organization.slug])
  16. response = self.client.get(
  17. f"{url}?startIndex=1&count=100&filter=userName%20eq%20%22test.user%40okta.local%22"
  18. )
  19. correct_get_data = {
  20. "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
  21. "totalResults": 0,
  22. "startIndex": 1,
  23. "itemsPerPage": 0,
  24. "Resources": [],
  25. }
  26. assert response.status_code == 200, response.content
  27. assert response.data == correct_get_data
  28. def test_post_users_successful(self):
  29. url = reverse("sentry-api-0-organization-scim-member-index", args=[self.organization.slug])
  30. response = self.client.post(url, CREATE_USER_POST_DATA)
  31. assert response.status_code == 201, response.content
  32. member = OrganizationMember.objects.get(
  33. organization=self.organization, email="test.user@okta.local"
  34. )
  35. correct_post_data = {
  36. "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  37. "id": str(member.id),
  38. "userName": "test.user@okta.local",
  39. "emails": [{"primary": True, "value": "test.user@okta.local", "type": "work"}],
  40. "active": True,
  41. "name": {"familyName": "N/A", "givenName": "N/A"},
  42. "meta": {"resourceType": "User"},
  43. }
  44. assert AuditLogEntry.objects.filter(
  45. target_object=member.id, event=AuditLogEntryEvent.MEMBER_INVITE
  46. ).exists()
  47. assert correct_post_data == response.data
  48. assert member.email == "test.user@okta.local"
  49. def test_post_users_already_exists(self):
  50. # test that response 409s if member already exists (by email)
  51. self.create_member(
  52. user=self.create_user(), organization=self.organization, email="test.user@okta.local"
  53. )
  54. url = reverse("sentry-api-0-organization-scim-member-index", args=[self.organization.slug])
  55. response = self.client.post(url, CREATE_USER_POST_DATA)
  56. assert response.status_code == 409, response.content
  57. assert response.data == {
  58. "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
  59. "detail": "User already exists in the database.",
  60. }
  61. def test_users_get_populated(self):
  62. member = self.create_member(organization=self.organization, email="test.user@okta.local")
  63. url = reverse("sentry-api-0-organization-scim-member-index", args=[self.organization.slug])
  64. response = self.client.get(
  65. f"{url}?startIndex=1&count=100&filter=userName%20eq%20%22test.user%40okta.local%22"
  66. )
  67. correct_get_data = {
  68. "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
  69. "totalResults": 1,
  70. "startIndex": 1,
  71. "itemsPerPage": 1,
  72. "Resources": [
  73. {
  74. "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  75. "id": str(member.id),
  76. "userName": "test.user@okta.local",
  77. "emails": [{"primary": True, "value": "test.user@okta.local", "type": "work"}],
  78. "name": {"familyName": "N/A", "givenName": "N/A"},
  79. "active": True,
  80. "meta": {"resourceType": "User"},
  81. }
  82. ],
  83. }
  84. assert response.status_code == 200, response.content
  85. assert response.data == correct_get_data
  86. def test_users_get_filter_case_insensitive(self):
  87. member = self.create_member(organization=self.organization, email="test.user@okta.local")
  88. url = reverse("sentry-api-0-organization-scim-member-index", args=[self.organization.slug])
  89. response = self.client.get(
  90. f"{url}?startIndex=1&count=100&filter=userName%20eq%20%22TEST.USER%40okta.local%22"
  91. )
  92. correct_get_data = {
  93. "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
  94. "totalResults": 1,
  95. "startIndex": 1,
  96. "itemsPerPage": 1,
  97. "Resources": [
  98. {
  99. "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  100. "id": str(member.id),
  101. "userName": "test.user@okta.local",
  102. "emails": [{"primary": True, "value": "test.user@okta.local", "type": "work"}],
  103. "name": {"familyName": "N/A", "givenName": "N/A"},
  104. "active": True,
  105. "meta": {"resourceType": "User"},
  106. }
  107. ],
  108. }
  109. assert response.status_code == 200, response.content
  110. assert response.data == correct_get_data
  111. def test_pagination(self):
  112. for _ in range(0, 150):
  113. self.create_member(
  114. user=self.create_user(),
  115. organization=self.organization,
  116. role="member",
  117. teams=[],
  118. )
  119. url = reverse("sentry-api-0-organization-scim-member-index", args=[self.organization.slug])
  120. response = self.client.get(f"{url}?startIndex=1&count=100")
  121. assert response.data["totalResults"] == 151
  122. assert response.data["itemsPerPage"] == 100
  123. assert response.data["startIndex"] == 1
  124. assert len(response.data["Resources"]) == 100
  125. url = reverse("sentry-api-0-organization-scim-member-index", args=[self.organization.slug])
  126. response = self.client.get(f"{url}?startIndex=40&count=100")
  127. assert response.data["totalResults"] == 151
  128. assert response.data["itemsPerPage"] == 100
  129. assert response.data["startIndex"] == 40
  130. assert len(response.data["Resources"]) == 100
  131. url = reverse("sentry-api-0-organization-scim-member-index", args=[self.organization.slug])
  132. response = self.client.get(f"{url}?startIndex=101&count=100")
  133. assert len(response.data["Resources"]) == 51
  134. assert response.data["totalResults"] == 151
  135. assert response.data["itemsPerPage"] == 51
  136. assert response.data["startIndex"] == 101
  137. class SCIMMemberIndexAzureTests(SCIMAzureTestCase):
  138. def test_user_index_get_no_active(self):
  139. member = self.create_member(organization=self.organization, email="test.user@okta.local")
  140. url = reverse("sentry-api-0-organization-scim-member-index", args=[self.organization.slug])
  141. response = self.client.get(
  142. f"{url}?startIndex=1&count=100&filter=userName%20eq%20%22test.user%40okta.local%22"
  143. )
  144. assert response.status_code == 200, response.content
  145. assert response.data == {
  146. "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
  147. "totalResults": 1,
  148. "startIndex": 1,
  149. "itemsPerPage": 1,
  150. "Resources": [
  151. {
  152. "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  153. "id": str(member.id),
  154. "userName": "test.user@okta.local",
  155. "emails": [{"primary": True, "value": "test.user@okta.local", "type": "work"}],
  156. "name": {"familyName": "N/A", "givenName": "N/A"},
  157. "meta": {"resourceType": "User"},
  158. }
  159. ],
  160. }
  161. class SCIMQueryParameterSerializerTest(TestCase):
  162. def test_defaults(self):
  163. serializer = SCIMQueryParamSerializer(data={})
  164. assert serializer.is_valid()
  165. assert serializer.validated_data["start_index"] == 1
  166. assert serializer.validated_data["count"] == 100
  167. assert serializer.validated_data["excluded_attributes"] == []
  168. assert serializer.validated_data["filter"] is None
  169. def test_start_index(self):
  170. serializer = SCIMQueryParamSerializer(data={"startIndex": 0})
  171. assert not serializer.is_valid()
  172. serializer = SCIMQueryParamSerializer(data={"startIndex": 1})
  173. assert serializer.is_valid()
  174. def test_count(self):
  175. serializer = SCIMQueryParamSerializer(data={"count": -1})
  176. assert not serializer.is_valid()
  177. serializer = SCIMQueryParamSerializer(data={"count": 0})
  178. assert serializer.is_valid()
  179. def test_filter(self):
  180. serializer = SCIMQueryParamSerializer(data={"filter": "aoiwefjoi3j9f"})
  181. assert not serializer.is_valid()
  182. def test_excluded_attributes(self):
  183. serializer = SCIMQueryParamSerializer(data={"excludedAttributes": ["members"]})
  184. assert serializer.is_valid()