From cd829a3c9ac99384d3578b391a232ab74f403bc1 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 15 Aug 2022 11:33:44 +0200 Subject: [PATCH 01/10] WIP: Update config --- server/config/settings/base.py | 4 +++- server/vbv_lernwelt/sso/client.py | 11 ++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/server/config/settings/base.py b/server/config/settings/base.py index 86cc8254..c19d9792 100644 --- a/server/config/settings/base.py +++ b/server/config/settings/base.py @@ -525,12 +525,14 @@ OAUTH = { "access_token_url": env("IT_OAUTH_ACCESS_TOKEN_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/protocol/openid-connect/token"), "authorize_url": env("IT_OAUTH_AUTHORIZE_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/protocol/openid-connect/auth"), "authorize_params": IT_OAUTH_AUTHORIZE_PARAMS, + "access_token_params": IT_OAUTH_AUTHORIZE_PARAMS, "api_base_url": env("IT_OAUTH_API_BASE_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/protocol/openid-connect/"), "local_redirect_uri": env("IT_OAUTH_LOCAL_DIRECT_URI", default="http://localhost:8000/sso/callback/"), + "server_metadata_url": env("IT_OAUTH_SERVER_METADATA_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/.well-known/openid-configuration"), "client_kwargs": { 'scope': env("IT_OAUTH_SCOPE", default=''), 'token_endpoint_auth_method': 'client_secret_post', - 'token_placement': 'header', + 'token_placement': 'body', } } diff --git a/server/vbv_lernwelt/sso/client.py b/server/vbv_lernwelt/sso/client.py index 0170f2e3..71d1954a 100644 --- a/server/vbv_lernwelt/sso/client.py +++ b/server/vbv_lernwelt/sso/client.py @@ -20,10 +20,11 @@ oauth.register( client_secret=settings.OAUTH["client_secret"], request_token_url=None, request_token_params=None, - access_token_url=settings.OAUTH["access_token_url"], - access_token_params=None, - authorize_url=settings.OAUTH["authorize_url"], + # access_token_url=settings.OAUTH["access_token_url"], + access_token_params=settings.OAUTH["access_token_params"], + # authorize_url=settings.OAUTH["authorize_url"], authorize_params=settings.OAUTH["authorize_params"], - api_base_url=settings.OAUTH["api_base_url"], - client_kwargs=settings.OAUTH["client_kwargs"] + # api_base_url=settings.OAUTH["api_base_url"], + client_kwargs=settings.OAUTH["client_kwargs"], + server_metadata_url=settings.OAUTH["server_metadata_url"], ) From b06db37d0550a4c225d72dc6d00d80b5b7f2f85c Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 15 Aug 2022 11:42:34 +0200 Subject: [PATCH 02/10] WIP: Add test url --- server/config/settings/base.py | 4 ++-- server/vbv_lernwelt/sso/urls.py | 1 + server/vbv_lernwelt/sso/views.py | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/server/config/settings/base.py b/server/config/settings/base.py index c19d9792..9efc8117 100644 --- a/server/config/settings/base.py +++ b/server/config/settings/base.py @@ -522,8 +522,8 @@ OAUTH = { "client_name": env("IT_OAUTH_CLIENT_NAME", default="lernetz"), "client_id": env("IT_OAUTH_CLIENT_ID", default="iterativ"), "client_secret": env("IT_OAUTH_CLIENT_SECRET", default=""), - "access_token_url": env("IT_OAUTH_ACCESS_TOKEN_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/protocol/openid-connect/token"), - "authorize_url": env("IT_OAUTH_AUTHORIZE_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/protocol/openid-connect/auth"), + # "access_token_url": env("IT_OAUTH_ACCESS_TOKEN_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/protocol/openid-connect/token"), + # "authorize_url": env("IT_OAUTH_AUTHORIZE_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/protocol/openid-connect/auth"), "authorize_params": IT_OAUTH_AUTHORIZE_PARAMS, "access_token_params": IT_OAUTH_AUTHORIZE_PARAMS, "api_base_url": env("IT_OAUTH_API_BASE_URL", default="https://sso.test.b.lernetz.host/auth/realms/vbv/protocol/openid-connect/"), diff --git a/server/vbv_lernwelt/sso/urls.py b/server/vbv_lernwelt/sso/urls.py index 56785481..44f0d80e 100644 --- a/server/vbv_lernwelt/sso/urls.py +++ b/server/vbv_lernwelt/sso/urls.py @@ -7,4 +7,5 @@ app_name = 'sso' urlpatterns = [ path(r'login/', django_view_authentication_exempt(views.login), name='login'), path(r'callback/', django_view_authentication_exempt(views.authorize), name='authorize'), + path(r'foo/', django_view_authentication_exempt(views.foo), name='foo'), ] diff --git a/server/vbv_lernwelt/sso/views.py b/server/vbv_lernwelt/sso/views.py index 96298586..b3cb51c0 100644 --- a/server/vbv_lernwelt/sso/views.py +++ b/server/vbv_lernwelt/sso/views.py @@ -2,6 +2,7 @@ import structlog as structlog from authlib.integrations.base_client import OAuthError from django.conf import settings from django.shortcuts import redirect +from django.http import HttpResponse from sentry_sdk import capture_exception from django.contrib.auth import login as dj_login, get_user_model @@ -40,6 +41,10 @@ def authorize(request): return redirect(f'/{OAUTH_SUCCESS_REDIRECT}?state=success') # to be defined +def foo(request): + return HttpResponse(settings.OAUTH["server_metadata_url"]) + + def _user_data_from_token_data(token: dict) -> dict: return { "first_name": token.get("given_name", ""), From 67b8aa9f8d215d2fe55bc91b9172c18119382dd2 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 15 Aug 2022 13:02:52 +0200 Subject: [PATCH 03/10] Remove test data, read correct string --- server/vbv_lernwelt/sso/client.py | 4 ---- server/vbv_lernwelt/sso/urls.py | 1 - server/vbv_lernwelt/sso/views.py | 8 ++------ 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/server/vbv_lernwelt/sso/client.py b/server/vbv_lernwelt/sso/client.py index 71d1954a..123c06ff 100644 --- a/server/vbv_lernwelt/sso/client.py +++ b/server/vbv_lernwelt/sso/client.py @@ -20,11 +20,7 @@ oauth.register( client_secret=settings.OAUTH["client_secret"], request_token_url=None, request_token_params=None, - # access_token_url=settings.OAUTH["access_token_url"], - access_token_params=settings.OAUTH["access_token_params"], - # authorize_url=settings.OAUTH["authorize_url"], authorize_params=settings.OAUTH["authorize_params"], - # api_base_url=settings.OAUTH["api_base_url"], client_kwargs=settings.OAUTH["client_kwargs"], server_metadata_url=settings.OAUTH["server_metadata_url"], ) diff --git a/server/vbv_lernwelt/sso/urls.py b/server/vbv_lernwelt/sso/urls.py index 44f0d80e..56785481 100644 --- a/server/vbv_lernwelt/sso/urls.py +++ b/server/vbv_lernwelt/sso/urls.py @@ -7,5 +7,4 @@ app_name = 'sso' urlpatterns = [ path(r'login/', django_view_authentication_exempt(views.login), name='login'), path(r'callback/', django_view_authentication_exempt(views.authorize), name='authorize'), - path(r'foo/', django_view_authentication_exempt(views.foo), name='foo'), ] diff --git a/server/vbv_lernwelt/sso/views.py b/server/vbv_lernwelt/sso/views.py index b3cb51c0..21edd544 100644 --- a/server/vbv_lernwelt/sso/views.py +++ b/server/vbv_lernwelt/sso/views.py @@ -25,7 +25,7 @@ def authorize(request): try: logger.debug(request) token = getattr(oauth, settings.OAUTH["client_name"]).authorize_access_token(request) - deocded_token = decode_jwt(token["access_token"]) + deocded_token = decode_jwt(token["id_token"]) except OAuthError as e: logger.error(f'OAuth error: {e}') if not settings.DEBUG: @@ -41,14 +41,10 @@ def authorize(request): return redirect(f'/{OAUTH_SUCCESS_REDIRECT}?state=success') # to be defined -def foo(request): - return HttpResponse(settings.OAUTH["server_metadata_url"]) - - def _user_data_from_token_data(token: dict) -> dict: return { "first_name": token.get("given_name", ""), "last_name": token.get("family_name", ""), "username": token.get("preferred_username", ""), - "email": token.get("email", ""), + "email": token.get("emails", [])[""], } From 3280fc44fa6e3f85cf0bcc3cfa502d02b7de5402 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Tue, 16 Aug 2022 08:00:05 +0200 Subject: [PATCH 04/10] Fix get email, remove versions from deploy script --- caprover_deploy.sh | 5 ++--- server/vbv_lernwelt/sso/views.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/caprover_deploy.sh b/caprover_deploy.sh index 70a9ac69..dd6c138e 100755 --- a/caprover_deploy.sh +++ b/caprover_deploy.sh @@ -13,10 +13,9 @@ set -ev npm run build # create and push new docker container -docker buildx build --platform=linux/amd64 -f compose/django/Dockerfile -t "$TAG" -t "$LATEST" --build-arg VERSION="$VERSION" --build-arg BUILD_TIMESTAMP="$BUILD_TIMESTAMP" . +# docker buildx build --platform=linux/amd64 -f compose/django/Dockerfile -t "$TAG" -t "$LATEST" --build-arg VERSION="$VERSION" --build-arg BUILD_TIMESTAMP="$BUILD_TIMESTAMP" . +docker buildx build --platform=linux/amd64 -f compose/django/Dockerfile . docker push iterativ/vbv-lernwelt-django -docker push "$TAG" -docker push "$LATEST" # deploy to caprover caprover deploy -h https://captain.control.iterativ.ch -a vbv-lernwelt -i docker.io/iterativ/vbv-lernwelt-django diff --git a/server/vbv_lernwelt/sso/views.py b/server/vbv_lernwelt/sso/views.py index 21edd544..b37b41c2 100644 --- a/server/vbv_lernwelt/sso/views.py +++ b/server/vbv_lernwelt/sso/views.py @@ -46,5 +46,5 @@ def _user_data_from_token_data(token: dict) -> dict: "first_name": token.get("given_name", ""), "last_name": token.get("family_name", ""), "username": token.get("preferred_username", ""), - "email": token.get("emails", [])[""], + "email": token.get("emails", [''])[0], } From ec5b659ff083298bfea6b44b7751949f8574c7f0 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Tue, 16 Aug 2022 15:43:30 +0200 Subject: [PATCH 05/10] Fix background scroll on modal --- .../src/components/ui/ItFullScreenModal.vue | 22 ++++++++++++++++++- client/tailwind.css | 7 ++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/client/src/components/ui/ItFullScreenModal.vue b/client/src/components/ui/ItFullScreenModal.vue index 53ff4e5a..3aec3ba2 100644 --- a/client/src/components/ui/ItFullScreenModal.vue +++ b/client/src/components/ui/ItFullScreenModal.vue @@ -1,12 +1,32 @@ From 38d5fc3369971e014587a76e4df761021a78680b Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Thu, 18 Aug 2022 11:09:38 +0200 Subject: [PATCH 10/10] Add logout --- client/src/components/MainNavigationBar.vue | 8 ++++++-- client/src/components/MobileMenu.vue | 20 +++++++++++++------- client/src/stores/user.ts | 17 +++++++++++++---- server/config/urls.py | 3 ++- server/vbv_lernwelt/core/views.py | 8 +++++++- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/client/src/components/MainNavigationBar.vue b/client/src/components/MainNavigationBar.vue index d725dfd0..ec3a2f6b 100644 --- a/client/src/components/MainNavigationBar.vue +++ b/client/src/components/MainNavigationBar.vue @@ -58,13 +58,17 @@ function handleDropdownSelect(data) { router.push('/profile') break case 'logout': - router.push('/logout') + userStore.handleLogout(); break default: console.log('no action') } } +function logout () { + userStore.handleLogout(); +} + onMounted(() => { log.debug('MainNavigationBar mounted'); }) @@ -96,7 +100,7 @@ const profileDropdownData = [
() @@ -29,17 +29,19 @@ const clickLink = (to: string) => { >
-
+
-

{{user.first_name}} {{user.last_name}}

+

{{userStore.first_name}} {{userStore.last_name}}

-
+
+
diff --git a/client/src/stores/user.ts b/client/src/stores/user.ts index c756a08a..8097dba7 100644 --- a/client/src/stores/user.ts +++ b/client/src/stores/user.ts @@ -14,16 +14,18 @@ export type UserState = { loggedIn: boolean; } -export const useUserStore = defineStore({ - id: 'user', - state: () => ({ +const initialUserState: UserState = { email: '', first_name: '', last_name: '', username: '', avatar_url: '', loggedIn: false - } as UserState), + } + +export const useUserStore = defineStore({ + id: 'user', + state: () => (initialUserState as UserState), getters: { getFullName(): string { return `${this.first_name} ${this.last_name}`.trim(); @@ -46,6 +48,13 @@ export const useUserStore = defineStore({ }); } }, + handleLogout() { + itPost('/core/logout/', {}) + .then(data => { + Object.assign(this, initialUserState); + window.location.href = '/'; + }) + }, fetchUser() { const appStore = useAppStore(); itGet('/api/core/me/').then((data) => { diff --git a/server/config/urls.py b/server/config/urls.py index f99b3bdb..d5aeada9 100644 --- a/server/config/urls.py +++ b/server/config/urls.py @@ -16,7 +16,7 @@ from vbv_lernwelt.core.middleware.auth import django_view_authentication_exempt from vbv_lernwelt.core.views import ( rate_limit_exceeded_view, permission_denied_view, - check_rate_limit, cypress_reset_view, vue_home, vue_login, me_user_view, ) + check_rate_limit, cypress_reset_view, vue_home, vue_login, me_user_view, vue_logout, ) from .wagtail_api import wagtail_api_router @@ -42,6 +42,7 @@ urlpatterns = [ path('learnpath/', include("vbv_lernwelt.learnpath.urls")), path('api/completion/', include("vbv_lernwelt.completion.urls")), re_path(r'api/core/me/$', me_user_view, name='me_user_view'), + re_path(r'core/logout/$', vue_logout, name='vue_logout'), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) if settings.DEBUG: # Static file serving when using Gunicorn + Uvicorn for local web socket development diff --git a/server/vbv_lernwelt/core/views.py b/server/vbv_lernwelt/core/views.py index 36c3a3b9..4e035fd5 100644 --- a/server/vbv_lernwelt/core/views.py +++ b/server/vbv_lernwelt/core/views.py @@ -3,7 +3,7 @@ import requests import structlog from django.conf import settings -from django.contrib.auth import authenticate, login +from django.contrib.auth import authenticate, login, logout from django.core.management import call_command from django.http import JsonResponse, HttpResponse, HttpResponseRedirect from django.shortcuts import render @@ -69,6 +69,12 @@ def me_user_view(request): return Response(status=403) +@api_view(['POST']) +def vue_logout(request): + logout(request) + return Response({'success': True}, 200) + + def permission_denied_view(request, exception): return render(request, "403.html", status=403)