pas.plugins.oidc 2.0.0b1__tar.gz → 2.0.0b3__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 (101) hide show
  1. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/CHANGES.md +27 -0
  2. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/PKG-INFO +43 -13
  3. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/README.md +11 -11
  4. pas.plugins.oidc-2.0.0b3/docs/screenshot-settings.png +0 -0
  5. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/setup.py +5 -2
  6. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/configure.zcml +2 -7
  7. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/controlpanel/classic.py +174 -0
  8. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/controlpanel/configure.zcml +27 -0
  9. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/controlpanel/deserializer.py +80 -0
  10. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/controlpanel/oidc.py +20 -0
  11. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/controlpanel/serializer.py +45 -0
  12. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/interfaces.py +131 -0
  13. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/locales/de/LC_MESSAGES/pas.plugins.oidc.mo +0 -0
  14. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/locales/de/LC_MESSAGES/pas.plugins.oidc.po +167 -0
  15. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/locales/en/LC_MESSAGES/pas.plugins.oidc.mo +0 -0
  16. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/locales/en/LC_MESSAGES/pas.plugins.oidc.po +164 -0
  17. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/locales/es/LC_MESSAGES/pas.plugins.oidc.mo +0 -0
  18. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/locales/es/LC_MESSAGES/pas.plugins.oidc.po +169 -0
  19. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/locales/pas.plugins.oidc.pot +171 -0
  20. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/plugins.py +43 -1
  21. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/profiles/default/controlpanel.xml +21 -0
  22. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/profiles/default/metadata.xml +1 -1
  23. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/services/login/configure.zcml +11 -0
  24. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/services/login/get.py +29 -0
  25. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/upgrades/__init__.py +0 -0
  26. pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/upgrades/configure.zcml +25 -0
  27. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/utils.py +2 -0
  28. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas.plugins.oidc.egg-info/PKG-INFO +43 -13
  29. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas.plugins.oidc.egg-info/SOURCES.txt +12 -0
  30. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas.plugins.oidc.egg-info/requires.txt +4 -1
  31. pas.plugins.oidc-2.0.0b3/tests/controlpanel/conftest.py +59 -0
  32. pas.plugins.oidc-2.0.0b3/tests/controlpanel/test_controlpanel_api.py +24 -0
  33. pas.plugins.oidc-2.0.0b3/tests/functional/test_controlpanel_classic.py +19 -0
  34. pas.plugins.oidc-2.0.0b3/tests/keycloak/import/.gitkeep +0 -0
  35. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/services/conftest.py +1 -0
  36. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/setup/test_setup_install.py +1 -1
  37. pas.plugins.oidc-2.0.0b1/docs/screenshot-settings.png +0 -0
  38. pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/interfaces.py +0 -7
  39. pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/locales/de/LC_MESSAGES/pas.plugins.oidc.mo +0 -0
  40. pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/locales/de/LC_MESSAGES/pas.plugins.oidc.po +0 -63
  41. pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/locales/en/LC_MESSAGES/pas.plugins.oidc.po +0 -60
  42. pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/locales/es/LC_MESSAGES/pas.plugins.oidc.po +0 -65
  43. pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/locales/pas.plugins.oidc.pot +0 -63
  44. pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/services/login/configure.zcml +0 -15
  45. pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/services/login/get.py +0 -42
  46. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/.coveragerc +0 -0
  47. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/.pre-commit-config.yaml +0 -0
  48. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/CONTRIBUTORS.md +0 -0
  49. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/LICENSE.GPL +0 -0
  50. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/LICENSE.md +0 -0
  51. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/MANIFEST.in +0 -0
  52. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/Makefile +0 -0
  53. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/constraints.txt +0 -0
  54. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/docs/icon.png +0 -0
  55. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/instance.yaml +0 -0
  56. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/pyproject.toml +0 -0
  57. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/requirements-docs.txt +0 -0
  58. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/requirements.txt +0 -0
  59. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/setup.cfg +0 -0
  60. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/__init__.py +0 -0
  61. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/__init__.py +0 -0
  62. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/__init__.py +0 -0
  63. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/browser/__init__.py +0 -0
  64. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/browser/configure.zcml +0 -0
  65. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/browser/view.py +0 -0
  66. {pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/locales → pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/controlpanel}/__init__.py +0 -0
  67. {pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/services → pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/locales}/__init__.py +0 -0
  68. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/locales/update.py +0 -0
  69. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/profiles/default/browserlayer.xml +0 -0
  70. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/profiles/uninstall/browserlayer.xml +0 -0
  71. {pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/services/login → pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/services}/__init__.py +0 -0
  72. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/services/configure.zcml +0 -0
  73. {pas.plugins.oidc-2.0.0b1/src/pas/plugins/oidc/services/oidc → pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/services/login}/__init__.py +0 -0
  74. /pas.plugins.oidc-2.0.0b1/tests/keycloak/import/.gitkeep → /pas.plugins.oidc-2.0.0b3/src/pas/plugins/oidc/services/oidc/__init__.py +0 -0
  75. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/services/oidc/configure.zcml +0 -0
  76. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/services/oidc/oidc.py +0 -0
  77. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/session.py +0 -0
  78. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/setuphandlers.py +0 -0
  79. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/testing.py +0 -0
  80. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas/plugins/oidc/www/oidcPluginForm.zpt +0 -0
  81. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas.plugins.oidc.egg-info/dependency_links.txt +0 -0
  82. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas.plugins.oidc.egg-info/entry_points.txt +0 -0
  83. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas.plugins.oidc.egg-info/namespace_packages.txt +0 -0
  84. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas.plugins.oidc.egg-info/not-zip-safe +0 -0
  85. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/src/pas.plugins.oidc.egg-info/top_level.txt +0 -0
  86. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/conftest.py +0 -0
  87. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/docker-compose.yml +0 -0
  88. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/functional/conftest.py +0 -0
  89. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/functional/test_functional.py +0 -0
  90. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/keycloak/Dockerfile +0 -0
  91. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/keycloak/import/plone-realm.json +0 -0
  92. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/keycloak/import/plone-test-realm.json +0 -0
  93. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/plugin/test_plugin.py +0 -0
  94. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/services/test_services_login_get.py +0 -0
  95. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/services/test_services_oidc_get.py +0 -0
  96. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/services/test_services_oidc_post.py +0 -0
  97. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/services/test_servides_login_get_multiple_plugins.py +0 -0
  98. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/setup/test_setup_uninstall.py +0 -0
  99. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/utils/test_utils_flow.py +0 -0
  100. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/utils/test_utils_str.py +0 -0
  101. {pas.plugins.oidc-2.0.0b1 → pas.plugins.oidc-2.0.0b3}/tests/utils/test_utils_url.py +0 -0
@@ -9,6 +9,33 @@
9
9
 
10
10
  <!-- towncrier release notes start -->
11
11
 
12
+ ## 2.0.0b3 (2025-02-03)
13
+
14
+
15
+ ### New features:
16
+
17
+ - Register the adapter as needed by the @login endpoint present in plone.restapi @erral [#47](https://github.com/collective/pas.plugins.oidc/issues/47)
18
+
19
+
20
+ ### Internal:
21
+
22
+ - Bump plone.restapi to 9.10.0 [@ericof]
23
+
24
+
25
+ ## 2.0.0b2 (2024-12-09)
26
+
27
+
28
+ ### New features:
29
+
30
+ - Update the Deutsch translation [macagua] [#60](https://github.com/collective/pas.plugins.oidc/issues/60)
31
+ - Implement control panel to configure pas.plugins.oidc [@ericof] [#65](https://github.com/collective/pas.plugins.oidc/issues/65)
32
+
33
+
34
+ ### Documentation:
35
+
36
+ - Fixed port numbers on README file [macagua] [#51](https://github.com/collective/pas.plugins.oidc/issues/51)
37
+
38
+
12
39
  ## 2.0.0b1 (2024-06-25)
13
40
 
14
41
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pas.plugins.oidc
3
- Version: 2.0.0b1
3
+ Version: 2.0.0b3
4
4
  Summary: OIDC support for Plone sites
5
5
  Home-page: https://github.com/collective/pas.plugins.oidc
6
6
  Author: mamico
@@ -31,10 +31,13 @@ Requires-Dist: Plone
31
31
  Requires-Dist: Zope
32
32
  Requires-Dist: Products.CMFCore
33
33
  Requires-Dist: plone.api
34
+ Requires-Dist: plone.app.registry
34
35
  Requires-Dist: plone.base
35
36
  Requires-Dist: plone.protect
36
- Requires-Dist: plone.restapi>=8.34.0
37
+ Requires-Dist: plone.restapi>=9.10.0
37
38
  Requires-Dist: oic
39
+ Requires-Dist: requests
40
+ Requires-Dist: z3c.form
38
41
  Provides-Extra: test
39
42
  Requires-Dist: zope.pytestlayer; extra == "test"
40
43
  Requires-Dist: plone.app.contenttypes; extra == "test"
@@ -86,11 +89,11 @@ OAuth 2.0 should work as well because OpenID Connect is built on top of this pro
86
89
 
87
90
  ### Group Enumeration
88
91
 
89
- If you need to support group enumeration from a Keycloak server, we recommend installing the package `[pas.plugins.keycloakgroups](https://pypi.org/project/pas.plugins.keycloakgroups/)`.
92
+ If you need to support group enumeration from a Keycloak server, we recommend installing the package [pas.plugins.keycloakgroups](https://pypi.org/project/pas.plugins.keycloakgroups/).
90
93
 
91
94
  ## Installation
92
95
 
93
- This package supports Plone sites using Volto and ClassicUI.
96
+ This package supports Plone sites using Volto and Classic UI.
94
97
 
95
98
  For proper Volto support, the requirements are:
96
99
 
@@ -218,9 +221,9 @@ So, for Keycloak, it does not matter if we use the default or legacy mode if the
218
221
  *Notes:*
219
222
 
220
223
  * If legacy `redirect_uri` parameter is disabled in Keycloak, this is the default since version 18 of Keycloak according
221
- to this comment in *Starck Overflow*: https://stackoverflow.com/a/72142887.
224
+ to this comment in *Stack Overflow*: https://stackoverflow.com/a/72142887.
222
225
  * The plugin will work only if the `Use deprecated redirect_uri for logout url(/Plone/acl_users/oidc/logout)`
223
- option is un-checked at the plugin properties at http://localhost:8081/Plone/acl_users/oidc/manage_propertiesForm.
226
+ option is un-checked at the plugin properties at http://localhost:8080/Plone/acl_users/oidc/manage_propertiesForm.
224
227
 
225
228
  #### Additional Documentation
226
229
 
@@ -232,9 +235,9 @@ Specifically, here we will use a Docker image, so follow the instructions on how
232
235
  * Make sure **pas.plugins.oidc** is installed.
233
236
  * Start Plone and create a Plone site with id Plone.
234
237
  * In the Add-ons control panel, install `pas.plugins.oidc`.
235
- * In the ZMI go to the plugin properties at http://localhost:8081/Plone/acl_users/oidc/manage_propertiesForm
238
+ * In the ZMI go to the plugin properties at http://localhost:8080/Plone/acl_users/oidc/manage_propertiesForm
236
239
  * Set these properties:
237
- * `OIDC/Oauth2 Issuer`: http://127.0.0.1:8081/realms/plone/
240
+ * `OIDC/Oauth2 Issuer`: http://127.0.0.1:8180/realms/plone/
238
241
  * `Client ID`: *plone* (**Warning:** This property must match the `Client ID` you have set in Keycloak.)
239
242
  * `Client secret`: *12345678* (**Warning:** This property must match the `Client secret` you have get in Keycloak.)
240
243
  * `Use deprecated redirect_uri for logout url` checked. Use this if you need to run old versions of Keycloak.
@@ -252,10 +255,10 @@ See this screenshot:
252
255
 
253
256
  #### Login
254
257
 
255
- Go to the other browser, or logout as admin from [Keycloak Admin Console](http://localhost:8080/admin).
258
+ Go to the other browser, or logout as admin from [Keycloak Admin Console](http://127.0.0.1:8180/admin).
256
259
  Currently, the Plone login form is unchanged.
257
260
 
258
- Instead, for testing go to the login page of the plugin: http://localhost:8081/Plone/acl_users/oidc/login,
261
+ Instead, for testing go to the login page of the plugin: http://localhost:8080/Plone/acl_users/oidc/login,
259
262
  this will take you to Keycloak to login, and then return. You should now be logged in to Plone, and see the
260
263
  *full name* and *email*, if you have set this in Keycloak.
261
264
 
@@ -264,7 +267,7 @@ this will take you to Keycloak to login, and then return. You should now be logg
264
267
  If the login did work as expected you can try to Plone logout.
265
268
  Currently, the Plone logout form is unchanged.
266
269
 
267
- Instead, for testing go to the logout page of the plugin: http://localhost:8081/Plone/acl_users/oidc/logout,
270
+ Instead, for testing go to the logout page of the plugin: http://localhost:8080/Plone/acl_users/oidc/logout,
268
271
  this will take you to Keycloak to logout, and then return to the post-logout redirect URL.
269
272
 
270
273
  ## Technical Decisions
@@ -277,8 +280,8 @@ and comes back from there.
277
280
  The plugin has 2 ways of working with sessions:
278
281
 
279
282
  - Use the Zope Session Management: if the `Use Zope session data manager` option in the plugin configuration is enabled,
280
- the plugin will use the sessioning configuration configured in Zope. To do so we advise using [Products.mcdutils](https://pypi.org/project/Products.mcdutils/)
281
- to save the session data in a memcached based storage. Otherwise Zope will try to use ZODB based sessioning
283
+ the plugin will use the session configuration configured in Zope. To do so we advise using [Products.mcdutils](https://pypi.org/project/Products.mcdutils/)
284
+ to save the session data in a memcached based storage. Otherwise, Zope will try to use a ZODB-based session
282
285
  which has shown several problems in the past.
283
286
 
284
287
  - Use the cookie-based session management: if the `Use Zope session data manager` option in the plugin
@@ -408,6 +411,33 @@ The project is licensed under the GPLv2.
408
411
 
409
412
  <!-- towncrier release notes start -->
410
413
 
414
+ ## 2.0.0b3 (2025-02-03)
415
+
416
+
417
+ ### New features:
418
+
419
+ - Register the adapter as needed by the @login endpoint present in plone.restapi @erral [#47](https://github.com/collective/pas.plugins.oidc/issues/47)
420
+
421
+
422
+ ### Internal:
423
+
424
+ - Bump plone.restapi to 9.10.0 [@ericof]
425
+
426
+
427
+ ## 2.0.0b2 (2024-12-09)
428
+
429
+
430
+ ### New features:
431
+
432
+ - Update the Deutsch translation [macagua] [#60](https://github.com/collective/pas.plugins.oidc/issues/60)
433
+ - Implement control panel to configure pas.plugins.oidc [@ericof] [#65](https://github.com/collective/pas.plugins.oidc/issues/65)
434
+
435
+
436
+ ### Documentation:
437
+
438
+ - Fixed port numbers on README file [macagua] [#51](https://github.com/collective/pas.plugins.oidc/issues/51)
439
+
440
+
411
441
  ## 2.0.0b1 (2024-06-25)
412
442
 
413
443
 
@@ -32,11 +32,11 @@ OAuth 2.0 should work as well because OpenID Connect is built on top of this pro
32
32
 
33
33
  ### Group Enumeration
34
34
 
35
- If you need to support group enumeration from a Keycloak server, we recommend installing the package `[pas.plugins.keycloakgroups](https://pypi.org/project/pas.plugins.keycloakgroups/)`.
35
+ If you need to support group enumeration from a Keycloak server, we recommend installing the package [pas.plugins.keycloakgroups](https://pypi.org/project/pas.plugins.keycloakgroups/).
36
36
 
37
37
  ## Installation
38
38
 
39
- This package supports Plone sites using Volto and ClassicUI.
39
+ This package supports Plone sites using Volto and Classic UI.
40
40
 
41
41
  For proper Volto support, the requirements are:
42
42
 
@@ -164,9 +164,9 @@ So, for Keycloak, it does not matter if we use the default or legacy mode if the
164
164
  *Notes:*
165
165
 
166
166
  * If legacy `redirect_uri` parameter is disabled in Keycloak, this is the default since version 18 of Keycloak according
167
- to this comment in *Starck Overflow*: https://stackoverflow.com/a/72142887.
167
+ to this comment in *Stack Overflow*: https://stackoverflow.com/a/72142887.
168
168
  * The plugin will work only if the `Use deprecated redirect_uri for logout url(/Plone/acl_users/oidc/logout)`
169
- option is un-checked at the plugin properties at http://localhost:8081/Plone/acl_users/oidc/manage_propertiesForm.
169
+ option is un-checked at the plugin properties at http://localhost:8080/Plone/acl_users/oidc/manage_propertiesForm.
170
170
 
171
171
  #### Additional Documentation
172
172
 
@@ -178,9 +178,9 @@ Specifically, here we will use a Docker image, so follow the instructions on how
178
178
  * Make sure **pas.plugins.oidc** is installed.
179
179
  * Start Plone and create a Plone site with id Plone.
180
180
  * In the Add-ons control panel, install `pas.plugins.oidc`.
181
- * In the ZMI go to the plugin properties at http://localhost:8081/Plone/acl_users/oidc/manage_propertiesForm
181
+ * In the ZMI go to the plugin properties at http://localhost:8080/Plone/acl_users/oidc/manage_propertiesForm
182
182
  * Set these properties:
183
- * `OIDC/Oauth2 Issuer`: http://127.0.0.1:8081/realms/plone/
183
+ * `OIDC/Oauth2 Issuer`: http://127.0.0.1:8180/realms/plone/
184
184
  * `Client ID`: *plone* (**Warning:** This property must match the `Client ID` you have set in Keycloak.)
185
185
  * `Client secret`: *12345678* (**Warning:** This property must match the `Client secret` you have get in Keycloak.)
186
186
  * `Use deprecated redirect_uri for logout url` checked. Use this if you need to run old versions of Keycloak.
@@ -198,10 +198,10 @@ See this screenshot:
198
198
 
199
199
  #### Login
200
200
 
201
- Go to the other browser, or logout as admin from [Keycloak Admin Console](http://localhost:8080/admin).
201
+ Go to the other browser, or logout as admin from [Keycloak Admin Console](http://127.0.0.1:8180/admin).
202
202
  Currently, the Plone login form is unchanged.
203
203
 
204
- Instead, for testing go to the login page of the plugin: http://localhost:8081/Plone/acl_users/oidc/login,
204
+ Instead, for testing go to the login page of the plugin: http://localhost:8080/Plone/acl_users/oidc/login,
205
205
  this will take you to Keycloak to login, and then return. You should now be logged in to Plone, and see the
206
206
  *full name* and *email*, if you have set this in Keycloak.
207
207
 
@@ -210,7 +210,7 @@ this will take you to Keycloak to login, and then return. You should now be logg
210
210
  If the login did work as expected you can try to Plone logout.
211
211
  Currently, the Plone logout form is unchanged.
212
212
 
213
- Instead, for testing go to the logout page of the plugin: http://localhost:8081/Plone/acl_users/oidc/logout,
213
+ Instead, for testing go to the logout page of the plugin: http://localhost:8080/Plone/acl_users/oidc/logout,
214
214
  this will take you to Keycloak to logout, and then return to the post-logout redirect URL.
215
215
 
216
216
  ## Technical Decisions
@@ -223,8 +223,8 @@ and comes back from there.
223
223
  The plugin has 2 ways of working with sessions:
224
224
 
225
225
  - Use the Zope Session Management: if the `Use Zope session data manager` option in the plugin configuration is enabled,
226
- the plugin will use the sessioning configuration configured in Zope. To do so we advise using [Products.mcdutils](https://pypi.org/project/Products.mcdutils/)
227
- to save the session data in a memcached based storage. Otherwise Zope will try to use ZODB based sessioning
226
+ the plugin will use the session configuration configured in Zope. To do so we advise using [Products.mcdutils](https://pypi.org/project/Products.mcdutils/)
227
+ to save the session data in a memcached based storage. Otherwise, Zope will try to use a ZODB-based session
228
228
  which has shown several problems in the past.
229
229
 
230
230
  - Use the cookie-based session management: if the `Use Zope session data manager` option in the plugin
@@ -14,7 +14,7 @@ long_description = f"""
14
14
 
15
15
  setup(
16
16
  name="pas.plugins.oidc",
17
- version="2.0.0b1",
17
+ version="2.0.0b3",
18
18
  description="OIDC support for Plone sites",
19
19
  long_description=long_description,
20
20
  long_description_content_type="text/markdown",
@@ -56,10 +56,13 @@ setup(
56
56
  "Zope",
57
57
  "Products.CMFCore",
58
58
  "plone.api",
59
+ "plone.app.registry",
59
60
  "plone.base",
60
61
  "plone.protect",
61
- "plone.restapi>=8.34.0",
62
+ "plone.restapi>=9.10.0",
62
63
  "oic",
64
+ "requests",
65
+ "z3c.form",
63
66
  ],
64
67
  extras_require={
65
68
  "test": [
@@ -20,6 +20,7 @@
20
20
  <i18n:registerTranslations directory="locales" />
21
21
 
22
22
  <include package=".browser" />
23
+ <include package=".controlpanel" />
23
24
  <include package=".services" />
24
25
 
25
26
  <genericsetup:registerProfile
@@ -40,13 +41,7 @@
40
41
  post_handler=".setuphandlers.uninstall"
41
42
  />
42
43
 
43
- <genericsetup:upgradeStep
44
- title="Activate challenge plugin"
45
- profile="pas.plugins.oidc:default"
46
- source="1000"
47
- destination="1001"
48
- handler=".setuphandlers.activate_challenge_plugin"
49
- />
44
+ <include package=".upgrades" />
50
45
 
51
46
  <utility
52
47
  factory=".setuphandlers.HiddenProfiles"
@@ -0,0 +1,174 @@
1
+ from pas.plugins.oidc import _
2
+ from pas.plugins.oidc import PLUGIN_ID
3
+ from pas.plugins.oidc.interfaces import IOIDCSettings
4
+ from plone import api
5
+ from plone.app.registry.browser import controlpanel
6
+ from plone.base.interfaces import IPloneSiteRoot
7
+ from zope.component import adapter
8
+ from zope.interface import implementer
9
+
10
+
11
+ @adapter(IPloneSiteRoot)
12
+ @implementer(IOIDCSettings)
13
+ class OIDCControlPanelAdapter:
14
+
15
+ def __init__(self, context):
16
+ self.context = context
17
+ self.portal = api.portal.get()
18
+ self.encoding = "utf-8"
19
+ self.settings = self.portal.acl_users[PLUGIN_ID]
20
+
21
+ @property
22
+ def issuer(self):
23
+ return self.settings.issuer
24
+
25
+ @issuer.setter
26
+ def issuer(self, value):
27
+ self.settings.issuer = value
28
+
29
+ @property
30
+ def client_id(self):
31
+ return self.settings.client_id
32
+
33
+ @client_id.setter
34
+ def client_id(self, value):
35
+ self.settings.client_id = value
36
+
37
+ @property
38
+ def client_secret(self):
39
+ return self.settings.client_secret
40
+
41
+ @client_secret.setter
42
+ def client_secret(self, value):
43
+ self.settings.client_secret = value
44
+
45
+ @property
46
+ def redirect_uris(self):
47
+ return self.settings.redirect_uris
48
+
49
+ @redirect_uris.setter
50
+ def redirect_uris(self, value):
51
+ self.settings.redirect_uris = value
52
+
53
+ @property
54
+ def use_session_data_manager(self):
55
+ return self.settings.use_session_data_manager
56
+
57
+ @use_session_data_manager.setter
58
+ def use_session_data_manager(self, value):
59
+ self.settings.use_session_data_manager = value
60
+
61
+ @property
62
+ def create_user(self):
63
+ return self.settings.create_user
64
+
65
+ @create_user.setter
66
+ def create_user(self, value):
67
+ self.settings.create_user = value
68
+
69
+ @property
70
+ def create_groups(self):
71
+ return self.settings.create_groups
72
+
73
+ @create_groups.setter
74
+ def create_groups(self, value):
75
+ self.settings.create_groups = value
76
+
77
+ @property
78
+ def user_property_as_groupid(self):
79
+ return self.settings.user_property_as_groupid
80
+
81
+ @user_property_as_groupid.setter
82
+ def user_property_as_groupid(self, value):
83
+ self.settings.user_property_as_groupid = value
84
+
85
+ @property
86
+ def create_ticket(self):
87
+ return self.settings.create_ticket
88
+
89
+ @create_ticket.setter
90
+ def create_ticket(self, value):
91
+ self.settings.create_ticket = value
92
+
93
+ @property
94
+ def create_restapi_ticket(self):
95
+ return self.settings.create_restapi_ticket
96
+
97
+ @create_restapi_ticket.setter
98
+ def create_restapi_ticket(self, value):
99
+ self.settings.create_restapi_ticket = value
100
+
101
+ @property
102
+ def scope(self):
103
+ return self.settings.scope
104
+
105
+ @scope.setter
106
+ def scope(self, value):
107
+ self.settings.scope = value
108
+
109
+ @property
110
+ def use_pkce(self):
111
+ return self.settings.use_pkce
112
+
113
+ @use_pkce.setter
114
+ def use_pkce(self, value):
115
+ self.settings.use_pkce = value
116
+
117
+ @property
118
+ def use_deprecated_redirect_uri_for_logout(self):
119
+ return self.settings.use_deprecated_redirect_uri_for_logout
120
+
121
+ @use_deprecated_redirect_uri_for_logout.setter
122
+ def use_deprecated_redirect_uri_for_logout(self, value):
123
+ self.settings.use_deprecated_redirect_uri_for_logout = value
124
+
125
+ @property
126
+ def use_modified_openid_schema(self):
127
+ return self.settings.use_modified_openid_schema
128
+
129
+ @use_modified_openid_schema.setter
130
+ def use_modified_openid_schema(self, value):
131
+ self.settings.use_modified_openid_schema = value
132
+
133
+ @property
134
+ def user_property_as_userid(self):
135
+ return self.settings.user_property_as_userid
136
+
137
+ @user_property_as_userid.setter
138
+ def user_property_as_userid(self, value):
139
+ self.settings.user_property_as_userid = value
140
+
141
+ @property
142
+ def identity_domain_name(self):
143
+ return self.settings.identity_domain_name
144
+
145
+ @identity_domain_name.setter
146
+ def identity_domain_name(self, value):
147
+ self.settings.identity_domain_name = value
148
+
149
+
150
+ class OIDCSettingsForm(controlpanel.RegistryEditForm):
151
+ schema = IOIDCSettings
152
+ schema_prefix = "oidc_admin"
153
+ label = _("OIDC Plugin Settings")
154
+ description = ""
155
+
156
+ def getContent(self):
157
+ portal = api.portal.get()
158
+ return OIDCControlPanelAdapter(portal)
159
+
160
+ def applyChanges(self, data):
161
+ """See interfaces.IEditForm"""
162
+ content = self.getContent()
163
+ changes = {}
164
+ for name in data:
165
+ current = getattr(content, name)
166
+ value = data[name]
167
+ if current != value:
168
+ setattr(content, name, value)
169
+ changes.setdefault(IOIDCSettings, []).append(name)
170
+ return changes
171
+
172
+
173
+ class OIDCSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
174
+ form = OIDCSettingsForm
@@ -0,0 +1,27 @@
1
+ <configure
2
+ xmlns="http://namespaces.zope.org/zope"
3
+ xmlns:browser="http://namespaces.zope.org/browser"
4
+ i18n_domain="pas.plugins.oidc"
5
+ >
6
+
7
+ <!-- ClassicUI Control panel -->
8
+ <adapter factory=".classic.OIDCControlPanelAdapter" />
9
+ <browser:page
10
+ name="oidc-controlpanel"
11
+ for="Products.CMFPlone.interfaces.IPloneSiteRoot"
12
+ class=".classic.OIDCSettingsControlPanel"
13
+ permission="cmf.ManagePortal"
14
+ layer="pas.plugins.oidc.interfaces.IDefaultBrowserLayer"
15
+ />
16
+
17
+ <!-- Restapi Controlpanel -->
18
+ <adapter factory=".serializer.OIDCControlpanelSerializeToJson" />
19
+ <adapter factory=".deserializer.OIDCControlpanelDeserializeFromJson" />
20
+
21
+ <adapter
22
+ factory=".oidc.OIDCSettingsConfigletPanel"
23
+ provides="pas.plugins.oidc.interfaces.IOIDCControlpanel"
24
+ name="oidc_admin"
25
+ />
26
+
27
+ </configure>
@@ -0,0 +1,80 @@
1
+ from pas.plugins.oidc import PLUGIN_ID
2
+ from pas.plugins.oidc.interfaces import IOIDCControlpanel
3
+ from plone import api
4
+ from plone.restapi.deserializer import json_body
5
+ from plone.restapi.deserializer.controlpanels import ControlpanelDeserializeFromJson
6
+ from plone.restapi.deserializer.controlpanels import FakeDXContext
7
+ from plone.restapi.interfaces import IDeserializeFromJson
8
+ from plone.restapi.interfaces import IFieldDeserializer
9
+ from z3c.form.interfaces import IManagerValidator
10
+ from zExceptions import BadRequest
11
+ from zope.component import adapter
12
+ from zope.component import queryMultiAdapter
13
+ from zope.interface import implementer
14
+ from zope.interface.exceptions import Invalid
15
+ from zope.schema import getFields
16
+ from zope.schema.interfaces import ValidationError
17
+
18
+
19
+ @implementer(IDeserializeFromJson)
20
+ @adapter(IOIDCControlpanel)
21
+ class OIDCControlpanelDeserializeFromJson(ControlpanelDeserializeFromJson):
22
+ @property
23
+ def proxy(self):
24
+ portal = api.portal.get()
25
+ plugin = portal.acl_users[PLUGIN_ID]
26
+ return plugin
27
+
28
+ def __call__(self, mask_validation_errors=True):
29
+ controlpanel = self.controlpanel
30
+ request = controlpanel.request
31
+ data = json_body(request)
32
+
33
+ proxy = self.proxy
34
+
35
+ schema_data = {}
36
+ errors = []
37
+
38
+ # Make a fake context
39
+ fake_context = FakeDXContext()
40
+
41
+ for name, field in getFields(self.schema).items():
42
+ field_data = schema_data.setdefault(self.schema, {})
43
+
44
+ if field.readonly:
45
+ continue
46
+
47
+ if name in data:
48
+ deserializer = queryMultiAdapter(
49
+ (field, fake_context, request), IFieldDeserializer
50
+ )
51
+ try:
52
+ # Make it sane
53
+ value = deserializer(data[name])
54
+ # Validate required etc
55
+ field.validate(value)
56
+ # Set the value.
57
+ setattr(proxy, name, value)
58
+ except ValidationError as e:
59
+ errors.append({"message": e.doc(), "field": name, "error": e})
60
+ except (ValueError, Invalid) as e:
61
+ errors.append({"message": str(e), "field": name, "error": e})
62
+ else:
63
+ field_data[name] = value
64
+
65
+ # Validate schemata
66
+ for schema, field_data in schema_data.items():
67
+ validator = queryMultiAdapter(
68
+ (self.context, request, None, schema, None), IManagerValidator
69
+ )
70
+ for error in validator.validate(field_data):
71
+ errors.append({"error": error, "message": str(error)})
72
+
73
+ if errors:
74
+ for error in errors:
75
+ if mask_validation_errors:
76
+ # Drop Python specific error classes in order to
77
+ # be able to better handle errors on front-end
78
+ error["error"] = "ValidationError"
79
+ error["message"] = api.env.translate(error["message"], context=request)
80
+ raise BadRequest(errors)
@@ -0,0 +1,20 @@
1
+ from pas.plugins.oidc import _
2
+ from pas.plugins.oidc.interfaces import IDefaultBrowserLayer
3
+ from pas.plugins.oidc.interfaces import IOIDCControlpanel
4
+ from pas.plugins.oidc.interfaces import IOIDCSettings
5
+ from plone.restapi.controlpanels import RegistryConfigletPanel
6
+ from zope.component import adapter
7
+ from zope.interface import implementer
8
+ from zope.interface import Interface
9
+
10
+
11
+ @adapter(Interface, IDefaultBrowserLayer)
12
+ @implementer(IOIDCControlpanel)
13
+ class OIDCSettingsConfigletPanel(RegistryConfigletPanel):
14
+ """Control Panel endpoint"""
15
+
16
+ schema = IOIDCSettings
17
+ configlet_id = "oidc_admin"
18
+ configlet_category_id = "plone-users"
19
+ title = _("OIDC settings")
20
+ group = ""
@@ -0,0 +1,45 @@
1
+ from pas.plugins.oidc import PLUGIN_ID
2
+ from pas.plugins.oidc.interfaces import IOIDCControlpanel
3
+ from pas.plugins.oidc.plugins import OIDCPlugin
4
+ from plone import api
5
+ from plone.restapi.interfaces import ISerializeToJson
6
+ from plone.restapi.serializer.controlpanels import ControlpanelSerializeToJson
7
+ from plone.restapi.serializer.controlpanels import get_jsonschema_for_controlpanel
8
+ from plone.restapi.serializer.controlpanels import SERVICE_ID
9
+ from zope.component import adapter
10
+ from zope.interface import implementer
11
+
12
+
13
+ @implementer(ISerializeToJson)
14
+ @adapter(IOIDCControlpanel)
15
+ class OIDCControlpanelSerializeToJson(ControlpanelSerializeToJson):
16
+ def config_data(self) -> dict:
17
+ data = {}
18
+ portal = api.portal.get()
19
+ plugin = portal.acl_users[PLUGIN_ID]
20
+ properties = OIDCPlugin._properties
21
+ for prop in properties:
22
+ key = prop["id"]
23
+ data[key] = getattr(plugin, key, "")
24
+ return data
25
+
26
+ def __call__(self):
27
+ json_data = self.config_data()
28
+ controlpanel = self.controlpanel
29
+ context = controlpanel.context
30
+ request = controlpanel.request
31
+ url = context.absolute_url()
32
+ json_schema = get_jsonschema_for_controlpanel(
33
+ controlpanel,
34
+ context,
35
+ request,
36
+ )
37
+ response = {
38
+ "@id": f"{url}/{SERVICE_ID}/{controlpanel.__name__}",
39
+ "title": "OIDC settings",
40
+ "description": "Configure OIDC connection strings",
41
+ "group": controlpanel.group,
42
+ "data": json_data,
43
+ "schema": json_schema,
44
+ }
45
+ return response