scim2-server 0.6.2__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {scim2_server-0.6.2 → scim2_server-0.7.0}/PKG-INFO +4 -2
  2. {scim2_server-0.6.2 → scim2_server-0.7.0}/pyproject.toml +4 -2
  3. {scim2_server-0.6.2 → scim2_server-0.7.0}/pyproject.toml.orig +6 -2
  4. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/memory.py +6 -3
  5. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/resources/default-service-provider-config.json +1 -2
  6. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/service.py +0 -1
  7. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/testserver/cli.py +20 -1
  8. scim2_server-0.7.0/scim2_server/testserver/precis.py +29 -0
  9. {scim2_server-0.6.2 → scim2_server-0.7.0}/LICENSE +0 -0
  10. {scim2_server-0.6.2 → scim2_server-0.7.0}/README.md +0 -0
  11. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/__init__.py +0 -0
  12. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/applications/__init__.py +0 -0
  13. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/applications/asgi.py +0 -0
  14. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/applications/base.py +0 -0
  15. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/applications/wsgi.py +0 -0
  16. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/bulk.py +0 -0
  17. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/conditions.py +0 -0
  18. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/errors.py +0 -0
  19. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/handler.py +0 -0
  20. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/py.typed +0 -0
  21. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/requests.py +0 -0
  22. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/resources/default-resource-types.json +0 -0
  23. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/resources/default-schemas.json +0 -0
  24. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/responses.py +0 -0
  25. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/routing.py +0 -0
  26. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/storage.py +0 -0
  27. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/testing.py +0 -0
  28. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/testserver/__init__.py +0 -0
  29. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/testserver/application.py +0 -0
  30. {scim2_server-0.6.2 → scim2_server-0.7.0}/scim2_server/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: scim2-server
3
- Version: 0.6.2
3
+ Version: 0.7.0
4
4
  Summary: SCIM server core for any storage and web framework
5
5
  Keywords: scim,scim2,provisioning,rfc7643,rfc7644
6
6
  Author: Yaal Coop, Christian Friedrich Coors
@@ -217,11 +217,13 @@ Classifier: License :: OSI Approved :: Apache Software License
217
217
  Classifier: Environment :: Web Environment
218
218
  Classifier: Programming Language :: Python
219
219
  Classifier: Operating System :: OS Independent
220
- Requires-Dist: scim2-models>=0.10.6
220
+ Requires-Dist: scim2-models>=0.12.0
221
+ Requires-Dist: precis-i18n>=1.1.2 ; extra == 'precis'
221
222
  Requires-Dist: pytest>=9.1.1 ; extra == 'testing'
222
223
  Requires-Python: >=3.11
223
224
  Project-URL: repository, https://github.com/python-scim/scim2-server
224
225
  Project-URL: funding, https://github.com/sponsors/python-scim
226
+ Provides-Extra: precis
225
227
  Provides-Extra: testing
226
228
  Description-Content-Type: text/markdown
227
229
 
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "scim2-server"
7
- version = "0.6.2"
7
+ version = "0.7.0"
8
8
  description = "SCIM server core for any storage and web framework"
9
9
  readme = "README.md"
10
10
  keywords = [
@@ -28,7 +28,7 @@ classifiers = [
28
28
  "Operating System :: OS Independent",
29
29
  ]
30
30
  requires-python = ">= 3.11"
31
- dependencies = ["scim2-models>=0.10.6"]
31
+ dependencies = ["scim2-models>=0.12.0"]
32
32
 
33
33
  [[project.authors]]
34
34
  name = "Yaal Coop"
@@ -43,6 +43,7 @@ file = "LICENSE"
43
43
 
44
44
  [project.optional-dependencies]
45
45
  testing = ["pytest>=9.1.1"]
46
+ precis = ["precis-i18n>=1.1.2"]
46
47
 
47
48
  [project.urls]
48
49
  repository = "https://github.com/python-scim/scim2-server"
@@ -60,6 +61,7 @@ dev = [
60
61
  "time-machine>=2.14.2",
61
62
  "tox-uv>=1.16.0",
62
63
  "aiosqlite>=0.22.1",
64
+ "precis-i18n>=1.1.2",
63
65
  "mypy>=2.3.1",
64
66
  "scim2-client[werkzeug]>=0.11.2",
65
67
  "scim2-tester>=0.5.1",
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "scim2-server"
7
- version = "0.6.2"
7
+ version = "0.7.0"
8
8
  description = "SCIM server core for any storage and web framework"
9
9
  authors = [
10
10
  {name="Yaal Coop", email="contact@yaal.coop"},
@@ -29,13 +29,16 @@ classifiers = [
29
29
 
30
30
  requires-python = ">= 3.11"
31
31
  dependencies = [
32
- "scim2-models>=0.10.6",
32
+ "scim2-models>=0.12.0",
33
33
  ]
34
34
 
35
35
  [project.optional-dependencies]
36
36
  testing = [
37
37
  "pytest>=9.1.1",
38
38
  ]
39
+ precis = [
40
+ "precis-i18n>=1.1.2",
41
+ ]
39
42
 
40
43
  [project.urls]
41
44
  repository = "https://github.com/python-scim/scim2-server"
@@ -53,6 +56,7 @@ dev = [
53
56
  "time-machine>=2.14.2",
54
57
  "tox-uv>=1.16.0",
55
58
  "aiosqlite>=0.22.1",
59
+ "precis-i18n>=1.1.2",
56
60
  "mypy>=2.3.1",
57
61
  "scim2-client[werkzeug]>=0.11.2",
58
62
  "scim2-tester>=0.5.1",
@@ -203,13 +203,16 @@ class InMemoryStorage(ScimStorage):
203
203
  """Return the value a resource holds for a unique attribute, in the form it is compared in.
204
204
 
205
205
  A resource whose schemas do not declare the attribute holds no value.
206
+ A string the policy cannot compare is equal to no other value, so it
207
+ is held as missing too.
206
208
  """
207
209
  value = parametrize(Path, type(resource))(attribute.urn).get(
208
210
  resource, strict=False
209
211
  )
210
- if isinstance(value, str) and not attribute.case_exact:
211
- return value.casefold()
212
- return value
212
+ try:
213
+ return attribute.comparable(value)
214
+ except ValueError:
215
+ return None
213
216
 
214
217
 
215
218
  class AsyncInMemoryStorage(AsyncScimStorage):
@@ -22,6 +22,5 @@
22
22
  },
23
23
  "etag": {
24
24
  "supported": true
25
- },
26
- "authenticationSchemes": []
25
+ }
27
26
  }
@@ -122,7 +122,6 @@ def patch_only_config() -> ServiceProviderConfig:
122
122
  change_password=ChangePassword(supported=False),
123
123
  sort=Sort(supported=False),
124
124
  etag=ETag(supported=False),
125
- authentication_schemes=[],
126
125
  )
127
126
 
128
127
 
@@ -87,6 +87,12 @@ def build_parser() -> argparse.ArgumentParser:
87
87
  help="Accept a static bearer token, and announce the bearer token scheme. "
88
88
  "Can be repeated. Without it, the server accepts every request.",
89
89
  )
90
+ parser.add_argument(
91
+ "--precis",
92
+ action="store_true",
93
+ help="Compare the usernames and the passwords with the PRECIS profiles of "
94
+ "RFC 8265, and refuse the values they do not allow. Needs the precis extra.",
95
+ )
90
96
  parser.add_argument(
91
97
  "--hostname",
92
98
  default="127.0.0.1",
@@ -169,7 +175,20 @@ def main() -> None:
169
175
  BEARER_TOKEN_SCHEME,
170
176
  ]
171
177
 
172
- provider = ScimProvider.from_discovery(schemas, resource_types, config=config)
178
+ policy = None
179
+ if args.precis:
180
+ try:
181
+ # Imported on demand, so that the server runs without the precis extra.
182
+ from scim2_server.testserver.precis import PRECIS_POLICY
183
+ except ModuleNotFoundError:
184
+ parser.error(
185
+ "--precis needs the precis extra: pip install 'scim2-server[precis]'"
186
+ )
187
+ policy = PRECIS_POLICY
188
+
189
+ provider = ScimProvider.from_discovery(
190
+ schemas, resource_types, config=config, policy=policy
191
+ )
173
192
 
174
193
  storages: dict[str | None, InMemoryStorage] = {}
175
194
 
@@ -0,0 +1,29 @@
1
+ """The PRECIS comparison of the ``--precis`` option of the ``scim2-server`` command."""
2
+
3
+ from typing import Any
4
+
5
+ from precis_i18n import get_profile
6
+ from scim2_models import ScimPolicy
7
+ from scim2_models import default_comparison_key
8
+
9
+ USER_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:User"
10
+
11
+ PROFILES = {
12
+ f"{USER_SCHEMA}:userName": get_profile("UsernameCaseMapped"),
13
+ f"{USER_SCHEMA}:password": get_profile("OpaqueString"),
14
+ }
15
+
16
+
17
+ def precis_comparison_key(binding: Any, value: str) -> str:
18
+ """Compare the usernames and the passwords with the PRECIS profiles of RFC 8265.
19
+
20
+ Per RFC 7644 §5, the usernames and the passwords are prepared with PRECIS
21
+ before they are compared. The other strings are compared as by default.
22
+ """
23
+ profile = PROFILES.get(binding.urn)
24
+ if profile is None:
25
+ return default_comparison_key(binding, value)
26
+ return str(profile.enforce(value))
27
+
28
+
29
+ PRECIS_POLICY = ScimPolicy(comparison_key=precis_comparison_key)
File without changes
File without changes