diff --git a/package-lock.json b/package-lock.json
index 92e002e1..8cb0d4c5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,7 +6,7 @@
"packages": {
"": {
"name": "objects",
- "version": "2.3.0",
+ "version": "2.4.0",
"license": "UNLICENSED",
"dependencies": {
"microscope-sass": "latest",
@@ -2882,11 +2882,11 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -4014,9 +4014,9 @@
}
},
"node_modules/engine.io": {
- "version": "6.5.4",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz",
- "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==",
+ "version": "6.5.5",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz",
+ "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==",
"dev": true,
"dependencies": {
"@types/cookie": "^0.4.1",
@@ -4028,7 +4028,7 @@
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
- "ws": "~8.11.0"
+ "ws": "~8.17.1"
},
"engines": {
"node": ">=10.2.0"
@@ -4264,17 +4264,17 @@
}
},
"node_modules/express": {
- "version": "4.18.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
- "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "version": "4.19.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
+ "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"dev": true,
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.20.1",
+ "body-parser": "1.20.2",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
- "cookie": "0.5.0",
+ "cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
@@ -4305,34 +4305,10 @@
"node": ">= 0.10.0"
}
},
- "node_modules/express/node_modules/body-parser": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
- "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
- "dev": true,
- "dependencies": {
- "bytes": "3.1.2",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.11.0",
- "raw-body": "2.5.1",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
"node_modules/express/node_modules/cookie": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
- "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"dev": true,
"engines": {
"node": ">= 0.6"
@@ -4377,21 +4353,6 @@
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
"dev": true
},
- "node_modules/express/node_modules/raw-body": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
- "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
- "dev": true,
- "dependencies": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
"node_modules/express/node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -4537,9 +4498,9 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -4640,9 +4601,9 @@
"dev": true
},
"node_modules/follow-redirects": {
- "version": "1.15.5",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
- "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
+ "version": "1.15.6",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"dev": true,
"funding": [
{
@@ -8592,12 +8553,13 @@
}
},
"node_modules/socket.io-adapter": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz",
- "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==",
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
+ "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
"dev": true,
"dependencies": {
- "ws": "~8.11.0"
+ "debug": "~4.3.4",
+ "ws": "~8.17.1"
}
},
"node_modules/socket.io-parser": {
@@ -9521,9 +9483,9 @@
}
},
"node_modules/webpack-dev-middleware": {
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
- "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz",
+ "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==",
"dev": true,
"dependencies": {
"colorette": "^2.0.10",
@@ -9602,27 +9564,6 @@
}
}
},
- "node_modules/webpack-dev-server/node_modules/ws": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
- "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
- "dev": true,
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": ">=5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
"node_modules/webpack-merge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
@@ -9809,16 +9750,16 @@
"dev": true
},
"node_modules/ws": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
- "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"dev": true,
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
+ "utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
diff --git a/requirements/base.txt b/requirements/base.txt
index 04225b7d..75ce49d7 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -1,5 +1,5 @@
#
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --no-emit-index-url requirements/base.in
@@ -9,6 +9,7 @@ amqp==5.2.0
asgiref==3.7.2
# via
# django
+ # django-axes
# django-cors-headers
asn1crypto==1.5.1
# via webauthn
@@ -16,7 +17,7 @@ attrs==20.3.0
# via
# glom
# jsonschema
-billiard==3.6.4.0
+billiard==4.2.0
# via celery
bleach==6.1.0
# via open-api-framework
@@ -24,14 +25,14 @@ boltons==21.0.0
# via
# face
# glom
-cbor2==5.6.1
+cbor2==5.6.2
# via webauthn
-celery==5.2.7
+celery==5.4.0
# via
# flower
# notifications-api-common
# open-api-framework
-certifi==2020.12.5
+certifi==2023.7.22
# via
# django-simple-certmanager
# elastic-apm
@@ -66,7 +67,7 @@ cryptography==41.0.7
# mozilla-django-oidc
# pyopenssl
# webauthn
-django==4.2.11
+django==4.2.14
# via
# commonground-api-common
# django-admin-index
@@ -104,17 +105,17 @@ django-admin-index==3.1.0
# via open-api-framework
django-appconf==1.0.6
# via django-log-outgoing-requests
-django-axes==6.3.0
+django-axes==6.5.1
# via open-api-framework
-django-cors-headers==4.3.1
+django-cors-headers==4.4.0
# via open-api-framework
-django-filter==23.5
+django-filter==24.2
# via
# commonground-api-common
# open-api-framework
django-formtools==2.3
# via django-two-factor-auth
-django-jsonform==2.21.4
+django-jsonform==2.22.0
# via
# mozilla-django-oidc-db
# open-api-framework
@@ -151,7 +152,7 @@ django-solo==2.2.0
# zgw-consumers
django-two-factor-auth[phonenumberslite,webauthn]==1.16.0
# via maykin-2fa
-djangorestframework==3.14.0
+djangorestframework==3.15.2
# via
# commonground-api-common
# djangorestframework-gis
@@ -171,13 +172,13 @@ djangorestframework-inclusions==1.2.0
# via open-api-framework
drf-nested-routers==0.93.3
# via commonground-api-common
-drf-spectacular==0.27.0
+drf-spectacular==0.27.2
# via open-api-framework
drf-yasg==1.21.7
# via commonground-api-common
ecs-logging==2.1.0
# via elastic-apm
-elastic-apm==6.20.0
+elastic-apm==6.23.0
# via open-api-framework
face==20.1.1
# via glom
@@ -198,7 +199,7 @@ glom==23.5.0
# mozilla-django-oidc-db
humanize==4.9.0
# via flower
-idna==2.10
+idna==3.7
# via requests
inflection==0.5.1
# via
@@ -210,7 +211,7 @@ isodate==0.6.0
# via commonground-api-common
itypes==1.2.0
# via coreapi
-jinja2==3.1.3
+jinja2==3.1.4
# via coreschema
josepy==1.9.0
# via mozilla-django-oidc
@@ -222,17 +223,17 @@ kombu==5.3.5
# via celery
markupsafe==2.1.3
# via jinja2
-maykin-2fa==1.0.0
+maykin-2fa==1.0.1
# via open-api-framework
mozilla-django-oidc==4.0.0
# via mozilla-django-oidc-db
-mozilla-django-oidc-db==0.14.1
+mozilla-django-oidc-db==0.19.0
# via open-api-framework
notifications-api-common==0.2.2
# via
# -r requirements/base.in
# commonground-api-common
-open-api-framework==0.5.0
+open-api-framework==0.6.1
# via -r requirements/base.in
orderedmultidict==1.0.1
# via furl
@@ -262,8 +263,9 @@ pyopenssl==23.3.0
# zgw-consumers
pyrsistent==0.17.3
# via jsonschema
-python-dateutil==2.8.1
+python-dateutil==2.9.0.post0
# via
+ # celery
# django-relativedelta
# faker
python-decouple==3.8
@@ -272,8 +274,6 @@ python-dotenv==1.0.0
# via open-api-framework
pytz==2024.1
# via
- # celery
- # djangorestframework
# drf-yasg
# flower
pyyaml==6.0.1
@@ -286,7 +286,7 @@ qrcode==6.1
# via django-two-factor-auth
redis==3.5.3
# via django-redis
-requests==2.31.0
+requests==2.32.3
# via
# commonground-api-common
# coreapi
@@ -298,7 +298,7 @@ requests==2.31.0
# zgw-consumers
requests-mock==1.8.0
# via zgw-consumers
-sentry-sdk==1.39.2
+sentry-sdk==2.12.0
# via open-api-framework
six==1.16.0
# via
@@ -309,20 +309,22 @@ six==1.16.0
# python-dateutil
# qrcode
# requests-mock
-sqlparse==0.4.2
+sqlparse==0.5.0
# via django
text-unidecode==1.3
# via faker
-tornado==6.4
+tornado==6.4.1
# via flower
typing-extensions==4.9.0
- # via asgiref
+ # via mozilla-django-oidc-db
+tzdata==2024.1
+ # via celery
uritemplate==3.0.1
# via
# coreapi
# drf-spectacular
# drf-yasg
-urllib3==2.2.1
+urllib3==2.2.2
# via
# elastic-apm
# requests
diff --git a/requirements/ci.txt b/requirements/ci.txt
index 7be57728..c7a5300a 100644
--- a/requirements/ci.txt
+++ b/requirements/ci.txt
@@ -1,5 +1,5 @@
#
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --no-emit-index-url --output-file=requirements/ci.txt requirements/base.txt requirements/test-tools.in
@@ -12,6 +12,7 @@ asgiref==3.7.2
# via
# -r requirements/base.txt
# django
+ # django-axes
# django-cors-headers
asn1crypto==1.5.1
# via
@@ -24,7 +25,7 @@ attrs==20.3.0
# jsonschema
beautifulsoup4==4.9.3
# via webtest
-billiard==3.6.4.0
+billiard==4.2.0
# via
# -r requirements/base.txt
# celery
@@ -37,17 +38,17 @@ boltons==21.0.0
# -r requirements/base.txt
# face
# glom
-cbor2==5.6.1
+cbor2==5.6.2
# via
# -r requirements/base.txt
# webauthn
-celery==5.2.7
+celery==5.4.0
# via
# -r requirements/base.txt
# flower
# notifications-api-common
# open-api-framework
-certifi==2020.12.5
+certifi==2023.7.22
# via
# -r requirements/base.txt
# django-simple-certmanager
@@ -105,7 +106,7 @@ cryptography==41.0.7
# webauthn
cssselect==1.1.0
# via pyquery
-django==4.2.11
+django==4.2.14
# via
# -r requirements/base.txt
# commonground-api-common
@@ -148,15 +149,15 @@ django-appconf==1.0.6
# via
# -r requirements/base.txt
# django-log-outgoing-requests
-django-axes==6.3.0
+django-axes==6.5.1
# via
# -r requirements/base.txt
# open-api-framework
-django-cors-headers==4.3.1
+django-cors-headers==4.4.0
# via
# -r requirements/base.txt
# open-api-framework
-django-filter==23.5
+django-filter==24.2
# via
# -r requirements/base.txt
# commonground-api-common
@@ -165,7 +166,7 @@ django-formtools==2.3
# via
# -r requirements/base.txt
# django-two-factor-auth
-django-jsonform==2.21.4
+django-jsonform==2.22.0
# via
# -r requirements/base.txt
# mozilla-django-oidc-db
@@ -229,11 +230,10 @@ django-solo==2.2.0
django-two-factor-auth[phonenumberslite,webauthn]==1.16.0
# via
# -r requirements/base.txt
- # django-two-factor-auth
# maykin-2fa
django-webtest==1.9.7
# via -r requirements/test-tools.in
-djangorestframework==3.14.0
+djangorestframework==3.15.2
# via
# -r requirements/base.txt
# commonground-api-common
@@ -261,7 +261,7 @@ drf-nested-routers==0.93.3
# via
# -r requirements/base.txt
# commonground-api-common
-drf-spectacular==0.27.0
+drf-spectacular==0.27.2
# via
# -r requirements/base.txt
# open-api-framework
@@ -273,7 +273,7 @@ ecs-logging==2.1.0
# via
# -r requirements/base.txt
# elastic-apm
-elastic-apm==6.20.0
+elastic-apm==6.23.0
# via
# -r requirements/base.txt
# open-api-framework
@@ -310,10 +310,11 @@ humanize==4.9.0
# via
# -r requirements/base.txt
# flower
-idna==2.10
+idna==3.7
# via
# -r requirements/base.txt
# requests
+ # yarl
inflection==0.5.1
# via
# -r requirements/base.txt
@@ -331,7 +332,7 @@ itypes==1.2.0
# via
# -r requirements/base.txt
# coreapi
-jinja2==3.1.3
+jinja2==3.1.4
# via
# -r requirements/base.txt
# coreschema
@@ -353,7 +354,7 @@ markupsafe==2.1.3
# via
# -r requirements/base.txt
# jinja2
-maykin-2fa==1.0.0
+maykin-2fa==1.0.1
# via
# -r requirements/base.txt
# open-api-framework
@@ -361,15 +362,17 @@ mozilla-django-oidc==4.0.0
# via
# -r requirements/base.txt
# mozilla-django-oidc-db
-mozilla-django-oidc-db==0.14.1
+mozilla-django-oidc-db==0.19.0
# via
# -r requirements/base.txt
# open-api-framework
+multidict==6.0.5
+ # via yarl
notifications-api-common==0.2.2
# via
# -r requirements/base.txt
# commonground-api-common
-open-api-framework==0.5.0
+open-api-framework==0.6.1
# via -r requirements/base.txt
orderedmultidict==1.0.1
# via
@@ -421,9 +424,10 @@ pyrsistent==0.17.3
# via
# -r requirements/base.txt
# jsonschema
-python-dateutil==2.8.1
+python-dateutil==2.9.0.post0
# via
# -r requirements/base.txt
+ # celery
# django-relativedelta
# faker
# freezegun
@@ -438,8 +442,6 @@ python-dotenv==1.0.0
pytz==2024.1
# via
# -r requirements/base.txt
- # celery
- # djangorestframework
# drf-yasg
# flower
pyyaml==6.0.1
@@ -449,6 +451,7 @@ pyyaml==6.0.1
# drf-yasg
# gemma-zds-client
# oyaml
+ # vcrpy
qrcode==6.1
# via
# -r requirements/base.txt
@@ -457,7 +460,7 @@ redis==3.5.3
# via
# -r requirements/base.txt
# django-redis
-requests==2.31.0
+requests==2.32.3
# via
# -r requirements/base.txt
# commonground-api-common
@@ -473,7 +476,7 @@ requests-mock==1.8.0
# -r requirements/base.txt
# -r requirements/test-tools.in
# zgw-consumers
-sentry-sdk==1.39.2
+sentry-sdk==2.12.0
# via
# -r requirements/base.txt
# open-api-framework
@@ -490,7 +493,7 @@ six==1.16.0
# webtest
soupsieve==2.2.1
# via beautifulsoup4
-sqlparse==0.4.2
+sqlparse==0.5.0
# via
# -r requirements/base.txt
# django
@@ -500,21 +503,25 @@ text-unidecode==1.3
# via
# -r requirements/base.txt
# faker
-tornado==6.4
+tornado==6.4.1
# via
# -r requirements/base.txt
# flower
typing-extensions==4.9.0
# via
# -r requirements/base.txt
- # asgiref
+ # mozilla-django-oidc-db
+tzdata==2024.1
+ # via
+ # -r requirements/base.txt
+ # celery
uritemplate==3.0.1
# via
# -r requirements/base.txt
# coreapi
# drf-spectacular
# drf-yasg
-urllib3==2.2.1
+urllib3==2.2.2
# via
# -r requirements/base.txt
# elastic-apm
@@ -524,13 +531,15 @@ uwsgi==2.0.23
# via
# -r requirements/base.txt
# open-api-framework
+vcrpy==6.0.1
+ # via -r requirements/test-tools.in
vine==5.1.0
# via
# -r requirements/base.txt
# amqp
# celery
# kombu
-waitress==2.1.1
+waitress==2.1.2
# via webtest
wcwidth==0.2.13
# via
@@ -552,6 +561,9 @@ wrapt==1.14.1
# via
# -r requirements/base.txt
# elastic-apm
+ # vcrpy
+yarl==1.9.4
+ # via vcrpy
zgw-consumers==0.27.0
# via
# -r requirements/base.txt
diff --git a/requirements/dev.txt b/requirements/dev.txt
index fc78f832..e6a3cb71 100644
--- a/requirements/dev.txt
+++ b/requirements/dev.txt
@@ -1,5 +1,5 @@
#
-# This file is autogenerated by pip-compile with Python 3.10
+# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --no-emit-index-url --output-file=requirements/dev.txt requirements/ci.txt requirements/dev.in
@@ -14,6 +14,7 @@ asgiref==3.7.2
# via
# -r requirements/ci.txt
# django
+ # django-axes
# django-cors-headers
asn1crypto==1.5.1
# via
@@ -30,11 +31,11 @@ beautifulsoup4==4.9.3
# via
# -r requirements/ci.txt
# webtest
-billiard==3.6.4.0
+billiard==4.2.0
# via
# -r requirements/ci.txt
# celery
-black==23.12.1
+black==24.3.0
# via -r requirements/dev.in
bleach==6.1.0
# via
@@ -51,17 +52,17 @@ bump2version==1.0.1
# via bumpversion
bumpversion==0.6.0
# via -r requirements/dev.in
-cbor2==5.6.1
+cbor2==5.6.2
# via
# -r requirements/ci.txt
# webauthn
-celery==5.2.7
+celery==5.4.0
# via
# -r requirements/ci.txt
# flower
# notifications-api-common
# open-api-framework
-certifi==2020.12.5
+certifi==2023.7.22
# via
# -r requirements/ci.txt
# django-simple-certmanager
@@ -125,7 +126,7 @@ cssselect==1.1.0
# via
# -r requirements/ci.txt
# pyquery
-django==4.2.11
+django==4.2.14
# via
# -r requirements/ci.txt
# commonground-api-common
@@ -170,11 +171,11 @@ django-appconf==1.0.6
# via
# -r requirements/ci.txt
# django-log-outgoing-requests
-django-axes==6.3.0
+django-axes==6.5.1
# via
# -r requirements/ci.txt
# open-api-framework
-django-cors-headers==4.3.1
+django-cors-headers==4.4.0
# via
# -r requirements/ci.txt
# open-api-framework
@@ -182,7 +183,7 @@ django-debug-toolbar==4.2.0
# via -r requirements/dev.in
django-extensions==3.2.3
# via -r requirements/dev.in
-django-filter==23.5
+django-filter==24.2
# via
# -r requirements/ci.txt
# commonground-api-common
@@ -191,7 +192,7 @@ django-formtools==2.3
# via
# -r requirements/ci.txt
# django-two-factor-auth
-django-jsonform==2.21.4
+django-jsonform==2.22.0
# via
# -r requirements/ci.txt
# mozilla-django-oidc-db
@@ -255,11 +256,10 @@ django-solo==2.2.0
django-two-factor-auth[phonenumberslite,webauthn]==1.16.0
# via
# -r requirements/ci.txt
- # django-two-factor-auth
# maykin-2fa
django-webtest==1.9.7
# via -r requirements/ci.txt
-djangorestframework==3.14.0
+djangorestframework==3.15.2
# via
# -r requirements/ci.txt
# commonground-api-common
@@ -293,7 +293,7 @@ drf-nested-routers==0.93.3
# via
# -r requirements/ci.txt
# commonground-api-common
-drf-spectacular==0.27.0
+drf-spectacular==0.27.2
# via
# -r requirements/ci.txt
# open-api-framework
@@ -305,7 +305,7 @@ ecs-logging==2.1.0
# via
# -r requirements/ci.txt
# elastic-apm
-elastic-apm==6.20.0
+elastic-apm==6.23.0
# via
# -r requirements/ci.txt
# open-api-framework
@@ -344,10 +344,11 @@ humanize==4.9.0
# via
# -r requirements/ci.txt
# flower
-idna==2.10
+idna==3.7
# via
# -r requirements/ci.txt
# requests
+ # yarl
imagesize==1.4.1
# via sphinx
inflection==0.5.1
@@ -369,7 +370,7 @@ itypes==1.2.0
# via
# -r requirements/ci.txt
# coreapi
-jinja2==3.1.3
+jinja2==3.1.4
# via
# -r requirements/ci.txt
# coreschema
@@ -394,7 +395,7 @@ markupsafe==2.1.3
# via
# -r requirements/ci.txt
# jinja2
-maykin-2fa==1.0.0
+maykin-2fa==1.0.1
# via
# -r requirements/ci.txt
# open-api-framework
@@ -404,17 +405,21 @@ mozilla-django-oidc==4.0.0
# via
# -r requirements/ci.txt
# mozilla-django-oidc-db
-mozilla-django-oidc-db==0.14.1
+mozilla-django-oidc-db==0.19.0
# via
# -r requirements/ci.txt
# open-api-framework
+multidict==6.0.5
+ # via
+ # -r requirements/ci.txt
+ # yarl
mypy-extensions==0.4.3
# via black
notifications-api-common==0.2.2
# via
# -r requirements/ci.txt
# commonground-api-common
-open-api-framework==0.5.0
+open-api-framework==0.6.1
# via -r requirements/ci.txt
orderedmultidict==1.0.1
# via
@@ -485,9 +490,10 @@ pyrsistent==0.17.3
# via
# -r requirements/ci.txt
# jsonschema
-python-dateutil==2.8.1
+python-dateutil==2.9.0.post0
# via
# -r requirements/ci.txt
+ # celery
# django-relativedelta
# faker
# freezegun
@@ -503,8 +509,6 @@ pytz==2024.1
# via
# -r requirements/ci.txt
# babel
- # celery
- # djangorestframework
# drf-yasg
# flower
pyyaml==6.0.1
@@ -514,6 +518,7 @@ pyyaml==6.0.1
# drf-yasg
# gemma-zds-client
# oyaml
+ # vcrpy
qrcode==6.1
# via
# -r requirements/ci.txt
@@ -524,7 +529,7 @@ redis==3.5.3
# via
# -r requirements/ci.txt
# django-redis
-requests==2.31.0
+requests==2.32.3
# via
# -r requirements/ci.txt
# commonground-api-common
@@ -540,7 +545,7 @@ requests-mock==1.8.0
# via
# -r requirements/ci.txt
# zgw-consumers
-sentry-sdk==1.39.2
+sentry-sdk==2.12.0
# via
# -r requirements/ci.txt
# open-api-framework
@@ -586,7 +591,7 @@ sphinxcontrib-qthelp==1.0.3
# via sphinx
sphinxcontrib-serializinghtml==1.1.5
# via sphinx
-sqlparse==0.4.2
+sqlparse==0.5.0
# via
# -r requirements/ci.txt
# django
@@ -597,28 +602,25 @@ text-unidecode==1.3
# via
# -r requirements/ci.txt
# faker
-tomli==2.0.1
- # via
- # black
- # build
- # pip-tools
- # pyproject-hooks
-tornado==6.4
+tornado==6.4.1
# via
# -r requirements/ci.txt
# flower
typing-extensions==4.9.0
# via
# -r requirements/ci.txt
- # asgiref
- # black
+ # mozilla-django-oidc-db
+tzdata==2024.1
+ # via
+ # -r requirements/ci.txt
+ # celery
uritemplate==3.0.1
# via
# -r requirements/ci.txt
# coreapi
# drf-spectacular
# drf-yasg
-urllib3==2.2.1
+urllib3==2.2.2
# via
# -r requirements/ci.txt
# elastic-apm
@@ -628,13 +630,15 @@ uwsgi==2.0.23
# via
# -r requirements/ci.txt
# open-api-framework
+vcrpy==6.0.1
+ # via -r requirements/ci.txt
vine==5.1.0
# via
# -r requirements/ci.txt
# amqp
# celery
# kombu
-waitress==2.1.1
+waitress==2.1.2
# via
# -r requirements/ci.txt
# webtest
@@ -664,6 +668,11 @@ wrapt==1.14.1
# via
# -r requirements/ci.txt
# elastic-apm
+ # vcrpy
+yarl==1.9.4
+ # via
+ # -r requirements/ci.txt
+ # vcrpy
zgw-consumers==0.27.0
# via
# -r requirements/ci.txt
diff --git a/requirements/test-tools.in b/requirements/test-tools.in
index f6f5c01d..e9d49af0 100644
--- a/requirements/test-tools.in
+++ b/requirements/test-tools.in
@@ -6,3 +6,4 @@ freezegun
pyquery # integrates with webtest
requests-mock
tblib
+vcrpy
diff --git a/src/objects/accounts/tests/factories.py b/src/objects/accounts/tests/factories.py
index 5b8130b1..843f3953 100644
--- a/src/objects/accounts/tests/factories.py
+++ b/src/objects/accounts/tests/factories.py
@@ -1,8 +1,26 @@
-import factory.fuzzy
+from django.contrib.auth import get_user_model
+import factory
+from factory.django import DjangoModelFactory
-class UserFactory(factory.django.DjangoModelFactory):
+User = get_user_model()
+
+
+class UserFactory(DjangoModelFactory):
username = factory.Sequence(lambda n: f"user-{n}")
+ first_name = factory.Faker("first_name")
+ last_name = factory.Faker("last_name")
+ password = factory.PostGenerationMethodCall("set_password", "password")
class Meta:
- model = "accounts.User"
+ model = User
+
+ class Params:
+ superuser = factory.Trait(
+ is_staff=True,
+ is_superuser=True,
+ )
+
+
+class StaffUserFactory(UserFactory):
+ is_staff = True
diff --git a/src/objects/accounts/tests/keycloak_cassets/duplicate_email.yaml b/src/objects/accounts/tests/keycloak_cassets/duplicate_email.yaml
new file mode 100644
index 00000000..a0d778ab
--- /dev/null
+++ b/src/objects/accounts/tests/keycloak_cassets/duplicate_email.yaml
@@ -0,0 +1,314 @@
+interactions:
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.2
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/auth?response_type=code&scope=openid&client_id=testid&redirect_uri=http%3A%2F%2Ftestserver%2Foidc%2Fcallback%2F&state=not-a-random-string&nonce=not-a-random-string
+ response:
+ body:
+ string: "\n\n\n
\n \n
+ \ \n \n\n \n Sign
+ in to test\n \n \n \n \n \n \n \n\n\n\n\n
+ \ \n
\n
+ \ \n
\n
+ \
\n\n\n
\n \n\n\n\n\n\n
+ \
\n
\n\n
\n
\n\n\n"
+ headers:
+ Cache-Control:
+ - no-store, must-revalidate, max-age=0
+ Content-Language:
+ - en
+ Content-Security-Policy:
+ - frame-src 'self'; frame-ancestors 'self'; object-src 'none';
+ Content-Type:
+ - text/html;charset=utf-8
+ Referrer-Policy:
+ - no-referrer
+ Set-Cookie:
+ - AUTH_SESSION_ID=f4033f92-6082-4b67-91de-204b6293d837; Version=1; Path=/realms/test/;
+ SameSite=None; Secure; HttpOnly
+ - AUTH_SESSION_ID_LEGACY=f4033f92-6082-4b67-91de-204b6293d837; Version=1; Path=/realms/test/;
+ HttpOnly
+ - KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJjaWQiOiJ0ZXN0aWQiLCJwdHkiOiJvcGVuaWQtY29ubmVjdCIsInJ1cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsImFjdCI6IkFVVEhFTlRJQ0FURSIsIm5vdGVzIjp7InNjb3BlIjoib3BlbmlkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwicmVzcG9uc2VfdHlwZSI6ImNvZGUiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsInN0YXRlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyJ9fQ.f7ZABGR0O48xm61gDKLOR_LjWH9a59wtTbGXUfm78sI;
+ Version=1; Path=/realms/test/; HttpOnly
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Robots-Tag:
+ - none
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '4466'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: username=admin&password=admin&credentialId=&login=Sign+In
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ Content-Length:
+ - '57'
+ Content-Type:
+ - application/x-www-form-urlencoded
+ Cookie:
+ - AUTH_SESSION_ID_LEGACY=f4033f92-6082-4b67-91de-204b6293d837; KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJjaWQiOiJ0ZXN0aWQiLCJwdHkiOiJvcGVuaWQtY29ubmVjdCIsInJ1cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsImFjdCI6IkFVVEhFTlRJQ0FURSIsIm5vdGVzIjp7InNjb3BlIjoib3BlbmlkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwicmVzcG9uc2VfdHlwZSI6ImNvZGUiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsInN0YXRlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyJ9fQ.f7ZABGR0O48xm61gDKLOR_LjWH9a59wtTbGXUfm78sI
+ User-Agent:
+ - python-requests/2.32.2
+ method: POST
+ uri: http://localhost:8080/realms/test/login-actions/authenticate?session_code=ekaLl2knQ5W0JOqU-pWd9EJUL04yHboA65r0sLewO0o&execution=670fb55e-641e-4beb-bd17-3c0cb001b805&client_id=testid&tab_id=T1IA4iU9hSw
+ response:
+ body:
+ string: ''
+ headers:
+ Cache-Control:
+ - no-store, must-revalidate, max-age=0
+ Content-Security-Policy:
+ - frame-src 'self'; frame-ancestors 'self'; object-src 'none';
+ Location:
+ - http://testserver/oidc/callback/?state=not-a-random-string&session_state=f4033f92-6082-4b67-91de-204b6293d837&iss=http%3A%2F%2Flocalhost%3A8080%2Frealms%2Ftest&code=a60785e5-c76b-4abb-bae7-bcb8b677f352.f4033f92-6082-4b67-91de-204b6293d837.adf4ad83-4550-4619-9231-73bd8d700f45
+ Referrer-Policy:
+ - no-referrer
+ Set-Cookie:
+ - KEYCLOAK_LOCALE=; Version=1; Comment=Expiring cookie; Expires=Thu, 01-Jan-1970
+ 00:00:10 GMT; Max-Age=0; Path=/realms/test/; HttpOnly
+ - KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0;
+ Path=/realms/test/; HttpOnly
+ - KC_AUTH_STATE=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0;
+ Path=/realms/test/
+ - KEYCLOAK_IDENTITY=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjAxNTU4MzIsImlhdCI6MTcyMDExOTgzMiwianRpIjoiOTVhMjNhODItZTJkNy00MjhiLTk2YzMtZTQ3MTY4MWZlZjE2IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiU2VyaWFsaXplZC1JRCIsInNlc3Npb25fc3RhdGUiOiJmNDAzM2Y5Mi02MDgyLTRiNjctOTFkZS0yMDRiNjI5M2Q4MzciLCJzaWQiOiJmNDAzM2Y5Mi02MDgyLTRiNjctOTFkZS0yMDRiNjI5M2Q4MzciLCJzdGF0ZV9jaGVja2VyIjoiejJ6RTJOQUQtVl9MQWFGempodUduU25GUWtfM3J6djROb0Z6bnJkSmNTdyJ9.xUSgByKk3ctl91InyibAfW-GyBBzpuE98GqWETzVFnc;
+ Version=1; Path=/realms/test/; SameSite=None; Secure; HttpOnly
+ - KEYCLOAK_IDENTITY_LEGACY=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjAxNTU4MzIsImlhdCI6MTcyMDExOTgzMiwianRpIjoiOTVhMjNhODItZTJkNy00MjhiLTk2YzMtZTQ3MTY4MWZlZjE2IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiU2VyaWFsaXplZC1JRCIsInNlc3Npb25fc3RhdGUiOiJmNDAzM2Y5Mi02MDgyLTRiNjctOTFkZS0yMDRiNjI5M2Q4MzciLCJzaWQiOiJmNDAzM2Y5Mi02MDgyLTRiNjctOTFkZS0yMDRiNjI5M2Q4MzciLCJzdGF0ZV9jaGVja2VyIjoiejJ6RTJOQUQtVl9MQWFGempodUduU25GUWtfM3J6djROb0Z6bnJkSmNTdyJ9.xUSgByKk3ctl91InyibAfW-GyBBzpuE98GqWETzVFnc;
+ Version=1; Path=/realms/test/; HttpOnly
+ - KEYCLOAK_SESSION=test/6db2db87-de31-4e30-9f25-cefe5da8b154/f4033f92-6082-4b67-91de-204b6293d837;
+ Version=1; Expires=Fri, 05-Jul-2024 05:03:52 GMT; Max-Age=36000; Path=/realms/test/;
+ SameSite=None; Secure
+ - KEYCLOAK_SESSION_LEGACY=test/6db2db87-de31-4e30-9f25-cefe5da8b154/f4033f92-6082-4b67-91de-204b6293d837;
+ Version=1; Expires=Fri, 05-Jul-2024 05:03:52 GMT; Max-Age=36000; Path=/realms/test/
+ - KEYCLOAK_REMEMBER_ME=; Version=1; Comment=Expiring cookie; Expires=Thu, 01-Jan-1970
+ 00:00:10 GMT; Max-Age=0; Path=/realms/test/; HttpOnly
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Robots-Tag:
+ - none
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '0'
+ status:
+ code: 302
+ message: Found
+- request:
+ body: client_id=testid&client_secret=7DB3KUAAizYCcmZufpHRVOcD0TOkNO3I&grant_type=authorization_code&code=a60785e5-c76b-4abb-bae7-bcb8b677f352.f4033f92-6082-4b67-91de-204b6293d837.adf4ad83-4550-4619-9231-73bd8d700f45&redirect_uri=http%3A%2F%2Ftestserver%2Foidc%2Fcallback%2F
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ Content-Length:
+ - '267'
+ Content-Type:
+ - application/x-www-form-urlencoded
+ User-Agent:
+ - python-requests/2.32.2
+ method: POST
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/token
+ response:
+ body:
+ string: '{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjAxMjAxMzIsImlhdCI6MTcyMDExOTgzMiwiYXV0aF90aW1lIjoxNzIwMTE5ODMyLCJqdGkiOiJmZWNlMjkyNC0yNWE0LTQ3ZDQtYTU5OS0xZDZkZjMyNTQwMTAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGVzdGlkIiwibm9uY2UiOiJub3QtYS1yYW5kb20tc3RyaW5nIiwic2Vzc2lvbl9zdGF0ZSI6ImY0MDMzZjkyLTYwODItNGI2Ny05MWRlLTIwNGI2MjkzZDgzNyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovLzEyNy4wLjAuMTo4MDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSBrdmsgZ3JvdXBzIGJzbiIsInNpZCI6ImY0MDMzZjkyLTYwODItNGI2Ny05MWRlLTIwNGI2MjkzZDgzNyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJncm91cHMiOlsiUmVnaXN0cmVlcmRlcnMiLCJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl0sInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBleGFtcGxlLmNvbSJ9.tZi3mh6PY61AgfGs8SKfN6KFZFUlnbWke1bJTsESZWfgCqKJIr3rNFMGVZIke70VaSlfop_m-4w6om-ZWmO7Z-6aOGbG93-QDjfsXlLW331u8-hZBD2CYKjZuMXo6Pno6SmI2It_L6I0ZGgsVPsXNM6Vx_dYerL3LXOpfw4R3QMElKOvb9llTpsgByYkWnDJrP8nCPHGQvWjkYepNkC6C1Hg51NT6l3MROQt5KDT74NWwFIfsYc2RPIABRVWY-vuWF_w01-zPkf34kfV5-02Qv8VYcQbFEx0oDbDzMHeDOzI6Je1RCwBsgEjy8OAtXrVwwJSUSx3qSyMYZlwkoGgbw","expires_in":300,"refresh_expires_in":1800,"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjAxMjE2MzIsImlhdCI6MTcyMDExOTgzMiwianRpIjoiYjUwNWQzNjYtNjAxNC00MmNlLTk0M2EtZDEyMmEzMzY5MjBkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InRlc3RpZCIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsInNlc3Npb25fc3RhdGUiOiJmNDAzM2Y5Mi02MDgyLTRiNjctOTFkZS0yMDRiNjI5M2Q4MzciLCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIGt2ayBncm91cHMgYnNuIiwic2lkIjoiZjQwMzNmOTItNjA4Mi00YjY3LTkxZGUtMjA0YjYyOTNkODM3In0.Wp4GdI_ynIGdc-ZzPSml8PkkXWywFMqBvcyv_J_JslI","token_type":"Bearer","id_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjAxMjAxMzIsImlhdCI6MTcyMDExOTgzMiwiYXV0aF90aW1lIjoxNzIwMTE5ODMyLCJqdGkiOiI2ZjYyMmFiZi00ZTRhLTRjNTQtYjBjZi1hZTFiYTk5NTY0MWIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJ0ZXN0aWQiLCJzdWIiOiI2ZGIyZGI4Ny1kZTMxLTRlMzAtOWYyNS1jZWZlNWRhOGIxNTQiLCJ0eXAiOiJJRCIsImF6cCI6InRlc3RpZCIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsInNlc3Npb25fc3RhdGUiOiJmNDAzM2Y5Mi02MDgyLTRiNjctOTFkZS0yMDRiNjI5M2Q4MzciLCJhdF9oYXNoIjoiQWplTjMzdEtFUUpjblY2M1hOMVVHUSIsImFjciI6IjEiLCJzaWQiOiJmNDAzM2Y5Mi02MDgyLTRiNjctOTFkZS0yMDRiNjI5M2Q4MzciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZ3JvdXBzIjpbIlJlZ2lzdHJlZXJkZXJzIiwiZGVmYXVsdC1yb2xlcy10ZXN0Iiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20ifQ.UWne7fWO36zAESCpdGsGuDZj0FwFggt75MwCgOebJ23mXLKqhIhWsuPD-ST4QsYouwkf1ref0fXqZDCMcDFCikBEK5zc-Gqw4OTeAIkwwUx_J5CFCWA64pJKYgt2rqOgems9wsLLY3DssW8BzGpqB74biTtqtlt2O6qHHaenH1F5e_Y3bSHuiUhxR7EQnG83IOpd4cPwVteU6lxkAIXUVq85Xso_Ntu_DBcnMRyCdx8uYbT3K2C8iLt9SojtQ13szTefWtj6ygSNTmoR0rpj2mQuX6ouKAxh1q3kMHTgvKLcEkUda7TzHNuomPQ0U5mQFJBzpGJ8KWtS2s7MIoEJhw","not-before-policy":0,"session_state":"f4033f92-6082-4b67-91de-204b6293d837","scope":"openid
+ email profile kvk groups bsn"}'
+ headers:
+ Cache-Control:
+ - no-store
+ Content-Type:
+ - application/json
+ Pragma:
+ - no-cache
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '3698'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.2
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/certs
+ response:
+ body:
+ string: '{"keys":[{"kid":"4UNQAcvUcv-DFUOx_4O1gt13OdJSotqEKPZurs2vQW8","kty":"RSA","alg":"RS256","use":"sig","n":"2DOZ0qHie73SuFVR7civrl6r82YUiAghfzaMowjCg0o06AF--2lIS7vNV_PbsVVznPAAMqVrNG-8CcevEzvVZMQD9nH4DI7xlOxK0lrYu8rmMeSfOvXVbBVsWBZe0jnGNukZqjwmRE5__ttJdxPfIBT5-2L6mguQbDfhSUEEdIW7y7UfOXvqLqEcBtoIEB-ORKDTUIQwGZM5mSCy-cY3cHvvZfZVgaUUy5NvujPRXTMje4n_hG0KfEV-40G9qC2_Xvx4EooJzBZ6FSThiWhCpwhIvzcQqB6M9lHW7nU6wADhYPNCa2OKWvphwZ_zbrF4B9dmS6Zli5rBvbox9Hh45w","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMLTANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgzmdKh4nu90rhVUe3Ir65eq/NmFIgIIX82jKMIwoNKNOgBfvtpSEu7zVfz27FVc5zwADKlazRvvAnHrxM71WTEA/Zx+AyO8ZTsStJa2LvK5jHknzr11WwVbFgWXtI5xjbpGao8JkROf/7bSXcT3yAU+fti+poLkGw34UlBBHSFu8u1Hzl76i6hHAbaCBAfjkSg01CEMBmTOZkgsvnGN3B772X2VYGlFMuTb7oz0V0zI3uJ/4RtCnxFfuNBvagtv178eBKKCcwWehUk4YloQqcISL83EKgejPZR1u51OsAA4WDzQmtjilr6YcGf826xeAfXZkumZYuawb26MfR4eOcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsnQG/Yi2g1XTCJn74hWv9MjxVAaZb4gBAc2AWm5VgAjhFEM9h6x6m1mQkq7JM4rIdAj8jw55Ok9CBVBIqq4G4cME3eUvVytkj2lC9zcRoAivjjZF2HPg7zNPa2TTR50asmHPRokppV6gewO/C+o5as+4P2zqDXBh61aRd/9kdQfkg14LBbH5/dYccAuvUqlTYC4IEPCvVmBNC1xsMjf0vohvoSjm9vL2bfqG/RJH0ScdCjOd5d2zju4/e2oVdluWm+vzKBQplc7tVMuKpn6LcLmVHiGNAl+EBIZH+WVLlTx0D1+kbHZsfLYG53lQg2LsvurRbWyF/a5fVM/oLTn5ag=="],"x5t":"H5xfs1pRtvX0HyVTskx7eTXx88U","x5t#S256":"XurVtKAIEyc4w9HCGOhnjoRHnYu4d9HCn_5YHmkScJg"},{"kid":"TV3Tl5jIY1nrJLSb53UKEubLR5gYiq9slq1SsDDg1HU","kty":"RSA","alg":"RSA-OAEP","use":"enc","n":"pNvU3ecpVHbJT4bCOEpw6cnV1yi65tB3I0bRF2ilLVOY944QRAGnjBBECPIzNbgqavghYp1j75F2nq6_ny1CYfoaxTV2iDpRUw8_f7sliYbl8FrLLat0S25ItlZrg5TEJHObvOqlG2_nXoeH36MRWwNhms2uCqfhn5VgtenIzpQIBolnM7zzGp21NvdJ1C_ZAUzkXC-l3oQ-BXTtpEVM4h2KpYh4gfZJWCbYij5d1e1YApKD6V61_Cs3Oa2OY7CAUyq5kgAWJZFDB6CpzIr226u3bV7F9RbrQu3Ybc_Lv33EwykscLznKWZY2Mbs3Iz_rFNv3sVX_vHpH4DHWlKu7Q","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMlzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTb1N3nKVR2yU+GwjhKcOnJ1dcouubQdyNG0RdopS1TmPeOEEQBp4wQRAjyMzW4Kmr4IWKdY++Rdp6uv58tQmH6GsU1dog6UVMPP3+7JYmG5fBayy2rdEtuSLZWa4OUxCRzm7zqpRtv516Hh9+jEVsDYZrNrgqn4Z+VYLXpyM6UCAaJZzO88xqdtTb3SdQv2QFM5Fwvpd6EPgV07aRFTOIdiqWIeIH2SVgm2Io+XdXtWAKSg+letfwrNzmtjmOwgFMquZIAFiWRQwegqcyK9turt21exfUW60Lt2G3Py799xMMpLHC85ylmWNjG7NyM/6xTb97FV/7x6R+Ax1pSru0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAQGJHeTYSMvp0yndbIn7DLohO9lom5nRrx/bLyb7TiRfogyJEF6rQZ66CAkQFk5eMF878fsHTuMVjtmXVBnhojhVmK91HwjsNQu/8xR6QMXNKJQMvHR245vwUGxlWRw/36ObM1D7QjCd/q+FonpBEY4m5Y6Uz1U0HR2Cbh0E2afVlPLeV+F0LKrlyVMdIaWBGWftCGIKDAHaG/PD66zbAKtxerv2fBIDq100WHPhd57BZxX+2aGJp1IaRDgkxV0E/CjEy3+Knd8xbAgUSW0Tl6OTC75exIvlbzeluEBe0wlapAb7WvBKYsipSW8G8Ey7tjoolDT4AU82EaKUPstiMnA=="],"x5t":"AlfHDI0FOPQpt3RBAILt0dtW1yw","x5t#S256":"a7bhm8-JsnfY7bL_m8Yl72hgmp5516VZlFcVloKzk08"}]}'
+ headers:
+ Cache-Control:
+ - no-cache
+ Content-Type:
+ - application/json;charset=UTF-8
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '2909'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjAxMjAxMzIsImlhdCI6MTcyMDExOTgzMiwiYXV0aF90aW1lIjoxNzIwMTE5ODMyLCJqdGkiOiJmZWNlMjkyNC0yNWE0LTQ3ZDQtYTU5OS0xZDZkZjMyNTQwMTAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGVzdGlkIiwibm9uY2UiOiJub3QtYS1yYW5kb20tc3RyaW5nIiwic2Vzc2lvbl9zdGF0ZSI6ImY0MDMzZjkyLTYwODItNGI2Ny05MWRlLTIwNGI2MjkzZDgzNyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovLzEyNy4wLjAuMTo4MDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSBrdmsgZ3JvdXBzIGJzbiIsInNpZCI6ImY0MDMzZjkyLTYwODItNGI2Ny05MWRlLTIwNGI2MjkzZDgzNyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJncm91cHMiOlsiUmVnaXN0cmVlcmRlcnMiLCJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl0sInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBleGFtcGxlLmNvbSJ9.tZi3mh6PY61AgfGs8SKfN6KFZFUlnbWke1bJTsESZWfgCqKJIr3rNFMGVZIke70VaSlfop_m-4w6om-ZWmO7Z-6aOGbG93-QDjfsXlLW331u8-hZBD2CYKjZuMXo6Pno6SmI2It_L6I0ZGgsVPsXNM6Vx_dYerL3LXOpfw4R3QMElKOvb9llTpsgByYkWnDJrP8nCPHGQvWjkYepNkC6C1Hg51NT6l3MROQt5KDT74NWwFIfsYc2RPIABRVWY-vuWF_w01-zPkf34kfV5-02Qv8VYcQbFEx0oDbDzMHeDOzI6Je1RCwBsgEjy8OAtXrVwwJSUSx3qSyMYZlwkoGgbw
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.2
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/userinfo
+ response:
+ body:
+ string: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJzdWIiOiI2ZGIyZGI4Ny1kZTMxLTRlMzAtOWYyNS1jZWZlNWRhOGIxNTQiLCJhdWQiOiJ0ZXN0aWQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwiZ3JvdXBzIjpbIlJlZ2lzdHJlZXJkZXJzIiwiZGVmYXVsdC1yb2xlcy10ZXN0Iiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20ifQ.vx4dCJ-Y-PEzjy8p7CNPB3yy0TyV_QugOHRbiV6UY3qHtZUnZqSsJD991QUostcYECuyTHefqfRtdCbvSJcPWI4ucosY65vshUMBtQeahsFOgNwWp2BvCkALJmEya4H_gh63vVlVZ2ZOSpWpah6eV2PNhiiYWD-Y9qEuLMzwngNvp5hna30BiRKAEsStB7izjE5pGECqkQm7pxCeZWHU81Lbh5fSo_2XvcGZ1Z-tf6DN95Oz4ers9YrG6dKSuh-HciY1zhv7mcee_tlJaeKjITue6r06163oKdjsYKRpiR4bLQ9256KafoxmU6O0IIlpkQhmtXrmaFSg0XyBYU8qcQ
+ headers:
+ Cache-Control:
+ - no-cache
+ Content-Type:
+ - application/jwt
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '813'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.2
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/certs
+ response:
+ body:
+ string: '{"keys":[{"kid":"4UNQAcvUcv-DFUOx_4O1gt13OdJSotqEKPZurs2vQW8","kty":"RSA","alg":"RS256","use":"sig","n":"2DOZ0qHie73SuFVR7civrl6r82YUiAghfzaMowjCg0o06AF--2lIS7vNV_PbsVVznPAAMqVrNG-8CcevEzvVZMQD9nH4DI7xlOxK0lrYu8rmMeSfOvXVbBVsWBZe0jnGNukZqjwmRE5__ttJdxPfIBT5-2L6mguQbDfhSUEEdIW7y7UfOXvqLqEcBtoIEB-ORKDTUIQwGZM5mSCy-cY3cHvvZfZVgaUUy5NvujPRXTMje4n_hG0KfEV-40G9qC2_Xvx4EooJzBZ6FSThiWhCpwhIvzcQqB6M9lHW7nU6wADhYPNCa2OKWvphwZ_zbrF4B9dmS6Zli5rBvbox9Hh45w","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMLTANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgzmdKh4nu90rhVUe3Ir65eq/NmFIgIIX82jKMIwoNKNOgBfvtpSEu7zVfz27FVc5zwADKlazRvvAnHrxM71WTEA/Zx+AyO8ZTsStJa2LvK5jHknzr11WwVbFgWXtI5xjbpGao8JkROf/7bSXcT3yAU+fti+poLkGw34UlBBHSFu8u1Hzl76i6hHAbaCBAfjkSg01CEMBmTOZkgsvnGN3B772X2VYGlFMuTb7oz0V0zI3uJ/4RtCnxFfuNBvagtv178eBKKCcwWehUk4YloQqcISL83EKgejPZR1u51OsAA4WDzQmtjilr6YcGf826xeAfXZkumZYuawb26MfR4eOcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsnQG/Yi2g1XTCJn74hWv9MjxVAaZb4gBAc2AWm5VgAjhFEM9h6x6m1mQkq7JM4rIdAj8jw55Ok9CBVBIqq4G4cME3eUvVytkj2lC9zcRoAivjjZF2HPg7zNPa2TTR50asmHPRokppV6gewO/C+o5as+4P2zqDXBh61aRd/9kdQfkg14LBbH5/dYccAuvUqlTYC4IEPCvVmBNC1xsMjf0vohvoSjm9vL2bfqG/RJH0ScdCjOd5d2zju4/e2oVdluWm+vzKBQplc7tVMuKpn6LcLmVHiGNAl+EBIZH+WVLlTx0D1+kbHZsfLYG53lQg2LsvurRbWyF/a5fVM/oLTn5ag=="],"x5t":"H5xfs1pRtvX0HyVTskx7eTXx88U","x5t#S256":"XurVtKAIEyc4w9HCGOhnjoRHnYu4d9HCn_5YHmkScJg"},{"kid":"TV3Tl5jIY1nrJLSb53UKEubLR5gYiq9slq1SsDDg1HU","kty":"RSA","alg":"RSA-OAEP","use":"enc","n":"pNvU3ecpVHbJT4bCOEpw6cnV1yi65tB3I0bRF2ilLVOY944QRAGnjBBECPIzNbgqavghYp1j75F2nq6_ny1CYfoaxTV2iDpRUw8_f7sliYbl8FrLLat0S25ItlZrg5TEJHObvOqlG2_nXoeH36MRWwNhms2uCqfhn5VgtenIzpQIBolnM7zzGp21NvdJ1C_ZAUzkXC-l3oQ-BXTtpEVM4h2KpYh4gfZJWCbYij5d1e1YApKD6V61_Cs3Oa2OY7CAUyq5kgAWJZFDB6CpzIr226u3bV7F9RbrQu3Ybc_Lv33EwykscLznKWZY2Mbs3Iz_rFNv3sVX_vHpH4DHWlKu7Q","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMlzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTb1N3nKVR2yU+GwjhKcOnJ1dcouubQdyNG0RdopS1TmPeOEEQBp4wQRAjyMzW4Kmr4IWKdY++Rdp6uv58tQmH6GsU1dog6UVMPP3+7JYmG5fBayy2rdEtuSLZWa4OUxCRzm7zqpRtv516Hh9+jEVsDYZrNrgqn4Z+VYLXpyM6UCAaJZzO88xqdtTb3SdQv2QFM5Fwvpd6EPgV07aRFTOIdiqWIeIH2SVgm2Io+XdXtWAKSg+letfwrNzmtjmOwgFMquZIAFiWRQwegqcyK9turt21exfUW60Lt2G3Py799xMMpLHC85ylmWNjG7NyM/6xTb97FV/7x6R+Ax1pSru0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAQGJHeTYSMvp0yndbIn7DLohO9lom5nRrx/bLyb7TiRfogyJEF6rQZ66CAkQFk5eMF878fsHTuMVjtmXVBnhojhVmK91HwjsNQu/8xR6QMXNKJQMvHR245vwUGxlWRw/36ObM1D7QjCd/q+FonpBEY4m5Y6Uz1U0HR2Cbh0E2afVlPLeV+F0LKrlyVMdIaWBGWftCGIKDAHaG/PD66zbAKtxerv2fBIDq100WHPhd57BZxX+2aGJp1IaRDgkxV0E/CjEy3+Knd8xbAgUSW0Tl6OTC75exIvlbzeluEBe0wlapAb7WvBKYsipSW8G8Ey7tjoolDT4AU82EaKUPstiMnA=="],"x5t":"AlfHDI0FOPQpt3RBAILt0dtW1yw","x5t#S256":"a7bhm8-JsnfY7bL_m8Yl72hgmp5516VZlFcVloKzk08"}]}'
+ headers:
+ Cache-Control:
+ - no-cache
+ Content-Type:
+ - application/json;charset=UTF-8
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '2909'
+ status:
+ code: 200
+ message: OK
+version: 1
diff --git a/src/objects/accounts/tests/keycloak_cassets/happy_flow.yaml b/src/objects/accounts/tests/keycloak_cassets/happy_flow.yaml
new file mode 100644
index 00000000..388adf3d
--- /dev/null
+++ b/src/objects/accounts/tests/keycloak_cassets/happy_flow.yaml
@@ -0,0 +1,314 @@
+interactions:
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.3
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/auth?response_type=code&scope=openid&client_id=testid&redirect_uri=http%3A%2F%2Ftestserver%2Foidc%2Fcallback%2F&state=not-a-random-string&nonce=not-a-random-string
+ response:
+ body:
+ string: "\n\n\n\n \n
+ \ \n \n\n \n Sign
+ in to test\n \n \n \n \n \n \n \n\n\n\n\n
+ \ \n
\n
+ \ \n
\n
+ \
\n\n\n
\n \n\n\n\n\n\n
+ \
\n
\n\n
\n
\n\n\n"
+ headers:
+ Cache-Control:
+ - no-store, must-revalidate, max-age=0
+ Content-Language:
+ - en
+ Content-Security-Policy:
+ - frame-src 'self'; frame-ancestors 'self'; object-src 'none';
+ Content-Type:
+ - text/html;charset=utf-8
+ Referrer-Policy:
+ - no-referrer
+ Set-Cookie:
+ - AUTH_SESSION_ID=fd1dfa4b-5306-4095-a37d-64c6122de3b2; Version=1; Path=/realms/test/;
+ SameSite=None; Secure; HttpOnly
+ - AUTH_SESSION_ID_LEGACY=fd1dfa4b-5306-4095-a37d-64c6122de3b2; Version=1; Path=/realms/test/;
+ HttpOnly
+ - KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJjaWQiOiJ0ZXN0aWQiLCJwdHkiOiJvcGVuaWQtY29ubmVjdCIsInJ1cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsImFjdCI6IkFVVEhFTlRJQ0FURSIsIm5vdGVzIjp7InNjb3BlIjoib3BlbmlkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwicmVzcG9uc2VfdHlwZSI6ImNvZGUiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsInN0YXRlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyJ9fQ.f7ZABGR0O48xm61gDKLOR_LjWH9a59wtTbGXUfm78sI;
+ Version=1; Path=/realms/test/; HttpOnly
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Robots-Tag:
+ - none
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '4474'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: username=admin&password=admin&credentialId=&login=Sign+In
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate
+ Connection:
+ - keep-alive
+ Content-Length:
+ - '57'
+ Content-Type:
+ - application/x-www-form-urlencoded
+ Cookie:
+ - AUTH_SESSION_ID_LEGACY=fd1dfa4b-5306-4095-a37d-64c6122de3b2; KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJjaWQiOiJ0ZXN0aWQiLCJwdHkiOiJvcGVuaWQtY29ubmVjdCIsInJ1cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsImFjdCI6IkFVVEhFTlRJQ0FURSIsIm5vdGVzIjp7InNjb3BlIjoib3BlbmlkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwicmVzcG9uc2VfdHlwZSI6ImNvZGUiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsInN0YXRlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyJ9fQ.f7ZABGR0O48xm61gDKLOR_LjWH9a59wtTbGXUfm78sI
+ User-Agent:
+ - python-requests/2.32.3
+ method: POST
+ uri: http://localhost:8080/realms/test/login-actions/authenticate?session_code=_BlhjuNy-r1uZKZi6uW7-MuqhG0ssYsdl32-1WXsHLE&execution=d5d6e7a6-23bf-482a-9dba-67b020da2142&client_id=testid&tab_id=Ve6V_UZ-O7k
+ response:
+ body:
+ string: ''
+ headers:
+ Cache-Control:
+ - no-store, must-revalidate, max-age=0
+ Content-Security-Policy:
+ - frame-src 'self'; frame-ancestors 'self'; object-src 'none';
+ Location:
+ - http://testserver/oidc/callback/?state=not-a-random-string&session_state=fd1dfa4b-5306-4095-a37d-64c6122de3b2&iss=http%3A%2F%2Flocalhost%3A8080%2Frealms%2Ftest&code=cae98c69-0cc1-40b9-b9ae-f17ea06e4b10.fd1dfa4b-5306-4095-a37d-64c6122de3b2.adf4ad83-4550-4619-9231-73bd8d700f45
+ Referrer-Policy:
+ - no-referrer
+ Set-Cookie:
+ - KEYCLOAK_LOCALE=; Version=1; Comment=Expiring cookie; Expires=Thu, 01-Jan-1970
+ 00:00:10 GMT; Max-Age=0; Path=/realms/test/; HttpOnly
+ - KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0;
+ Path=/realms/test/; HttpOnly
+ - KC_AUTH_STATE=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0;
+ Path=/realms/test/
+ - KEYCLOAK_IDENTITY=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjI1ODM1ODMsImlhdCI6MTcyMjU0NzU4MywianRpIjoiODRhZDFhZmQtNDU2NS00NzJmLWE2ZmQtNDY5ZWRkNTZiYWMxIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiMTM1NmMyYzItMDFlMC00MjhlLThmOTMtOWEwZGQ4Yzk1M2ZmIiwidHlwIjoiU2VyaWFsaXplZC1JRCIsInNlc3Npb25fc3RhdGUiOiJmZDFkZmE0Yi01MzA2LTQwOTUtYTM3ZC02NGM2MTIyZGUzYjIiLCJzaWQiOiJmZDFkZmE0Yi01MzA2LTQwOTUtYTM3ZC02NGM2MTIyZGUzYjIiLCJzdGF0ZV9jaGVja2VyIjoiZ29fTVNBX2VzR014OHF4S0Y0UkwxbUREUHNaVGUwczJMeXBsSEdHdmNNMCJ9.IcKOQwbSaTu1K9vWpy7LnzWalO4-snhnv4G_cN0cjdE;
+ Version=1; Path=/realms/test/; SameSite=None; Secure; HttpOnly
+ - KEYCLOAK_IDENTITY_LEGACY=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjI1ODM1ODMsImlhdCI6MTcyMjU0NzU4MywianRpIjoiODRhZDFhZmQtNDU2NS00NzJmLWE2ZmQtNDY5ZWRkNTZiYWMxIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiMTM1NmMyYzItMDFlMC00MjhlLThmOTMtOWEwZGQ4Yzk1M2ZmIiwidHlwIjoiU2VyaWFsaXplZC1JRCIsInNlc3Npb25fc3RhdGUiOiJmZDFkZmE0Yi01MzA2LTQwOTUtYTM3ZC02NGM2MTIyZGUzYjIiLCJzaWQiOiJmZDFkZmE0Yi01MzA2LTQwOTUtYTM3ZC02NGM2MTIyZGUzYjIiLCJzdGF0ZV9jaGVja2VyIjoiZ29fTVNBX2VzR014OHF4S0Y0UkwxbUREUHNaVGUwczJMeXBsSEdHdmNNMCJ9.IcKOQwbSaTu1K9vWpy7LnzWalO4-snhnv4G_cN0cjdE;
+ Version=1; Path=/realms/test/; HttpOnly
+ - KEYCLOAK_SESSION=test/1356c2c2-01e0-428e-8f93-9a0dd8c953ff/fd1dfa4b-5306-4095-a37d-64c6122de3b2;
+ Version=1; Expires=Fri, 02-Aug-2024 07:26:23 GMT; Max-Age=36000; Path=/realms/test/;
+ SameSite=None; Secure
+ - KEYCLOAK_SESSION_LEGACY=test/1356c2c2-01e0-428e-8f93-9a0dd8c953ff/fd1dfa4b-5306-4095-a37d-64c6122de3b2;
+ Version=1; Expires=Fri, 02-Aug-2024 07:26:23 GMT; Max-Age=36000; Path=/realms/test/
+ - KEYCLOAK_REMEMBER_ME=; Version=1; Comment=Expiring cookie; Expires=Thu, 01-Jan-1970
+ 00:00:10 GMT; Max-Age=0; Path=/realms/test/; HttpOnly
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Robots-Tag:
+ - none
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '0'
+ status:
+ code: 302
+ message: Found
+- request:
+ body: client_id=testid&client_secret=7DB3KUAAizYCcmZufpHRVOcD0TOkNO3I&grant_type=authorization_code&code=cae98c69-0cc1-40b9-b9ae-f17ea06e4b10.fd1dfa4b-5306-4095-a37d-64c6122de3b2.adf4ad83-4550-4619-9231-73bd8d700f45&redirect_uri=http%3A%2F%2Ftestserver%2Foidc%2Fcallback%2F
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate
+ Connection:
+ - keep-alive
+ Content-Length:
+ - '267'
+ Content-Type:
+ - application/x-www-form-urlencoded
+ User-Agent:
+ - python-requests/2.32.3
+ method: POST
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/token
+ response:
+ body:
+ string: '{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjI1NDc4ODMsImlhdCI6MTcyMjU0NzU4MywiYXV0aF90aW1lIjoxNzIyNTQ3NTgzLCJqdGkiOiJmYjU0NmI1Mi0wMDcyLTQ3M2UtYWVmYS03MTcwMjMzZjljOTciLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMTM1NmMyYzItMDFlMC00MjhlLThmOTMtOWEwZGQ4Yzk1M2ZmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGVzdGlkIiwibm9uY2UiOiJub3QtYS1yYW5kb20tc3RyaW5nIiwic2Vzc2lvbl9zdGF0ZSI6ImZkMWRmYTRiLTUzMDYtNDA5NS1hMzdkLTY0YzYxMjJkZTNiMiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovLzEyNy4wLjAuMTo4MDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSBrdmsgYnNuIiwic2lkIjoiZmQxZGZhNGItNTMwNi00MDk1LWEzN2QtNjRjNjEyMmRlM2IyIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsIm5hbWUiOiJhZG1pbiBhZG1pbiIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZ2l2ZW5fbmFtZSI6ImFkbWluIiwiZmFtaWx5X25hbWUiOiJhZG1pbiIsImVtYWlsIjoiYWRtaW5AYWRtaW4uYWRtaW4ifQ.in3vUi9Ml3XQSZ74DMDYUeLIjkcwmxl6r2yL0TSHfATYicjkLjx4YPyicF8NdgiXSHgjoz-zRYMqvNLmcV5gs-pNfLQ0D5hlEvv0UYEM5KsJe6x_FWqUKXkldeHl5L0TUIdzWrkJWLSzxdkK0hjbLVbqPG9JHf7V0OJyQcRF4syXoHj5CAXDn1IThVGN4WojkQwZAiv_CWYOlVVDlCU5cRP68pszf32K4ePkPVkl-YrBxJ9ZYoOofLEWe0PSjActdpjnsRKRQW5Vs0pjLsFnt7yX20NrvzH_lQy25wZArhYS4NL7UgZqugsIyCulzXoedNv-J655_gQSoq52utIkww","expires_in":300,"refresh_expires_in":1800,"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjI1NDkzODMsImlhdCI6MTcyMjU0NzU4MywianRpIjoiMTllNDM1YmItYzBjNy00MGM5LTk4OGItYzIxZmZlMTUzMzU0IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiMTM1NmMyYzItMDFlMC00MjhlLThmOTMtOWEwZGQ4Yzk1M2ZmIiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InRlc3RpZCIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsInNlc3Npb25fc3RhdGUiOiJmZDFkZmE0Yi01MzA2LTQwOTUtYTM3ZC02NGM2MTIyZGUzYjIiLCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIGt2ayBic24iLCJzaWQiOiJmZDFkZmE0Yi01MzA2LTQwOTUtYTM3ZC02NGM2MTIyZGUzYjIifQ.xypid3BhX4BhjW-OXTlmtaV2_pa0mY5mLXmmV1rzfo0","token_type":"Bearer","id_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjI1NDc4ODMsImlhdCI6MTcyMjU0NzU4MywiYXV0aF90aW1lIjoxNzIyNTQ3NTgzLCJqdGkiOiJiMDM4MzY2Yi02ZDU0LTQ5ZTQtOTgwMS1iNjZhMWVhYWM2YjUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJ0ZXN0aWQiLCJzdWIiOiIxMzU2YzJjMi0wMWUwLTQyOGUtOGY5My05YTBkZDhjOTUzZmYiLCJ0eXAiOiJJRCIsImF6cCI6InRlc3RpZCIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsInNlc3Npb25fc3RhdGUiOiJmZDFkZmE0Yi01MzA2LTQwOTUtYTM3ZC02NGM2MTIyZGUzYjIiLCJhdF9oYXNoIjoiMnJDNGdxM3ZvOWF5a1FpX0FXOV9wQSIsImFjciI6IjEiLCJzaWQiOiJmZDFkZmE0Yi01MzA2LTQwOTUtYTM3ZC02NGM2MTIyZGUzYjIiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6ImFkbWluIGFkbWluIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiYWRtaW4iLCJnaXZlbl9uYW1lIjoiYWRtaW4iLCJmYW1pbHlfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBhZG1pbi5hZG1pbiJ9.WIcn6D7fw3Hp1T6iA7C7nj46ivX0vbvwjl1P9UQT5CcmM8tVOoD8Bs85WtnfpdWwFsCgfcTBXKt_Mpr007ThZzdY67GssbQ50d7uKwb2ilUDxA4OU3fLtq9qBxtzk3xp3WxEaKxJ7i9IlBjPtdHARJlpAfvrS7CTVyUbWIeA-Gd_6rCXUFozOBsIqL9gpqXaBYj0XeleXhgtB_yhphHLrZvCxNK3jPcBlsT-fUx54RdDqBFm54mmoXss3A5xNp1YpnkpJ33QjN0DKf540Zc3IwA2Go8Cd_26XFUwpPJD5GBZIAC91a90X-EYbknqOBY47Ll8C6FY3mwEJ6fnI9RRGQ","not-before-policy":0,"session_state":"fd1dfa4b-5306-4095-a37d-64c6122de3b2","scope":"openid
+ email profile kvk bsn"}'
+ headers:
+ Cache-Control:
+ - no-store
+ Content-Type:
+ - application/json
+ Pragma:
+ - no-cache
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '3614'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.3
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/certs
+ response:
+ body:
+ string: '{"keys":[{"kid":"4UNQAcvUcv-DFUOx_4O1gt13OdJSotqEKPZurs2vQW8","kty":"RSA","alg":"RS256","use":"sig","n":"2DOZ0qHie73SuFVR7civrl6r82YUiAghfzaMowjCg0o06AF--2lIS7vNV_PbsVVznPAAMqVrNG-8CcevEzvVZMQD9nH4DI7xlOxK0lrYu8rmMeSfOvXVbBVsWBZe0jnGNukZqjwmRE5__ttJdxPfIBT5-2L6mguQbDfhSUEEdIW7y7UfOXvqLqEcBtoIEB-ORKDTUIQwGZM5mSCy-cY3cHvvZfZVgaUUy5NvujPRXTMje4n_hG0KfEV-40G9qC2_Xvx4EooJzBZ6FSThiWhCpwhIvzcQqB6M9lHW7nU6wADhYPNCa2OKWvphwZ_zbrF4B9dmS6Zli5rBvbox9Hh45w","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMLTANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgzmdKh4nu90rhVUe3Ir65eq/NmFIgIIX82jKMIwoNKNOgBfvtpSEu7zVfz27FVc5zwADKlazRvvAnHrxM71WTEA/Zx+AyO8ZTsStJa2LvK5jHknzr11WwVbFgWXtI5xjbpGao8JkROf/7bSXcT3yAU+fti+poLkGw34UlBBHSFu8u1Hzl76i6hHAbaCBAfjkSg01CEMBmTOZkgsvnGN3B772X2VYGlFMuTb7oz0V0zI3uJ/4RtCnxFfuNBvagtv178eBKKCcwWehUk4YloQqcISL83EKgejPZR1u51OsAA4WDzQmtjilr6YcGf826xeAfXZkumZYuawb26MfR4eOcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsnQG/Yi2g1XTCJn74hWv9MjxVAaZb4gBAc2AWm5VgAjhFEM9h6x6m1mQkq7JM4rIdAj8jw55Ok9CBVBIqq4G4cME3eUvVytkj2lC9zcRoAivjjZF2HPg7zNPa2TTR50asmHPRokppV6gewO/C+o5as+4P2zqDXBh61aRd/9kdQfkg14LBbH5/dYccAuvUqlTYC4IEPCvVmBNC1xsMjf0vohvoSjm9vL2bfqG/RJH0ScdCjOd5d2zju4/e2oVdluWm+vzKBQplc7tVMuKpn6LcLmVHiGNAl+EBIZH+WVLlTx0D1+kbHZsfLYG53lQg2LsvurRbWyF/a5fVM/oLTn5ag=="],"x5t":"H5xfs1pRtvX0HyVTskx7eTXx88U","x5t#S256":"XurVtKAIEyc4w9HCGOhnjoRHnYu4d9HCn_5YHmkScJg"},{"kid":"TV3Tl5jIY1nrJLSb53UKEubLR5gYiq9slq1SsDDg1HU","kty":"RSA","alg":"RSA-OAEP","use":"enc","n":"pNvU3ecpVHbJT4bCOEpw6cnV1yi65tB3I0bRF2ilLVOY944QRAGnjBBECPIzNbgqavghYp1j75F2nq6_ny1CYfoaxTV2iDpRUw8_f7sliYbl8FrLLat0S25ItlZrg5TEJHObvOqlG2_nXoeH36MRWwNhms2uCqfhn5VgtenIzpQIBolnM7zzGp21NvdJ1C_ZAUzkXC-l3oQ-BXTtpEVM4h2KpYh4gfZJWCbYij5d1e1YApKD6V61_Cs3Oa2OY7CAUyq5kgAWJZFDB6CpzIr226u3bV7F9RbrQu3Ybc_Lv33EwykscLznKWZY2Mbs3Iz_rFNv3sVX_vHpH4DHWlKu7Q","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMlzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTb1N3nKVR2yU+GwjhKcOnJ1dcouubQdyNG0RdopS1TmPeOEEQBp4wQRAjyMzW4Kmr4IWKdY++Rdp6uv58tQmH6GsU1dog6UVMPP3+7JYmG5fBayy2rdEtuSLZWa4OUxCRzm7zqpRtv516Hh9+jEVsDYZrNrgqn4Z+VYLXpyM6UCAaJZzO88xqdtTb3SdQv2QFM5Fwvpd6EPgV07aRFTOIdiqWIeIH2SVgm2Io+XdXtWAKSg+letfwrNzmtjmOwgFMquZIAFiWRQwegqcyK9turt21exfUW60Lt2G3Py799xMMpLHC85ylmWNjG7NyM/6xTb97FV/7x6R+Ax1pSru0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAQGJHeTYSMvp0yndbIn7DLohO9lom5nRrx/bLyb7TiRfogyJEF6rQZ66CAkQFk5eMF878fsHTuMVjtmXVBnhojhVmK91HwjsNQu/8xR6QMXNKJQMvHR245vwUGxlWRw/36ObM1D7QjCd/q+FonpBEY4m5Y6Uz1U0HR2Cbh0E2afVlPLeV+F0LKrlyVMdIaWBGWftCGIKDAHaG/PD66zbAKtxerv2fBIDq100WHPhd57BZxX+2aGJp1IaRDgkxV0E/CjEy3+Knd8xbAgUSW0Tl6OTC75exIvlbzeluEBe0wlapAb7WvBKYsipSW8G8Ey7tjoolDT4AU82EaKUPstiMnA=="],"x5t":"AlfHDI0FOPQpt3RBAILt0dtW1yw","x5t#S256":"a7bhm8-JsnfY7bL_m8Yl72hgmp5516VZlFcVloKzk08"}]}'
+ headers:
+ Cache-Control:
+ - no-cache
+ Content-Type:
+ - application/json;charset=UTF-8
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '2909'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjI1NDc4ODMsImlhdCI6MTcyMjU0NzU4MywiYXV0aF90aW1lIjoxNzIyNTQ3NTgzLCJqdGkiOiJmYjU0NmI1Mi0wMDcyLTQ3M2UtYWVmYS03MTcwMjMzZjljOTciLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMTM1NmMyYzItMDFlMC00MjhlLThmOTMtOWEwZGQ4Yzk1M2ZmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGVzdGlkIiwibm9uY2UiOiJub3QtYS1yYW5kb20tc3RyaW5nIiwic2Vzc2lvbl9zdGF0ZSI6ImZkMWRmYTRiLTUzMDYtNDA5NS1hMzdkLTY0YzYxMjJkZTNiMiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovLzEyNy4wLjAuMTo4MDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSBrdmsgYnNuIiwic2lkIjoiZmQxZGZhNGItNTMwNi00MDk1LWEzN2QtNjRjNjEyMmRlM2IyIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsIm5hbWUiOiJhZG1pbiBhZG1pbiIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZ2l2ZW5fbmFtZSI6ImFkbWluIiwiZmFtaWx5X25hbWUiOiJhZG1pbiIsImVtYWlsIjoiYWRtaW5AYWRtaW4uYWRtaW4ifQ.in3vUi9Ml3XQSZ74DMDYUeLIjkcwmxl6r2yL0TSHfATYicjkLjx4YPyicF8NdgiXSHgjoz-zRYMqvNLmcV5gs-pNfLQ0D5hlEvv0UYEM5KsJe6x_FWqUKXkldeHl5L0TUIdzWrkJWLSzxdkK0hjbLVbqPG9JHf7V0OJyQcRF4syXoHj5CAXDn1IThVGN4WojkQwZAiv_CWYOlVVDlCU5cRP68pszf32K4ePkPVkl-YrBxJ9ZYoOofLEWe0PSjActdpjnsRKRQW5Vs0pjLsFnt7yX20NrvzH_lQy25wZArhYS4NL7UgZqugsIyCulzXoedNv-J655_gQSoq52utIkww
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.3
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/userinfo
+ response:
+ body:
+ string: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJzdWIiOiIxMzU2YzJjMi0wMWUwLTQyOGUtOGY5My05YTBkZDhjOTUzZmYiLCJhdWQiOiJ0ZXN0aWQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6ImFkbWluIGFkbWluIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwicHJlZmVycmVkX3VzZXJuYW1lIjoiYWRtaW4iLCJnaXZlbl9uYW1lIjoiYWRtaW4iLCJmYW1pbHlfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBhZG1pbi5hZG1pbiJ9.s6mDhNLibfQz8GoNzdK1kxI1PtBOkoggYnDXflARWYnhztZucIhz77SrUu9e7rfyYdQZhNEAYu43MBeaUl9Z7ITf0qKrwruju54i51dwRcLxchu86SNxgmoDDj8000un4tpV-y6YTZ_QsaLevkTFhsT0OOv6mvzHvbu7AmJSQMnGNj4IZlvEc-8aJ-5dxGXNfdcyJeqVVB85j_M4SHNsYT2qLrU5A3oTL7g6h05l5Ex8MQ-uNCCDHBWSwmlfKwzyJiTtJS8TKwMiQnVYpebSuKhA36dXQd72DuaxQmejZodzrtXStS6w3yYAgUyIAfVdf7S5peLygs2IVqf_UNohzQ
+ headers:
+ Cache-Control:
+ - no-cache
+ Content-Type:
+ - application/jwt
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '783'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.3
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/certs
+ response:
+ body:
+ string: '{"keys":[{"kid":"4UNQAcvUcv-DFUOx_4O1gt13OdJSotqEKPZurs2vQW8","kty":"RSA","alg":"RS256","use":"sig","n":"2DOZ0qHie73SuFVR7civrl6r82YUiAghfzaMowjCg0o06AF--2lIS7vNV_PbsVVznPAAMqVrNG-8CcevEzvVZMQD9nH4DI7xlOxK0lrYu8rmMeSfOvXVbBVsWBZe0jnGNukZqjwmRE5__ttJdxPfIBT5-2L6mguQbDfhSUEEdIW7y7UfOXvqLqEcBtoIEB-ORKDTUIQwGZM5mSCy-cY3cHvvZfZVgaUUy5NvujPRXTMje4n_hG0KfEV-40G9qC2_Xvx4EooJzBZ6FSThiWhCpwhIvzcQqB6M9lHW7nU6wADhYPNCa2OKWvphwZ_zbrF4B9dmS6Zli5rBvbox9Hh45w","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMLTANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgzmdKh4nu90rhVUe3Ir65eq/NmFIgIIX82jKMIwoNKNOgBfvtpSEu7zVfz27FVc5zwADKlazRvvAnHrxM71WTEA/Zx+AyO8ZTsStJa2LvK5jHknzr11WwVbFgWXtI5xjbpGao8JkROf/7bSXcT3yAU+fti+poLkGw34UlBBHSFu8u1Hzl76i6hHAbaCBAfjkSg01CEMBmTOZkgsvnGN3B772X2VYGlFMuTb7oz0V0zI3uJ/4RtCnxFfuNBvagtv178eBKKCcwWehUk4YloQqcISL83EKgejPZR1u51OsAA4WDzQmtjilr6YcGf826xeAfXZkumZYuawb26MfR4eOcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsnQG/Yi2g1XTCJn74hWv9MjxVAaZb4gBAc2AWm5VgAjhFEM9h6x6m1mQkq7JM4rIdAj8jw55Ok9CBVBIqq4G4cME3eUvVytkj2lC9zcRoAivjjZF2HPg7zNPa2TTR50asmHPRokppV6gewO/C+o5as+4P2zqDXBh61aRd/9kdQfkg14LBbH5/dYccAuvUqlTYC4IEPCvVmBNC1xsMjf0vohvoSjm9vL2bfqG/RJH0ScdCjOd5d2zju4/e2oVdluWm+vzKBQplc7tVMuKpn6LcLmVHiGNAl+EBIZH+WVLlTx0D1+kbHZsfLYG53lQg2LsvurRbWyF/a5fVM/oLTn5ag=="],"x5t":"H5xfs1pRtvX0HyVTskx7eTXx88U","x5t#S256":"XurVtKAIEyc4w9HCGOhnjoRHnYu4d9HCn_5YHmkScJg"},{"kid":"TV3Tl5jIY1nrJLSb53UKEubLR5gYiq9slq1SsDDg1HU","kty":"RSA","alg":"RSA-OAEP","use":"enc","n":"pNvU3ecpVHbJT4bCOEpw6cnV1yi65tB3I0bRF2ilLVOY944QRAGnjBBECPIzNbgqavghYp1j75F2nq6_ny1CYfoaxTV2iDpRUw8_f7sliYbl8FrLLat0S25ItlZrg5TEJHObvOqlG2_nXoeH36MRWwNhms2uCqfhn5VgtenIzpQIBolnM7zzGp21NvdJ1C_ZAUzkXC-l3oQ-BXTtpEVM4h2KpYh4gfZJWCbYij5d1e1YApKD6V61_Cs3Oa2OY7CAUyq5kgAWJZFDB6CpzIr226u3bV7F9RbrQu3Ybc_Lv33EwykscLznKWZY2Mbs3Iz_rFNv3sVX_vHpH4DHWlKu7Q","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMlzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTb1N3nKVR2yU+GwjhKcOnJ1dcouubQdyNG0RdopS1TmPeOEEQBp4wQRAjyMzW4Kmr4IWKdY++Rdp6uv58tQmH6GsU1dog6UVMPP3+7JYmG5fBayy2rdEtuSLZWa4OUxCRzm7zqpRtv516Hh9+jEVsDYZrNrgqn4Z+VYLXpyM6UCAaJZzO88xqdtTb3SdQv2QFM5Fwvpd6EPgV07aRFTOIdiqWIeIH2SVgm2Io+XdXtWAKSg+letfwrNzmtjmOwgFMquZIAFiWRQwegqcyK9turt21exfUW60Lt2G3Py799xMMpLHC85ylmWNjG7NyM/6xTb97FV/7x6R+Ax1pSru0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAQGJHeTYSMvp0yndbIn7DLohO9lom5nRrx/bLyb7TiRfogyJEF6rQZ66CAkQFk5eMF878fsHTuMVjtmXVBnhojhVmK91HwjsNQu/8xR6QMXNKJQMvHR245vwUGxlWRw/36ObM1D7QjCd/q+FonpBEY4m5Y6Uz1U0HR2Cbh0E2afVlPLeV+F0LKrlyVMdIaWBGWftCGIKDAHaG/PD66zbAKtxerv2fBIDq100WHPhd57BZxX+2aGJp1IaRDgkxV0E/CjEy3+Knd8xbAgUSW0Tl6OTC75exIvlbzeluEBe0wlapAb7WvBKYsipSW8G8Ey7tjoolDT4AU82EaKUPstiMnA=="],"x5t":"AlfHDI0FOPQpt3RBAILt0dtW1yw","x5t#S256":"a7bhm8-JsnfY7bL_m8Yl72hgmp5516VZlFcVloKzk08"}]}'
+ headers:
+ Cache-Control:
+ - no-cache
+ Content-Type:
+ - application/json;charset=UTF-8
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '2909'
+ status:
+ code: 200
+ message: OK
+version: 1
diff --git a/src/objects/accounts/tests/keycloak_cassets/happy_flow_existing_user.yaml b/src/objects/accounts/tests/keycloak_cassets/happy_flow_existing_user.yaml
new file mode 100644
index 00000000..fd490802
--- /dev/null
+++ b/src/objects/accounts/tests/keycloak_cassets/happy_flow_existing_user.yaml
@@ -0,0 +1,314 @@
+interactions:
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.2
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/auth?response_type=code&scope=openid&client_id=testid&redirect_uri=http%3A%2F%2Ftestserver%2Foidc%2Fcallback%2F&state=not-a-random-string&nonce=not-a-random-string
+ response:
+ body:
+ string: "\n\n\n\n \n
+ \ \n \n\n \n Sign
+ in to test\n \n \n \n \n \n \n \n\n\n\n\n
+ \ \n
\n
+ \ \n
\n
+ \
\n\n\n
\n \n\n\n\n\n\n
+ \
\n
\n\n
\n
\n\n\n"
+ headers:
+ Cache-Control:
+ - no-store, must-revalidate, max-age=0
+ Content-Language:
+ - en
+ Content-Security-Policy:
+ - frame-src 'self'; frame-ancestors 'self'; object-src 'none';
+ Content-Type:
+ - text/html;charset=utf-8
+ Referrer-Policy:
+ - no-referrer
+ Set-Cookie:
+ - AUTH_SESSION_ID=4d37b9ff-7840-4c0e-ae54-61797c065617; Version=1; Path=/realms/test/;
+ SameSite=None; Secure; HttpOnly
+ - AUTH_SESSION_ID_LEGACY=4d37b9ff-7840-4c0e-ae54-61797c065617; Version=1; Path=/realms/test/;
+ HttpOnly
+ - KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJjaWQiOiJ0ZXN0aWQiLCJwdHkiOiJvcGVuaWQtY29ubmVjdCIsInJ1cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsImFjdCI6IkFVVEhFTlRJQ0FURSIsIm5vdGVzIjp7InNjb3BlIjoib3BlbmlkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwicmVzcG9uc2VfdHlwZSI6ImNvZGUiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsInN0YXRlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyJ9fQ.f7ZABGR0O48xm61gDKLOR_LjWH9a59wtTbGXUfm78sI;
+ Version=1; Path=/realms/test/; HttpOnly
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Robots-Tag:
+ - none
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '4466'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: username=admin&password=admin&credentialId=&login=Sign+In
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ Content-Length:
+ - '57'
+ Content-Type:
+ - application/x-www-form-urlencoded
+ Cookie:
+ - AUTH_SESSION_ID_LEGACY=4d37b9ff-7840-4c0e-ae54-61797c065617; KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJjaWQiOiJ0ZXN0aWQiLCJwdHkiOiJvcGVuaWQtY29ubmVjdCIsInJ1cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsImFjdCI6IkFVVEhFTlRJQ0FURSIsIm5vdGVzIjp7InNjb3BlIjoib3BlbmlkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwicmVzcG9uc2VfdHlwZSI6ImNvZGUiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vdGVzdHNlcnZlci9vaWRjL2NhbGxiYWNrLyIsInN0YXRlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyJ9fQ.f7ZABGR0O48xm61gDKLOR_LjWH9a59wtTbGXUfm78sI
+ User-Agent:
+ - python-requests/2.32.2
+ method: POST
+ uri: http://localhost:8080/realms/test/login-actions/authenticate?session_code=4l-JY6BOiZ8bacQRJjI1QXUfbJ3HXTqG6qkCFLdKlQA&execution=670fb55e-641e-4beb-bd17-3c0cb001b805&client_id=testid&tab_id=mi2knizGlJM
+ response:
+ body:
+ string: ''
+ headers:
+ Cache-Control:
+ - no-store, must-revalidate, max-age=0
+ Content-Security-Policy:
+ - frame-src 'self'; frame-ancestors 'self'; object-src 'none';
+ Location:
+ - http://testserver/oidc/callback/?state=not-a-random-string&session_state=4d37b9ff-7840-4c0e-ae54-61797c065617&iss=http%3A%2F%2Flocalhost%3A8080%2Frealms%2Ftest&code=79d14c65-ffcd-4066-8cbe-98423d3b0f9d.4d37b9ff-7840-4c0e-ae54-61797c065617.adf4ad83-4550-4619-9231-73bd8d700f45
+ Referrer-Policy:
+ - no-referrer
+ Set-Cookie:
+ - KEYCLOAK_LOCALE=; Version=1; Comment=Expiring cookie; Expires=Thu, 01-Jan-1970
+ 00:00:10 GMT; Max-Age=0; Path=/realms/test/; HttpOnly
+ - KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0;
+ Path=/realms/test/; HttpOnly
+ - KC_AUTH_STATE=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0;
+ Path=/realms/test/
+ - KEYCLOAK_IDENTITY=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjAxNTU4MzMsImlhdCI6MTcyMDExOTgzMywianRpIjoiOGRhYzBkZTItMGMzMC00NWNkLWI2NTctMjA2OGRlZjU2ZGU1IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiU2VyaWFsaXplZC1JRCIsInNlc3Npb25fc3RhdGUiOiI0ZDM3YjlmZi03ODQwLTRjMGUtYWU1NC02MTc5N2MwNjU2MTciLCJzaWQiOiI0ZDM3YjlmZi03ODQwLTRjMGUtYWU1NC02MTc5N2MwNjU2MTciLCJzdGF0ZV9jaGVja2VyIjoiS29jaEZHYjRwU1hLVHl4ZTFhdUtCUDhnYmZPWWxGNnNKNFJZRmJ1ZmI3ZyJ9.B9lZZIe-jlw3iAIJi3ZLoho2-rGpYn7X86-xzwPgBUk;
+ Version=1; Path=/realms/test/; SameSite=None; Secure; HttpOnly
+ - KEYCLOAK_IDENTITY_LEGACY=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjAxNTU4MzMsImlhdCI6MTcyMDExOTgzMywianRpIjoiOGRhYzBkZTItMGMzMC00NWNkLWI2NTctMjA2OGRlZjU2ZGU1IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiU2VyaWFsaXplZC1JRCIsInNlc3Npb25fc3RhdGUiOiI0ZDM3YjlmZi03ODQwLTRjMGUtYWU1NC02MTc5N2MwNjU2MTciLCJzaWQiOiI0ZDM3YjlmZi03ODQwLTRjMGUtYWU1NC02MTc5N2MwNjU2MTciLCJzdGF0ZV9jaGVja2VyIjoiS29jaEZHYjRwU1hLVHl4ZTFhdUtCUDhnYmZPWWxGNnNKNFJZRmJ1ZmI3ZyJ9.B9lZZIe-jlw3iAIJi3ZLoho2-rGpYn7X86-xzwPgBUk;
+ Version=1; Path=/realms/test/; HttpOnly
+ - KEYCLOAK_SESSION=test/6db2db87-de31-4e30-9f25-cefe5da8b154/4d37b9ff-7840-4c0e-ae54-61797c065617;
+ Version=1; Expires=Fri, 05-Jul-2024 05:03:53 GMT; Max-Age=36000; Path=/realms/test/;
+ SameSite=None; Secure
+ - KEYCLOAK_SESSION_LEGACY=test/6db2db87-de31-4e30-9f25-cefe5da8b154/4d37b9ff-7840-4c0e-ae54-61797c065617;
+ Version=1; Expires=Fri, 05-Jul-2024 05:03:53 GMT; Max-Age=36000; Path=/realms/test/
+ - KEYCLOAK_REMEMBER_ME=; Version=1; Comment=Expiring cookie; Expires=Thu, 01-Jan-1970
+ 00:00:10 GMT; Max-Age=0; Path=/realms/test/; HttpOnly
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Robots-Tag:
+ - none
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '0'
+ status:
+ code: 302
+ message: Found
+- request:
+ body: client_id=testid&client_secret=7DB3KUAAizYCcmZufpHRVOcD0TOkNO3I&grant_type=authorization_code&code=79d14c65-ffcd-4066-8cbe-98423d3b0f9d.4d37b9ff-7840-4c0e-ae54-61797c065617.adf4ad83-4550-4619-9231-73bd8d700f45&redirect_uri=http%3A%2F%2Ftestserver%2Foidc%2Fcallback%2F
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ Content-Length:
+ - '267'
+ Content-Type:
+ - application/x-www-form-urlencoded
+ User-Agent:
+ - python-requests/2.32.2
+ method: POST
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/token
+ response:
+ body:
+ string: '{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjAxMjAxMzMsImlhdCI6MTcyMDExOTgzMywiYXV0aF90aW1lIjoxNzIwMTE5ODMzLCJqdGkiOiIzNjZlNDJmOS01ZTdjLTQ0N2YtYTExMS1kYzBmZGU4NTAyMjciLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGVzdGlkIiwibm9uY2UiOiJub3QtYS1yYW5kb20tc3RyaW5nIiwic2Vzc2lvbl9zdGF0ZSI6IjRkMzdiOWZmLTc4NDAtNGMwZS1hZTU0LTYxNzk3YzA2NTYxNyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovLzEyNy4wLjAuMTo4MDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSBrdmsgZ3JvdXBzIGJzbiIsInNpZCI6IjRkMzdiOWZmLTc4NDAtNGMwZS1hZTU0LTYxNzk3YzA2NTYxNyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJncm91cHMiOlsiUmVnaXN0cmVlcmRlcnMiLCJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl0sInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBleGFtcGxlLmNvbSJ9.pLHSN-f0pCdn1Rqy9-nAPqVFeJjPRElkySwfXTvBKHkgSqqCf3eo3IoDluU4rmlIE4wXi4GpeusADlru_jc76zeDUi5haMUtHNQ2m70tl31DTP4DnfV7jppoIq2n_CMDfwhqP9zG-d2QNznPSa5aIaXHGmD48LnbeLlgue5a2Y1Zljg6r0GZJY-9dm3W4n_pgTt-254gsSh_sxbo42OZEUk4Pq0dAzzW4SZ72r0SxzFA9WC1w_-L3kaZ6Ohe1p9ZaizzccKikIq1mEc0tSEgBardNDhwSMIBNTCnfuojIiiU7ro9u8_1TT_BKgNmEm3QhyMdRw3IBMUzYCSPNmaAow","expires_in":300,"refresh_expires_in":1800,"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjAxMjE2MzMsImlhdCI6MTcyMDExOTgzMywianRpIjoiMjRhYWU3ZTQtMDk5Mi00MmJkLWI1MGItNmVmNjY4Zjk1ZjEwIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InRlc3RpZCIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsInNlc3Npb25fc3RhdGUiOiI0ZDM3YjlmZi03ODQwLTRjMGUtYWU1NC02MTc5N2MwNjU2MTciLCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIGt2ayBncm91cHMgYnNuIiwic2lkIjoiNGQzN2I5ZmYtNzg0MC00YzBlLWFlNTQtNjE3OTdjMDY1NjE3In0.xB2_pY-y-_70SgH4xDxR02SjaYglIKTgP6Wz7t6SIW0","token_type":"Bearer","id_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjAxMjAxMzMsImlhdCI6MTcyMDExOTgzMywiYXV0aF90aW1lIjoxNzIwMTE5ODMzLCJqdGkiOiIwZmVhODkwYS1jYWUxLTRhMTItYmQ4Yi05MWIzZjIzZWU3MmYiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJ0ZXN0aWQiLCJzdWIiOiI2ZGIyZGI4Ny1kZTMxLTRlMzAtOWYyNS1jZWZlNWRhOGIxNTQiLCJ0eXAiOiJJRCIsImF6cCI6InRlc3RpZCIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsInNlc3Npb25fc3RhdGUiOiI0ZDM3YjlmZi03ODQwLTRjMGUtYWU1NC02MTc5N2MwNjU2MTciLCJhdF9oYXNoIjoiUTJTZ3phYWNhM1JQWHZfZ05qU3BQUSIsImFjciI6IjEiLCJzaWQiOiI0ZDM3YjlmZi03ODQwLTRjMGUtYWU1NC02MTc5N2MwNjU2MTciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZ3JvdXBzIjpbIlJlZ2lzdHJlZXJkZXJzIiwiZGVmYXVsdC1yb2xlcy10ZXN0Iiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20ifQ.copggZp0m60QmYfo4cjtiRNbvOsYg_LhT-qVH2zCkhlIFN4GQvx46uLY-u5AL1wQHXDhL708h8ZfQNSY3ZVh3I-gPn-h3uKiL5bwyfdXX_9XHCOh8KfeMTuXJLgJF-ebzP41i7un1Wjsi8StlL-uTkrKxWjG0BIUwmhU6z5UqGFQvg5US83mpFWhtPN_BkBC2IWZDtGthjBhGBxzdPCYpAsfZsQuZpzIHkdcqw1-mjjVwmPDfma8q2-MgweL9zpbmAgbdzPUx8byHuJFir3gtnU5liS4Yy_DmsRr51c43cH_7wtmH_6aLAxe6f5srZ9BbNZ2XD016Wj8x1xLEY9k8Q","not-before-policy":0,"session_state":"4d37b9ff-7840-4c0e-ae54-61797c065617","scope":"openid
+ email profile kvk groups bsn"}'
+ headers:
+ Cache-Control:
+ - no-store
+ Content-Type:
+ - application/json
+ Pragma:
+ - no-cache
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '3698'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.2
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/certs
+ response:
+ body:
+ string: '{"keys":[{"kid":"4UNQAcvUcv-DFUOx_4O1gt13OdJSotqEKPZurs2vQW8","kty":"RSA","alg":"RS256","use":"sig","n":"2DOZ0qHie73SuFVR7civrl6r82YUiAghfzaMowjCg0o06AF--2lIS7vNV_PbsVVznPAAMqVrNG-8CcevEzvVZMQD9nH4DI7xlOxK0lrYu8rmMeSfOvXVbBVsWBZe0jnGNukZqjwmRE5__ttJdxPfIBT5-2L6mguQbDfhSUEEdIW7y7UfOXvqLqEcBtoIEB-ORKDTUIQwGZM5mSCy-cY3cHvvZfZVgaUUy5NvujPRXTMje4n_hG0KfEV-40G9qC2_Xvx4EooJzBZ6FSThiWhCpwhIvzcQqB6M9lHW7nU6wADhYPNCa2OKWvphwZ_zbrF4B9dmS6Zli5rBvbox9Hh45w","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMLTANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgzmdKh4nu90rhVUe3Ir65eq/NmFIgIIX82jKMIwoNKNOgBfvtpSEu7zVfz27FVc5zwADKlazRvvAnHrxM71WTEA/Zx+AyO8ZTsStJa2LvK5jHknzr11WwVbFgWXtI5xjbpGao8JkROf/7bSXcT3yAU+fti+poLkGw34UlBBHSFu8u1Hzl76i6hHAbaCBAfjkSg01CEMBmTOZkgsvnGN3B772X2VYGlFMuTb7oz0V0zI3uJ/4RtCnxFfuNBvagtv178eBKKCcwWehUk4YloQqcISL83EKgejPZR1u51OsAA4WDzQmtjilr6YcGf826xeAfXZkumZYuawb26MfR4eOcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsnQG/Yi2g1XTCJn74hWv9MjxVAaZb4gBAc2AWm5VgAjhFEM9h6x6m1mQkq7JM4rIdAj8jw55Ok9CBVBIqq4G4cME3eUvVytkj2lC9zcRoAivjjZF2HPg7zNPa2TTR50asmHPRokppV6gewO/C+o5as+4P2zqDXBh61aRd/9kdQfkg14LBbH5/dYccAuvUqlTYC4IEPCvVmBNC1xsMjf0vohvoSjm9vL2bfqG/RJH0ScdCjOd5d2zju4/e2oVdluWm+vzKBQplc7tVMuKpn6LcLmVHiGNAl+EBIZH+WVLlTx0D1+kbHZsfLYG53lQg2LsvurRbWyF/a5fVM/oLTn5ag=="],"x5t":"H5xfs1pRtvX0HyVTskx7eTXx88U","x5t#S256":"XurVtKAIEyc4w9HCGOhnjoRHnYu4d9HCn_5YHmkScJg"},{"kid":"TV3Tl5jIY1nrJLSb53UKEubLR5gYiq9slq1SsDDg1HU","kty":"RSA","alg":"RSA-OAEP","use":"enc","n":"pNvU3ecpVHbJT4bCOEpw6cnV1yi65tB3I0bRF2ilLVOY944QRAGnjBBECPIzNbgqavghYp1j75F2nq6_ny1CYfoaxTV2iDpRUw8_f7sliYbl8FrLLat0S25ItlZrg5TEJHObvOqlG2_nXoeH36MRWwNhms2uCqfhn5VgtenIzpQIBolnM7zzGp21NvdJ1C_ZAUzkXC-l3oQ-BXTtpEVM4h2KpYh4gfZJWCbYij5d1e1YApKD6V61_Cs3Oa2OY7CAUyq5kgAWJZFDB6CpzIr226u3bV7F9RbrQu3Ybc_Lv33EwykscLznKWZY2Mbs3Iz_rFNv3sVX_vHpH4DHWlKu7Q","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMlzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTb1N3nKVR2yU+GwjhKcOnJ1dcouubQdyNG0RdopS1TmPeOEEQBp4wQRAjyMzW4Kmr4IWKdY++Rdp6uv58tQmH6GsU1dog6UVMPP3+7JYmG5fBayy2rdEtuSLZWa4OUxCRzm7zqpRtv516Hh9+jEVsDYZrNrgqn4Z+VYLXpyM6UCAaJZzO88xqdtTb3SdQv2QFM5Fwvpd6EPgV07aRFTOIdiqWIeIH2SVgm2Io+XdXtWAKSg+letfwrNzmtjmOwgFMquZIAFiWRQwegqcyK9turt21exfUW60Lt2G3Py799xMMpLHC85ylmWNjG7NyM/6xTb97FV/7x6R+Ax1pSru0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAQGJHeTYSMvp0yndbIn7DLohO9lom5nRrx/bLyb7TiRfogyJEF6rQZ66CAkQFk5eMF878fsHTuMVjtmXVBnhojhVmK91HwjsNQu/8xR6QMXNKJQMvHR245vwUGxlWRw/36ObM1D7QjCd/q+FonpBEY4m5Y6Uz1U0HR2Cbh0E2afVlPLeV+F0LKrlyVMdIaWBGWftCGIKDAHaG/PD66zbAKtxerv2fBIDq100WHPhd57BZxX+2aGJp1IaRDgkxV0E/CjEy3+Knd8xbAgUSW0Tl6OTC75exIvlbzeluEBe0wlapAb7WvBKYsipSW8G8Ey7tjoolDT4AU82EaKUPstiMnA=="],"x5t":"AlfHDI0FOPQpt3RBAILt0dtW1yw","x5t#S256":"a7bhm8-JsnfY7bL_m8Yl72hgmp5516VZlFcVloKzk08"}]}'
+ headers:
+ Cache-Control:
+ - no-cache
+ Content-Type:
+ - application/json;charset=UTF-8
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '2909'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Authorization:
+ - Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjAxMjAxMzMsImlhdCI6MTcyMDExOTgzMywiYXV0aF90aW1lIjoxNzIwMTE5ODMzLCJqdGkiOiIzNjZlNDJmOS01ZTdjLTQ0N2YtYTExMS1kYzBmZGU4NTAyMjciLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGVzdGlkIiwibm9uY2UiOiJub3QtYS1yYW5kb20tc3RyaW5nIiwic2Vzc2lvbl9zdGF0ZSI6IjRkMzdiOWZmLTc4NDAtNGMwZS1hZTU0LTYxNzk3YzA2NTYxNyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovLzEyNy4wLjAuMTo4MDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSBrdmsgZ3JvdXBzIGJzbiIsInNpZCI6IjRkMzdiOWZmLTc4NDAtNGMwZS1hZTU0LTYxNzk3YzA2NTYxNyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJncm91cHMiOlsiUmVnaXN0cmVlcmRlcnMiLCJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl0sInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBleGFtcGxlLmNvbSJ9.pLHSN-f0pCdn1Rqy9-nAPqVFeJjPRElkySwfXTvBKHkgSqqCf3eo3IoDluU4rmlIE4wXi4GpeusADlru_jc76zeDUi5haMUtHNQ2m70tl31DTP4DnfV7jppoIq2n_CMDfwhqP9zG-d2QNznPSa5aIaXHGmD48LnbeLlgue5a2Y1Zljg6r0GZJY-9dm3W4n_pgTt-254gsSh_sxbo42OZEUk4Pq0dAzzW4SZ72r0SxzFA9WC1w_-L3kaZ6Ohe1p9ZaizzccKikIq1mEc0tSEgBardNDhwSMIBNTCnfuojIiiU7ro9u8_1TT_BKgNmEm3QhyMdRw3IBMUzYCSPNmaAow
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.2
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/userinfo
+ response:
+ body:
+ string: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJzdWIiOiI2ZGIyZGI4Ny1kZTMxLTRlMzAtOWYyNS1jZWZlNWRhOGIxNTQiLCJhdWQiOiJ0ZXN0aWQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwiZ3JvdXBzIjpbIlJlZ2lzdHJlZXJkZXJzIiwiZGVmYXVsdC1yb2xlcy10ZXN0Iiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20ifQ.vx4dCJ-Y-PEzjy8p7CNPB3yy0TyV_QugOHRbiV6UY3qHtZUnZqSsJD991QUostcYECuyTHefqfRtdCbvSJcPWI4ucosY65vshUMBtQeahsFOgNwWp2BvCkALJmEya4H_gh63vVlVZ2ZOSpWpah6eV2PNhiiYWD-Y9qEuLMzwngNvp5hna30BiRKAEsStB7izjE5pGECqkQm7pxCeZWHU81Lbh5fSo_2XvcGZ1Z-tf6DN95Oz4ers9YrG6dKSuh-HciY1zhv7mcee_tlJaeKjITue6r06163oKdjsYKRpiR4bLQ9256KafoxmU6O0IIlpkQhmtXrmaFSg0XyBYU8qcQ
+ headers:
+ Cache-Control:
+ - no-cache
+ Content-Type:
+ - application/jwt
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '813'
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - '*/*'
+ Accept-Encoding:
+ - gzip, deflate, br
+ Connection:
+ - keep-alive
+ User-Agent:
+ - python-requests/2.32.2
+ method: GET
+ uri: http://localhost:8080/realms/test/protocol/openid-connect/certs
+ response:
+ body:
+ string: '{"keys":[{"kid":"4UNQAcvUcv-DFUOx_4O1gt13OdJSotqEKPZurs2vQW8","kty":"RSA","alg":"RS256","use":"sig","n":"2DOZ0qHie73SuFVR7civrl6r82YUiAghfzaMowjCg0o06AF--2lIS7vNV_PbsVVznPAAMqVrNG-8CcevEzvVZMQD9nH4DI7xlOxK0lrYu8rmMeSfOvXVbBVsWBZe0jnGNukZqjwmRE5__ttJdxPfIBT5-2L6mguQbDfhSUEEdIW7y7UfOXvqLqEcBtoIEB-ORKDTUIQwGZM5mSCy-cY3cHvvZfZVgaUUy5NvujPRXTMje4n_hG0KfEV-40G9qC2_Xvx4EooJzBZ6FSThiWhCpwhIvzcQqB6M9lHW7nU6wADhYPNCa2OKWvphwZ_zbrF4B9dmS6Zli5rBvbox9Hh45w","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMLTANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgzmdKh4nu90rhVUe3Ir65eq/NmFIgIIX82jKMIwoNKNOgBfvtpSEu7zVfz27FVc5zwADKlazRvvAnHrxM71WTEA/Zx+AyO8ZTsStJa2LvK5jHknzr11WwVbFgWXtI5xjbpGao8JkROf/7bSXcT3yAU+fti+poLkGw34UlBBHSFu8u1Hzl76i6hHAbaCBAfjkSg01CEMBmTOZkgsvnGN3B772X2VYGlFMuTb7oz0V0zI3uJ/4RtCnxFfuNBvagtv178eBKKCcwWehUk4YloQqcISL83EKgejPZR1u51OsAA4WDzQmtjilr6YcGf826xeAfXZkumZYuawb26MfR4eOcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsnQG/Yi2g1XTCJn74hWv9MjxVAaZb4gBAc2AWm5VgAjhFEM9h6x6m1mQkq7JM4rIdAj8jw55Ok9CBVBIqq4G4cME3eUvVytkj2lC9zcRoAivjjZF2HPg7zNPa2TTR50asmHPRokppV6gewO/C+o5as+4P2zqDXBh61aRd/9kdQfkg14LBbH5/dYccAuvUqlTYC4IEPCvVmBNC1xsMjf0vohvoSjm9vL2bfqG/RJH0ScdCjOd5d2zju4/e2oVdluWm+vzKBQplc7tVMuKpn6LcLmVHiGNAl+EBIZH+WVLlTx0D1+kbHZsfLYG53lQg2LsvurRbWyF/a5fVM/oLTn5ag=="],"x5t":"H5xfs1pRtvX0HyVTskx7eTXx88U","x5t#S256":"XurVtKAIEyc4w9HCGOhnjoRHnYu4d9HCn_5YHmkScJg"},{"kid":"TV3Tl5jIY1nrJLSb53UKEubLR5gYiq9slq1SsDDg1HU","kty":"RSA","alg":"RSA-OAEP","use":"enc","n":"pNvU3ecpVHbJT4bCOEpw6cnV1yi65tB3I0bRF2ilLVOY944QRAGnjBBECPIzNbgqavghYp1j75F2nq6_ny1CYfoaxTV2iDpRUw8_f7sliYbl8FrLLat0S25ItlZrg5TEJHObvOqlG2_nXoeH36MRWwNhms2uCqfhn5VgtenIzpQIBolnM7zzGp21NvdJ1C_ZAUzkXC-l3oQ-BXTtpEVM4h2KpYh4gfZJWCbYij5d1e1YApKD6V61_Cs3Oa2OY7CAUyq5kgAWJZFDB6CpzIr226u3bV7F9RbrQu3Ybc_Lv33EwykscLznKWZY2Mbs3Iz_rFNv3sVX_vHpH4DHWlKu7Q","e":"AQAB","x5c":["MIIClzCCAX8CBgGNeYaMlzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0MB4XDTI0MDIwNTEzNDYxN1oXDTM0MDIwNTEzNDc1N1owDzENMAsGA1UEAwwEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTb1N3nKVR2yU+GwjhKcOnJ1dcouubQdyNG0RdopS1TmPeOEEQBp4wQRAjyMzW4Kmr4IWKdY++Rdp6uv58tQmH6GsU1dog6UVMPP3+7JYmG5fBayy2rdEtuSLZWa4OUxCRzm7zqpRtv516Hh9+jEVsDYZrNrgqn4Z+VYLXpyM6UCAaJZzO88xqdtTb3SdQv2QFM5Fwvpd6EPgV07aRFTOIdiqWIeIH2SVgm2Io+XdXtWAKSg+letfwrNzmtjmOwgFMquZIAFiWRQwegqcyK9turt21exfUW60Lt2G3Py799xMMpLHC85ylmWNjG7NyM/6xTb97FV/7x6R+Ax1pSru0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAQGJHeTYSMvp0yndbIn7DLohO9lom5nRrx/bLyb7TiRfogyJEF6rQZ66CAkQFk5eMF878fsHTuMVjtmXVBnhojhVmK91HwjsNQu/8xR6QMXNKJQMvHR245vwUGxlWRw/36ObM1D7QjCd/q+FonpBEY4m5Y6Uz1U0HR2Cbh0E2afVlPLeV+F0LKrlyVMdIaWBGWftCGIKDAHaG/PD66zbAKtxerv2fBIDq100WHPhd57BZxX+2aGJp1IaRDgkxV0E/CjEy3+Knd8xbAgUSW0Tl6OTC75exIvlbzeluEBe0wlapAb7WvBKYsipSW8G8Ey7tjoolDT4AU82EaKUPstiMnA=="],"x5t":"AlfHDI0FOPQpt3RBAILt0dtW1yw","x5t#S256":"a7bhm8-JsnfY7bL_m8Yl72hgmp5516VZlFcVloKzk08"}]}'
+ headers:
+ Cache-Control:
+ - no-cache
+ Content-Type:
+ - application/json;charset=UTF-8
+ Referrer-Policy:
+ - no-referrer
+ Strict-Transport-Security:
+ - max-age=31536000; includeSubDomains
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-XSS-Protection:
+ - 1; mode=block
+ content-length:
+ - '2909'
+ status:
+ code: 200
+ message: OK
+version: 1
diff --git a/src/objects/accounts/tests/test_oidc.py b/src/objects/accounts/tests/test_oidc.py
index b677f192..9eaa0732 100644
--- a/src/objects/accounts/tests/test_oidc.py
+++ b/src/objects/accounts/tests/test_oidc.py
@@ -1,9 +1,30 @@
+from functools import partial
+from pathlib import Path
+
from django.urls import reverse
from django.utils.translation import gettext as _
+import vcr
from django_webtest import WebTest
from mozilla_django_oidc_db.models import OpenIDConnectConfig
+from objects.utils.tests.keycloak import keycloak_login, mock_oidc_db_config
+
+from ..models import User
+from .factories import StaffUserFactory
+
+TEST_FILES = (Path(__file__).parent / "keycloak_cassets").resolve()
+
+
+mock_admin_oidc_config = partial(
+ mock_oidc_db_config,
+ app_label="mozilla_django_oidc_db",
+ model="OpenIDConnectConfig",
+ id=1, # required for the group queries because we're using in-memory objects
+ make_users_staff=True,
+ username_claim=["preferred_username"],
+)
+
class OIDCLoginButtonTestCase(WebTest):
def test_oidc_button_disabled(self):
@@ -40,3 +61,86 @@ def test_oidc_button_enabled(self):
self.assertEqual(
oidc_login_link.attrs["href"], reverse("oidc_authentication_init")
)
+
+
+class OIDCFLowTests(WebTest):
+ @vcr.use_cassette(str(TEST_FILES / "duplicate_email.yaml"))
+ @mock_admin_oidc_config()
+ def test_duplicate_email_unique_constraint_violated(self):
+ # this user collides on the email address
+ staff_user = StaffUserFactory.create(
+ username="no-match", email="admin@example.com"
+ )
+ login_page = self.app.get(reverse("admin:login"))
+ start_response = login_page.click(
+ description=_("Login with organization account")
+ )
+ assert start_response.status_code == 302
+ redirect_uri = keycloak_login(
+ start_response["Location"], username="admin", password="admin"
+ )
+
+ error_page = self.app.get(redirect_uri, auto_follow=True)
+
+ with self.subTest("error page"):
+ self.assertEqual(error_page.status_code, 200)
+ self.assertEqual(error_page.request.path, reverse("admin-oidc-error"))
+ self.assertEqual(
+ error_page.context["oidc_error"],
+ 'duplicate key value violates unique constraint "filled_email_unique"\n'
+ "DETAIL: Key (email)=(admin@example.com) already exists.\n",
+ )
+ self.assertContains(
+ error_page, "duplicate key value violates unique constraint"
+ )
+
+ with self.subTest("user state unmodified"):
+ self.assertEqual(User.objects.count(), 1)
+ staff_user.refresh_from_db()
+ self.assertEqual(staff_user.username, "no-match")
+ self.assertEqual(staff_user.email, "admin@example.com")
+ self.assertTrue(staff_user.is_staff)
+
+ @vcr.use_cassette(str(TEST_FILES / "happy_flow.yaml"))
+ @mock_admin_oidc_config()
+ def test_happy_flow(self):
+ login_page = self.app.get(reverse("admin:login"))
+ start_response = login_page.click(
+ description=_("Login with organization account")
+ )
+ assert start_response.status_code == 302
+ redirect_uri = keycloak_login(
+ start_response["Location"], username="admin", password="admin"
+ )
+
+ admin_index = self.app.get(redirect_uri, auto_follow=True)
+
+ self.assertEqual(admin_index.status_code, 200)
+ self.assertEqual(admin_index.request.path, reverse("admin:index"))
+
+ self.assertEqual(User.objects.count(), 1)
+ user = User.objects.get()
+ self.assertEqual(user.username, "admin")
+
+ @vcr.use_cassette(str(TEST_FILES / "happy_flow_existing_user.yaml"))
+ @mock_admin_oidc_config(make_users_staff=False)
+ def test_happy_flow_existing_user(self):
+ staff_user = StaffUserFactory.create(username="admin", email="update-me")
+ login_page = self.app.get(reverse("admin:login"))
+ start_response = login_page.click(
+ description=_("Login with organization account")
+ )
+ assert start_response.status_code == 302
+ redirect_uri = keycloak_login(
+ start_response["Location"], username="admin", password="admin"
+ )
+
+ admin_index = self.app.get(redirect_uri, auto_follow=True)
+
+ self.assertEqual(admin_index.status_code, 200)
+ self.assertEqual(admin_index.request.path, reverse("admin:index"))
+
+ self.assertEqual(User.objects.count(), 1)
+ staff_user.refresh_from_db()
+ self.assertEqual(staff_user.username, "admin")
+ self.assertEqual(staff_user.email, "admin@example.com")
diff --git a/src/objects/api/v2/openapi.yaml b/src/objects/api/v2/openapi.yaml
index fc9aa086..c5315589 100644
--- a/src/objects/api/v2/openapi.yaml
+++ b/src/objects/api/v2/openapi.yaml
@@ -934,6 +934,9 @@ components:
$ref: '#/components/schemas/GeoWithin'
PaginatedHistoryRecordList:
type: object
+ required:
+ - count
+ - results
properties:
count:
type: integer
@@ -954,6 +957,9 @@ components:
$ref: '#/components/schemas/HistoryRecord'
PaginatedObjectList:
type: object
+ required:
+ - count
+ - results
properties:
count:
type: integer
@@ -974,6 +980,9 @@ components:
$ref: '#/components/schemas/Object'
PaginatedPermissionList:
type: object
+ required:
+ - count
+ - results
properties:
count:
type: integer
diff --git a/src/objects/conf/base.py b/src/objects/conf/base.py
index 686459cc..8ab45a50 100644
--- a/src/objects/conf/base.py
+++ b/src/objects/conf/base.py
@@ -66,6 +66,16 @@
"objects.utils.admin_index.should_display_dropdown_menu"
)
+#
+# MAYKIN-2FA
+#
+# It uses django-two-factor-auth under the hood so you can configure
+# those settings too.
+#
+# we run the admin site monkeypatch instead.
+# Relying Party name for WebAuthn (hardware tokens)
+TWO_FACTOR_WEBAUTHN_RP_NAME = "objects api"
+
# VNG API Common
CUSTOM_CLIENT_FETCHER = "objects.utils.client.get_client"
diff --git a/src/objects/tests/commands/test_setup_configuration.py b/src/objects/tests/commands/test_setup_configuration.py
index 5a0d06e6..5ba3add9 100644
--- a/src/objects/tests/commands/test_setup_configuration.py
+++ b/src/objects/tests/commands/test_setup_configuration.py
@@ -57,7 +57,7 @@ def test_setup_configuration(self, m):
f"{ObjecttypesStep()} is successfully configured",
f"Configuring {DemoUserStep()}...",
f"{DemoUserStep()} is successfully configured",
- "Instance configuration completed.",
+ f"Instance configuration completed.",
]
self.assertEqual(command_output, expected_output)
diff --git a/src/objects/urls.py b/src/objects/urls.py
index e54bba45..74647f37 100644
--- a/src/objects/urls.py
+++ b/src/objects/urls.py
@@ -9,6 +9,7 @@
from maykin_2fa import monkeypatch_admin
from maykin_2fa.urls import urlpatterns as maykin_2fa_urlpatterns, webauthn_urlpatterns
+from mozilla_django_oidc_db.views import AdminLoginFailure
from rest_framework.settings import api_settings
handler500 = "objects.utils.views.server_error"
@@ -29,6 +30,7 @@
auth_views.PasswordResetDoneView.as_view(),
name="password_reset_done",
),
+ path("admin/login/failure/", AdminLoginFailure.as_view(), name="admin-oidc-error"),
path("admin/", include((maykin_2fa_urlpatterns, "maykin_2fa"))),
path("admin/", include((webauthn_urlpatterns, "two_factor"))),
path("admin/", admin.site.urls),
diff --git a/src/objects/utils/tests/__init__.py b/src/objects/utils/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/objects/utils/tests/keycloak.py b/src/objects/utils/tests/keycloak.py
new file mode 100644
index 00000000..73633ed6
--- /dev/null
+++ b/src/objects/utils/tests/keycloak.py
@@ -0,0 +1,89 @@
+from contextlib import contextmanager, nullcontext
+from unittest.mock import patch
+
+from django.apps import apps
+
+from pyquery import PyQuery as pq
+from requests import Session
+
+KEYCLOAK_BASE_URL = "http://localhost:8080/realms/test/protocol/openid-connect"
+
+
+def keycloak_login(
+ login_url: str,
+ username: str = "testuser",
+ password: str = "testuser",
+ host: str = "http://testserver/",
+ session: Session | None = None,
+) -> str:
+ """
+ Test helper to perform a keycloak login.
+
+ :param login_url: A login URL for keycloak with all query string parameters. E.g.
+ `client.get(reverse("login"))["Location"]`.
+ :returns: The redirect URI to consume in the django application, with the ``code``
+ ``state`` query parameters. Consume this with ``response = client.get(url)``.
+ """
+ cm = Session() if session is None else nullcontext(session)
+ with cm as session:
+ login_page = session.get(login_url)
+ assert login_page.status_code == 200
+
+ # process keycloak's login form and submit the username + password to
+ # authenticate
+ document = pq(login_page.text)
+ login_form = document("form#kc-form-login")
+ submit_url = login_form.attr("action")
+ assert isinstance(submit_url, str)
+ login_response = session.post(
+ submit_url,
+ data={
+ "username": username,
+ "password": password,
+ "credentialId": "",
+ "login": "Sign In",
+ },
+ allow_redirects=False,
+ )
+
+ assert login_response.status_code == 302
+ assert (redirect_uri := login_response.headers["Location"]).startswith(host)
+
+ return redirect_uri
+
+
+@contextmanager
+def mock_oidc_db_config(app_label: str, model: str, **overrides):
+ """
+ Bundle all the required mocks.
+
+ This context manager deliberately prevents the mocked things from being injected in
+ the test method signature.
+ """
+ defaults = {
+ "enabled": True,
+ "oidc_rp_client_id": "testid",
+ "oidc_rp_client_secret": "7DB3KUAAizYCcmZufpHRVOcD0TOkNO3I",
+ "oidc_rp_sign_algo": "RS256",
+ "oidc_rp_scopes_list": ["openid"],
+ "oidc_op_jwks_endpoint": f"{KEYCLOAK_BASE_URL}/certs",
+ "oidc_op_authorization_endpoint": f"{KEYCLOAK_BASE_URL}/auth",
+ "oidc_op_token_endpoint": f"{KEYCLOAK_BASE_URL}/token",
+ "oidc_op_user_endpoint": f"{KEYCLOAK_BASE_URL}/userinfo",
+ }
+ field_values = {**defaults, **overrides}
+ model_cls = apps.get_model(app_label, model)
+ with (
+ # bypass django-solo queries + cache hits
+ patch(
+ f"{model_cls.__module__}.{model}.get_solo",
+ return_value=model_cls(**field_values),
+ ),
+ # mock the state & nonce random value generation so we get predictable URLs to
+ # match with VCR
+ patch(
+ "mozilla_django_oidc.views.get_random_string",
+ return_value="not-a-random-string",
+ ),
+ ):
+ yield