diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 791b8eb..e583a72 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,21 +29,21 @@ jobs:
- name: Get changed PY files
id: changed-py-files
- uses: tj-actions/changed-files@v8.5
+ uses: tj-actions/changed-files@v41
with:
files: |
^src/.+\.py
- name: Get changed JS files
id: changed-js-files
- uses: tj-actions/changed-files@v8.5
+ uses: tj-actions/changed-files@v41
with:
files: |
^src/.+\.js
- name: Get changed requirements files
id: changed-requirements
- uses: tj-actions/changed-files@v8.5
+ uses: tj-actions/changed-files@v41
with:
files: ^requirements/.+\.txt$
diff --git a/package-lock.json b/package-lock.json
index 3746b8e..cae96ec 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2818,11 +2818,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"
@@ -3013,7 +3013,7 @@
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dependencies": {
"anymatch": "~3.1.2",
- "braces": "~3.0.2",
+ "braces": "~3.0.3",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
@@ -3960,9 +3960,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",
@@ -3974,7 +3974,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"
@@ -4379,9 +4379,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"
},
@@ -4580,19 +4580,6 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -5553,7 +5540,7 @@
"dependencies": {
"@colors/colors": "1.5.0",
"body-parser": "^1.19.0",
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"chokidar": "^3.5.1",
"connect": "^3.7.0",
"di": "^0.0.1",
@@ -6102,7 +6089,7 @@
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"dev": true,
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -8298,13 +8285,13 @@
}
},
"node_modules/socket.io-adapter": {
- "version": "2.5.4",
- "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz",
- "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==",
+ "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": {
"debug": "~4.3.4",
- "ws": "~8.11.0"
+ "ws": "~8.17.1"
}
},
"node_modules/socket.io-parser": {
@@ -9322,27 +9309,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "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",
@@ -9611,16 +9577,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 20bae7d..ea67109 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -6,11 +6,12 @@
#
amqp==5.2.0
# via kombu
-ape-pie==0.1.0
+ape-pie==0.2.0
# via zgw-consumers
asgiref==3.8.1
# via
# django
+ # django-axes
# django-cors-headers
asn1crypto==1.5.1
# via webauthn
@@ -29,14 +30,14 @@ boltons==24.0.0
# via
# face
# glom
-cbor2==5.6.3
+cbor2==5.6.4
# via webauthn
celery==5.4.0
# via
# flower
# notifications-api-common
# open-api-framework
-certifi==2024.2.2
+certifi==2024.7.4
# via
# elastic-apm
# requests
@@ -57,13 +58,13 @@ click-plugins==1.1.1
# via celery
click-repl==0.3.0
# via celery
-commonground-api-common==1.13.0
+commonground-api-common==1.13.2
# via open-api-framework
coreapi==2.3.3
# via commonground-api-common
coreschema==0.0.4
# via coreapi
-cryptography==42.0.5
+cryptography==43.0.0
# via
# django-simple-certmanager
# josepy
@@ -72,7 +73,7 @@ cryptography==42.0.5
# webauthn
diff-match-patch==20230430
# via django-import-export
-django==4.2.11
+django==4.2.14
# via
# commonground-api-common
# django-admin-index
@@ -111,9 +112,9 @@ django-admin-index==3.1.1
# via open-api-framework
django-appconf==1.0.6
# via django-log-outgoing-requests
-django-axes==6.4.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==24.2
# via
@@ -121,7 +122,7 @@ django-filter==24.2
# open-api-framework
django-formtools==2.5.1
# via django-two-factor-auth
-django-import-export[xlsx]==4.0.9
+django-import-export[xlsx]==4.1.1
# via -r requirements/base.in
django-jsonform==2.22.0
# via
@@ -133,7 +134,7 @@ django-markup==1.8.1
# via open-api-framework
django-ordered-model==3.7.4
# via django-admin-index
-django-otp==1.5.0
+django-otp==1.5.1
# via django-two-factor-auth
django-phonenumber-field==7.3.0
# via django-two-factor-auth
@@ -147,11 +148,11 @@ django-rest-framework-condition==0.1.1
# via commonground-api-common
django-sendfile2==0.7.1
# via django-privates
-django-setup-configuration==0.1.0
+django-setup-configuration==0.3.0
# via open-api-framework
-django-simple-certmanager==2.0.0
+django-simple-certmanager==2.3.0
# via zgw-consumers
-django-solo==2.2.0
+django-solo==2.3.0
# via
# commonground-api-common
# django-log-outgoing-requests
@@ -160,7 +161,7 @@ django-solo==2.2.0
# zgw-consumers
django-two-factor-auth[phonenumberslite,webauthn]==1.16.0
# via maykin-2fa
-djangorestframework==3.15.1
+djangorestframework==3.15.2
# via
# commonground-api-common
# djangorestframework-gis
@@ -178,15 +179,15 @@ djangorestframework-gis==1.0
# via open-api-framework
djangorestframework-inclusions==1.2.0
# via open-api-framework
-drf-nested-routers==0.93.5
+drf-nested-routers==0.94.1
# via commonground-api-common
drf-spectacular==0.27.2
# via open-api-framework
drf-yasg==1.21.7
# via commonground-api-common
-ecs-logging==2.1.0
+ecs-logging==2.2.0
# via elastic-apm
-elastic-apm==6.22.0
+elastic-apm==6.23.0
# via open-api-framework
et-xmlfile==1.1.0
# via openpyxl
@@ -202,7 +203,7 @@ gemma-zds-client==2.0.0
# notifications-api-common
glom==23.5.0
# via mozilla-django-oidc-db
-humanize==4.9.0
+humanize==4.10.0
# via flower
idna==3.7
# via requests
@@ -216,11 +217,11 @@ isodate==0.6.1
# via commonground-api-common
itypes==1.2.0
# via coreapi
-jinja2==3.1.3
+jinja2==3.1.4
# via coreschema
josepy==1.14.0
# via mozilla-django-oidc
-jsonschema==4.21.1
+jsonschema==4.23.0
# via drf-spectacular
jsonschema-specifications==2023.12.1
# via jsonschema
@@ -228,29 +229,29 @@ kombu==5.3.7
# via celery
markupsafe==2.1.5
# via jinja2
-maykin-2fa==1.0.0
+maykin-2fa==1.0.1
# via open-api-framework
mozilla-django-oidc==4.0.1
# via mozilla-django-oidc-db
-mozilla-django-oidc-db==0.15.0
+mozilla-django-oidc-db==0.19.0
# via open-api-framework
notifications-api-common==0.2.2
# via commonground-api-common
-open-api-framework==0.6.0
+open-api-framework==0.6.1
# via -r requirements/base.in
-openpyxl==3.1.4
+openpyxl==3.1.5
# via tablib
orderedmultidict==1.0.1
# via furl
oyaml==1.0
# via commonground-api-common
-packaging==24.0
+packaging==24.1
# via drf-yasg
-phonenumberslite==8.13.35
+phonenumberslite==8.13.42
# via django-two-factor-auth
prometheus-client==0.20.0
# via flower
-prompt-toolkit==3.0.43
+prompt-toolkit==3.0.47
# via click-repl
psycopg2==2.9.9
# via open-api-framework
@@ -261,7 +262,7 @@ pyjwt==2.8.0
# commonground-api-common
# gemma-zds-client
# zgw-consumers
-pyopenssl==24.1.0
+pyopenssl==24.2.1
# via
# josepy
# webauthn
@@ -287,13 +288,13 @@ pyyaml==6.0.1
# oyaml
qrcode==7.4.2
# via django-two-factor-auth
-redis==5.0.4
+redis==5.0.8
# via django-redis
-referencing==0.35.0
+referencing==0.35.1
# via
# jsonschema
# jsonschema-specifications
-requests==2.31.0
+requests==2.32.3
# via
# ape-pie
# commonground-api-common
@@ -303,11 +304,11 @@ requests==2.31.0
# mozilla-django-oidc
# open-api-framework
# zgw-consumers
-rpds-py==0.18.0
+rpds-py==0.19.1
# via
# jsonschema
# referencing
-sentry-sdk==2.0.0
+sentry-sdk==2.12.0
# via open-api-framework
six==1.16.0
# via
@@ -316,14 +317,15 @@ six==1.16.0
# isodate
# orderedmultidict
# python-dateutil
-sqlparse==0.5.0
+sqlparse==0.5.1
# via django
tablib[xlsx]==3.5.0
# via django-import-export
-tornado==6.4
+tornado==6.4.1
# via flower
-typing-extensions==4.11.0
+typing-extensions==4.12.2
# via
+ # mozilla-django-oidc-db
# qrcode
# zgw-consumers
tzdata==2024.1
@@ -333,12 +335,12 @@ uritemplate==4.1.1
# coreapi
# drf-spectacular
# drf-yasg
-urllib3==2.2.1
+urllib3==2.2.2
# via
# elastic-apm
# requests
# sentry-sdk
-uwsgi==2.0.25.1
+uwsgi==2.0.26
# via open-api-framework
vine==5.1.0
# via
@@ -347,13 +349,13 @@ vine==5.1.0
# kombu
wcwidth==0.2.13
# via prompt-toolkit
-webauthn==2.1.0
+webauthn==2.2.0
# via django-two-factor-auth
webencodings==0.5.1
# via bleach
-wrapt==1.14.1
+wrapt==1.16.0
# via elastic-apm
-zgw-consumers==0.33.0
+zgw-consumers==0.34.0
# via
# notifications-api-common
# open-api-framework
diff --git a/requirements/ci.txt b/requirements/ci.txt
index 6312308..dc5f42f 100644
--- a/requirements/ci.txt
+++ b/requirements/ci.txt
@@ -8,7 +8,7 @@ amqp==5.2.0
# via
# -r requirements/base.txt
# kombu
-ape-pie==0.1.0
+ape-pie==0.2.0
# via
# -r requirements/base.txt
# zgw-consumers
@@ -16,6 +16,7 @@ asgiref==3.8.1
# via
# -r requirements/base.txt
# django
+ # django-axes
# django-cors-headers
asn1crypto==1.5.1
# via
@@ -48,7 +49,7 @@ boltons==24.0.0
# -r requirements/base.txt
# face
# glom
-cbor2==5.6.3
+cbor2==5.6.4
# via
# -r requirements/base.txt
# webauthn
@@ -58,7 +59,7 @@ celery==5.4.0
# flower
# notifications-api-common
# open-api-framework
-certifi==2024.2.2
+certifi==2024.7.4
# via
# -r requirements/base.txt
# elastic-apm
@@ -93,7 +94,7 @@ click-repl==0.3.0
# via
# -r requirements/base.txt
# celery
-commonground-api-common==1.13.0
+commonground-api-common==1.13.2
# via
# -r requirements/base.txt
# open-api-framework
@@ -105,9 +106,9 @@ coreschema==0.0.4
# via
# -r requirements/base.txt
# coreapi
-coverage==4.5.4
+coverage==7.6.0
# via -r requirements/test-tools.in
-cryptography==42.0.5
+cryptography==43.0.0
# via
# -r requirements/base.txt
# django-simple-certmanager
@@ -119,7 +120,7 @@ diff-match-patch==20230430
# via
# -r requirements/base.txt
# django-import-export
-django==4.2.11
+django==4.2.14
# via
# -r requirements/base.txt
# commonground-api-common
@@ -163,11 +164,11 @@ django-appconf==1.0.6
# via
# -r requirements/base.txt
# django-log-outgoing-requests
-django-axes==6.4.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
@@ -180,7 +181,7 @@ django-formtools==2.5.1
# via
# -r requirements/base.txt
# django-two-factor-auth
-django-import-export[xlsx]==4.0.9
+django-import-export[xlsx]==4.1.1
# via -r requirements/base.txt
django-jsonform==2.22.0
# via
@@ -199,7 +200,7 @@ django-ordered-model==3.7.4
# via
# -r requirements/base.txt
# django-admin-index
-django-otp==1.5.0
+django-otp==1.5.1
# via
# -r requirements/base.txt
# django-two-factor-auth
@@ -227,15 +228,15 @@ django-sendfile2==0.7.1
# via
# -r requirements/base.txt
# django-privates
-django-setup-configuration==0.1.0
+django-setup-configuration==0.3.0
# via
# -r requirements/base.txt
# open-api-framework
-django-simple-certmanager==2.0.0
+django-simple-certmanager==2.3.0
# via
# -r requirements/base.txt
# zgw-consumers
-django-solo==2.2.0
+django-solo==2.3.0
# via
# -r requirements/base.txt
# commonground-api-common
@@ -249,7 +250,7 @@ django-two-factor-auth[phonenumberslite,webauthn]==1.16.0
# maykin-2fa
django-webtest==1.9.11
# via -r requirements/test-tools.in
-djangorestframework==3.15.1
+djangorestframework==3.15.2
# via
# -r requirements/base.txt
# commonground-api-common
@@ -273,7 +274,7 @@ djangorestframework-inclusions==1.2.0
# via
# -r requirements/base.txt
# open-api-framework
-drf-nested-routers==0.93.5
+drf-nested-routers==0.94.1
# via
# -r requirements/base.txt
# commonground-api-common
@@ -285,11 +286,11 @@ drf-yasg==1.21.7
# via
# -r requirements/base.txt
# commonground-api-common
-ecs-logging==2.1.0
+ecs-logging==2.2.0
# via
# -r requirements/base.txt
# elastic-apm
-elastic-apm==6.22.0
+elastic-apm==6.23.0
# via
# -r requirements/base.txt
# open-api-framework
@@ -303,15 +304,15 @@ face==20.1.1
# glom
factory-boy==3.3.0
# via -r requirements/test-tools.in
-faker==24.11.0
+faker==26.0.0
# via factory-boy
-flake8==7.0.0
+flake8==7.1.0
# via -r requirements/test-tools.in
flower==2.0.1
# via
# -r requirements/base.txt
# open-api-framework
-freezegun==1.5.0
+freezegun==1.5.1
# via -r requirements/test-tools.in
furl==2.1.3
# via
@@ -326,7 +327,7 @@ glom==23.5.0
# via
# -r requirements/base.txt
# mozilla-django-oidc-db
-humanize==4.9.0
+humanize==4.10.0
# via
# -r requirements/base.txt
# flower
@@ -334,6 +335,7 @@ idna==3.7
# via
# -r requirements/base.txt
# requests
+ # yarl
inflection==0.5.1
# via
# -r requirements/base.txt
@@ -353,7 +355,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
@@ -361,7 +363,7 @@ josepy==1.14.0
# via
# -r requirements/base.txt
# mozilla-django-oidc
-jsonschema==4.21.1
+jsonschema==4.23.0
# via
# -r requirements/base.txt
# drf-spectacular
@@ -377,7 +379,7 @@ markupsafe==2.1.5
# via
# -r requirements/base.txt
# jinja2
-maykin-2fa==1.0.0
+maykin-2fa==1.0.1
# via
# -r requirements/base.txt
# open-api-framework
@@ -387,19 +389,21 @@ mozilla-django-oidc==4.0.1
# via
# -r requirements/base.txt
# mozilla-django-oidc-db
-mozilla-django-oidc-db==0.15.0
+mozilla-django-oidc-db==0.19.0
# via
# -r requirements/base.txt
# open-api-framework
+multidict==6.0.5
+ # via yarl
mypy-extensions==1.0.0
# via black
notifications-api-common==0.2.2
# via
# -r requirements/base.txt
# commonground-api-common
-open-api-framework==0.6.0
+open-api-framework==0.6.1
# via -r requirements/base.txt
-openpyxl==3.1.4
+openpyxl==3.1.5
# via
# -r requirements/base.txt
# tablib
@@ -411,24 +415,24 @@ oyaml==1.0
# via
# -r requirements/base.txt
# commonground-api-common
-packaging==24.0
+packaging==24.1
# via
# -r requirements/base.txt
# black
# drf-yasg
pathspec==0.12.1
# via black
-phonenumberslite==8.13.35
+phonenumberslite==8.13.42
# via
# -r requirements/base.txt
# django-two-factor-auth
-platformdirs==4.2.1
+platformdirs==4.2.2
# via black
prometheus-client==0.20.0
# via
# -r requirements/base.txt
# flower
-prompt-toolkit==3.0.43
+prompt-toolkit==3.0.47
# via
# -r requirements/base.txt
# click-repl
@@ -436,7 +440,7 @@ psycopg2==2.9.9
# via
# -r requirements/base.txt
# open-api-framework
-pycodestyle==2.11.1
+pycodestyle==2.12.0
# via flake8
pycparser==2.22
# via
@@ -450,7 +454,7 @@ pyjwt==2.8.0
# commonground-api-common
# gemma-zds-client
# zgw-consumers
-pyopenssl==24.1.0
+pyopenssl==24.2.1
# via
# -r requirements/base.txt
# josepy
@@ -486,20 +490,21 @@ pyyaml==6.0.1
# drf-yasg
# gemma-zds-client
# oyaml
+ # vcrpy
qrcode==7.4.2
# via
# -r requirements/base.txt
# django-two-factor-auth
-redis==5.0.4
+redis==5.0.8
# via
# -r requirements/base.txt
# django-redis
-referencing==0.35.0
+referencing==0.35.1
# via
# -r requirements/base.txt
# jsonschema
# jsonschema-specifications
-requests==2.31.0
+requests==2.32.3
# via
# -r requirements/base.txt
# ape-pie
@@ -513,12 +518,12 @@ requests==2.31.0
# zgw-consumers
requests-mock==1.12.1
# via -r requirements/test-tools.in
-rpds-py==0.18.0
+rpds-py==0.19.1
# via
# -r requirements/base.txt
# jsonschema
# referencing
-sentry-sdk==2.0.0
+sentry-sdk==2.12.0
# via
# -r requirements/base.txt
# open-api-framework
@@ -532,7 +537,7 @@ six==1.16.0
# python-dateutil
soupsieve==2.5
# via beautifulsoup4
-sqlparse==0.5.0
+sqlparse==0.5.1
# via
# -r requirements/base.txt
# django
@@ -542,13 +547,14 @@ tablib[xlsx]==3.5.0
# django-import-export
tblib==3.0.0
# via -r requirements/test-tools.in
-tornado==6.4
+tornado==6.4.1
# via
# -r requirements/base.txt
# flower
-typing-extensions==4.11.0
+typing-extensions==4.12.2
# via
# -r requirements/base.txt
+ # mozilla-django-oidc-db
# qrcode
# zgw-consumers
tzdata==2024.1
@@ -561,16 +567,18 @@ uritemplate==4.1.1
# coreapi
# drf-spectacular
# drf-yasg
-urllib3==2.2.1
+urllib3==2.2.2
# via
# -r requirements/base.txt
# elastic-apm
# requests
# sentry-sdk
-uwsgi==2.0.25.1
+uwsgi==2.0.26
# 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
@@ -583,7 +591,7 @@ wcwidth==0.2.13
# via
# -r requirements/base.txt
# prompt-toolkit
-webauthn==2.1.0
+webauthn==2.2.0
# via
# -r requirements/base.txt
# django-two-factor-auth
@@ -595,11 +603,14 @@ webob==1.8.7
# via webtest
webtest==3.0.0
# via django-webtest
-wrapt==1.14.1
+wrapt==1.16.0
# via
# -r requirements/base.txt
# elastic-apm
-zgw-consumers==0.33.0
+ # vcrpy
+yarl==1.9.4
+ # via vcrpy
+zgw-consumers==0.34.0
# via
# -r requirements/base.txt
# notifications-api-common
diff --git a/requirements/dev.txt b/requirements/dev.txt
index 7a8e20e..5bc51d2 100644
--- a/requirements/dev.txt
+++ b/requirements/dev.txt
@@ -11,7 +11,7 @@ amqp==5.2.0
# -c requirements/ci.txt
# -r requirements/ci.txt
# kombu
-ape-pie==0.1.0
+ape-pie==0.2.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -21,6 +21,7 @@ asgiref==3.8.1
# -c requirements/ci.txt
# -r requirements/ci.txt
# django
+ # django-axes
# django-cors-headers
asn1crypto==1.5.1
# via
@@ -39,7 +40,7 @@ attrs==23.2.0
# glom
# jsonschema
# referencing
-babel==2.14.0
+babel==2.15.0
# via sphinx
beautifulsoup4==4.12.3
# via
@@ -71,7 +72,7 @@ build==1.2.1
# via pip-tools
bump2version==1.0.1
# via -r requirements/dev.in
-cbor2==5.6.3
+cbor2==5.6.4
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -83,7 +84,7 @@ celery==5.4.0
# flower
# notifications-api-common
# open-api-framework
-certifi==2024.2.2
+certifi==2024.7.4
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -127,7 +128,7 @@ click-repl==0.3.0
# celery
colorama==0.4.6
# via isort
-commonground-api-common==1.13.0
+commonground-api-common==1.13.2
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -142,11 +143,11 @@ coreschema==0.0.4
# -c requirements/ci.txt
# -r requirements/ci.txt
# coreapi
-coverage==4.5.4
+coverage==7.6.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
-cryptography==42.0.5
+cryptography==43.0.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -160,7 +161,7 @@ diff-match-patch==20230430
# -c requirements/ci.txt
# -r requirements/ci.txt
# django-import-export
-django==4.2.11
+django==4.2.14
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -209,17 +210,17 @@ django-appconf==1.0.6
# -c requirements/ci.txt
# -r requirements/ci.txt
# django-log-outgoing-requests
-django-axes==6.4.0
+django-axes==6.5.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# open-api-framework
-django-cors-headers==4.3.1
+django-cors-headers==4.4.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# open-api-framework
-django-debug-toolbar==4.3.0
+django-debug-toolbar==4.4.6
# via -r requirements/dev.in
django-extensions==3.2.3
# via -r requirements/dev.in
@@ -234,7 +235,7 @@ django-formtools==2.5.1
# -c requirements/ci.txt
# -r requirements/ci.txt
# django-two-factor-auth
-django-import-export[xlsx]==4.0.9
+django-import-export[xlsx]==4.1.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -259,7 +260,7 @@ django-ordered-model==3.7.4
# -c requirements/ci.txt
# -r requirements/ci.txt
# django-admin-index
-django-otp==1.5.0
+django-otp==1.5.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -294,17 +295,17 @@ django-sendfile2==0.7.1
# -c requirements/ci.txt
# -r requirements/ci.txt
# django-privates
-django-setup-configuration==0.1.0
+django-setup-configuration==0.3.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# open-api-framework
-django-simple-certmanager==2.0.0
+django-simple-certmanager==2.3.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# zgw-consumers
-django-solo==2.2.0
+django-solo==2.3.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -322,7 +323,7 @@ django-webtest==1.9.11
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
-djangorestframework==3.15.1
+djangorestframework==3.15.2
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -354,7 +355,7 @@ docutils==0.20.1
# via
# sphinx
# sphinx-rtd-theme
-drf-nested-routers==0.93.5
+drf-nested-routers==0.94.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -369,12 +370,12 @@ drf-yasg==1.21.7
# -c requirements/ci.txt
# -r requirements/ci.txt
# commonground-api-common
-ecs-logging==2.1.0
+ecs-logging==2.2.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# elastic-apm
-elastic-apm==6.22.0
+elastic-apm==6.23.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -393,12 +394,12 @@ factory-boy==3.3.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
-faker==24.11.0
+faker==26.0.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# factory-boy
-flake8==7.0.0
+flake8==7.1.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -407,7 +408,7 @@ flower==2.0.1
# -c requirements/ci.txt
# -r requirements/ci.txt
# open-api-framework
-freezegun==1.5.0
+freezegun==1.5.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -431,7 +432,7 @@ glom==23.5.0
# -c requirements/ci.txt
# -r requirements/ci.txt
# mozilla-django-oidc-db
-humanize==4.9.0
+humanize==4.10.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -441,6 +442,7 @@ idna==3.7
# -c requirements/ci.txt
# -r requirements/ci.txt
# requests
+ # yarl
imagesize==1.4.1
# via sphinx
inflection==0.5.1
@@ -469,7 +471,7 @@ itypes==1.2.0
# -c requirements/ci.txt
# -r requirements/ci.txt
# coreapi
-jinja2==3.1.3
+jinja2==3.1.4
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -480,7 +482,7 @@ josepy==1.14.0
# -c requirements/ci.txt
# -r requirements/ci.txt
# mozilla-django-oidc
-jsonschema==4.21.1
+jsonschema==4.23.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -500,7 +502,7 @@ markupsafe==2.1.5
# -c requirements/ci.txt
# -r requirements/ci.txt
# jinja2
-maykin-2fa==1.0.0
+maykin-2fa==1.0.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -515,11 +517,16 @@ mozilla-django-oidc==4.0.1
# -c requirements/ci.txt
# -r requirements/ci.txt
# mozilla-django-oidc-db
-mozilla-django-oidc-db==0.15.0
+mozilla-django-oidc-db==0.19.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# open-api-framework
+multidict==6.0.5
+ # via
+ # -c requirements/ci.txt
+ # -r requirements/ci.txt
+ # yarl
mypy-extensions==1.0.0
# via
# -c requirements/ci.txt
@@ -530,11 +537,11 @@ notifications-api-common==0.2.2
# -c requirements/ci.txt
# -r requirements/ci.txt
# commonground-api-common
-open-api-framework==0.6.0
+open-api-framework==0.6.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
-openpyxl==3.1.4
+openpyxl==3.1.5
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -549,7 +556,7 @@ oyaml==1.0
# -c requirements/ci.txt
# -r requirements/ci.txt
# commonground-api-common
-packaging==24.0
+packaging==24.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -562,14 +569,14 @@ pathspec==0.12.1
# -c requirements/ci.txt
# -r requirements/ci.txt
# black
-phonenumberslite==8.13.35
+phonenumberslite==8.13.42
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# django-two-factor-auth
pip-tools==7.4.1
# via -r requirements/dev.in
-platformdirs==4.2.1
+platformdirs==4.2.2
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -579,7 +586,7 @@ prometheus-client==0.20.0
# -c requirements/ci.txt
# -r requirements/ci.txt
# flower
-prompt-toolkit==3.0.43
+prompt-toolkit==3.0.47
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -589,7 +596,7 @@ psycopg2==2.9.9
# -c requirements/ci.txt
# -r requirements/ci.txt
# open-api-framework
-pycodestyle==2.11.1
+pycodestyle==2.12.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -604,7 +611,7 @@ pyflakes==3.2.0
# -c requirements/ci.txt
# -r requirements/ci.txt
# flake8
-pygments==2.17.2
+pygments==2.18.0
# via sphinx
pyjwt==2.8.0
# via
@@ -613,7 +620,7 @@ pyjwt==2.8.0
# commonground-api-common
# gemma-zds-client
# zgw-consumers
-pyopenssl==24.1.0
+pyopenssl==24.2.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -624,7 +631,7 @@ pypng==0.20220715.0
# -c requirements/ci.txt
# -r requirements/ci.txt
# qrcode
-pyproject-hooks==1.0.0
+pyproject-hooks==1.1.0
# via
# build
# pip-tools
@@ -660,23 +667,24 @@ pyyaml==6.0.1
# drf-yasg
# gemma-zds-client
# oyaml
+ # vcrpy
qrcode==7.4.2
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# django-two-factor-auth
-redis==5.0.4
+redis==5.0.8
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# django-redis
-referencing==0.35.0
+referencing==0.35.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# jsonschema
# jsonschema-specifications
-requests==2.31.0
+requests==2.32.3
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -694,13 +702,13 @@ requests-mock==1.12.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
-rpds-py==0.18.0
+rpds-py==0.19.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# jsonschema
# referencing
-sentry-sdk==2.0.0
+sentry-sdk==2.12.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -723,28 +731,28 @@ soupsieve==2.5
# -c requirements/ci.txt
# -r requirements/ci.txt
# beautifulsoup4
-sphinx==7.3.7
+sphinx==7.4.7
# via
# -r requirements/dev.in
# sphinx-rtd-theme
# sphinxcontrib-jquery
sphinx-rtd-theme==2.0.0
# via -r requirements/dev.in
-sphinxcontrib-applehelp==1.0.8
+sphinxcontrib-applehelp==2.0.0
# via sphinx
-sphinxcontrib-devhelp==1.0.6
+sphinxcontrib-devhelp==2.0.0
# via sphinx
-sphinxcontrib-htmlhelp==2.0.5
+sphinxcontrib-htmlhelp==2.1.0
# via sphinx
sphinxcontrib-jquery==4.1
# via sphinx-rtd-theme
sphinxcontrib-jsmath==1.0.1
# via sphinx
-sphinxcontrib-qthelp==1.0.7
+sphinxcontrib-qthelp==2.0.0
# via sphinx
-sphinxcontrib-serializinghtml==1.1.10
+sphinxcontrib-serializinghtml==2.0.0
# via sphinx
-sqlparse==0.5.0
+sqlparse==0.5.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -759,15 +767,16 @@ tblib==3.0.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
-tornado==6.4
+tornado==6.4.1
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# flower
-typing-extensions==4.11.0
+typing-extensions==4.12.2
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
+ # mozilla-django-oidc-db
# qrcode
# zgw-consumers
tzdata==2024.1
@@ -782,18 +791,22 @@ uritemplate==4.1.1
# coreapi
# drf-spectacular
# drf-yasg
-urllib3==2.2.1
+urllib3==2.2.2
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# elastic-apm
# requests
# sentry-sdk
-uwsgi==2.0.25.1
+uwsgi==2.0.26
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# open-api-framework
+vcrpy==6.0.1
+ # via
+ # -c requirements/ci.txt
+ # -r requirements/ci.txt
vine==5.1.0
# via
# -c requirements/ci.txt
@@ -811,7 +824,7 @@ wcwidth==0.2.13
# -c requirements/ci.txt
# -r requirements/ci.txt
# prompt-toolkit
-webauthn==2.1.0
+webauthn==2.2.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -833,12 +846,18 @@ webtest==3.0.0
# django-webtest
wheel==0.43.0
# via pip-tools
-wrapt==1.14.1
+wrapt==1.16.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
# elastic-apm
-zgw-consumers==0.33.0
+ # vcrpy
+yarl==1.9.4
+ # via
+ # -c requirements/ci.txt
+ # -r requirements/ci.txt
+ # vcrpy
+zgw-consumers==0.34.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
@@ -846,7 +865,7 @@ zgw-consumers==0.33.0
# open-api-framework
# The following packages are considered to be unsafe in a requirements file:
-pip==24.0
+pip==24.2
# via pip-tools
-setuptools==69.5.1
+setuptools==72.1.0
# via pip-tools
diff --git a/requirements/test-tools.in b/requirements/test-tools.in
index 7bacb7c..e5fc74f 100644
--- a/requirements/test-tools.in
+++ b/requirements/test-tools.in
@@ -5,6 +5,7 @@ factory-boy
freezegun
requests-mock
tblib
+vcrpy
# Code formatting
isort
diff --git a/src/referentielijsten/accounts/tests/keycloak_cassets/duplicate_email.yaml b/src/referentielijsten/accounts/tests/keycloak_cassets/duplicate_email.yaml
new file mode 100644
index 0000000..a0d778a
--- /dev/null
+++ b/src/referentielijsten/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/referentielijsten/accounts/tests/keycloak_cassets/happy_flow.yaml b/src/referentielijsten/accounts/tests/keycloak_cassets/happy_flow.yaml
new file mode 100644
index 0000000..b38df63
--- /dev/null
+++ b/src/referentielijsten/accounts/tests/keycloak_cassets/happy_flow.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=5cb27876-547b-4f65-9ca3-8ee5f6dc5a47; Version=1; Path=/realms/test/;
+ SameSite=None; Secure; HttpOnly
+ - AUTH_SESSION_ID_LEGACY=5cb27876-547b-4f65-9ca3-8ee5f6dc5a47; 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=5cb27876-547b-4f65-9ca3-8ee5f6dc5a47; 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=d7ajMtpQMR0KvTmiUVY1HMd1awnC92vmTIfXKQsVZW0&execution=670fb55e-641e-4beb-bd17-3c0cb001b805&client_id=testid&tab_id=1ROlbtHm-BU
+ 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=5cb27876-547b-4f65-9ca3-8ee5f6dc5a47&iss=http%3A%2F%2Flocalhost%3A8080%2Frealms%2Ftest&code=cbf9bede-0d10-4085-907f-83d0f48f5dc5.5cb27876-547b-4f65-9ca3-8ee5f6dc5a47.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.eyJleHAiOjE3MjAxNTU4MzMsImlhdCI6MTcyMDExOTgzMywianRpIjoiMzg4ZjcxN2ItZTc3YS00NDVlLWFjZWQtZTQ5Y2UzMDY3NTExIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiU2VyaWFsaXplZC1JRCIsInNlc3Npb25fc3RhdGUiOiI1Y2IyNzg3Ni01NDdiLTRmNjUtOWNhMy04ZWU1ZjZkYzVhNDciLCJzaWQiOiI1Y2IyNzg3Ni01NDdiLTRmNjUtOWNhMy04ZWU1ZjZkYzVhNDciLCJzdGF0ZV9jaGVja2VyIjoiSFFFcXpUSHJsU0gtT3ZieS11ekQ5NlVqaWRtYW9DZ2NRZlk4dzNEcDJlNCJ9.jebeEc6dM0E3w99U2jGHpjiuIQH8uUhXa_YdcdIJl3s;
+ Version=1; Path=/realms/test/; SameSite=None; Secure; HttpOnly
+ - KEYCLOAK_IDENTITY_LEGACY=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjAxNTU4MzMsImlhdCI6MTcyMDExOTgzMywianRpIjoiMzg4ZjcxN2ItZTc3YS00NDVlLWFjZWQtZTQ5Y2UzMDY3NTExIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiU2VyaWFsaXplZC1JRCIsInNlc3Npb25fc3RhdGUiOiI1Y2IyNzg3Ni01NDdiLTRmNjUtOWNhMy04ZWU1ZjZkYzVhNDciLCJzaWQiOiI1Y2IyNzg3Ni01NDdiLTRmNjUtOWNhMy04ZWU1ZjZkYzVhNDciLCJzdGF0ZV9jaGVja2VyIjoiSFFFcXpUSHJsU0gtT3ZieS11ekQ5NlVqaWRtYW9DZ2NRZlk4dzNEcDJlNCJ9.jebeEc6dM0E3w99U2jGHpjiuIQH8uUhXa_YdcdIJl3s;
+ Version=1; Path=/realms/test/; HttpOnly
+ - KEYCLOAK_SESSION=test/6db2db87-de31-4e30-9f25-cefe5da8b154/5cb27876-547b-4f65-9ca3-8ee5f6dc5a47;
+ 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/5cb27876-547b-4f65-9ca3-8ee5f6dc5a47;
+ 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=cbf9bede-0d10-4085-907f-83d0f48f5dc5.5cb27876-547b-4f65-9ca3-8ee5f6dc5a47.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.eyJleHAiOjE3MjAxMjAxMzMsImlhdCI6MTcyMDExOTgzMywiYXV0aF90aW1lIjoxNzIwMTE5ODMzLCJqdGkiOiJlNmFiMzhlOS1iYjE3LTQwYzYtYWQ4ZS05N2E1ZDA5NTAzMWIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGVzdGlkIiwibm9uY2UiOiJub3QtYS1yYW5kb20tc3RyaW5nIiwic2Vzc2lvbl9zdGF0ZSI6IjVjYjI3ODc2LTU0N2ItNGY2NS05Y2EzLThlZTVmNmRjNWE0NyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovLzEyNy4wLjAuMTo4MDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSBrdmsgZ3JvdXBzIGJzbiIsInNpZCI6IjVjYjI3ODc2LTU0N2ItNGY2NS05Y2EzLThlZTVmNmRjNWE0NyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJncm91cHMiOlsiUmVnaXN0cmVlcmRlcnMiLCJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl0sInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBleGFtcGxlLmNvbSJ9.rYMU92-R4LnPNpM2qri8MbDB4btdO4rF2lNtSn_hsQUCVFZg4d0uMjphwVIwf8we2EsdkfT_IfEqHiBMb6u7hHKVhAXX45rvCvDkByw3yhY6cWsN52aNRuvzXDfLY_XkjTKV8NRGLN88xk7XupjeBKYYOJZxqeaoKgLjC3VehyvjT_wcb69LCNuIp2eF5mKYoPhzS94mVuuz4g6QIY31z7EOR4Trfy2T_rmUWdQJKZQXZgTWK_mNRQUX5l2MaxZIn_9jXwmbApGsJlSr7cPZmvvYQwnnqBDgn9FbuxYJYOVWWIk5WvHikKcs_5Yy425bNgQeAQuuOkE2muen6BNvIQ","expires_in":300,"refresh_expires_in":1800,"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlNzE1ZTA1MS02Y2RiLTQ4Y2MtYjRmNC1mMDcyMmM4MWY5ZDMifQ.eyJleHAiOjE3MjAxMjE2MzMsImlhdCI6MTcyMDExOTgzMywianRpIjoiYjIxZjQxNGUtMTkyMy00MTQzLWIwMmQtM2NjNjg3ODIwYTIxIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL3JlYWxtcy90ZXN0Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InRlc3RpZCIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsInNlc3Npb25fc3RhdGUiOiI1Y2IyNzg3Ni01NDdiLTRmNjUtOWNhMy04ZWU1ZjZkYzVhNDciLCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIGt2ayBncm91cHMgYnNuIiwic2lkIjoiNWNiMjc4NzYtNTQ3Yi00ZjY1LTljYTMtOGVlNWY2ZGM1YTQ3In0.qauc8QuFnFEYbwUn2VwTHfcayal0EuXLOMactj3mvI4","token_type":"Bearer","id_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0VU5RQWN2VWN2LURGVU94XzRPMWd0MTNPZEpTb3RxRUtQWnVyczJ2UVc4In0.eyJleHAiOjE3MjAxMjAxMzMsImlhdCI6MTcyMDExOTgzMywiYXV0aF90aW1lIjoxNzIwMTE5ODMzLCJqdGkiOiI3OWZjYTAwMC0yZDE2LTQ4OWItODkwYi1kOGQxZWFjNDVlMTIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJ0ZXN0aWQiLCJzdWIiOiI2ZGIyZGI4Ny1kZTMxLTRlMzAtOWYyNS1jZWZlNWRhOGIxNTQiLCJ0eXAiOiJJRCIsImF6cCI6InRlc3RpZCIsIm5vbmNlIjoibm90LWEtcmFuZG9tLXN0cmluZyIsInNlc3Npb25fc3RhdGUiOiI1Y2IyNzg3Ni01NDdiLTRmNjUtOWNhMy04ZWU1ZjZkYzVhNDciLCJhdF9oYXNoIjoiV1gwMG5IYi1pckU4ZEVnb2RMeXhGUSIsImFjciI6IjEiLCJzaWQiOiI1Y2IyNzg3Ni01NDdiLTRmNjUtOWNhMy04ZWU1ZjZkYzVhNDciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZ3JvdXBzIjpbIlJlZ2lzdHJlZXJkZXJzIiwiZGVmYXVsdC1yb2xlcy10ZXN0Iiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20ifQ.zI_btIoIRd_3Zh2Kcj1_zORT8tFAcRKPWPeXOrmGVpbe7TPIcIDL6bRoyyDFQgT_QCiIgD5SZ1SGrOuUu1eMkfGEc3fdwpbQhCwjAOudngvgSJ21e6NcBpn4eEOkwPOS2CUXV472xCgiK9EICYLJMmWg_qR5ct83ee6IGIoHpAg1tPtoGnm6k_gPGCGIkssQYE80yB8gdBmb2ldwRR1B1SqLg0G4kKzeLAK3PnoudJJ3g7_fKG6tvu4Vj4Tb3Pvl9o09NvAjyII-N6hsxzxmR2J1KUz80oIdiu-yT8xNVUkLWwFddxvN1H2_k3gIMdlkBW711FMtC-3kbrvIi8KhtQ","not-before-policy":0,"session_state":"5cb27876-547b-4f65-9ca3-8ee5f6dc5a47","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.eyJleHAiOjE3MjAxMjAxMzMsImlhdCI6MTcyMDExOTgzMywiYXV0aF90aW1lIjoxNzIwMTE5ODMzLCJqdGkiOiJlNmFiMzhlOS1iYjE3LTQwYzYtYWQ4ZS05N2E1ZDA5NTAzMWIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVhbG1zL3Rlc3QiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNmRiMmRiODctZGUzMS00ZTMwLTlmMjUtY2VmZTVkYThiMTU0IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidGVzdGlkIiwibm9uY2UiOiJub3QtYS1yYW5kb20tc3RyaW5nIiwic2Vzc2lvbl9zdGF0ZSI6IjVjYjI3ODc2LTU0N2ItNGY2NS05Y2EzLThlZTVmNmRjNWE0NyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovLzEyNy4wLjAuMTo4MDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSBrdmsgZ3JvdXBzIGJzbiIsInNpZCI6IjVjYjI3ODc2LTU0N2ItNGY2NS05Y2EzLThlZTVmNmRjNWE0NyIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJncm91cHMiOlsiUmVnaXN0cmVlcmRlcnMiLCJkZWZhdWx0LXJvbGVzLXRlc3QiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl0sInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbkBleGFtcGxlLmNvbSJ9.rYMU92-R4LnPNpM2qri8MbDB4btdO4rF2lNtSn_hsQUCVFZg4d0uMjphwVIwf8we2EsdkfT_IfEqHiBMb6u7hHKVhAXX45rvCvDkByw3yhY6cWsN52aNRuvzXDfLY_XkjTKV8NRGLN88xk7XupjeBKYYOJZxqeaoKgLjC3VehyvjT_wcb69LCNuIp2eF5mKYoPhzS94mVuuz4g6QIY31z7EOR4Trfy2T_rmUWdQJKZQXZgTWK_mNRQUX5l2MaxZIn_9jXwmbApGsJlSr7cPZmvvYQwnnqBDgn9FbuxYJYOVWWIk5WvHikKcs_5Yy425bNgQeAQuuOkE2muen6BNvIQ
+ 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/referentielijsten/accounts/tests/keycloak_cassets/happy_flow_existing_user.yaml b/src/referentielijsten/accounts/tests/keycloak_cassets/happy_flow_existing_user.yaml
new file mode 100644
index 0000000..fd49080
--- /dev/null
+++ b/src/referentielijsten/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/referentielijsten/accounts/tests/test_oidc.py b/src/referentielijsten/accounts/tests/test_oidc.py
index 4dda1a1..2e784cd 100644
--- a/src/referentielijsten/accounts/tests/test_oidc.py
+++ b/src/referentielijsten/accounts/tests/test_oidc.py
@@ -1,15 +1,30 @@
-from unittest.mock import patch
+from functools import partial
+from pathlib import Path
-from django.test import TestCase
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 referentielijsten.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):
@@ -48,150 +63,84 @@ def test_oidc_button_enabled(self):
)
-class OIDCFLowTests(TestCase):
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.get_userinfo")
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.store_tokens")
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.verify_token")
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.get_token")
- @patch(
- "mozilla_django_oidc_db.mixins.OpenIDConnectConfig.get_solo",
- return_value=OpenIDConnectConfig(id=1, enabled=True),
- )
- def test_duplicate_email_unique_constraint_violated(
- self,
- mock_get_solo,
- mock_get_token,
- mock_verify_token,
- mock_store_tokens,
- mock_get_userinfo,
- ):
- # set up a user with a colliding email address
- mock_get_userinfo.return_value = {
- "email": "collision@example.com",
- "sub": "some_username",
- }
- StaffUserFactory.create(
- username="nonmatchingusername", email="collision@example.com"
+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"
)
- session = self.client.session
- session["oidc_states"] = {"mock": {"nonce": "nonce"}}
- session.save()
- callback_url = reverse("oidc_authentication_callback")
-
- # enter the login flow
- callback_response = self.client.get(
- callback_url, {"code": "mock", "state": "mock"}
+ 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_url = reverse("admin-oidc-error")
-
- with self.subTest("error redirects"):
- self.assertRedirects(callback_response, error_url)
-
- with self.subTest("exception info on error page"):
- error_page = self.client.get(error_url)
+ 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"""
- """"\nDETAIL: Key (email)=(collision@example.com) already exists.\n""",
+ '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"
)
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.get_userinfo")
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.store_tokens")
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.verify_token")
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.get_token")
- @patch(
- "mozilla_django_oidc_db.mixins.OpenIDConnectConfig.get_solo",
- return_value=OpenIDConnectConfig(id=1, enabled=True),
- )
- def test_happy_flow(
- self,
- mock_get_solo,
- mock_get_token,
- mock_verify_token,
- mock_store_tokens,
- mock_get_userinfo,
- ):
- # set up a user with a colliding email address
- mock_get_userinfo.return_value = {
- "email": "nocollision@example.com",
- "sub": "some_username",
- }
- StaffUserFactory.create(
- username="nonmatchingusername", email="collision@example.com"
+ 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")
)
- session = self.client.session
- session["oidc_states"] = {"mock": {"nonce": "nonce"}}
- session.save()
- callback_url = reverse("oidc_authentication_callback")
-
- # enter the login flow
- callback_response = self.client.get(
- callback_url, {"code": "mock", "state": "mock"}
+ assert start_response.status_code == 302
+ redirect_uri = keycloak_login(
+ start_response["Location"], username="admin", password="admin"
)
- self.assertRedirects(
- callback_response, reverse("admin:index"), fetch_redirect_response=False
+ 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"
)
- self.assertTrue(User.objects.filter(email="nocollision@example.com").exists())
-
- def test_error_page_direct_access_forbidden(self):
- error_url = reverse("admin-oidc-error")
-
- response = self.client.get(error_url)
-
- self.assertEqual(response.status_code, 403)
-
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.get_userinfo")
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.store_tokens")
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.verify_token")
- @patch("mozilla_django_oidc_db.backends.OIDCAuthenticationBackend.get_token")
- @patch(
- "mozilla_django_oidc_db.mixins.OpenIDConnectConfig.get_solo",
- return_value=OpenIDConnectConfig(id=1, enabled=True),
- )
- def test_error_first_cleared_after_succesful_login(
- self,
- mock_get_solo,
- mock_get_token,
- mock_verify_token,
- mock_store_tokens,
- mock_get_userinfo,
- ):
- mock_get_userinfo.return_value = {
- "email": "nocollision@example.com",
- "sub": "some_username",
- }
- session = self.client.session
- session["oidc-error"] = "some error"
- session.save()
- error_url = reverse("admin-oidc-error")
-
- with self.subTest("with error"):
- response = self.client.get(error_url)
-
- self.assertEqual(response.status_code, 200)
-
- with self.subTest("after succesful login"):
- session["oidc_states"] = {"mock": {"nonce": "nonce"}}
- session.save()
- callback_url = reverse("oidc_authentication_callback")
-
- # enter the login flow
- callback_response = self.client.get(
- callback_url, {"code": "mock", "state": "mock"}
- )
- self.assertRedirects(
- callback_response, reverse("admin:index"), fetch_redirect_response=False
- )
+ admin_index = self.app.get(redirect_uri, auto_follow=True)
- with self.subTest("check error page again"):
- response = self.client.get(error_url)
+ self.assertEqual(admin_index.status_code, 200)
+ self.assertEqual(admin_index.request.path, reverse("admin:index"))
- self.assertEqual(response.status_code, 403)
+ 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/referentielijsten/urls.py b/src/referentielijsten/urls.py
index a439df6..43ccf46 100644
--- a/src/referentielijsten/urls.py
+++ b/src/referentielijsten/urls.py
@@ -37,9 +37,9 @@
name="password_reset_done",
),
# Use custom login views for the admin + support hardware tokens
+ path("admin/login/failure/", AdminLoginFailure.as_view(), name="admin-oidc-error"),
path("admin/", include((urlpatterns, "maykin_2fa"))),
path("admin/", include((webauthn_urlpatterns, "two_factor"))),
- path("admin/login/failure/", AdminLoginFailure.as_view(), name="admin-oidc-error"),
path("admin/", admin.site.urls),
path(
"reset///",
diff --git a/src/referentielijsten/utils/tests/keycloak.py b/src/referentielijsten/utils/tests/keycloak.py
new file mode 100644
index 0000000..73633ed
--- /dev/null
+++ b/src/referentielijsten/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